advent-of-code/2024/16/two.py
2024-12-25 12:59:49 +01:00

106 lines
2.4 KiB
Python

#!/usr/bin/env python3
import pprint
import sys
input_file = sys.argv[1]
with open(input_file) as fd:
lines = [line.rstrip() for line in fd.readlines()]
height = len(lines)
width = len(lines[0])
vec = tuple[int, int]
directions = [
(-1, 0), # ^ North
(0, 1), # > East
(1, 0), # v South
(0, -1), # < West
]
directions_keys = ("^", ">", "v", "<")
min_scores: list[list[list[None | int]]] = list()
for _ in range(height):
line: list[list[None | int]] = list()
for _ in range(width):
cell: list[None | int] = [None] * len(directions)
line.append(cell)
min_scores.append(line)
start = height - 2, 1
valid_paths: list[tuple[int, set[vec]]] = list()
def walk(pos: vec, dir: int, score: int, path: list[vec]) -> int | None:
i, j = pos
char = lines[i][j]
depth = len(path)
path = path + [pos]
if depth > 1000:
return None
# print("-" * depth, 28, pos, char, directions_keys[dir], score)
if char == "E":
valid_paths.append((score, set(path)))
return score
elif char == "#":
return None
min_score = min_scores[i][j][dir]
if min_score is not None and score > min_score:
# print("-" * depth, f" 32 already taken {score} >= {min_score}")
return None
min_scores[i][j][dir] = score
mscore = None
for ndir, direction in enumerate(directions):
ii, jj = i + direction[0], j + direction[1]
price = 1 if dir == ndir else 1001
nscore = walk((ii, jj), ndir, score + price, path)
if nscore is None:
continue
if mscore is None or nscore < mscore:
mscore = nscore
return mscore
sys.setrecursionlimit(9000)
tot_score = walk(start, 1, 0, [])
print(76, len(valid_paths))
all_best: set[vec] = set()
for s, path in valid_paths:
if s != tot_score:
continue
print(81, "BEST")
all_best |= path
# Viz
for i in range(height):
cline = ""
for j in range(width):
char = lines[i][j]
pos = i, j
if pos in all_best:
min_score = None
for d in range(len(directions)):
score = min_scores[i][j][d]
if score is None:
continue
if min_score is None or score < min_score:
char = directions_keys[d]
min_score = score
cline += char
print(cline)
print()
print(tot_score)
print(len(all_best))