import Text.Parsec.String (Parser) import Text.Parsec import System.Environment import Data.List import Data.Function import Data.Maybe import qualified Data.Map as M import Control.Monad data Color = Red | Green | Blue deriving (Show,Eq,Ord) type Handful = (Color, Int) type Set = M.Map Color Int type Game = (Int, [Set]) red = try $ string "red" *> pure Red green = try $ string "green" *> pure Green blue = try $ string "blue" *> pure Blue color :: Parser Color color = red <|> green <|> blue handful :: Parser Handful handful = space *> (flip (,) <$> read <$> many1 digit) <* space <*> color set = M.fromList <$> (sepBy handful $ string ",") game = string "Game " *> ((,) <$> read <$> many1 digit) <* string ":" <*> sepBy set (string ";") games = sepBy game newline solution :: Game -> Maybe Int solution (i,m) = do let m' = M.unionsWith max m guard $ M.findWithDefault 0 Red m' <= 12 guard $ M.findWithDefault 0 Green m' <= 13 guard $ M.findWithDefault 0 Blue m' <= 14 return i main = head <$> getArgs >>= readFile >>= print . sum . catMaybes . map solution . either (error.show) id . parse games ""