advent-of-code-2019/intcode.py

104 lines
2.4 KiB
Python

from collections import defaultdict
from opcodes import run_op, CONTINUE, HALT, WAIT
class StackIO:
def __init__(self):
self.input_stack = []
self.output_stack = []
def input(self):
return self.input_stack.pop(0)
def output(self, val):
self.output_stack.append(val)
def wait_for_input(self):
return len(self.input_stack) == 0
def pop_out(self):
return self.output_stack.pop(0)
class Memory:
def __init__(self, program=[]):
self.memory = program[:]
def write(self, i, val):
self.memory += [0] * (i - len(self.memory) + 1)
self.memory[i] = val
def read(self, i):
if i >= len(self.memory):
return 0
return self.memory[i]
def copy(self):
return Memory(self.memory[:])
class Computer(object):
def __init__(self, program, IO, i=0, rel_base=0):
self.memory = Memory(program)
self.IO = IO
self.i = i
self.rel_base = rel_base
def run(self):
for exe_state in self:
if exe_state != CONTINUE:
break
return exe_state
def __iter__(self):
return self
def __next__(self):
return self.run_opcode()
def copy(self):
return Computer(self.memory.memory[:], self.IO, self.i, self.rel_base)
class IntComp(Computer):
run_opcode = run_op
def copy(self):
return IntComp(self.memory.memory[:], self.IO, self.i, self.rel_base)
class Display(defaultdict):
def __init__(self, encoding):
super(Display, self).__init__(int)
self.encoding = encoding
def __str__(self):
xs, ys = zip(*self.keys())
X, Y = max(xs)+1, max(ys)+1
return '\n'.join(''.join(self.encoding[self[(x, y)]]
for x in range(X))
for y in range(Y))
class DisplayIO(object):
def __init__(self, display):
self.display = display
self.block = tuple()
def input(self):
return NotImplemented
def wait_for_input(self):
return NotImplemented
def output(self, x):
self.block += (x,)
if len(self.block) == 3:
self.display[self.block[:2]] = self.block[2]
self.block = tuple()
def output(program, input=[], computer=IntComp):
IO = StackIO()
IO.input_stack = input[:]
comp = computer(program, IO)
if comp.run() != HALT:
return False
return IO.output_stack