aoc2022/day12.py
2022-12-12 06:52:36 +01:00

99 lines
2.9 KiB
Python

from heapq import heappush, heappop
from tools.aoc import AOCDay
from tools.coordinate import Coordinate
from tools.grid import Grid
from typing import Any
def get_dijkstra_path(height_map: Grid, start: Coordinate, end: Coordinate) -> list | None:
f_costs = []
openNodes = {}
closedNodes = {}
openNodes[start] = (0, start.getDistanceTo(end), None)
heappush(f_costs, (0, start))
while f_costs:
_, currentCoord = heappop(f_costs)
if currentCoord not in openNodes:
continue
currentNode = openNodes[currentCoord]
closedNodes[currentCoord] = currentNode
del openNodes[currentCoord]
if currentCoord == end:
break
for neighbour in height_map.getNeighboursOf(currentCoord, includeDiagonal=False):
if neighbour in closedNodes or height_map.get(neighbour) - 1 > height_map.get(currentCoord):
continue
neighbourDist = 1
targetDist = neighbour.getDistanceTo(end)
f_cost = targetDist + neighbourDist + currentNode[1]
if neighbour not in openNodes or f_cost < openNodes[neighbour][0]:
openNodes[neighbour] = (f_cost, currentNode[1] + neighbourDist, currentCoord)
heappush(f_costs, (f_cost, neighbour))
if end not in closedNodes:
return None
else:
currentNode = closedNodes[end]
pathCoords = [end]
while currentNode[2]:
pathCoords.append(currentNode[2])
currentNode = closedNodes[currentNode[2]]
return pathCoords
class Day(AOCDay):
inputs = [
[
(31, "input12_test"),
(423, "input12"),
],
[
(29, "input12_test"),
(416, "input12"),
]
]
def get_map(self) -> (Grid, Coordinate, Coordinate):
grid = Grid(30)
start = None
end = None
for y, line in enumerate(self.getInput()):
for x, char in enumerate(line):
if char == 'S':
start = Coordinate(x, y)
grid.set(start, 0)
elif char == 'E':
end = Coordinate(x, y)
grid.set(end, 25)
else:
grid.set(Coordinate(x, y), ord(char) - ord('a'))
return grid, start, end
def part1(self) -> Any:
return len(get_dijkstra_path(*self.get_map())) - 1
def part2(self) -> Any:
min_steps = float("inf")
height_map, start, end = self.get_map()
for c in height_map.getActiveCells():
if height_map.get(c) == 0:
steps_from_here = get_dijkstra_path(height_map, c, end)
if steps_from_here is not None and len(steps_from_here) < min_steps:
min_steps = len(steps_from_here)
return min_steps - 1
if __name__ == '__main__':
day = Day(2022, 12)
day.run(verbose=True)