12 December 2020 ; tagged in: advent of code , haskell

Advent of Code 2020 day 6

First steps with Attoparsec

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

Code

You can find the code here or on Gitlab.