1 -- Writeup at https://work.njae.me.uk/2021/12/21/advent-of-code-2021-day-18/
4 import qualified Data.Text.IO as TIO
5 import Data.Attoparsec.Text
6 import Control.Applicative
10 data Tree = Pair Tree Tree | Leaf Int
13 instance Show Tree where
14 show (Leaf n) = show n
15 show (Pair l r) = "[" ++ show l ++ "," ++ show r ++ "]"
17 data Cxt = Top | L Cxt Tree | R Tree Cxt
20 -- type Context = [(Direction, Tree)]
21 -- data Direction = Lft | Rght
22 -- deriving (Show, Eq)
24 type Loc = (Tree, Cxt)
28 do text <- TIO.readFile "data/advent18.txt"
29 let numbers = successfulParse text
33 part1 numbers = magnitude total
34 where total = foldl1' snailAdd numbers
36 part2 numbers = maximum [ magnitude $ snailAdd a b
37 | a <- numbers, b <- numbers]
39 magnitude :: Tree -> Int
40 magnitude (Leaf n) = n
41 magnitude (Pair a b) = 3 * (magnitude a) + 2 * (magnitude b)
45 left (Pair l r, c) = (l, L c r)
48 right (Pair l r, c) = (r, R l c)
54 up (t, Top) = (t, Top)
55 up (t, L c r) = (Pair t r, c)
56 up (t, R l c) = (Pair l t, c)
60 upmost l = upmost (up l)
62 modify :: Loc -> (Tree -> Tree) -> Loc
63 modify (t, c) f = (f t, c)
66 explode :: Tree -> Maybe Tree
72 mp0 = pairAtDepth 4 num
74 ((Pair (Leaf nl) (Leaf nr)), _) = p0
75 p1 = case rightmostOnLeft p0 of
77 Just leftReg -> modify leftReg (\(Leaf n) -> Leaf (n + nl))
78 p2 = case pairAtDepthC 4 (upmost p1) >>= leftmostOnRight of
80 Just rightReg -> modify rightReg (\(Leaf n) -> Leaf (n + nr))
81 p3 = case pairAtDepthC 4 (upmost p2) of
83 Just centrePair -> modify centrePair (\_ -> Leaf 0)
86 pairAtDepth :: Int -> Tree -> Maybe Loc
87 pairAtDepth n t = pairAtDepthC n (top t)
89 pairAtDepthC :: Int -> Loc -> Maybe Loc
90 pairAtDepthC _ (Leaf _, _) = Nothing
91 pairAtDepthC 0 t@(Pair _ _, _) = Just t
92 pairAtDepthC n t@(Pair _ _, _) =
93 pairAtDepthC (n - 1) (left t) <|> pairAtDepthC (n - 1) (right t)
95 rightmostOnLeft :: Loc -> Maybe Loc
96 rightmostOnLeft (_, Top) = Nothing
97 rightmostOnLeft t@(_, L c r) = rightmostOnLeft $ up t
98 rightmostOnLeft t@(_, R l c) = Just $ rightmostNum $ left $ up t
100 rightmostNum :: Loc -> Loc
101 rightmostNum t@(Leaf _, _) = t
102 rightmostNum t@(Pair _ _, _) = rightmostNum $ right t
104 leftmostOnRight :: Loc -> Maybe Loc
105 leftmostOnRight (_, Top) = Nothing
106 leftmostOnRight t@(_, R l c) = leftmostOnRight $ up t
107 leftmostOnRight t@(_, L c r) = Just $ leftmostNum $ right $ up t
109 leftmostNum :: Loc -> Loc
110 leftmostNum t@(Leaf _, _) = t
111 leftmostNum t@(Pair _ _, _) = leftmostNum $ left t
113 split :: Tree -> Maybe Tree
124 n1 = modify n0 (\_ -> Pair (Leaf ln) (Leaf rn))
125 (num1, _) = upmost n1
127 splittable :: Tree -> Maybe Loc
128 splittable t = splittableC (top t)
130 splittableC :: Loc -> Maybe Loc
131 splittableC t@(Leaf n, _)
133 | otherwise = Nothing
134 splittableC t@(Pair _ _, _) = splittableC (left t) <|> splittableC (right t)
136 reduce :: Tree -> Tree
137 reduce num = case explode num <|> split num of
139 Just num1 -> reduce num1
141 snailAdd :: Tree -> Tree -> Tree
142 snailAdd a b = reduce $ Pair a b
145 -- Parse the input file
147 sfNumbersP = sfNumberP `sepBy` endOfLine
149 sfNumberP = regularP <|> pairP
151 regularP = Leaf <$> decimal
152 pairP = Pair <$> ("[" *> sfNumberP) <*> ("," *> sfNumberP) <* "]"
154 -- successfulParse :: Text -> (Integer, [Maybe Integer])
155 successfulParse input =
156 case parseOnly sfNumbersP input of
157 Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err
158 Right numbers -> numbers