feat: add solution 2025/10

This commit is contained in:
2025-12-10 21:01:47 +01:00
parent 000002201f
commit 21bbeff9d2
3 changed files with 106 additions and 0 deletions

3
data/example/2025/10.txt Normal file
View File

@@ -0,0 +1,3 @@
[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7}
[...#.] (0,2,3,4) (2,3) (0,4) (0,1,2) (1,2,3,4) {7,5,12,7,2}
[.###.#] (0,1,2,3,4) (0,3,4) (0,1,2,4,5) (1,2) {10,11,11,5,10,5}

View File

@@ -1,2 +1,7 @@
# cli
python-dotenv==1.2.1 python-dotenv==1.2.1
requests==2.32.5 requests==2.32.5
# solutions
numpy==2.3.5
scipy==1.16.3

View File

@@ -0,0 +1,98 @@
import collections
import re
from typing import Any
import numpy as np
from scipy import optimize
def _parse_input(input_data: str):
res: list[tuple[int, list[list[int]], list[int]]] = []
for line in input_data.splitlines():
_state = re.findall(r"\[([.#]*)\]", line)[0]
state = sum(1 << i for i, x in enumerate(_state) if x == "#")
_buttons = re.findall(r"\(([0-9,]*)\)", line)
buttons = [[int(n) for n in m.split(",")] for m in _buttons]
_joltage = re.findall(r" {([0-9,]*)}$", line)[0].strip()
joltage = list(map(int, _joltage.split(",")))
res.append((state, buttons, joltage))
return res
def _bfs(end: int, neighs: list[int]) -> int:
start = 0
dq = collections.deque([(0, start)])
visited = {0}
while dq:
d, p = dq.popleft()
if p == end:
return d
for n in neighs:
np = p ^ n
if np in visited:
continue
visited.add(np)
dq.append((d + 1, np))
raise ValueError(f"unable to calibrate {end}")
def _milp(vecs: list[list[int]], goal: list[int]) -> int:
n = len(goal)
m = len(vecs)
a = np.zeros((n, m), dtype=int)
for j, vec in enumerate(vecs):
for i in vec:
a[i][j] = 1
c = np.ones(m)
b = np.array(goal)
constraints = optimize.LinearConstraint(a, b, b) # type: ignore
bounds = optimize.Bounds(0, np.inf)
integrality = np.ones(m)
result = optimize.milp(
c,
constraints=constraints,
bounds=bounds,
integrality=integrality,
)
return int(result.fun)
def part_1(input_data: str) -> Any:
parsed = _parse_input(input_data)
s = 0
for end, switches, _ in parsed:
neighs = [sum(1 << n for n in m) for m in switches]
s += _bfs(end, neighs)
return s
def part_2(input_data: str) -> Any:
return sum(_milp(vecs, goal) for _, vecs, goal in _parse_input(input_data))
def test_part_1(example_data):
assert part_1(example_data) == 7
def test_part_2(example_data):
assert part_2(example_data) == 33