This commit is contained in:
parent
291c627c79
commit
30e0bb3665
107
src/holt59/aoc/2015/day23.py
Normal file
107
src/holt59/aoc/2015/day23.py
Normal file
@ -0,0 +1,107 @@
|
||||
import inspect
|
||||
from typing import Any, Callable, Final, Iterator, Mapping
|
||||
|
||||
from ..base import BaseSolver
|
||||
|
||||
|
||||
class Instruction:
|
||||
def __init__(self, fn: Callable[..., None]):
|
||||
self._fn = fn
|
||||
|
||||
args = inspect.getfullargspec(fn)
|
||||
|
||||
self._argtypes = [args.annotations[arg] for arg in args.args[1:]]
|
||||
|
||||
def __call__(self, args: tuple[str, ...]):
|
||||
self._fn(
|
||||
*(argtype(arg) for arg, argtype in zip(args, self._argtypes, strict=True))
|
||||
)
|
||||
|
||||
|
||||
class Machine:
|
||||
def __init__(
|
||||
self, instructions: list[str], registers: dict[str, int] = {"a": 0, "b": 1}
|
||||
):
|
||||
self.instructions: Final = [
|
||||
(part[0], tuple(arg.strip() for arg in " ".join(part[1:]).split(",")))
|
||||
for instruction in instructions
|
||||
if (part := instruction.split())
|
||||
]
|
||||
|
||||
self._fns = {
|
||||
name: Instruction(getattr(self, name))
|
||||
for name in ("hlf", "tpl", "inc", "jmp", "jie", "jio")
|
||||
}
|
||||
|
||||
self._registers = registers.copy()
|
||||
self._ip = 0
|
||||
|
||||
@property
|
||||
def registers(self) -> Mapping[str, int]:
|
||||
return self._registers
|
||||
|
||||
@property
|
||||
def ip(self) -> int:
|
||||
return self._ip
|
||||
|
||||
def reset(self, registers: dict[str, int] = {"a": 0, "b": 0}):
|
||||
self._registers = registers.copy()
|
||||
self._ip = 0
|
||||
|
||||
def hlf(self, register: str):
|
||||
self._registers[register] //= 2
|
||||
self._ip += 1
|
||||
|
||||
def tpl(self, register: str):
|
||||
self._registers[register] *= 3
|
||||
self._ip += 1
|
||||
|
||||
def inc(self, register: str):
|
||||
self._registers[register] += 1
|
||||
self._ip += 1
|
||||
|
||||
def jmp(self, offset: int):
|
||||
self._ip += offset
|
||||
assert 0 <= self._ip < len(self.instructions)
|
||||
|
||||
def jie(self, register: str, offset: int):
|
||||
if self._registers[register] % 2 == 0:
|
||||
self._ip += offset
|
||||
else:
|
||||
self._ip += 1
|
||||
|
||||
def jio(self, register: str, offset: int):
|
||||
if self._registers[register] == 1:
|
||||
self._ip += offset
|
||||
else:
|
||||
self._ip += 1
|
||||
|
||||
def _exec(self) -> bool:
|
||||
# execute next instruction
|
||||
if self._ip >= len(self.instructions):
|
||||
return False
|
||||
|
||||
ins, args = self.instructions[self._ip]
|
||||
|
||||
if ins not in self._fns:
|
||||
return False
|
||||
|
||||
self._fns[ins](args)
|
||||
return True
|
||||
|
||||
def run(self):
|
||||
while self._exec():
|
||||
...
|
||||
return self.registers
|
||||
|
||||
|
||||
class Solver(BaseSolver):
|
||||
def solve(self, input: str) -> Iterator[Any]:
|
||||
machine = Machine(input.splitlines())
|
||||
|
||||
registers = machine.run()
|
||||
yield registers["b"]
|
||||
|
||||
machine.reset({"a": 1, "b": 0})
|
||||
registers = machine.run()
|
||||
yield registers["b"]
|
49
src/holt59/aoc/inputs/holt59/2015/day23.txt
Normal file
49
src/holt59/aoc/inputs/holt59/2015/day23.txt
Normal file
@ -0,0 +1,49 @@
|
||||
jio a, +19
|
||||
inc a
|
||||
tpl a
|
||||
inc a
|
||||
tpl a
|
||||
inc a
|
||||
tpl a
|
||||
tpl a
|
||||
inc a
|
||||
inc a
|
||||
tpl a
|
||||
tpl a
|
||||
inc a
|
||||
inc a
|
||||
tpl a
|
||||
inc a
|
||||
inc a
|
||||
tpl a
|
||||
jmp +23
|
||||
tpl a
|
||||
tpl a
|
||||
inc a
|
||||
inc a
|
||||
tpl a
|
||||
inc a
|
||||
inc a
|
||||
tpl a
|
||||
inc a
|
||||
tpl a
|
||||
inc a
|
||||
tpl a
|
||||
inc a
|
||||
tpl a
|
||||
inc a
|
||||
inc a
|
||||
tpl a
|
||||
inc a
|
||||
inc a
|
||||
tpl a
|
||||
tpl a
|
||||
inc a
|
||||
jio a, +8
|
||||
inc b
|
||||
jie a, +4
|
||||
tpl a
|
||||
inc a
|
||||
jmp +2
|
||||
hlf a
|
||||
jmp -7
|
4
src/holt59/aoc/inputs/tests/2015/day23.txt
Normal file
4
src/holt59/aoc/inputs/tests/2015/day23.txt
Normal file
@ -0,0 +1,4 @@
|
||||
inc a
|
||||
jio a, +2
|
||||
tpl a
|
||||
inc a
|
Loading…
Reference in New Issue
Block a user