73 lines
3.3 KiB
Python
73 lines
3.3 KiB
Python
from typing import List
|
|
from queue import Queue
|
|
|
|
|
|
class IntCode:
|
|
def __init__(self, memory: List[int], mem_size: int = 0):
|
|
self.instr_ptr = 0
|
|
self.halted = False
|
|
self.memory = memory
|
|
self.input = Queue()
|
|
self.output = Queue()
|
|
if len(self.memory) < mem_size:
|
|
self.memory.extend([0] * (mem_size - len(self.memory)))
|
|
|
|
def get_parameter_value(self, address: int, mode: int) -> int:
|
|
if mode == 0:
|
|
return self.memory[self.memory[address]]
|
|
elif mode == 1:
|
|
return self.memory[address]
|
|
|
|
def run(self):
|
|
while not self.halted:
|
|
instr = self.memory[self.instr_ptr] % 100
|
|
p1_mode = self.memory[self.instr_ptr] // 100 % 10
|
|
p2_mode = self.memory[self.instr_ptr] // 1_000 % 10
|
|
# p3_mode = self.memory[self.instr_ptr] // 10_000 % 10
|
|
|
|
if instr == 1: # add
|
|
param1 = self.get_parameter_value(self.instr_ptr + 1, p1_mode)
|
|
param2 = self.get_parameter_value(self.instr_ptr + 2, p2_mode)
|
|
target_addr = self.memory[self.instr_ptr + 3]
|
|
self.memory[target_addr] = param1 + param2
|
|
self.instr_ptr += 4
|
|
elif instr == 2: # multiply
|
|
param1 = self.get_parameter_value(self.instr_ptr + 1, p1_mode)
|
|
param2 = self.get_parameter_value(self.instr_ptr + 2, p2_mode)
|
|
target_addr = self.memory[self.instr_ptr + 3]
|
|
self.memory[target_addr] = param1 * param2
|
|
self.instr_ptr += 4
|
|
elif instr == 3: # input
|
|
target_addr = self.memory[self.instr_ptr + 3]
|
|
self.memory[target_addr] = self.input.get()
|
|
self.instr_ptr += 2
|
|
elif instr == 4: # output
|
|
self.output.put(self.get_parameter_value(self.instr_ptr + 1, p1_mode))
|
|
self.instr_ptr += 2
|
|
elif instr == 5: # jump-if-true
|
|
if self.get_parameter_value(self.instr_ptr + 1, p1_mode) != 0:
|
|
self.instr_ptr = self.get_parameter_value(self.instr_ptr + 2, p2_mode)
|
|
else:
|
|
self.instr_ptr += 3
|
|
elif instr == 6: # jump-if-false
|
|
if self.get_parameter_value(self.instr_ptr + 1, p1_mode) == 0:
|
|
self.instr_ptr = self.get_parameter_value(self.instr_ptr + 2, p2_mode)
|
|
else:
|
|
self.instr_ptr += 3
|
|
elif instr == 7: # less than
|
|
param1 = self.get_parameter_value(self.instr_ptr + 1, p1_mode)
|
|
param2 = self.get_parameter_value(self.instr_ptr + 2, p2_mode)
|
|
target_addr = self.memory[self.instr_ptr + 3]
|
|
self.memory[target_addr] = param1 < param2
|
|
self.instr_ptr += 4
|
|
elif instr == 8: # equals
|
|
param1 = self.get_parameter_value(self.instr_ptr + 1, p1_mode)
|
|
param2 = self.get_parameter_value(self.instr_ptr + 2, p2_mode)
|
|
target_addr = self.memory[self.instr_ptr + 3]
|
|
self.memory[target_addr] = param1 == param2
|
|
self.instr_ptr += 4
|
|
elif instr == 99:
|
|
self.halted = True
|
|
else:
|
|
raise ValueError("Invalid instruction encountered at pos %d: %d" % (self.instr_ptr, instr))
|