aboutsummaryrefslogtreecommitdiff
path: root/2024/24/solve.hs
blob: 788655c32a5e45c8b42b59f7218afd53c15272ec (plain) (blame)
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