-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun.hs
91 lines (71 loc) · 1.99 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
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import Data.Maybe (maybe)
import Data.List (nub)
import Data.Ord (comparing)
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Void (Void)
import Text.Megaparsec
import Text.Megaparsec.Char
data Inst = Inst Op Reg Int Cond
instance Show Inst where
show (Inst op (Reg reg) val cond) =
show op ++ " " ++ show val ++ " " ++ reg ++ " cond"
data Op = Inc | Dec
deriving (Show, Eq)
inst :: Inst -> Int -> Int
inst (Inst Dec _ val _) = (\x -> x - val)
inst (Inst Inc _ val _) = (+ val)
newtype Reg = Reg String
deriving (Show, Eq, Ord)
data Cond = Cond Reg CompOp
type CompOp = Int -> Bool
type Parser = Parsec Void String
rights = map f
where f (Left x) = error $ show x
f (Right x) = x
constP :: String -> a -> Parser a
constP str v = string str *> pure v
regP = Reg <$> some alphaNumChar
opP = constP "inc" Inc <|> constP "dec" Dec
compOpP :: Parser (Int -> Int -> Bool)
compOpP =
constP ">=" (>=)
<|> constP "<=" (<=)
<|> constP ">" (>)
<|> constP "==" (==)
<|> constP "<" (<)
<|> constP "!=" (/=)
numP = do
sign <- maybe 1 (const $ -1) <$> optional (char '-')
num <- read <$> some digitChar
pure $ sign * num
instrP = do
reg <- regP
space
op <- opP
space
val <- numP
_ <- string " if "
compReg <- regP
space
compOp <- compOpP
space
compTo <- numP
pure $ Inst op reg val (Cond compReg (`compOp` compTo))
parseAll = rights . map (parse instrP "") . lines
lookupDefault :: (Ord k) => Map k a -> k -> a -> a
lookupDefault m k d = maybe d id (Map.lookup k m)
eval = scanl step Map.empty
where step m i@(Inst op r v (Cond r' p))
| p (lookupDefault m r' 0) =
let f = inst i
in
Map.insertWith (\_ o -> f o) r (f 0) m
| otherwise = m
part1 = maximum . map snd . Map.toList . last . eval
part2 = maximum . map snd . concatMap Map.toList . eval
main = do
input <- parseAll <$> readFile "input.txt"
print $ part1 input
print $ part2 input