Refactor 2023 for new system.

This commit is contained in:
Mikael CAPELLE
2024-12-04 17:09:24 +01:00
parent a9bcf9ef8f
commit 664dcfe7ba
24 changed files with 1119 additions and 1085 deletions

View File

@@ -1,11 +1,7 @@
import logging
import os
import sys
from collections import defaultdict
from typing import Literal, Sequence, TypeAlias, cast
from typing import Any, Iterator, Literal, Sequence, TypeAlias, cast
VERBOSE = os.getenv("AOC_VERBOSE") == "True"
logging.basicConfig(level=logging.INFO if VERBOSE else logging.WARNING)
from ..base import BaseSolver
DirectionType: TypeAlias = Literal[">", "<", "^", "v", ".", "#"]
@@ -35,6 +31,7 @@ def neighbors(
Compute neighbors of the given node, ignoring the given set of nodes and considering
that you can go uphill on slopes.
"""
n_rows, n_cols = len(grid), len(grid[0])
i, j = node
for di, dj in Neighbors[grid[i][j]]:
@@ -103,65 +100,66 @@ def compute_direct_links(
return direct
def longest_path_length(
links: dict[tuple[int, int], list[tuple[tuple[int, int], int]]],
start: tuple[int, int],
target: tuple[int, int],
) -> int:
max_distance: int = -1
queue: list[tuple[tuple[int, int], int, frozenset[tuple[int, int]]]] = [
(start, 0, frozenset({start}))
]
class Solver(BaseSolver):
def longest_path_length(
self,
links: dict[tuple[int, int], list[tuple[tuple[int, int], int]]],
start: tuple[int, int],
target: tuple[int, int],
) -> int:
max_distance: int = -1
queue: list[tuple[tuple[int, int], int, frozenset[tuple[int, int]]]] = [
(start, 0, frozenset({start}))
]
nodes = 0
while queue:
node, distance, path = queue.pop()
nodes = 0
while queue:
node, distance, path = queue.pop()
nodes += 1
nodes += 1
if node == target:
max_distance = max(distance, max_distance)
continue
if node == target:
max_distance = max(distance, max_distance)
continue
queue.extend(
(reach, distance + length, path | {reach})
for reach, length in links.get(node, [])
if reach not in path
queue.extend(
(reach, distance + length, path | {reach})
for reach, length in links.get(node, [])
if reach not in path
)
self.logger.info(f"processed {nodes} nodes")
return max_distance
def solve(self, input: str) -> Iterator[Any]:
lines = cast(list[Sequence[DirectionType]], input.splitlines())
start = (0, 1)
target = (len(lines) - 1, len(lines[0]) - 2)
direct_links: dict[tuple[int, int], list[tuple[tuple[int, int], int]]] = {
start: [reachable(lines, start, target)]
}
direct_links.update(
compute_direct_links(lines, direct_links[start][0][0], target)
)
logging.info(f"processed {nodes} nodes")
# part 1
yield self.longest_path_length(direct_links, start, target)
return max_distance
# part 2
reverse_links: dict[tuple[int, int], list[tuple[tuple[int, int], int]]] = (
defaultdict(list)
)
for origin, links in direct_links.items():
for destination, distance in links:
if origin != start:
reverse_links[destination].append((origin, distance))
links = {
k: direct_links.get(k, []) + reverse_links.get(k, [])
for k in direct_links.keys() | reverse_links.keys()
}
lines = cast(list[Sequence[DirectionType]], sys.stdin.read().splitlines())
n_rows, n_cols = len(lines), len(lines[0])
start = (0, 1)
target = (len(lines) - 1, len(lines[0]) - 2)
direct_links: dict[tuple[int, int], list[tuple[tuple[int, int], int]]] = {
start: [reachable(lines, start, target)]
}
direct_links.update(compute_direct_links(lines, direct_links[start][0][0], target))
# part 1
answer_1 = longest_path_length(direct_links, start, target)
print(f"answer 1 is {answer_1}")
# part 2
reverse_links: dict[tuple[int, int], list[tuple[tuple[int, int], int]]] = defaultdict(
list
)
for origin, links in direct_links.items():
for destination, distance in links:
if origin != start:
reverse_links[destination].append((origin, distance))
links = {
k: direct_links.get(k, []) + reverse_links.get(k, [])
for k in direct_links.keys() | reverse_links.keys()
}
answer_2 = longest_path_length(links, start, target)
print(f"answer 2 is {answer_2}")
yield self.longest_path_length(links, start, target)