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))