1 -- Writeup at https://work.njae.me.uk/2021/12/16/advent-of-code-2021-day-14/
8 import Control.Monad.State.Lazy
10 import qualified Data.ByteString as BYS
11 import qualified Data.Bitstream as BS
13 type Transmission = BS.Bitstream BS.Right
15 type ParseTrans = State Transmission
17 data Packet = Packet Integer PacketContents
22 -- | Operator [Packet]
27 | GreaterThan Packet Packet
28 | LessThan Packet Packet
29 | EqualTo Packet Packet
34 do text <- readFile "data/advent16.txt"
35 let packetStream = bitify text
36 let (packet, _remaining) = runState getPacket packetStream
40 part1 :: Packet -> Integer
41 part1 = packetVersionSum
43 part2 :: Packet -> Integer
44 part2 = evaluatePacket
46 bitify :: String -> Transmission
47 bitify = BS.fromByteString . BYS.pack . hexPack . map (fromIntegral . digitToInt)
49 hexPack :: [Word8] -> [Word8]
51 hexPack (x:[]) = hexPack [x, 0]
52 hexPack (x:y:xs) = ((x `shift` 4) .|. y) : hexPack xs
54 getBool :: ParseTrans Bool
57 let value = head $ BS.unpack $ BS.take 1 bs
61 getInt :: Int64 -> ParseTrans Integer
64 let value = BS.toBits $ BS.take n bs
68 getBits :: Int64 -> ParseTrans Transmission
71 let bits = BS.take n bs
75 getLiteral :: ParseTrans Integer
76 getLiteral = getLiteralAcc 0
78 getLiteralAcc :: Integer -> ParseTrans Integer
80 do continues <- getBool
82 let acc' = acc * 16 + nybble
84 then (do getLiteralAcc acc')
87 -- getLiteralPacket :: ParseTrans (Integer, Integer, Integer)
89 -- do version <- getInt 3
92 -- return (version, pType, val)
95 getPacket :: ParseTrans Packet
97 do version <- getInt 3
99 payload <- case pType of
100 4 -> do val <- getLiteral
102 _ -> do contents <- getOperatorContents
103 return $ mkOperator pType contents
104 return $ Packet version payload
106 mkOperator :: Integer -> [Packet] -> PacketContents
107 mkOperator pType contents = case pType of
109 1 -> Product contents
110 2 -> Minimum contents
111 3 -> Maximum contents
112 5 -> GreaterThan (contents!!0) (contents!!1)
113 6 -> LessThan (contents!!0) (contents!!1)
114 7 -> EqualTo (contents!!0) (contents!!1)
117 getOperatorContents :: ParseTrans [Packet]
118 getOperatorContents =
119 do isNumPackets <- getBool
121 then do numPackets <- getInt 11
122 getPacketsByCount numPackets
123 else do numBits <- getInt 15
124 subString <- getBits (fromIntegral numBits)
125 return $ getPacketsByLength subString
127 getPacketsByLength :: Transmission -> [Packet]
128 getPacketsByLength bits
130 | otherwise = p : (getPacketsByLength remaining)
131 where (p, remaining) = runState getPacket bits
133 getPacketsByCount :: Integer -> ParseTrans [Packet]
134 getPacketsByCount 0 = return []
135 getPacketsByCount n =
137 ps <- getPacketsByCount (n - 1)
140 packetVersionSum :: Packet -> Integer
141 packetVersionSum (Packet version contents) =
142 version + (contentsVersionSum contents)
144 contentsVersionSum :: PacketContents -> Integer
145 contentsVersionSum (Sum packets) = sum $ map packetVersionSum packets
146 contentsVersionSum (Product packets) = sum $ map packetVersionSum packets
147 contentsVersionSum (Minimum packets) = sum $ map packetVersionSum packets
148 contentsVersionSum (Maximum packets) = sum $ map packetVersionSum packets
149 contentsVersionSum (Literal _) = 0
150 contentsVersionSum (GreaterThan packet1 packet2) =
151 (packetVersionSum packet1) + (packetVersionSum packet2)
152 contentsVersionSum (LessThan packet1 packet2) =
153 (packetVersionSum packet1) + (packetVersionSum packet2)
154 contentsVersionSum (EqualTo packet1 packet2) =
155 (packetVersionSum packet1) + (packetVersionSum packet2)
157 evaluatePacket :: Packet -> Integer
158 evaluatePacket (Packet _version contents) = evaluateContents contents
160 evaluateContents :: PacketContents -> Integer
161 evaluateContents (Sum packets) = sum $ map evaluatePacket packets
162 evaluateContents (Product packets) = product $ map evaluatePacket packets
163 evaluateContents (Minimum packets) = minimum $ map evaluatePacket packets
164 evaluateContents (Maximum packets) = maximum $ map evaluatePacket packets
165 evaluateContents (Literal n) = n
166 evaluateContents (GreaterThan packet1 packet2) =
167 if (evaluatePacket packet1) > (evaluatePacket packet2) then 1 else 0
168 evaluateContents (LessThan packet1 packet2) =
169 if (evaluatePacket packet1) < (evaluatePacket packet2) then 1 else 0
170 evaluateContents (EqualTo packet1 packet2) =
171 if (evaluatePacket packet1) == (evaluatePacket packet2) then 1 else 0