99 lines
2.2 KiB
Python
99 lines
2.2 KiB
Python
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)
|