Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

80 řádky
2.1KB

  1. {-# LANGUAGE FlexibleContexts #-}
  2. import Text.Parsec
  3. data Bag = Bag Label [(Quantity, Label)]
  4. deriving Show
  5. type Label = String
  6. type Quantity = Int
  7. main :: IO ()
  8. main = do
  9. raw <- readFile "day7.txt"
  10. let bags = validate $ map (parse lineP []) $ lines raw
  11. ansA = pred $ length $ filter (\x -> (snd x) == True)
  12. $ loeb $ map loebifyA bags
  13. ansB = pred $ unMaybe $ lookup "shiny gold"
  14. $ loeb $ map loebifyB bags
  15. in do
  16. putStrLn $ "day7a: " ++ (show ansA)
  17. putStrLn $ "day7b: " ++ (show ansB)
  18. loeb :: Functor f => f (f a -> a) -> f a
  19. loeb x = go where go = fmap ($ go) x
  20. loebifyA :: Bag -> ([(Label, Bool)] -> (Label, Bool))
  21. loebifyA (Bag "shiny gold" _) = const ("shiny gold", True)
  22. loebifyA (Bag l bs) =
  23. (\ls -> (l, or (unMaybes (map (\f -> f ls) (map lookupify bs)))))
  24. where
  25. lookupify (_,s) = lookup s
  26. loebifyB :: Bag -> ([(Label, Int)] -> (Label, Int))
  27. loebifyB (Bag l []) = const (l, 1)
  28. loebifyB (Bag l bs) =
  29. (\ls -> (l, sum (1:(map (\f -> f ls) (map lookupify bs)))))
  30. where
  31. lookupify (q,s) = (\ms -> q * (unMaybe $ lookup s ms))
  32. unMaybe :: Maybe a -> a
  33. unMaybe Nothing = error "invalid bag label"
  34. unMaybe (Just v) = v
  35. unMaybes :: [Maybe a] -> [a]
  36. unMaybes = map unMaybe
  37. validate :: [Either ParseError Bag] -> [Bag]
  38. validate [] = []
  39. validate ((Left _):_) = error "invalid input"
  40. validate ((Right b):bs) = b:(validate bs)
  41. lineP :: Parsec String () Bag
  42. lineP = do
  43. l <- initlabelP
  44. ls <- baglistP
  45. eof
  46. return $ Bag l ls
  47. baglistP :: Parsec String () [(Quantity, Label)]
  48. baglistP = do
  49. ((string "no other bags.") >> return []) <|>
  50. (endBy qlabelP $ oneOf [',', '.'] >> whitespaces)
  51. initlabelP :: Parsec String () String
  52. initlabelP = manyTill anyChar
  53. (try $ whitespaces >> (string "bags contain") >> whitespaces)
  54. whitespaces :: Parsec String () String
  55. whitespaces = many $ char ' '
  56. qlabelP :: Parsec String () (Quantity, Label)
  57. qlabelP = do
  58. q <- many1 digit
  59. whitespaces
  60. s <- labelP
  61. return (read q,s)
  62. labelP :: Parsec String () String
  63. labelP = manyTill anyChar
  64. (try $ whitespaces >> (string "bag") >> optional (char 's'))