-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun.hs
82 lines (71 loc) · 2.6 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
import Control.Monad.State
import Control.Lens
import Data.Vector ((!?))
import qualified Data.Vector as V
import Data.Void (Void)
import Text.Megaparsec
import Text.Megaparsec.Char
import ProgramState
type Offset = Int
data Register = RA | RB deriving (Eq)
instance Show Register where
show RA = "a"
show RB = "b"
data Instruction = JIO !Register !Offset
| INC !Register
| TPL !Register
| HLF !Register
| JMP !Offset
| JIE !Register !Offset
deriving (Show, Eq)
type Parser = Parsec Void String
offset :: Parser Int
offset = toInt <$> oneOf "+-" <*> some digitChar
where toInt x xs
| x == '+' = read xs
| otherwise = read (x:xs)
register = (\x -> if x == 'a' then RA else RB) <$> oneOf "ab"
instruction :: Parser Instruction
instruction =
choice $ map try [ jif JIO "jio"
, jif JIE "jie"
, jmp JMP "jmp"
, mod HLF "hlf"
, mod INC "inc"
, mod TPL "tpl"
]
where mod :: (Register -> Instruction) -> String -> Parser Instruction
mod sym str = sym <$> (string (str ++ " ") *> register)
jmp :: (Int -> Instruction) -> String -> Parser Instruction
jmp sym str = sym <$> (string (str ++ " ") *> offset)
jif :: (Register -> Int -> Instruction) -> String -> Parser Instruction
jif sym str = sym <$> (string (str ++ " ") *> register) <*> (string ", " *> offset)
unsafeRight (Right x) = x
parseAll = V.fromList
. map unsafeRight
. map (parse instruction "")
. lines
emulate a inst = runState eval (PState a 0 0)
where eval = do
i <- currentInstruction
s <- get
case i of
Nothing -> pure ()
Just (JIO r o) -> (if getR r s == 1 then rins += o else rins += 1) >> eval
Just (INC r ) -> modR r += 1 >> (rins += 1) >> eval
Just (TPL r ) -> modR r *= 3 >> (rins += 1) >> eval
Just (HLF r ) -> modR r ///= 2 >> (rins += 1) >> eval
Just (JMP o ) -> rins += o >> eval
Just (JIE r o) -> (if even (getR r s) then rins += o else rins += 1) >> eval
currentInstruction = (\s -> inst !? (_rins s)) <$> get
x ///= y = x %= (`div` y)
getR RA = _ra
getR RB = _rb
modR RA = ra
modR RB = rb
part1 = _rb . snd . emulate 0
part2 = _rb . snd . emulate 1
main = do
input <- parseAll <$> readFile "input.txt"
print (part1 input)
print (part2 input)