2021-12-15 12:04:10 +01:00
|
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
# Copyright (c) 2021 Akumatic
|
|
|
|
#
|
|
|
|
# https://adventofcode.com/2021/day/15
|
|
|
|
|
|
|
|
from queue import PriorityQueue
|
|
|
|
|
|
|
|
def read_file(filename: str = "input.txt") -> tuple:
|
|
|
|
with open(f"{__file__.rstrip('code.py')}{filename}", "r") as f:
|
|
|
|
lines = [line for line in f.read().strip().split("\n")]
|
|
|
|
data = list()
|
|
|
|
for line in lines:
|
|
|
|
data += [int(x) for x in line]
|
|
|
|
return len(lines[0]), data
|
|
|
|
|
2021-12-15 13:29:32 +01:00
|
|
|
def get_neighbors(dim: int) -> dict:
|
|
|
|
neighbors = dict()
|
|
|
|
for y in range(dim):
|
|
|
|
for x in range(dim):
|
|
|
|
neighbors[x + y*dim] = [x + d[0] + (y + d[1]) * dim for d in ((-1, 0), (1, 0), (0, -1), (0, 1))
|
|
|
|
if 0 <= x + d[0] < dim and 0 <= y + d[1] < dim]
|
|
|
|
return neighbors
|
2021-12-15 12:04:10 +01:00
|
|
|
|
|
|
|
def dijkstra(cavern: tuple) -> dict:
|
|
|
|
dimension, graph = cavern[0], cavern[1]
|
|
|
|
graph_size = len(graph)
|
2021-12-15 13:29:32 +01:00
|
|
|
neighbors = get_neighbors(dimension)
|
2021-12-15 12:04:10 +01:00
|
|
|
queue = PriorityQueue()
|
|
|
|
queue.put((0, 0))
|
|
|
|
dist = {0: 0}
|
|
|
|
|
|
|
|
while not queue.empty():
|
|
|
|
distance, idx = queue.get()
|
|
|
|
|
2021-12-15 13:29:32 +01:00
|
|
|
for neighbor in neighbors[idx]:
|
2021-12-15 12:04:10 +01:00
|
|
|
d = distance + graph[neighbor]
|
|
|
|
if neighbor not in dist or dist[neighbor] > d:
|
|
|
|
dist[neighbor] = d
|
|
|
|
queue.put((d, neighbor))
|
|
|
|
|
|
|
|
return dist
|
|
|
|
|
|
|
|
def expand(cavern: tuple) -> tuple:
|
|
|
|
dim = cavern[0]
|
|
|
|
# expand to the right
|
|
|
|
tmp = list()
|
|
|
|
for y in range(dim):
|
|
|
|
for i in range(5):
|
|
|
|
for x in range(dim):
|
2021-12-15 13:29:32 +01:00
|
|
|
val = cavern[1][x + y * dim] + i
|
2021-12-15 12:04:10 +01:00
|
|
|
if val > 9:
|
|
|
|
val -= 9
|
|
|
|
tmp.append(val)
|
|
|
|
cave = tmp
|
|
|
|
|
|
|
|
# expand to the bottom
|
|
|
|
for _ in range(4):
|
|
|
|
tmp = [n + 1 if n + 1 < 10 else n - 8 for n in tmp]
|
|
|
|
cave += tmp
|
|
|
|
|
|
|
|
return dim * 5, cave
|
|
|
|
|
|
|
|
def part1(cavern: tuple) -> int:
|
|
|
|
return dijkstra(cavern)[cavern[0]**2 - 1]
|
|
|
|
|
|
|
|
def part2(cavern: tuple) -> int:
|
|
|
|
cavern = expand(cavern)
|
|
|
|
return dijkstra(cavern)[cavern[0]**2 - 1]
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
vals = read_file()
|
|
|
|
print(f"Part 1: {part1(vals)}")
|
|
|
|
print(f"Part 2: {part2(vals)}")
|