Files
aocpy/2024/d20.py
2024-12-20 01:54:25 -05:00

91 lines
1.8 KiB
Python

from collections import deque
from lib import get_data
from lib import Grid2D
data = """###############
#...#...#.....#
#.#.#.#.#.###.#
#S#...#.#.#...#
#######.#.#.###
#######.#.#...#
#######.#.###.#
###..E#...#...#
###.#######.###
#...###...#...#
#.#####.#.###.#
#.#...#.#.#...#
#.#.#.#.#.#.###
#...#...#...###
###############
"""
data = get_data(__file__)
g = Grid2D(data)
(start,) = g.find("S")
(end,) = g.find("E")
cost = 0
sd = dict()
de = dict()
queue = deque([(start[0], start[1], 0)])
seen = set()
while queue:
r, c, cost = queue.popleft()
if (r, c) in sd:
continue
sd[(r, c)] = cost
if (r, c) == end:
break
for r, c in g.neighbors_ort((r, c)):
if g[(r, c)] != "#":
queue.append((r, c, cost + 1))
seen = set()
queue = deque([(end[0], end[1], 0)])
while queue:
r, c, cost = queue.popleft()
if (r, c) in de:
continue
de[(r, c)] = cost
if (r, c) == start:
break
for r, c in g.neighbors_ort((r, c)):
if g[(r, c)] != "#":
queue.append((r, c, cost + 1))
for max_steps in [2, 20]:
cheats = set()
for cr, cc in g.find("S."):
start = cr, cc, 0
seen = set()
queue = deque([start])
while queue:
r, c, steps = queue.popleft()
if steps > max_steps:
continue
if (r, c) in seen:
continue
seen.add((r, c))
if g[(r, c)] != "#":
ncost = sd[(cr, cc)] + steps + de[(r, c)]
if cost - ncost >= 100:
cheats.add((cr, cc, r, c))
for dr, dc in [(-1, 0), (0, 1), (1, 0), (0, -1)]:
nr, nc = r + dr, c + dc
if g.contains((nr, nc)):
queue.append((nr, nc, steps + 1))
print(len(cheats))