-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day7.hs
59 lines (51 loc) · 2.15 KB
/
Day7.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
module Day7
( part1
, part2
) where
import Control.Monad (void)
import Data.Char (isDigit)
import Data.Graph.Inductive.Graph (Graph, Node, labNodes, lsuc)
import Data.Graph.Inductive.Query.BFS (bfs)
import Data.Maybe (Maybe (Just, Nothing),
catMaybes)
import Helpers.Graph (assocsToGraph,
assocsToReverseGraph)
import Helpers.Parsers (Parser, parseByLine)
import Text.Megaparsec (manyTill, takeWhile1P, try,
(<|>))
import Text.Megaparsec.Char (char, digitChar, eol,
printChar, string)
parser :: Parser (String, [(String, Int)])
parser = do
node <- manyTill printChar (string " bags contain ")
edges <- manyTill edge eol
return (node, catMaybes edges)
where
edge = try someBags <|> noBags
consumeBag =
try (string "s, ") <|> try (string ", ") <|> try (string "s.") <|>
string "."
someBags = do
num <- takeWhile1P Nothing isDigit
void $ char ' '
node <- manyTill printChar (string " bag")
void consumeBag
return . Just $ (node, read num)
noBags = do
void . string $ "no other bags."
return Nothing
findGoldBag :: (Graph gr) => gr String Int -> [Node]
findGoldBag invRules = bfs (goldBag invRules) invRules
goldBag :: (Graph gr) => gr String Int -> Node
goldBag = fst . head . filter ((== "shiny gold") . snd) . labNodes
foldRules :: (Graph gr) => gr String Int -> Node -> Int
foldRules rules =
(1 +) . sum . map (\(a, b) -> b * foldRules rules a) . lsuc rules
emptyGoldBag :: (Graph gr) => gr String Int -> Int
emptyGoldBag rules = foldRules rules . goldBag $ rules
part1 :: Bool -> String -> String
part1 _ =
show .
(+ (-1)) . length . findGoldBag . assocsToReverseGraph . parseByLine parser
part2 :: Bool -> String -> String
part2 _ = show . (+ (-1)) . emptyGoldBag . assocsToGraph . parseByLine parser