day 17
clumsy crucible
approach
both parts run dijkstra with a heap whose states are position, last direction and how many steps have been taken in that direction. reversing is not allowed, and states are marked as seen when pushed.
part 1 caps a straight run at 3 steps. part 2 needs at least 4 steps before turning (or stopping at the end) and at most 10; the start has an infinite run length so it can set off in any direction. part 2 also records each state's parent, used by commented-out code that drew the path.
the trick
put the direction and run length in the dijkstra state, so the movement rules are just filters on neighbours.
python
for nr, nc, dr, dc in neighbors(grid, r, c):
nn = cn + 1 if (pdr,pdc) == (dr,dc) else 1
if dr == -pdr and dc == -pdc:
continue
if (cn < 4 and nn == 1) or nn > 10:
continue
if (nr, nc, dr, dc, nn) in seen:
continue
# can use the same object if it is too slow
#seen.add((nr, nc, dr, dc, nn))
seen[(nr, nc, dr, dc, nn)] = (r, c, pdr, pdc, cn)
heappush(h, (w + grid[nr][nc], nr, nc, dr, dc, nn))