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.
100 lines
2.3 KiB
Python
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)
|