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
|
{-# LANGUAGE DeriveGeneric #-}
import Data.Bits ( (.&.)
, (.|.)
, xor
)
import Data.Functor ( ($>) )
import qualified Data.HashMap.Strict as M
import Data.HashMap.Strict ( HashMap )
import Data.Hashable
import Data.List ( sort )
import Data.Void
import GHC.Generics ( Generic )
import Text.Megaparsec hiding ( Pos
, single
)
import Text.Megaparsec.Char
import qualified Text.Megaparsec.Char.Lexer as L
type Parser = Parsec Void String
data Term = Term Reg Operator Reg
deriving (Show, Generic, Eq)
data Operator = AND | OR | XOR
deriving (Show, Generic, Eq)
instance Hashable Operator
instance Hashable Term
type Reg = String
type Regs = HashMap Reg Int
type Wires = HashMap Reg Term
reg :: Parser Reg
reg = some alphaNumChar
regs :: Parser Regs
regs = M.fromList <$> many
(do
r <- reg
string ": "
val <- L.decimal
char '\n'
return (r, val)
)
operator :: Parser Operator
operator =
(string "AND" $> AND) <|> (string "OR" $> OR) <|> (string "XOR" $> XOR)
wires :: Parser Wires
wires = M.fromList <$> many
(do
a <- reg
char ' '
op <- operator
char ' '
b <- reg
string " -> "
out <- reg
char '\n'
return (out, Term a op b)
)
eval :: Int -> Operator -> Int -> Int
eval a AND b = a .&. b
eval a OR b = a .|. b
eval a XOR b = a `xor` b
solve1 :: (Regs, Wires) -> Reg -> Int
solve1 (rs, _) r | r `M.member` rs = rs M.! r
solve1 s@(_, ws) r = eval (solve1 s a) op (solve1 s b)
where Term a op b = ws M.! r
toDec :: [Char] -> Int
toDec [] = 0
toDec (x : xs) = (read [x] :: Int) + 2 * toDec xs
outRegs :: [Reg] -> [Reg]
outRegs [] = []
outRegs (r@('z' : _) : rs) = r : outRegs rs
outRegs (_ : rs) = outRegs rs
part1 :: Parser Int
part1 = do
rs <- regs
char '\n'
ws <- wires
return $ toDec $ concat $ show . solve1 (rs, ws) <$> sort
(outRegs $ M.keys rs ++ M.keys ws)
main :: IO ()
main = do
f <- readFile "input"
case runParser (part1 <* eof) "" f of
Right res -> print res
Left err -> putStrLn $ errorBundlePretty err
|