0 | module Days.Day3
 1 |
 2 | import Data.String
 3 | import Data.List.Lazy
 4 | import Data.Regex
 5 | import System
 6 |
 7 | digit : Char -> Integer
 8 | digit c = cast c - cast '0'
 9 |
10 | Mul : TyRE (Integer, Integer)
11 | Mul =
12 |   f `map` r "mul\\(`[0-9]+`,`[0-9]+`\\)"
13 |   where
14 |     f : (String, String) -> (Integer, Integer)
15 |     f (x, y) =
16 |       let raw : Maybe (Integer, Integer) =
17 |               do x <- parseInteger x
18 |                  y <- parseInteger y
19 |                  pure (x, y)
20 |       in case raw of
21 |         Nothing =>
22 |           assert_total
23 |             (idris_crash "Somehow failed to convert regex validated numbers: \{show (x,y)}")
24 |         Just x => x
25 |
26 | data Cmd : Type where
27 |   CDo : Cmd
28 |   CDont : Cmd
29 |   CMul : Integer -> Integer -> Cmd
30 |
31 | Show Cmd where
32 |   show CDo = "do()"
33 |   show CDont = "don't()"
34 |   show (CMul i j) = "mul(\{show i},\{show j})"
35 |
36 | pairToCMul : (Integer, Integer) -> Cmd
37 | pairToCMul (x, y) = CMul x y
38 |
39 | DoR : TyRE Cmd
40 | DoR = f `map` r "do\\(\\)"
41 |   where f : () -> Cmd
42 |         f _ = CDo
43 |
44 | DontR : TyRE Cmd
45 | DontR = f `map` r "don't\\(\\)"
46 |   where f : () -> Cmd
47 |         f _ = CDont
48 |
49 | MulR : TyRE Cmd
50 | MulR = pairToCMul `map` Mul
51 |
52 | CmdR : TyRE Cmd
53 | CmdR = DoR `or` (DontR `or` MulR)
54 |
55 | justMatches : DisjointMatches a -> LazyList a
56 | justMatches (Suffix cs) = []
57 | justMatches (Cons cs x y) =
58 |   let rest = justMatches y
59 |   in x :: rest
60 |
61 | handleProgram : LazyList Cmd -> Integer
62 | handleProgram x = handleProgram' x True 0
63 |   where
64 |     handleProgram' : LazyList Cmd -> (enabled : Bool) -> (acc : Integer) -> Integer
65 |     handleProgram' [] enabled acc = acc
66 |     handleProgram' (CDo :: xs) enabled acc =
67 |       handleProgram' xs True acc
68 |     handleProgram' (CDont :: xs) enabled acc =
69 |       handleProgram' xs False acc
70 |     handleProgram' ((CMul _ _) :: xs) False acc =
71 |       handleProgram' xs False acc
72 |     handleProgram' ((CMul x y) :: xs) True acc =
73 |       handleProgram' xs True (acc + (x * y))
74 |
75 | export
76 | part1 : String -> IO (String, ())
77 | part1 str = do
78 |   let matches =
79 |     sum . map (\(x,y) => x * y) . justMatches $
80 |       asDisjointMatches Mul str True
81 |   pure (show matches, ())
82 |
83 | export
84 | part2 : () -> String -> IO String
85 | part2 x str =
86 |   let matches =
87 |     handleProgram .
88 |     justMatches $
89 |     asDisjointMatches CmdR str True
90 |   in pure (show matches)
91 |