diff --git a/2018/d16/ex1/ex1.py b/2018/d16/ex1/ex1.py new file mode 100755 index 0000000..2bc4551 --- /dev/null +++ b/2018/d16/ex1/ex1.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python + +import copy +import enum +import sys +from typing import NamedTuple + + +class OpCode(enum.StrEnum): + ADDR = "addr" + ADDI = "addi" + MULR = "mulr" + MULI = "muli" + BANR = "banr" + BANI = "bani" + BORR = "borr" + BORI = "bori" + SETR = "setr" + SETI = "seti" + GTIR = "gtir" + GTRI = "gtri" + GTRR = "gtrr" + EQIR = "eqir" + EQRI = "eqri" + EQRR = "eqrr" + + def apply(self, registers: list[int], a: int, b: int, c: int) -> list[int]: + registers = copy.deepcopy(registers) + if self == OpCode.ADDR: + registers[c] = registers[a] + registers[b] + if self == OpCode.ADDI: + registers[c] = registers[a] + b + if self == OpCode.MULR: + registers[c] = registers[a] * registers[b] + if self == OpCode.MULI: + registers[c] = registers[a] * b + if self == OpCode.BANR: + registers[c] = registers[a] & registers[b] + if self == OpCode.BANI: + registers[c] = registers[a] & b + if self == OpCode.BORR: + registers[c] = registers[a] | registers[b] + if self == OpCode.BORI: + registers[c] = registers[a] | b + if self == OpCode.SETR: + registers[c] = registers[a] + if self == OpCode.SETI: + registers[c] = a + if self == OpCode.GTIR: + registers[c] = a > registers[b] + if self == OpCode.GTRI: + registers[c] = registers[a] > b + if self == OpCode.GTRR: + registers[c] = registers[a] > registers[b] + if self == OpCode.EQIR: + registers[c] = a == registers[b] + if self == OpCode.EQRI: + registers[c] = registers[a] == b + if self == OpCode.EQRR: + registers[c] = registers[a] == registers[b] + return registers + + +Instruction = list[int] + + +class Example(NamedTuple): + before: list[int] + data: Instruction + after: list[int] + + +def solve(input: str) -> int: + def parse_example(input: list[str]) -> Example: + before = input[0].removeprefix("Before: [").removesuffix("]") + data = input[1] + after = input[2].removeprefix("After: [").removesuffix("]") + return Example( + [int(n) for n in before.split(", ")], + [int(n) for n in data.split()], + [int(n) for n in after.split(", ")], + ) + + def parse_examples(input: str) -> list[Example]: + return [parse_example(example.splitlines()) for example in input.split("\n\n")] + + def parse_data(input: list[str]) -> list[Instruction]: + return [[int(n) for n in line.split()] for line in input] + + def parse(input: str) -> tuple[list[Example], list[Instruction]]: + examples, data = input.split("\n\n\n\n") + return parse_examples(examples), parse_data(data.splitlines()) + + def num_candidates(example: Example) -> int: + return sum( + op.apply(example.before, *example.data[1:]) == example.after + for op in OpCode + ) + + examples, data = parse(input) + return sum(num_candidates(example) >= 3 for example in examples) + + +def main() -> None: + input = sys.stdin.read() + print(solve(input)) + + +if __name__ == "__main__": + main()