day2: Shorten parsers a bit

This commit is contained in:
Alexander Kobjolke 2023-12-03 20:21:59 +01:00
parent ba418a6ded
commit 84a3159e05

View file

@ -24,28 +24,29 @@ pCube =
, Blue <$ string "blue" , Blue <$ string "blue"
] ]
-- | Parse a single set of cubes
--
-- >>> parseText pCubes "3 green"
-- Right (Green,3)
pCubes :: Parser (Cube, Integer) pCubes :: Parser (Cube, Integer)
pCubes = do pCubes = flip (,) <$> L.decimal <* space1 <*> pCube
n <- L.decimal
_ <- space1
c <- pCube
pure (c, n)
type Game = (Integer, [Round]) type Game = [Round]
-- | Parse a single Game
--
-- >>> parseText pGame "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green"
-- Right [fromList [(Red,4),(Blue,3)],fromList [(Red,1),(Green,2),(Blue,6)],fromList [(Green,2)]]
pGame :: Parser Game pGame :: Parser Game
pGame = do pGame = do
_ <- string "Game" >> ws string "Game" >> ws >> (L.decimal :: Parser Integer) >> char ':' >> ws
n <- L.decimal pRound `sepBy` (char ';' >> ws)
_ <- char ':' >> ws
rs <- pRound `sepBy` (char ';' >> ws)
pure (n, rs)
pPuzzle :: Parser [Game] pPuzzle :: Parser [Game]
pPuzzle = linewise pGame pPuzzle = linewise pGame
isGameValid :: Game -> Bool isGameValid :: Game -> Bool
isGameValid (_, rounds) = all isRoundValid rounds isGameValid = all isRoundValid
isRoundValid :: Round -> Bool isRoundValid :: Round -> Bool
isRoundValid = getAll . M.foldMapWithKey (\c n -> All $ cubesPossible c n) isRoundValid = getAll . M.foldMapWithKey (\c n -> All $ cubesPossible c n)
@ -56,17 +57,17 @@ cubesPossible Green = (<= 13)
cubesPossible Blue = (<= 14) cubesPossible Blue = (<= 14)
minimumSet :: Game -> Round minimumSet :: Game -> Round
minimumSet (_, rounds) = foldr (M.unionWith max) M.empty rounds minimumSet = foldr (M.unionWith max) M.empty
power :: Round -> Integer power :: Round -> Integer
power = product . M.elems power = product
solve :: (MonadIO m) => Text -> m (Either Text Solution) solve :: (MonadIO m) => Text -> m (Either Text Solution)
solve riddle = case parseText pPuzzle riddle of solve riddle = case parseText pPuzzle riddle of
Right puzzle -> Right puzzle ->
let let
part1 :: Integer part1 :: Integer
part1 = sum . fmap fst . filter isGameValid $ puzzle part1 = sum . fmap fst . filter (\(_, g) -> isGameValid g) $ zip [1 ..] puzzle
part2 :: Integer part2 :: Integer
part2 = sum . fmap (power . minimumSet) $ puzzle part2 = sum . fmap (power . minimumSet) $ puzzle