never executed always true always false
1 {-|
2 Module: Y2021.D18
3 Description: Advent of Code 2021 Day 18 Solutions.
4 License: MIT
5 Maintainer: @tylerjl
6
7 Solutions to the 2021 day 18 set of problems for <adventofcode.com>.
8 -}
9 module Y2021.D18
10 ( parse18
11 , part18A
12 , part18B
13 ) where
14
15 import Control.Applicative
16 import Data.Attoparsec.Text hiding (take, takeWhile)
17 import Data.Either.Utils (fromRight)
18 import Data.List (foldl1')
19 import Data.Text (Text)
20
21 data SnailTree
22 = SnailNumber Int
23 | SnailPair SnailTree SnailTree
24 deriving Eq
25 instance Show SnailTree where
26 show (SnailNumber n) = show n
27 show (SnailPair a b) = "[" <> show a <> "," <> show b <> "]"
28
29 -- |Solution to part A
30 part18A :: Text -> Int
31 part18A = magnitude . reduce . foldl1' combine . map reduce . parse18
32
33 combine :: SnailTree -> SnailTree -> SnailTree
34 combine (reduce -> a) (reduce -> b) = snailAdd a b
35
36 -- |Solution to part B
37 part18B :: Text -> Int
38 part18B (parse18 -> rows) =
39 maximum [(magnitude . reduce) (combine x y) | x <- rows, y <- rows, x /= y]
40
41 snailAdd :: SnailTree -> SnailTree -> SnailTree
42 snailAdd = SnailPair
43
44 magnitude :: SnailTree -> Int
45 magnitude (SnailNumber n) = n
46 magnitude (SnailPair (magnitude -> l) (magnitude -> r)) = l * 3 + r * 2
47
48 explode :: SnailTree -> Either SnailTree SnailTree
49 explode = either (\(_, tree, _) -> Left tree) Right . go (0 :: Int)
50 where
51 go _ (SnailNumber n) = pure (SnailNumber n)
52 go d (SnailPair (SnailNumber l) (SnailNumber r)) | d >= 4 = Left (l, SnailNumber 0, r)
53 go d (SnailPair l r) =
54 case go (succ d) l of
55 Left (ln, l', rn) -> Left (ln, SnailPair l' (withLeft r rn), 0)
56 _ -> case go (succ d) r of
57 Left (ln, r', rn) -> Left (0, SnailPair (withRight l ln) r', rn)
58 _ -> pure $ SnailPair l r
59 withLeft (SnailNumber v) n = SnailNumber (v + n)
60 withLeft (SnailPair l r) n = SnailPair (withLeft l n) r
61 withRight (SnailNumber v) n = SnailNumber (v + n)
62 withRight (SnailPair l r) n = SnailPair l (withRight r n)
63
64 split :: SnailTree -> Either SnailTree SnailTree
65 split s@(SnailNumber n)
66 | n >= 10 = Left $ SnailPair (SnailNumber $ n `div` 2) (SnailNumber $ succ n `div` 2)
67 | otherwise = Right s
68 split (SnailPair l r) =
69 case split l of
70 Left l' -> Left (SnailPair l' r)
71 _ -> case split r of
72 Left r' -> Left (SnailPair l r')
73 _ -> Right $ SnailPair l r
74
75 reduce :: SnailTree -> SnailTree
76 reduce (explode -> Right (split -> Right tree)) = tree
77 reduce (explode -> Right (split -> Left tree)) = reduce tree
78 reduce (explode -> Left tree) = reduce tree
79
80 -- |Parse.
81 parse18 :: Text -> [SnailTree]
82 parse18 = fromRight . parseOnly (parser <* atEnd)
83 where
84 parser = snail `sepBy1` endOfLine
85 snail = SnailPair <$> (char '[' *> sv <* char ',') <*> (sv <* char ']')
86 sv = (SnailNumber <$> decimal) <|> snail