Files
advent-of-code/2019/day-5/python/main.py
2019-12-07 18:03:50 -06:00

114 lines
3.5 KiB
Python

import os
import sys
class IntCodeExit(Exception):
pass
class IntCodeStatus(Exception):
def __init__(self, code):
self.code = code
return super().__init__(f"Status code '{self.code}' was raised by the Intcode Computer.")
class IntcodeComputer(object):
def __init__(self, memory, _input=[], pointer=0, silent=True):
self.memory = memory
self._input = iter(_input)
self.pointer = pointer
self.silent = silent
self.READ_MODES = {
0: (self.point, self.point, self.point),
100: (self.point, self.point, self.value),
10: (self.point, self.value, self.point),
110: (self.point, self.value, self.value),
1: (self.value, self.point, self.point),
101: (self.value, self.point, self.value),
11: (self.value, self.value, self.point),
111: (self.value, self.value, self.value),
}
self.OP_CODES = {
1 : (self.op_add, 3),
2 : (self.op_multiply, 3),
3 : (self.op_input, 1),
4 : (self.op_print, 1),
5 : (self.op_jit, 2),
6 : (self.op_jif, 2),
7 : (self.op_lth, 3),
8 : (self.op_eq, 3),
99 : (self.op_exit, 0)
}
def hasNext(self):
return self.pointer < len(self.memory)
def next(self):
op, params, offset = self.read(self.pointer)
self.pointer += offset
op(*params)
def run(self):
statuses = []
while self.hasNext():
try:
self.next()
except IntCodeStatus as s:
statuses.append(s.code)
except IntCodeExit:
return statuses[-1]
def read(self, pointer):
code = self.memory[pointer]
readmodes, opcode = divmod(code, 100)
op, nargs = self.OP_CODES[opcode]
argument_functions = self.READ_MODES[readmodes][:nargs]
parameters = [f(ptr) for f, ptr in zip(argument_functions, range(pointer+1, pointer+4))]
return op, parameters, nargs + 1
def op_add(self, param1, param2, param3):
self.memory[param3] = self.memory[param1] + self.memory[param2]
def op_multiply(self, param1, param2, param3):
self.memory[param3] = self.memory[param1] * self.memory[param2]
def op_input(self, param1):
self.memory[param1] = next(self._input)
def op_print(self, param1):
if not self.silent:
print(self.memory[param1])
raise IntCodeStatus(self.memory[param1])
def op_exit(self):
raise IntCodeExit()
def op_jit(self, param1, param2):
if self.memory[param1] != 0:
self.pointer = self.memory[param2]
def op_jif(self, param1, param2):
if self.memory[param1] == 0:
self.pointer = self.memory[param2]
def op_lth(self, param1, param2, param3):
self.memory[param3] = 1 if self.memory[param1] < self.memory[param2] else 0
def op_eq(self, param1, param2, param3):
self.memory[param3] = 1 if self.memory[param1] == self.memory[param2] else 0
def value(self, location):
return location
def point(self, location):
ptr = self.memory[location]
return ptr
def day5(memory, _input, silent=True):
computer = IntcodeComputer(memory.copy(), _input=_input, silent=silent)
print(computer.run())
path = os.path.join(sys.path[0], '..', 'input')
data = list(map(int, open(path, 'r').read().split(',')))
day5(data, _input=[1])
day5(data, _input=[5])