106 lines
2.4 KiB
Python
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))
|