-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day16.hs
119 lines (108 loc) · 3.01 KB
/
Day16.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
module Javran.AdventOfCode.Y2021.Day16 (
) where
import Control.Monad
import Control.Monad.State.Strict
import Data.Bits
import qualified Data.DList as DL
import Data.Functor.Base (TreeF (..))
import Data.Functor.Foldable
import Data.List
import Data.Tree
import Javran.AdventOfCode.Prelude
import Numeric
data Day16 deriving (Generic)
hexToBits :: Char -> [Int]
hexToBits ch = (\pos -> bool 0 1 (testBit v pos)) <$> [3, 2, 1, 0]
where
v :: Int
[(v, "")] = readHex [ch]
bitsToInt :: [Int] -> Int
bitsToInt = foldl' (\a i -> a * 2 + i) 0
type Packet = Tree PacketData
data PacketData
= PacketLiteral
{ pVersion :: Int
, pType :: Int
, pLiteral :: Int
}
| PacketOperator
{ pVersion :: Int
, pType :: Int
}
deriving (Show)
parsePacket :: State [Int] Packet
parsePacket = do
pVersion <- consumeInt 3
pType <- consumeInt 3
case pType of
4 ->
-- literal
fix
( \loop acc -> do
grp <- consume 5
case grp of
0 : gs ->
pure $
Node
( PacketLiteral
{ pVersion
, pType
, pLiteral =
bitsToInt $
DL.toList (acc <> DL.fromList gs)
}
)
[]
1 : gs -> loop (acc <> DL.fromList gs)
_ -> unreachable
)
DL.empty
_ -> do
-- operator
lenTyp <- consume 1
case lenTyp of
[0] -> do
-- next 15 bit for bit len
bitLen <- consumeInt 15
payload <- consume bitLen
let subP =
unfoldr
( \leftover -> do
guard $ not (null leftover)
pure $ runState parsePacket leftover
)
payload
pure $ Node PacketOperator {pVersion, pType} subP
[1] -> do
packetCount <- consumeInt 11
ps <- replicateM packetCount parsePacket
pure $ Node PacketOperator {pVersion, pType} ps
_ -> unreachable
where
consume n = state (splitAt n)
consumeInt n = bitsToInt <$> consume n
packetVersionSum :: Packet -> Int
packetVersionSum = cata \(NodeF d rs) -> pVersion d + sum rs
evalPacket :: Packet -> Int
evalPacket = cata \(NodeF d rs) ->
case d of
PacketLiteral {pLiteral} -> pLiteral
PacketOperator {pType} -> ($ rs) $
case pType of
0 -> sum
1 -> product
2 -> minimum
3 -> maximum
5 -> binOp (>)
6 -> binOp (<)
7 -> binOp (==)
_ -> unreachable
where
binOp (<~>) [l, r] = bool 0 1 (l <~> r)
binOp _ _ = unreachable
instance Solution Day16 where
solutionRun _ SolutionContext {getInputS, answerShow} = do
xs <- concatMap hexToBits . head . lines <$> getInputS
let r = evalState parsePacket xs
answerShow (packetVersionSum r)
answerShow (evalPacket r)