import operator
from collections import defaultdict
from dataclasses import dataclass
from typing import Callable
operators = {
"inc": operator.add,
"dec": operator.sub,
}
comparisons = {
"<": operator.lt,
"<=": operator.le,
"==": operator.eq,
"!=": operator.ne,
">=": operator.ge,
">": operator.gt,
}
def parse_op(op):
reg, op, value = op.split()
value = int(value)
op = operators[op]
return (
lambda registers: operator.setitem(registers, reg, op(registers[reg], value))
or registers[reg]
)
def parse_cond(cond):
reg, cond, target = cond.split()
target = int(target)
cond = comparisons[cond]
return lambda registers: cond(registers[reg], target)
@dataclass
class Instruction(object):
line: str
operation: Callable[[dict], int]
condition: Callable[[dict], bool]
@classmethod
def from_line(cls, line):
line = line.strip()
instr, cond = line.split("if")
return cls(line, parse_op(instr.strip()), parse_cond(cond.strip()))
def execute(self, registers):
if self.condition(registers):
return self.operation(registers)
return 0
def read_program(lines):
return [Instruction.from_line(line) for line in lines if line.strip()]
def largest_register_value(program):
registers = defaultdict(int)
return (max(instr.execute(registers) for instr in program), max(registers.values()))
test_program = read_program(
"""\
b inc 5 if a > 1
a inc 1 if b < 5
c dec -10 if a >= 1
c inc -20 if c == 10
""".splitlines()
)
assert largest_register_value(test_program) == (10, 1)