module Main where import System.Environment (getArgs) import Control.Monad (void) import Text.Parsec (Parsec, try, (<|>), skipMany, anyChar, many, manyTill, parse, string, char) import Text.ParserCombinators.Parsec (GenParser, eof) import Text.ParserCombinators.Parsec.Number (decimal) type Report = [Level] type Level = Int mul :: GenParser Char st (Int, Int) mul = do _ <- string "mul(" l <- decimal _ <- char ',' r <- decimal _ <- char ')'; return (l, r) allMuls :: GenParser Char () [(Int, Int)] allMuls = many loop where loop = try mul <|> try (anyChar >> loop) dont :: GenParser Char () () dont = void $ try $ string "don't()" >> manyTill anyChar (try (eof <|> void (string "do()"))) allMulsConditional :: GenParser Char () [(Int, Int)] allMulsConditional = many loop where loop = try (skipMany dont >> (try mul <|> try (anyChar >> loop))) solve :: FilePath -> Parsec [Char] () [(Int, Int)] -> IO Int solve fp parser = do content <- readFile fp case parse parser fp content of Right m -> return $ sum $ map (uncurry (*)) m Left e -> fail $ "Oh no! : " ++ show e main :: IO () main = do args <- getArgs (fp:_) <- return args resPart1 <- solve fp allMuls resPart2 <- solve fp allMulsConditional putStrLn ("Solution (Part 1) : " ++ show resPart1) putStrLn ("Solution (Part 2) : " ++ show resPart2)