advent-of-code/2023/haskell/solutions/Day02.hs

75 lines
1.9 KiB
Haskell
Raw Normal View History

2023-12-02 13:42:14 +01:00
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
2023-12-02 14:32:05 +01:00
module Day02 (Cube(..), Game(..), parse, solveA, solveB) where
2023-11-28 22:21:26 +01:00
2023-12-02 13:42:14 +01:00
import Data.Void (Void)
import Data.Text (Text)
import Data.Bifunctor (first)
import Text.Megaparsec (Parsec, optional, choice, eof, many, sepBy, runParser, errorBundlePretty)
import Text.Megaparsec.Char (string, space, char, newline)
import Text.Megaparsec.Char.Lexer (decimal)
data Cube = R Int | G Int | B Int deriving Show
data Game = Game
2023-12-02 14:32:05 +01:00
{ gId :: Int
, gSets :: [[Cube]]
2023-12-02 13:42:14 +01:00
} deriving Show
type Parser = Parsec Void Text
parse :: Text -> Either String [Game]
parse = first errorBundlePretty . runParser games ""
where
cube :: Parser Cube
cube = do
2023-12-02 14:32:05 +01:00
_ <- optional space
count <- decimal
2023-12-02 13:42:14 +01:00
space
color <- choice
[ R <$ string "red"
, G <$ string "green"
, B <$ string "blue"
]
2023-12-02 14:32:05 +01:00
return $ color count
2023-12-02 13:42:14 +01:00
set :: Parser [Cube]
set = space *> cube `sepBy` char ','
sets :: Parser [[Cube]]
sets = set `sepBy` char ';'
game :: Parser Game
game = do
2023-12-02 14:32:05 +01:00
_ <- string "Game"
2023-12-02 13:42:14 +01:00
space
2023-12-02 14:32:05 +01:00
gId <- decimal
_ <- char ':'
gSets <- sets
_ <- optional newline
2023-12-02 13:42:14 +01:00
return $ Game {..}
games :: Parser [Game]
games = many game <* eof
solveA :: [Game] -> Int
2023-12-02 14:32:05 +01:00
solveA = sum . map gId . filter isValid
2023-12-02 13:42:14 +01:00
where
isSetValid :: Cube -> Bool
isSetValid count = case count of
R r -> r <= 12
G g -> g <= 13
B b -> b <= 14
isValid :: Game -> Bool
2023-12-02 14:32:05 +01:00
isValid Game {..} = all (all isSetValid) gSets
solveB :: [Game] -> Int
solveB = sum . map toPower
where
update :: (Int, Int, Int) -> Cube -> (Int, Int, Int)
update (r, g, b) cube = case cube of
R r' -> (max r r', g, b)
G g' -> (r, max g g', b)
B b' -> (r, g, max b b')
toPower :: Game -> Int
toPower Game {..} = (\(r, g, b) -> r * g * b) . foldl update (0, 0, 0) . concat $ gSets