diff --git a/2017/d18/ex1/ex1.py b/2017/d18/ex1/ex1.py new file mode 100755 index 0000000..daa8cdf --- /dev/null +++ b/2017/d18/ex1/ex1.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python + +import collections +import enum +import sys +from typing import NamedTuple + + +class Op(enum.StrEnum): + SND = "snd" + SET = "set" + ADD = "add" + MUL = "mul" + MOD = "mod" + RCV = "rcv" + JGZ = "jgz" + + +class Instruction(NamedTuple): + op: Op + x: str + y: str | None = None + + @classmethod + def from_str(cls, input: str) -> "Instruction": + op, *rest = input.split() + return cls(Op(op), *rest) + + +def solve(input: str) -> int: + def parse(input: str) -> list[Instruction]: + return [Instruction.from_str(line) for line in input.splitlines()] + + def resolve(y: str | None, registers: dict[str, int]) -> int: + assert y is not None # Sanity check + try: + return int(y) + except ValueError: + return registers[y] + + instructions = parse(input) + registers: dict[str, int] = collections.defaultdict(int) + + ip = 0 + freq: int | None = None + while True: + assert 0 <= ip < len(instructions) # Sanity check + instr = instructions[ip] + ip += 1 + match instr.op: + case Op.SND: + freq = resolve(instr.x, registers) + case Op.SET: + registers[instr.x] = resolve(instr.y, registers) + case Op.ADD: + registers[instr.x] += resolve(instr.y, registers) + case Op.MUL: + registers[instr.x] *= resolve(instr.y, registers) + case Op.MOD: + registers[instr.x] %= resolve(instr.y, registers) + case Op.RCV: + if resolve(instr.x, registers) != 0: + assert freq is not None + return freq + case Op.JGZ: + if resolve(instr.x, registers) > 0: + ip += resolve(instr.y, registers) - 1 # Account auto-increment + + +def main() -> None: + input = sys.stdin.read() + print(solve(input)) + + +if __name__ == "__main__": + main()