-
Notifications
You must be signed in to change notification settings - Fork 0
/
intcode.py
65 lines (55 loc) · 2.07 KB
/
intcode.py
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
import typing
from instruction import IntcodeInstruction, AddressingMode
class IntcodeMachine:
def __init__(self, initial_memory : typing.List[int], instruction_set : typing.Dict[int, IntcodeInstruction], inpt=[]):
self.memory = {
i:initial_memory[i] for i in range(len(initial_memory))
}
self.memory_top = len(initial_memory) + 1
self.pc = -1
self.running = True
self.jumped = False
self.input = inpt
self.output = []
self.instruction_set = instruction_set
self.relbase = 0
def next_pc(self):
if self.jumped:
self.jumped = False
return self.pc
self.pc += 1
while self.pc not in self.memory:
self.pc += 1
if self.pc > self.memory_top:
# Halt; run off the end of memory
raise KeyError("Run off the end of memory!")
return self.pc
def step(self) -> bool:
try: full_opcode = self.memory[self.next_pc()]
except KeyError: return False
inst = self.instruction_set[full_opcode % 100]
args = tuple(
self.memory[self.next_pc()]
for _ in range(inst.OPERANDS)
)
inst.exec(full_opcode, self, *args)
return self.running
def fetch(self, op, mode : AddressingMode):
if mode == AddressingMode.IMMEDIATE: return op
# else
if mode == AddressingMode.RELATIVE:
op += self.relbase
if op in self.memory:
return self.memory[op]
elif op < 0:
raise RuntimeError(f"Negative access at address {op}")
else:
# print(f"Uninitialised access at address {op}, returning 0")
return 0
def store(self, address : int, value : int, mode : AddressingMode):
address = address + self.relbase if mode == AddressingMode.RELATIVE else address
self.memory[address] = value
if address > self.memory_top: self.memory_top = address + 1
def jump(self, address):
self.pc = address
self.jumped = True