From bdaf6fdf0f1456ef3b133444c2bcf27be465f7f2 Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Wed, 10 Dec 2025 09:39:33 +0000 Subject: [PATCH] 2025: d10: ex1: add solution --- 2025/d10/ex1/ex1.py | 65 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100755 2025/d10/ex1/ex1.py diff --git a/2025/d10/ex1/ex1.py b/2025/d10/ex1/ex1.py new file mode 100755 index 0000000..212beaa --- /dev/null +++ b/2025/d10/ex1/ex1.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python + +import itertools +import sys +from typing import NamedTuple + + +class Machine(NamedTuple): + lights: tuple[bool, ...] + buttons: list[list[int]] + joltage: list[int] + + @classmethod + def from_str(cls, input: str) -> "Machine": + raw_lights, *raw_buttons, raw_joltage = input.split() + lights = [c == "#" for c in raw_lights[1:-1]] + buttons = [[int(n) for n in button[1:-1].split(",")] for button in raw_buttons] + joltage = [int(n) for n in raw_joltage[1:-1].split(",")] + return cls(tuple(lights), buttons, joltage) + + +def solve(input: list[str]) -> int: + def parse(input: list[str]) -> list[Machine]: + return [Machine.from_str(line) for line in input] + + def apply_schematic( + lights: tuple[bool, ...], + button: list[int], + ) -> tuple[bool, ...]: + assert all(n < len(lights) for n in button) # Sanity check + return tuple((l if i not in button else not l) for i, l in enumerate(lights)) + + def start_presses(machine: Machine) -> int: + start = tuple(False for _ in machine.lights) + queue = [start] + seen = {start} + for i in itertools.count(1): + new_queue: list[tuple[bool, ...]] = [] + for p in queue: + for button in machine.buttons: + n = apply_schematic(p, button) + # If we've seen `n` before, it was in less or equal number of steps + if n in seen: + continue + # If we're at the end state, we've found the fastest path + if n == machine.lights: + return i + # Else, explore from that state + new_queue.append(n) + seen.add(n) + assert new_queue # Sanity check + queue = new_queue + assert False # Sanity check + + manual = parse(input) + return sum(start_presses(machine) for machine in manual) + + +def main() -> None: + input = sys.stdin.read().splitlines() + print(solve(input)) + + +if __name__ == "__main__": + main()