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 )