Refactor 2023 for new system.
This commit is contained in:
@@ -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)
|
||||
|
Reference in New Issue
Block a user