Modules for intcode computer. Old code, commiting before changes

master
Tibor Bizjak 2023-03-07 20:23:27 +01:00
parent 554ea25596
commit 31d860b227
2 changed files with 201 additions and 0 deletions

103
intcode.py 100644
View File

@ -0,0 +1,103 @@
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

98
opcodes.py 100644
View File

@ -0,0 +1,98 @@
from operator import add, mul, eq, lt
import enum
@enum.unique
class State(enum.Enum):
"""Execution state class."""
CONTINUE = 0
HALT = 1
WAIT = 2
class Opcode:
def __init__(self, func, parnum):
self.parnum = parnum
self.run = func
def operation(operator):
"""Make opcode from operator."""
def opcode(state, p1, p2, p3):
state.memory.write(p3, operator(state.memory.read(p1), state.memory.read(p2)))
state.i += 4
return State.CONTINUE
return Opcode(opcode, 3)
def jump(flag):
def opcode(state, p1, p2):
state.i = state.memory.read(p2) if (state.memory.read(p1) > 0)==flag else state.i+3
return State.CONTINUE
return Opcode(opcode, 2)
def adjust_base(state, p1):
state.rel_base += state.memory.read(p1)
state.i += 2
return State.CONTINUE
def input(state, p1):
if state.IO.wait_for_input():
return State.WAIT
state.memory.write(p1, state.IO.input())
state.i += 2
return State.CONTINUE
def output(state, p1):
state.IO.output(state.memory.read(p1))
state.i += 2
return State.CONTINUE
op_add = operation(add)
op_mul = operation(mul)
op_lt = operation(lt)
op_eq = operation(eq)
op_jump_if_true = jump(True)
op_jump_if_false = jump(False)
op_adjust_relative_base = Opcode(adjust_base, 1)
op_input = Opcode(input, 1)
op_output = Opcode(output, 1)
op_halt = Opcode(lambda x: State.HALT, 0)
opcodes = {1 : op_add,
2 : op_mul,
3 : op_input,
4 : op_output,
5 : op_jump_if_true,
6 : op_jump_if_false,
7 : op_lt,
8 : op_eq,
9 : op_adjust_relative_base,
99 : op_halt}
def parse_op(op):
op = str(op)
par_modes, op = op[:-2][::-1], int(op[-2:])
par_modes = par_modes + '0'*(opcodes[op].parnum - len(par_modes))
return op, map(int, par_modes)
def run_op(state):
op, par_modes = parse_op(state.memory.read(state.i))
pars = []
for pn, mode in enumerate(par_modes, start=1):
p = state.i + pn
if mode == 0:
p = state.memory.read(p)
elif mode == 2:
p = state.rel_base + state.memory.read(p)
pars.append(p)
return opcodes[op].run(state, *pars)