88 lines
2.8 KiB
Python
88 lines
2.8 KiB
Python
from enum import Enum
|
|
|
|
|
|
class Command(str, Enum):
|
|
COPY = "cpy"
|
|
INCREASE = "inc"
|
|
DECREASE = "dec"
|
|
JUMP_NON_ZERO = "jnz"
|
|
TOGGLE = "tgl"
|
|
|
|
|
|
class Computer:
|
|
def __init__(
|
|
self, code: list[tuple[Command, str | int, ...]], reg_a: int = 0, reg_b: int = 0, reg_c: int = 0, reg_d: int = 0
|
|
):
|
|
self.reg = {
|
|
"a": reg_a,
|
|
"b": reg_b,
|
|
"c": reg_c,
|
|
"d": reg_d,
|
|
}
|
|
self.code = code
|
|
self.instr_ptr = 0
|
|
|
|
def get_value(self, source: int | str) -> int:
|
|
if isinstance(source, int):
|
|
return source
|
|
|
|
if source not in "abcd":
|
|
raise ValueError(f"Invalid source: {source}")
|
|
|
|
return self.reg[source]
|
|
|
|
def run(self):
|
|
while self.instr_ptr < len(self.code):
|
|
cmd, *args = self.code[self.instr_ptr]
|
|
if cmd == Command.COPY:
|
|
if isinstance(args[0], int):
|
|
self.reg[args[1]] = args[0]
|
|
else:
|
|
self.reg[args[1]] = self.reg[args[0]]
|
|
self.instr_ptr += 1
|
|
elif cmd == Command.INCREASE:
|
|
self.reg[args[0]] += 1
|
|
self.instr_ptr += 1
|
|
elif cmd == Command.DECREASE:
|
|
self.reg[args[0]] -= 1
|
|
self.instr_ptr += 1
|
|
elif cmd == Command.JUMP_NON_ZERO:
|
|
if isinstance(args[0], int):
|
|
check = args[0]
|
|
else:
|
|
check = self.reg[args[0]]
|
|
if check:
|
|
self.instr_ptr += self.get_value(args[1])
|
|
else:
|
|
self.instr_ptr += 1
|
|
elif cmd == Command.TOGGLE:
|
|
target = self.instr_ptr + self.reg[args[0]]
|
|
if target >= len(self.code) or target < 0:
|
|
self.instr_ptr += 1
|
|
continue
|
|
|
|
target_instr = self.code[target]
|
|
if len(target_instr) == 2:
|
|
if target_instr[0] != Command.INCREASE:
|
|
self.code[target] = (Command.INCREASE, target_instr[1])
|
|
else:
|
|
self.code[target] = (Command.DECREASE, target_instr[1])
|
|
else:
|
|
if target_instr[0] != Command.JUMP_NON_ZERO:
|
|
self.code[target] = (Command.JUMP_NON_ZERO, *target_instr[1:])
|
|
else:
|
|
self.code[target] = (Command.COPY, *target_instr[1:])
|
|
|
|
self.instr_ptr += 1
|
|
|
|
|
|
def parse_assembunny_code(code_lines: list[str]) -> list[tuple[Command, str | int, ...]]:
|
|
code = []
|
|
for line in code_lines:
|
|
args = line.split()
|
|
cmd = Command(args[0])
|
|
args = [int(arg) if arg not in "abcd" else arg for arg in args[1:]]
|
|
code.append((cmd, *args))
|
|
|
|
return code
|