#!/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))