1 module Main(main) where
3 import Text.Parsec hiding (State)
4 import Text.ParserCombinators.Parsec.Number
5 import Control.Monad.State.Lazy
11 data Instruction = Inc Register
14 | Cpy Register Register
19 data Machine = Machine { a :: Int
24 , instructions :: [Instruction]}
27 -- testInstructions = "set c 0\n\
30 testInstructions = "set c 0\n\
42 emptyMachine :: Machine
43 emptyMachine = Machine {a=0, b=0, c=0, d=0, pc=0, instructions=[]}
47 text <- readFile "07-program.txt"
48 let instructions = successfulParse $ parseIfile text
51 -- let text = testInstructions
52 -- let instrs = successfulParse $ parseIfile text
53 -- let m0 = emptyMachine {instructions=instrs, a = 7, b = 3}
54 -- let mf = snd $ runState runMachine m0
57 part1 :: [Instruction] -> IO ()
59 do let m0 = emptyMachine {instructions=instrs, a = 7}
60 let mf = snd $ runState runMachine m0
63 part2 :: [Instruction] -> IO ()
65 do let m0 = emptyMachine {instructions=instrs, a = 937}
66 let mf = snd $ runState runMachine m0
70 runMachine :: State Machine ()
73 if (pc m) >= (length $ instructions m)
78 executeStep :: State Machine ()
81 let i = (instructions m)!!(pc m)
82 put (executeInstruction i m)
85 executeInstruction :: Instruction -> Machine -> Machine
86 -- executeInstruction i m | trace (show i ++ " " ++ show m) False = undefined
87 executeInstruction (Inc r) m = m' {pc=pc1}
88 where pc1 = (pc m) + 1
90 m' = writeRegister m r (v+1)
91 executeInstruction (Dec r) m = m' {pc=pc1}
92 where pc1 = (pc m) + 1
94 m' = writeRegister m r (v-1)
95 executeInstruction (Set r v) m = m' {pc=pc1}
96 where pc1 = (pc m) + 1
97 m' = writeRegister m r v
98 executeInstruction (Cpy s d) m = m' {pc=pc1}
99 where pc1 = (pc m) + 1
101 m' = writeRegister m d v
102 executeInstruction (Jmp d) m = m {pc=pcj}
103 where pcj = (pc m) + d
104 executeInstruction (Jpz r d) m
105 | v == 0 = m {pc=pcj}
106 | otherwise = m {pc=pc1}
107 where pc1 = (pc m) + 1
113 readRegister :: Machine -> Register -> Int
121 writeRegister :: Machine -> Register -> Int -> Machine
122 writeRegister m r v =
130 instructionFile = instructionLine `sepEndBy` newline
131 instructionLine = incL <|> decL <|> setL <|> cpyL <|> jmpL <|> jpzL
133 incL = Inc <$> (try (string "inc") *> spaces *> register)
134 decL = Dec <$> (try (string "dec") *> spaces *> register)
135 setL = Set <$> (try (string "set") *> spaces *> register) <*> (spaces *> location)
136 cpyL = Cpy <$> (try (string "cpy") *> spaces *> register) <*> (spaces *> register)
137 jmpL = Jmp <$> (try (string "jmp") *> spaces *> location)
138 jpzL = Jpz <$> (try (string "jpz") *> spaces *> register) <*> (spaces *> location)
141 register = oneOf "abcd"
143 parseIfile :: String -> Either ParseError [Instruction]
144 parseIfile input = parse instructionFile "(unknown)" input
146 parseIline :: String -> Either ParseError Instruction
147 parseIline input = parse instructionLine "(unknown)" input
149 successfulParse :: Either ParseError [a] -> [a]
150 successfulParse (Left _) = []
151 successfulParse (Right a) = a