5 import Data.Text (Text)
6 import qualified Data.Text.IO as TIO
8 import Data.Void (Void)
10 import Text.Megaparsec hiding (State)
11 import Text.Megaparsec.Char
12 import qualified Text.Megaparsec.Char.Lexer as L
13 import qualified Control.Applicative as CA
15 -- import Control.Monad (unless)
16 import Control.Monad.State.Strict
17 import Control.Monad.Reader
18 import Control.Monad.Writer
19 import Control.Monad.RWS.Strict
22 import qualified Data.Map.Strict as M
23 import Data.Map.Strict ((!))
26 type Memory = M.Map Integer Integer
28 data Machine = Machine { _memory :: Memory
35 type ProgrammedMachine = RWS [Integer] [Integer] Machine
37 data ExecutionState = Runnable | Blocked | Terminated deriving (Ord, Eq, Show)
39 data ParameterMode = Position | Immediate | Relative deriving (Ord, Eq, Show)
42 -- returns (returnValue, finalMachine, outputs)
43 runProgram :: [Integer] -> [Integer] -> (ExecutionState, Machine, [Integer])
44 runProgram inputs program = runMachine inputs (makeMachine program)
46 runMachine :: [Integer] -> Machine -> (ExecutionState, Machine, [Integer])
47 runMachine inputs machine = runRWS runAll inputs machine
50 makeMachine :: [Integer] -> Machine
51 makeMachine memory = Machine {_ip = 0, _inputIndex = 0, _rb = 0
52 , _memory = M.fromList $ zip [0..] memory
56 runAll :: ProgrammedMachine ExecutionState
57 runAll = do mem <- gets _memory
60 iIndex <- gets _inputIndex
61 let acutalInputLength = length input
62 let requiredInputLength = iIndex + 1
64 then return Terminated
65 else if (mem!ip == 3 && requiredInputLength > acutalInputLength)
70 runStep :: ProgrammedMachine ()
72 do mem <- gets _memory
75 let opcode = (mem!ip) `mod` 100
76 let modes = parameterModes ((mem!ip) `div` 100)
77 fetchInput opcode modes
78 putOutput opcode modes
80 let (mem'', ip', rb') = perform opcode ip modes rb mem'
81 modify (\m -> m {_ip = ip', _memory = mem'', _rb = rb'})
83 fetchInput :: Integer -> [ParameterMode] -> ProgrammedMachine ()
84 -- fetchInput opcode _modes | trace ("Input with opcode " ++ show opcode) False = undefined
86 do mem <- gets _memory
89 inputIndex <- gets _inputIndex
91 let mem' = iInsert (ip + 1) (modes!!0) rb (inputs!!inputIndex) mem
92 modify (\m -> m {_inputIndex = inputIndex + 1, _memory = mem'})
93 fetchInput _ _ = return ()
95 putOutput :: Integer -> [ParameterMode] -> ProgrammedMachine ()
96 -- putOutput opcode _modes | trace ("Output with opcode " ++ show opcode) False = undefined
98 do mem <- gets _memory
101 let v = getMemoryValue (ip + 1) (modes!!0) rb mem
103 putOutput _ _ = return ()
106 perform :: Integer -> Integer -> [ParameterMode] -> Integer -> Memory -> (Memory, Integer, Integer)
107 -- perform instr ip modes rb mem | trace ("Perform ip " ++ show ip ++ " opcode " ++ show instr ++ " modes " ++ (show (take 3 modes)) ++ " rb " ++ (show rb) ++ " args " ++ (intercalate ", " (map show [(mem!(ip+1)), (mem!(ip+2)), (mem!(ip+3))]))) False = undefined
108 perform 1 ip modes rb mem = (iInsert (ip + 3) (modes!!2) rb (a + b) mem, ip + 4, rb)
109 where a = getMemoryValue (ip + 1) (modes!!0) rb mem
110 b = getMemoryValue (ip + 2) (modes!!1) rb mem
111 perform 2 ip modes rb mem = (iInsert (ip + 3) (modes!!2) rb (a * b) mem, ip + 4, rb)
112 where a = getMemoryValue (ip + 1) (modes!!0) rb mem
113 b = getMemoryValue (ip + 2) (modes!!1) rb mem
114 perform 3 ip _ rb mem = (mem, ip + 2, rb)
115 perform 4 ip _ rb mem = (mem, ip + 2, rb)
116 perform 5 ip modes rb mem = (mem, ip', rb)
117 where a = getMemoryValue (ip + 1) (modes!!0) rb mem
118 b = getMemoryValue (ip + 2) (modes!!1) rb mem
119 ip' = if a /= 0 then b else ip + 3
120 perform 6 ip modes rb mem = (mem, ip', rb)
121 where a = getMemoryValue (ip + 1) (modes!!0) rb mem
122 b = getMemoryValue (ip + 2) (modes!!1) rb mem
123 ip' = if a == 0 then b else ip + 3
124 perform 7 ip modes rb mem = (iInsert (ip + 3) (modes!!2) rb res mem, ip + 4, rb)
125 where a = getMemoryValue (ip + 1) (modes!!0) rb mem
126 b = getMemoryValue (ip + 2) (modes!!1) rb mem
127 res = if a < b then 1 else 0
128 perform 8 ip modes rb mem = (iInsert (ip + 3) (modes!!2) rb res mem, ip + 4, rb)
129 where a = getMemoryValue (ip + 1) (modes!!0) rb mem
130 b = getMemoryValue (ip + 2) (modes!!1) rb mem
131 res = if a == b then 1 else 0
132 perform 9 ip modes rb mem = (mem, ip + 2, rb + a)
133 where a = getMemoryValue (ip + 1) (modes!!0) rb mem
134 perform _ ip _ rb mem = (mem, ip, rb)
137 getMemoryValue :: Integer -> ParameterMode -> Integer -> Memory -> Integer
138 getMemoryValue loc Position rb mem = getMemoryValue loc' Immediate rb mem
139 where loc' = M.findWithDefault 0 loc mem
140 getMemoryValue loc Immediate _ mem = M.findWithDefault 0 loc mem
141 getMemoryValue loc Relative rb mem = getMemoryValue loc' Immediate 0 mem
142 where loc' = rb + M.findWithDefault 0 loc mem
145 iInsert :: Integer -> ParameterMode -> Integer -> Integer -> Memory -> Memory
146 iInsert loc Position _rb value mem = M.insert loc' value mem
147 where loc' = M.findWithDefault 0 loc mem
148 iInsert loc Immediate _rb value mem = M.insert loc value mem
149 iInsert loc Relative rb value mem = M.insert loc' value mem
150 where loc' = rb + M.findWithDefault 0 loc mem
152 parameterModes :: Integer -> [ParameterMode]
153 parameterModes modeCode = unfoldr generateMode modeCode
155 generateMode :: Integer -> Maybe (ParameterMode, Integer)
156 generateMode modeCode = Just (mode, modeCode `div` 10)
157 where mode = case (modeCode `mod` 10) of
163 -- Parse the input file
164 type Parser = Parsec Void Text
167 sc = L.space (skipSome spaceChar) CA.empty CA.empty
168 -- sc = L.space (skipSome (char ' ')) CA.empty CA.empty
171 integer = lexeme L.decimal
172 signedInteger = L.signed sc integer
176 memoryP = signedInteger `sepBy` comma
179 parseMachineMemory :: Text -> [Integer]
180 parseMachineMemory input =
181 case parse memoryP "input" input of
182 Left _err -> [] -- TIO.putStr $ T.pack $ parseErrorPretty err
183 Right memory -> memory