import Text.Parsec import Text.Parsec.Char import Data.List contain = do { num <- many1 digit; many1 space; x <- many1 letter; many1 space; y <- many1 letter; many1 space; if num == "1" then string "bag" else string "bags"; return (x ++ " " ++ y, read num :: Integer); } line = do { x <- many1 letter; many1 space; y <- many1 letter; many1 space; string "bags contain"; many1 space; z <- do { rcar <- contain; rcdr <- many $ (string "," >> many space >> contain); return $ rcar:rcdr; } <|> (string "no other bags" >> return []); char '.'; return (x ++ " " ++ y, z) } p = many1 $ line >>= \x -> many1 space >> return x calc :: [(String, [(String, Integer)])] -> String -> Integer calc dict target = case lookup target dict of Just lst -> sum $ map (\(s, i) -> i + i * calc dict s) lst Nothing -> error "" main = readFile "7" >>= \x -> putStrLn $ case runParser p () "7" x of Left err -> show err Right x -> show $ calc x "shiny gold"