1
1
module Main where
2
2
3
+ import Data.Either (fromRight )
4
+ import Data.Bifunctor (first )
3
5
import Data.Map.Strict (Map (.. ),fromList , (!) , insert )
4
6
import Text.Parsec
5
7
@@ -8,42 +10,33 @@ data Rule = Single Int | And Rule Rule | Or Rule Rule | Token Char
8
10
9
11
-- * Parsing stuff
10
12
getToken :: Parsec String () Rule
11
- getToken = do
12
- char ' \" '
13
- val <- letter
14
- char ' \" '
15
- return (Token val)
13
+ getToken = Token <$> between (char ' \" ' ) (char ' \" ' ) letter
16
14
17
15
getSingle :: Parsec String () Rule
18
16
getSingle = Single . read <$> many digit
19
17
20
18
getAnd :: Parsec String () Rule
21
- getAnd = do
22
- rule1 <- getSingle
23
- char ' '
24
- And rule1 <$> getSingle
19
+ getAnd = And <$> getSingle <*> (char ' ' >> getSingle)
25
20
26
21
getOr :: Parsec String () Rule
27
- getOr = try (Or <$> getSingle <*> (string " | " >> getSingle)) <|> (Or <$> getAnd <*> (string " | " >> getAnd))
22
+ getOr = try (Or <$> getSingle <*> (string " | " >> getSingle))
23
+ <|> (Or <$> getAnd <*> (string " | " >> getAnd))
28
24
25
+ getKey :: Parsec String () Int
26
+ getKey = read <$> between (string " " ) (string " : " ) (many digit)
27
+
28
+ getRule :: Parsec String () Rule
29
+ getRule = try getToken <|> try getOr <|> try getAnd <|> getSingle
29
30
30
31
getData :: Parsec String () (Int , Rule )
31
- getData = do
32
- key <- read <$> many digit
33
- string " : "
34
- rule <- try getToken <|> try getOr <|> try getAnd <|> getSingle
35
- return (key, rule)
32
+ getData = (,) <$> getKey <*> getRule
36
33
37
34
parseMap :: [String ] -> Map Int Rule
38
- parseMap css = fromList $ map (fromEither . parse getData " " ) css
39
-
40
- fromEither :: Show a => Either a b -> b
41
- fromEither (Right x) = x
42
- fromEither (Left x) = error $ show x
35
+ parseMap = fromList . map (fromRight (0 , Single 0 ) . parse getData " " )
43
36
44
37
-- * Non-deterministic finite automata
45
38
runNDFA :: Map Int Rule -> Int -> String -> Bool
46
- runNDFA rules k = elem " " . go (Single k)
39
+ runNDFA rules k = elem " " . go (rules ! k)
47
40
where
48
41
go _ " " = []
49
42
go (Token c) (c': cs) = [cs | c== c']
@@ -57,11 +50,8 @@ r11 = Or (And (Single 42) (Single 31)) (And (And (Single 42) (Single 11)) (Singl
57
50
main :: IO ()
58
51
main = do
59
52
dat <- lines <$> readFile " day19.txt"
60
- let rulesStr = takeWhile (/= " " ) dat
61
- strings = tail $ dropWhile (/= " " ) dat
62
- rules = parseMap rulesStr
63
- part1 = map (runNDFA rules 0 ) strings
64
- rules' = insert 8 r8 $ insert 11 r11 rules
65
- part2 = map (runNDFA rules' 0 ) strings
66
- print $ length $ filter id part1
67
- print $ length $ filter id part2
53
+ let (rules, strings) = first parseMap . span (/= " " ) $ dat
54
+ rules' = insert 8 r8 . insert 11 r11 $ rules
55
+ countWith r = length . filter (runNDFA r 0 ) $ strings
56
+ print $ countWith rules
57
+ print $ countWith rules'
0 commit comments