|
|
|
@ -25,7 +25,7 @@ class PMode(IntEnum):
|
|
|
|
|
|
|
|
|
|
class Intcode(object):
|
|
|
|
|
|
|
|
|
|
def __init__(self, program, print_output=False):
|
|
|
|
|
def __init__(self, program, print_output=False, debug=False):
|
|
|
|
|
self._memory = program.copy()
|
|
|
|
|
self.ip = 0
|
|
|
|
|
self.rel_base = 0
|
|
|
|
@ -35,23 +35,22 @@ class Intcode(object):
|
|
|
|
|
self.halt = False
|
|
|
|
|
self.outputs = []
|
|
|
|
|
self.print_output = print_output
|
|
|
|
|
self.debug = debug
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def parse_input(text):
|
|
|
|
|
return [int(i) for i in text.rstrip().split(",")]
|
|
|
|
|
|
|
|
|
|
def log(self, message, *args):
|
|
|
|
|
if self.debug:
|
|
|
|
|
print("debug:", message, *args)
|
|
|
|
|
|
|
|
|
|
def run(self, inputs=None):
|
|
|
|
|
self.inputs = inputs or []
|
|
|
|
|
handlers = self.get_handlers()
|
|
|
|
|
while not self.halt:
|
|
|
|
|
self.read_code()
|
|
|
|
|
handler = handlers.get(self.ctx_op)
|
|
|
|
|
if not handler:
|
|
|
|
|
sys.exit("Wrong opcode: {}".format(self.ctx_op))
|
|
|
|
|
try:
|
|
|
|
|
handler()
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
sys.exit("Exception: {}".format(exc))
|
|
|
|
|
handlers.get(self.ctx_op)()
|
|
|
|
|
return self.outputs[-1] if self.outputs else 0
|
|
|
|
|
|
|
|
|
|
def get_handlers(self):
|
|
|
|
@ -78,48 +77,45 @@ class Intcode(object):
|
|
|
|
|
|
|
|
|
|
def _check_memory_limits(self, index):
|
|
|
|
|
if index >= len(self._memory):
|
|
|
|
|
self._extend_memory(index + 1)
|
|
|
|
|
|
|
|
|
|
def _extend_memory(self, new_size):
|
|
|
|
|
if len(self._memory) >= new_size:
|
|
|
|
|
return
|
|
|
|
|
self._memory += [0] * (new_size - len(self._memory))
|
|
|
|
|
new_size = index + 1
|
|
|
|
|
self._memory += [0] * (new_size - len(self._memory))
|
|
|
|
|
|
|
|
|
|
def read_code(self):
|
|
|
|
|
code = self.mem_get(self.ip)
|
|
|
|
|
self.ctx_op = code % 100
|
|
|
|
|
code //= 100
|
|
|
|
|
raw_code = self.mem_get(self.ip)
|
|
|
|
|
code = raw_code % 100
|
|
|
|
|
self.ctx_op = Op(code)
|
|
|
|
|
|
|
|
|
|
code = raw_code // 100
|
|
|
|
|
self.ctx_modes = []
|
|
|
|
|
for _ in range(0, 3):
|
|
|
|
|
self.ctx_modes.append(PMode(code % 10))
|
|
|
|
|
code //= 10
|
|
|
|
|
self.log("read_code", raw_code, self.ctx_op, self.ctx_modes)
|
|
|
|
|
|
|
|
|
|
def param(self, index):
|
|
|
|
|
def param(self, index, pointer=False):
|
|
|
|
|
mode = self.ctx_modes[index - 1]
|
|
|
|
|
if mode == PMode.POS:
|
|
|
|
|
address = self.mem_get(self.ip + index)
|
|
|
|
|
return self.mem_get(address)
|
|
|
|
|
return address if pointer else self.mem_get(address)
|
|
|
|
|
elif mode == PMode.IMM:
|
|
|
|
|
return self.mem_get(self.ip + index)
|
|
|
|
|
elif mode == PMode.REL:
|
|
|
|
|
relative_jump = self.mem_get(self.ip + index)
|
|
|
|
|
address = self.rel_base + relative_jump
|
|
|
|
|
return self.mem_get(address)
|
|
|
|
|
|
|
|
|
|
def write_pos_ofs(self, pos_offset, value):
|
|
|
|
|
output_pos = self.mem_get(self.ip + pos_offset)
|
|
|
|
|
self.mem_set(output_pos, value)
|
|
|
|
|
address = self.rel_base + self.mem_get(self.ip + index)
|
|
|
|
|
return address if pointer else self.mem_get(address)
|
|
|
|
|
|
|
|
|
|
def write_at_param(self, param_offset, value):
|
|
|
|
|
self.mem_set(self.param(param_offset, pointer=True), value)
|
|
|
|
|
|
|
|
|
|
def op_add(self):
|
|
|
|
|
self.write_pos_ofs(3, self.param(1) + self.param(2))
|
|
|
|
|
self.write_at_param(3, self.param(1) + self.param(2))
|
|
|
|
|
self.ip += 4
|
|
|
|
|
|
|
|
|
|
def op_mul(self):
|
|
|
|
|
self.write_pos_ofs(3, self.param(1) * self.param(2))
|
|
|
|
|
self.write_at_param(3, self.param(1) * self.param(2))
|
|
|
|
|
self.ip += 4
|
|
|
|
|
|
|
|
|
|
def op_in(self):
|
|
|
|
|
self.write_pos_ofs(1, self.inputs.pop(0))
|
|
|
|
|
self.mem_set(self.param(1, pointer=True), self.inputs.pop(0))
|
|
|
|
|
self.ip += 2
|
|
|
|
|
|
|
|
|
|
def op_out(self):
|
|
|
|
@ -141,11 +137,11 @@ class Intcode(object):
|
|
|
|
|
self.ip += 3
|
|
|
|
|
|
|
|
|
|
def op_lt(self):
|
|
|
|
|
self.write_pos_ofs(3, int(self.param(1) < self.param(2)))
|
|
|
|
|
self.write_at_param(3, int(self.param(1) < self.param(2)))
|
|
|
|
|
self.ip += 4
|
|
|
|
|
|
|
|
|
|
def op_eq(self):
|
|
|
|
|
self.write_pos_ofs(3, int(self.param(1) == self.param(2)))
|
|
|
|
|
self.write_at_param(3, int(self.param(1) == self.param(2)))
|
|
|
|
|
self.ip += 4
|
|
|
|
|
|
|
|
|
|
def op_srb(self):
|
|
|
|
|