49 lines
1.3 KiB
Haskell
49 lines
1.3 KiB
Haskell
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"
|