Advent of Code 2020 day 6

    Day 6 was another input file of groups separated by blank lines. As I mentioned on day 4, this isn't what Megaparsec is good for, so time to try out Attoparsec.

    Without space consumers to worry about, and therefore more control over how and when whitespace is consumed, the parser ended up much neater than the Megaparsec version would have been. Conversely, it's a quite fragile parser: changes in the positioning of whitespace would cause the parsing to fail.

    blankLines = skipMany1 endOfLine
    personP = S.fromList <$> many1 letter
    groupP = sepBy1 personP endOfLine
    groupsP = sepBy groupP blankLines

    I think that's quite readable: a person is a set of letters. A group is a collection of people, separated by single newlines. Groups are separated by at least one blank line.

    Given a list of list of sets of questions, we're back to territory where the code is much shorter than the explanation. I can find all the questions answered by a group by finding the S.unions of the group; I count them with S.size. That's mappped over all the groups and the counts summed.

    part1 groups = sum $ map (S.size . S.unions) groups

    Part 2 is the same, only there isn't an S.intersections function already in the library (what would the base case be, for a general Foldable?). So I had to build one.

    part2 groups = sum $ map (S.size . intersections) groups
    intersections :: Ord a => [S.Set a] -> S.Set a
    intersections group = foldl S.intersection (head group) group


    You can find the code here or on Gitlab.

    Neil Smith

    Read more posts by this author.