aoc2016/day24.py
2025-03-17 09:39:20 +01:00

98 lines
2.6 KiB
Python

from collections import deque
from tools.aoc import AOCDay
from tools.coordinate import Coordinate
from tools.grid import Grid
from typing import Any
class Node:
def __init__(self, node_id: int, pos: Coordinate) -> None:
self.node_id = node_id
self.pos = pos
self.others: dict[Node, int] = {}
def __repr__(self):
return f"Node({self.node_id}, {self.pos})"
def get_dist(grid: Grid, start: Coordinate, end: Coordinate) -> int:
q = deque([(0, start)])
seen = set()
while q:
dist, pos = q.popleft()
if pos == end:
return dist
if pos in seen:
continue
seen.add(pos)
for n in grid.getNeighboursOf(pos, includeDiagonal=False, includeDefault=False):
q.append((dist + 1, n))
def get_min_dist(
nodes: dict[int, Node], return_to_zero: bool = False, start: int = 0, dist: int = 0, seen: set = None
) -> int:
if seen is None:
seen = {start}
if len(seen) == len(nodes):
return dist + nodes[start].others[nodes[0]] if return_to_zero else dist
min_dist = int(1e9)
for n, n_dist in nodes[start].others.items():
if n.node_id in seen or n.node_id == start:
continue
this_dist = get_min_dist(
nodes, return_to_zero=return_to_zero, start=n.node_id, dist=dist + n_dist, seen=seen | {n.node_id}
)
if this_dist < min_dist:
min_dist = this_dist
return min_dist
class Day(AOCDay):
inputs = [
[
(14, "input24_test"),
(502, "input24"),
],
[
(724, "input24"),
],
]
def parse_input(self) -> dict[int, Node]:
grid = Grid.from_data(self.getInput(), translate={"[0-9]": int}, default="#")
nodes = {}
for c in grid.getActiveCells():
if isinstance(grid.get(c), int):
nodes[grid.get(c)] = Node(grid.get(c), c)
grid.set(c, ".")
for node_a in nodes.values():
for node_b in nodes.values():
if node_b.node_id == node_a.node_id:
continue
if node_a.node_id in node_b.others:
continue
dist = get_dist(grid, node_a.pos, node_b.pos)
node_a.others[node_b] = dist
node_b.others[node_a] = dist
return nodes
def part1(self) -> Any:
return get_min_dist(self.parse_input())
def part2(self) -> Any:
return get_min_dist(self.parse_input(), True)
if __name__ == "__main__":
day = Day(2016, 24)
day.run(verbose=True)