2025: d10: ex1: add solution
This commit is contained in:
parent
4238433f53
commit
bdaf6fdf0f
1 changed files with 65 additions and 0 deletions
65
2025/d10/ex1/ex1.py
Executable file
65
2025/d10/ex1/ex1.py
Executable file
|
|
@ -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()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue