Advent of Code 2022 day 12
Got stuck multiple times as shown in the code. Multiple attempts were aborted.
Again reading questions properly would have helped. Part 2 was fairly simple
after part 1 was worked out. Crucial to the algorithm was keeping a dictionary
used.
# import sys
# import numpy as np
# np.set_printoptions(threshold=sys.maxsize, linewidth=120)
import sys
sys.setrecursionlimit(15000000)
# with open("12_test.txt") as f:
with open("12.txt") as f:
lines = f.read().splitlines()
map = [[x for x in line] for line in lines]
m = len(map)
n = len(map[0])
for row in range(m):
for col in range(n):
if map[row][col] == "S":
start = (row, col)
elif map[row][col] == "E":
end = (row, col)
# distances = np.matrix([[0]*m*n]*m*n)
def neighbours(element, row, col):
if element == "S":
val = 97
elif element == "E":
val = 122
else:
val = ord(element)
for i in reversed(range(row-1, row+2)):
for j in reversed(range(col-1, col+2)):
if (
i >= 0 and
j >= 0 and
i < m and
j < n and
(i, j) != (row, col) and
(
i-row == 0 or j-col == 0
)
):
neighbour = map[i][j]
if neighbour == "S":
neighbour_val = 97
elif neighbour == "E":
neighbour_val = 122
else:
neighbour_val = ord(neighbour)
if neighbour_val <= val+1:
yield i, j
# for row in range(m):
# for col in range(n):
# element = map[row][col]
# for neighbour in neighbours(element, row, col):
# i, j = neighbour
# distances[col*m+row, j*m+i] = 1
used = {start: 1}
paths = []
def valid_neighbours(node, path):
row, col = node
for neighbour in neighbours(map[row][col], row, col):
if neighbour not in used or used[neighbour] > len(path)+1:
yield neighbour
def add_to_path(path):
last = path[-1]
new_paths = []
if len(path) < 500:
for node in valid_neighbours(last, path):
new_path = path+[node]
paths.append(new_path)
new_paths.append(new_path)
used[node] = len(new_path)
for new_path in new_paths:
if new_path[-1] != end:
add_to_path(new_path)
# else:
# with open("12diffa.txt", "w") as f:
# f.write("\n".join([str(node)+" "+map[node[0]][node[1]] for node in new_path]))
add_to_path([start])
# for path in [path for path in paths if path[-1] == end]:
# print(path)
print(min([len(path) for path in paths if path[-1] == end])-1)
# def distance(x, start):
# return (x[0] - start[0]) + (x[1] - start[1])
# def valid_choices(route):
# last = route[-1]
# choices = []
# if last[0] > 0:
# choices.append((last[0]-1, last[1]))
# if last[0] < len(map)-1:
# choices.append((last[0]+1, last[1]))
# if last[1] > 0:
# choices.append((last[0], last[1]-1))
# if last[1] < len(map[0])-1:
# choices.append((last[0], last[1]+1))
# for choice in sorted(choices, key=lambda x: distance(x, start)):
# if (
# choice == start or
# choice not in route and
# (
# (
# map[last[0]][last[1]] == "E" and
# map[choice[0]][choice[1]] == "z"
# ) or
# (
# map[last[0]][last[1]] == "a" and
# map[choice[0]][choice[1]] == "S"
# ) or
# abs(
# ord(map[choice[0]][choice[1]]) -
# ord(map[last[0]][last[1]])
# ) < 2 or
# (
# (
# ord(map[choice[0]][choice[1]]) >
# ord(map[last[0]][last[1]])
# )
# )
# )
# ):
# yield choice
# def next_path(route):
# for choice in valid_choices(route):
# if map[choice[0]][choice[1]] == "S":
# yield route + [choice]
# yield from next_path(route + [choice])
# min_length = 10*6
# for route in next_path([end]):
# if route[-1] == start and (length:=len(route)) < min_length:
# print(length)
# min_length = length
# print(min_length)
## PART 2
used = {end: 1}
paths = []
def neighbours_2(element, row, col):
if element == "S":
val = 97
elif element == "E":
val = 122
else:
val = ord(element)
for i in range(row-1, row+2):
for j in range(col-1, col+2):
if (
i >= 0 and
j >= 0 and
i < m and
j < n and
(i, j) != (row, col) and
(
i-row == 0 or j-col == 0
)
):
neighbour = map[i][j]
if neighbour == "S":
neighbour_val = 97
elif neighbour == "E":
neighbour_val = 122
else:
neighbour_val = ord(neighbour)
if neighbour_val >= val-1:
yield i, j
def valid_neighbours_2(node, path):
row, col = node
for neighbour in neighbours_2(map[row][col], row, col):
if neighbour not in used or used[neighbour] > len(path)+1:
yield neighbour
def add_to_path_2(path):
last = path[-1]
new_paths = []
for node in valid_neighbours_2(last, path):
new_path = path+[node]
paths.append(new_path)
new_paths.append(new_path)
used[node] = len(new_path)
for new_path in new_paths:
if map[new_path[-1][0]][new_path[-1][1]] != "a":
add_to_path_2(new_path)
add_to_path_2([end])
print(
min(
[len(path) for path in paths if map[path[-1][0]][path[-1][1]] == "a"]
)-1
)