advent-of-code/2023-python/output/day_17.py
Anders Englöf Ytterström 178d96494a Solve 2023:17 p1-2 "Clumsy Crucible"
Revenge, blast from the past etc!

Had to learn Dijkstra's for this one. Was as stuck
as one can be on AOC. This stopped my progress
2023, and kept me busy at least 20-30h this year
(2024) as well. I never came past part 1, but got
part 2 in minutes when I hit home.

Turns out the initial queue was to blame, after
studying Dijkstras, reading hints on the subreddit
and tutorials in blogs. I was off-by-1 in costs,
since I misplaced a read from the grid.

I also struggled a really, really long time with
a bug where I resetted the steps to aggresively.

What helped me to figure it out was to create
simpler test case grids and step-debug them.

Example 1:

241
321

should give a least heat loss of 6 in pt1.

Example 2:

11199
12199
99199
99131
99111

should give a least heat loss of 9 in pt2.
2025-01-05 00:10:26 +01:00

100 lines
2.3 KiB
Python

from heapq import heappop, heappush
from output import answer # D, DD, ADJ, ints, mhd, mdbg, vdbg
n = 17
title = "Clumsy Crucible"
@answer(1, "Using std crucible, least heat loss incured: {}")
def part_1(presolved):
return presolved[0]
@answer(2, "Using ultra crucible, least heat loss incured: {}")
def part_2(presolved):
return presolved[1]
def solve(data):
grid = {
(r, c): int(col)
for r, row in enumerate(data.split())
for c, col in enumerate(row)
}
p1 = least_heat_loss(grid, 1, 3)
p2 = least_heat_loss(grid, 4, 10)
return p1, p2
def least_heat_loss(grid, minsteps, maxsteps):
target = max(grid)
seen = set()
queue = [(0, (0, 0), (0, 1), 0)]
while queue:
cost, pos, direction, steps = heappop(queue)
y, x = pos
dy, dx = direction
if pos == target:
return cost
if ((pos, direction, steps)) in seen:
continue
seen.add((pos, direction, steps))
if steps >= minsteps:
cwdy, cwdx = clockwise(*direction)
if (cw := (y + cwdy, x + cwdx)) in grid:
cwy, cwx = cw
heappush(queue, (cost + grid[cw], (cwy, cwx), (cwdy, cwdx), 1))
ccwdy, ccwdx = counterclockwise(*direction)
if (ccw := (y + ccwdy, x + ccwdx)) in grid:
ccwy, ccwx = ccw
heappush(queue, (cost + grid[ccw], (ccwy, ccwx), (ccwdy, ccwdx), 1))
if steps < maxsteps and (fwd := (y + dy, x + dx)) in grid:
fwdy, fwdx = fwd
heappush(queue, (cost + grid[fwd], (fwdy, fwdx), direction, steps + 1))
return -1
def clockwise(y, x):
"""
>>> clockwise(-1, 0)
(0, 1)
>>> clockwise(0, 1)
(1, 0)
>>> clockwise(1, 0)
(0, -1)
>>> clockwise(0, -1)
(-1, 0)
"""
return (x, y) if y == 0 else (x, -y)
def counterclockwise(y, x):
"""
>>> counterclockwise(-1, 0)
(0, -1)
>>> counterclockwise(0, -1)
(1, 0)
>>> counterclockwise(1, 0)
(0, 1)
>>> counterclockwise(0, 1)
(-1, 0)
"""
return (x, y) if x == 0 else (-x, y)
if __name__ == "__main__":
with open("./input/17.txt", "r") as f:
inp = f.read().strip()
inp = solve(inp)
a = part_1(inp)
b = part_2(inp)