Implement 2024 day 16 part 2

This commit is contained in:
2024-12-16 18:16:05 +01:00
parent f0556c6afe
commit b23f24c567

View File

@@ -2,7 +2,7 @@ import heapq
import numpy import numpy
from . import SeparateRunner from . import CombinedRunner
TURNS = ( TURNS = (
(-1, 1), (-1, 1),
@@ -10,9 +10,9 @@ TURNS = (
) )
class DayRunner(SeparateRunner): class DayRunner(CombinedRunner):
@classmethod @classmethod
def part1(cls, input: str) -> int: def run_both(cls, input: str) -> tuple[int, int]:
grid = numpy.array([list(line) for line in input.strip().split("\n")]) grid = numpy.array([list(line) for line in input.strip().split("\n")])
y, x = numpy.where(grid == "S") y, x = numpy.where(grid == "S")
@@ -20,37 +20,57 @@ class DayRunner(SeparateRunner):
todo = [(0, x, y, 1, 0)] todo = [(0, x, y, 1, 0)]
best = { best = {
(x, y, 1, 0): 0, (x, y, 1, 0): (0, []),
} }
def enqueue(dist, x, y, dx, dy): def enqueue(dist, x, y, dx, dy, cx, cy, cdx, cdy):
if grid[y, x] == "#": if grid[y, x] == "#":
return return
if (x, y, dx, dy) not in best or best[x, y, dx, dy] > dist: if (x, y, dx, dy) not in best or best[x, y, dx, dy][0] > dist:
best[x, y, dx, dy] = dist best[x, y, dx, dy] = (dist, [(cx, cy, cdx, cdy)])
heapq.heappush(todo, (dist, x, y, dx, dy)) heapq.heappush(todo, (dist, x, y, dx, dy))
elif best[x, y, dx, dy][0] == dist:
best[x, y, dx, dy][1].append((cx, cy, cdx, cdy))
shortest_dist = None
finishes = set()
while todo: while todo:
dist, x, y, dx, dy = heapq.heappop(todo) dist, x, y, dx, dy = heapq.heappop(todo)
if best[x, y, dx, dy] < dist: if best[x, y, dx, dy][0] < dist:
continue continue
if grid[y, x] == "E": if shortest_dist is not None and shortest_dist < dist:
return dist break
enqueue(dist + 1, x + dx, y + dy, dx, dy) if grid[y, x] == "E":
enqueue(dist + 2001, x - dx, y - dy, dx, dy) shortest_dist = dist
finishes.add((x, y, dx, dy))
enqueue(dist + 1, x + dx, y + dy, dx, dy, x, y, dx, dy)
enqueue(dist + 2001, x - dx, y - dy, dx, dy, x, y, dx, dy)
for tx, ty in TURNS: for tx, ty in TURNS:
ndx = dy * ty ndx = dy * ty
ndy = dx * ty ndy = dx * ty
enqueue(dist + 1001, x + ndx, y + ndy, ndx, ndy) enqueue(dist + 1001, x + ndx, y + ndy, ndx, ndy, x, y, dx, dy)
raise ValueError("Did not find path to exit") assert shortest_dist is not None, "Should find a path to the exit"
@classmethod visited_tiles = {(x, y) for x, y, _, _ in finishes}
def part2(cls, input: str) -> int: todo2 = [f for f in finishes]
pass visited_states = set(todo2)
while todo2:
state = todo2.pop()
for prev in best[state][1]:
if prev not in visited_states:
visited_states.add(prev)
visited_tiles.add((prev[0], prev[1]))
todo2.append(prev)
return shortest_dist, len(visited_tiles)