-
Notifications
You must be signed in to change notification settings - Fork 0
/
run.hs
167 lines (139 loc) · 4.34 KB
/
run.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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
import AoC
import AoC.Grid
import Control.Applicative
import Control.Monad (replicateM)
import Data.Bifunctor
import Data.Bits (FiniteBits, Bits, finiteBitSize)
import Data.Foldable
import Data.List
import Data.Maybe
import Data.Ord
import Numeric (readHex)
import Data.Word
import Data.List.Split (chunksOf)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Sequence (Seq)
import qualified Data.Sequence as Seq
import Data.Set (Set)
import qualified Data.Set as Set
import Data.IntSet (IntSet)
import qualified Data.IntSet as IntSet
newtype Get a = Get { runGet :: [Bool] -> Maybe (a, [Bool]) }
deriving Functor
instance Applicative Get where
pure x = Get $ \v -> Just (x, v)
mf <*> mx = Get $ \v -> do
(f, v') <- runGet mf v
(x, v'') <- runGet mx v'
pure (f x, v'')
instance Monad Get where
mx >>= f = Get $ \v -> do
(x, v') <- runGet mx v
runGet (f x) v'
instance Alternative Get where
empty = Get $ const Nothing
mx <|> my = try mx >>= \case Just v -> pure v
Nothing -> my
bits :: forall a. (Num a, FiniteBits a) => Get a
bits = bitsN (finiteBitSize (0 :: a))
bitsN :: (Num a, Bits a) => Int -> Get a
bitsN n = Get $ \v ->
case splitAt n v of
([], _) -> Nothing
(h, t) | length h == n -> Just (bitsFromBools h, t)
| otherwise -> Nothing
integer :: Get Integer
integer = Get $ \v -> Just (bitsFromBools v, [])
bit :: Get Bool
bit = Get $ \case (x:xs) -> Just (x, xs)
_ -> Nothing
variable :: Get a -> Get a
variable g = Get $ \v -> do
(x, v') <- runGet go v
(y, _) <- runGet g x
pure (y, v')
where go = bit >>= \case False -> replicateM 4 bit
True -> (++) <$> replicateM 4 bit <*> go
restrict :: Int -> Get a -> Get a
restrict n g = Get $ \v ->
case splitAt n v of
([], _) -> Nothing
(h, t) -> do
(x, _) <- runGet g h
pure (x, t)
try :: Get a -> Get (Maybe a)
try g = Get $ \v ->
case runGet g v of
Just (x, v') -> Just (Just x, v')
Nothing -> Just (Nothing, v)
decode :: [Word8] -> Get a -> Maybe a
decode x g = fst <$> runGet g (concatMap (boolsFromBits 8) x)
parseAll :: String -> [Word8]
parseAll = concatMap (fmap fst . readHex @Word8) . chunksOf 2
data Packet = Packet { version :: Int
, typeId :: Int
, content :: Content
}
data Content = Literal Integer | Operator (Integer -> Integer -> Integer) [Packet]
gt :: (Ord a, Num a) => a -> a -> a
gt x y | x > y = 1
| otherwise = 0
lt :: (Ord a, Num a) => a -> a -> a
lt x y | x < y = 1
| otherwise = 0
eq :: (Eq a, Num a) => a -> a -> a
eq x y | x == y = 1
| otherwise = 0
packet :: Get Packet
packet = do
version <- bitsN @Int 3
typeId <- bitsN @Int 3
content <- case typeId of
4 -> Literal <$> literal
0 -> Operator (+) <$> subpackets
1 -> Operator (*) <$> subpackets
2 -> Operator min <$> subpackets
3 -> Operator max <$> subpackets
5 -> Operator gt <$> subpackets
6 -> Operator lt <$> subpackets
7 -> Operator eq <$> subpackets
pure $ Packet version typeId content
literal :: Get Integer
literal = variable integer
subpackets :: Get [Packet]
subpackets =
bit >>= \case
False -> bitsN @Int 15 >>= \n -> restrict n (some packet)
True -> bitsN @Int 11 >>= \n -> replicateM n packet
versions :: Packet -> Int
versions = go
where go Packet {..} =
version + case content of
Literal _ -> 0
Operator _ ps -> sum $ map go ps
value :: Packet -> Integer
value = go . content
where go = \case
Literal v -> v
Operator f ps -> foldl1' f (map (go . content) ps)
part1 input =
let Just p = decode input packet
in versions p
part2 input =
let Just p = decode input packet
in value p
main = main' "input.txt"
exampleMain = main' "example.txt"
main' file = do
input <- parseAll <$> readFile file
print (part1 input)
print (part2 input)