Solve 2024:16 pt2 "Reindeer Maze"
Part 1 was easily solved by Dijkstras (using heapq). Tricky part was to find the way to serialize the queue items for the heappush and heappop to behave as required. Part 2 was incredible hard to figure out, and I could not do it by myself. From the subreddit, it is hinted that a traditional set of visited nodes to determine algorithm exit would not work. After some laboration and readin some hints, I managed to find a solution where the code keeps tracks using a defaultdict.
This commit is contained in:
parent
fbe6994e3a
commit
7c2b4c835a
1 changed files with 56 additions and 63 deletions
|
|
@ -1,85 +1,78 @@
|
||||||
import re
|
|
||||||
from collections import Counter, defaultdict, deque
|
|
||||||
from heapq import heappop, heappush
|
from heapq import heappop, heappush
|
||||||
from itertools import chain, combinations, compress, permutations
|
|
||||||
|
|
||||||
from output import ADJ, DD, D, ccw, cw, ints, matrix, mdbg, mhd, vdbg
|
from output import D, matrix
|
||||||
|
|
||||||
|
|
||||||
def solve(data):
|
def solve(data):
|
||||||
grid, H, W = matrix(data)
|
grid, H, W = matrix(data)
|
||||||
S = [(r, c) for r in range(H) for c in range(W) if grid[r][c] == "S"][0]
|
S = [(r, c) for r in range(H) for c in range(W) if grid[r][c] == "S"][0]
|
||||||
E = [(r, c) for r in range(H) for c in range(W) if grid[r][c] == "E"][0]
|
E = [(r, c) for r in range(H) for c in range(W) if grid[r][c] == "E"][0]
|
||||||
p1 = float('inf')
|
Q = [(0, S, 1)]
|
||||||
Q = deque([(0, (S,), 1)])
|
p1 = float("inf")
|
||||||
|
SE = dict()
|
||||||
|
ES = dict()
|
||||||
seen = set()
|
seen = set()
|
||||||
lowest = []
|
|
||||||
while Q:
|
while Q:
|
||||||
cost, path, facing = heappop(Q)
|
cost, pos, dir = heappop(Q)
|
||||||
pos = path[-1]
|
|
||||||
if (pos, facing) in seen:
|
|
||||||
continue
|
|
||||||
seen.add((pos, facing))
|
|
||||||
if pos == E:
|
|
||||||
p1 = min(cost, p1)
|
|
||||||
lowest.append(path)
|
|
||||||
r, c = pos
|
r, c = pos
|
||||||
for d, delta in enumerate(D):
|
if grid[r][c] == "#":
|
||||||
|
continue
|
||||||
|
if (r, c, dir) in seen:
|
||||||
|
continue
|
||||||
|
seen.add((r, c, dir))
|
||||||
|
if (r, c, dir) not in SE:
|
||||||
|
SE[(r, c, dir)] = cost
|
||||||
|
if pos == E:
|
||||||
|
p1 = min(p1, cost)
|
||||||
|
continue
|
||||||
|
for inc, delta, facing in [
|
||||||
|
(1, D[dir], dir),
|
||||||
|
(1000, (0, 0), (dir + 1) % 4),
|
||||||
|
(1000, (0, 0), (dir - 1) % 4),
|
||||||
|
]:
|
||||||
|
nc = cost + inc
|
||||||
dr, dc = delta
|
dr, dc = delta
|
||||||
if grid[r + dr][c + dc] == "#":
|
heappush(Q, (nc, (r + dr, c + dc), facing))
|
||||||
continue
|
Q = [(0, E, 0), (0, E, 1), (0, E, 2), (0, E, 3)]
|
||||||
if abs(facing - d) == 2:
|
seen = set()
|
||||||
continue
|
while Q:
|
||||||
if d != facing:
|
cost, pos, dir = heappop(Q)
|
||||||
heappush(Q, (cost + 1000, path, d))
|
r, c = pos
|
||||||
else:
|
if grid[r][c] == "#":
|
||||||
heappush(Q, (cost + 1, path + ((r + dr, c + dc),), d))
|
continue
|
||||||
return p1, None
|
if (r, c, dir) in seen:
|
||||||
|
continue
|
||||||
|
seen.add((r, c, dir))
|
||||||
|
if (r, c, (dir + 2) % 4) not in ES:
|
||||||
|
ES[(r, c, (dir + 2) % 4)] = cost
|
||||||
|
if pos == S:
|
||||||
|
continue
|
||||||
|
for inc, delta, facing in [
|
||||||
|
(1, D[dir], dir),
|
||||||
|
(1000, (0, 0), (dir + 1) % 4),
|
||||||
|
(1000, (0, 0), (dir - 1) % 4),
|
||||||
|
]:
|
||||||
|
nc = cost + inc
|
||||||
|
dr, dc = delta
|
||||||
|
heappush(Q, (nc, (r + dr, c + dc), facing))
|
||||||
|
p2 = set()
|
||||||
|
for r in range(H):
|
||||||
|
for c in range(W):
|
||||||
|
for d in range(4):
|
||||||
|
if (
|
||||||
|
(r, c, d) in SE
|
||||||
|
and (r, c, d) in ES
|
||||||
|
and SE[(r, c, d)] + ES[(r, c, d)] == p1
|
||||||
|
):
|
||||||
|
p2.add((r, c))
|
||||||
|
return p1, len(p2)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import os
|
|
||||||
|
|
||||||
# use dummy data
|
|
||||||
inp = """
|
|
||||||
#################
|
|
||||||
#...#...#...#..E#
|
|
||||||
#.#.#.#.#.#.#.#.#
|
|
||||||
#.#.#.#...#...#.#
|
|
||||||
#.#.#.#.###.#.#.#
|
|
||||||
#...#.#.#.....#.#
|
|
||||||
#.#.#.#.#.#####.#
|
|
||||||
#.#...#.#.#.....#
|
|
||||||
#.#.#####.#.###.#
|
|
||||||
#.#.#.......#...#
|
|
||||||
#.#.###.#####.###
|
|
||||||
#.#.#...#.....#.#
|
|
||||||
#.#.#.#####.###.#
|
|
||||||
#.#.#.........#.#
|
|
||||||
#.#.#.#########.#
|
|
||||||
#S#.............#
|
|
||||||
#################
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
""".strip()
|
|
||||||
|
|
||||||
# uncomment to instead use stdin
|
|
||||||
# import sys; inp = sys.stdin.read().strip()
|
|
||||||
|
|
||||||
# uncomment to use AoC provided puzzle input
|
|
||||||
with open("./input/16.txt", "r") as f:
|
with open("./input/16.txt", "r") as f:
|
||||||
inp = f.read().strip()
|
inp = f.read().strip()
|
||||||
|
|
||||||
# uncomment to do initial data processing shared by part 1-2
|
|
||||||
p1, p2 = solve(inp)
|
p1, p2 = solve(inp)
|
||||||
|
|
||||||
print(p1)
|
print(p1)
|
||||||
os.system(f"echo {p1} | wl-copy")
|
|
||||||
print(p2)
|
print(p2)
|
||||||
os.system(f"echo {p2} | wl-copy")
|
|
||||||
|
|
||||||
# uncomment and replace 0 with actual output to refactor code
|
|
||||||
# and ensure nonbreaking changes
|
|
||||||
# assert p1 == 0
|
|
||||||
# assert p2 == 0
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue