-
Notifications
You must be signed in to change notification settings - Fork 5
/
Day09.hs
50 lines (41 loc) · 1.41 KB
/
Day09.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
module AOC2017.Day09 (day09a, day09b) where
import AOC2017.Types (Challenge)
import Control.Applicative (many)
import Data.Maybe (catMaybes)
import Data.Void (Void)
import qualified Text.Megaparsec as P
import qualified Text.Megaparsec.Char as P
data Tree = Garbage String
| Group [Tree]
type Parser = P.Parsec Void String
parseTree :: Parser Tree
parseTree = P.choice [ Group <$> parseGroup
, Garbage <$> parseGarbage
]
where
parseGroup :: Parser [Tree]
parseGroup = P.between (P.char '{') (P.char '}') $
parseTree `P.sepBy` P.char ','
parseGarbage :: Parser String
parseGarbage = P.between (P.char '<') (P.char '>') $
catMaybes <$> many garbageTok
where
garbageTok :: Parser (Maybe Char)
garbageTok = P.choice
[ Nothing <$ (P.char '!' *> P.anyChar)
, Just <$> P.noneOf ">"
]
treeScore :: Tree -> Int
treeScore = go 1
where
go _ (Garbage _ ) = 0
go n (Group ts) = n + sum (go (n + 1) <$> ts)
treeGarbage :: Tree -> Int
treeGarbage (Garbage n ) = length n
treeGarbage (Group ts) = sum (treeGarbage <$> ts)
parse :: String -> Tree
parse = either (error . show) id . P.runParser parseTree ""
day09a :: Challenge
day09a = show . treeScore . parse
day09b :: Challenge
day09b = show . treeGarbage . parse