import copy from queue import PriorityQueue MAX_PRIO = ord('z') - ord('a') log_this_is_n = 0 n_solutions = 0 q = PriorityQueue() point_cost = {} def log_every_n(message): global log_this_is_n log_this_is_n = (log_this_is_n + 1) % 100000 if log_this_is_n == 0: print(message) class PossiblePath: def __init__(self, y, x, visited): self.x = x self.y = y self.visited = tuple(visited) def __lt__(self, other): return (len(self.visited) < len(other.visited) or self.x < other.x or self.y < other.y) def MakeCandidate(x, y, visited, value_diff): if (y, x) in point_cost and point_cost[(y, x)] <= len(visited): return point_cost[(y, x)] = len(visited) prio_valuediff = value_diff * -1 prio_distance = (max(End[0], x) - min(End[0], x)) + (max(End[1], y) - min(End[1], y)) prio_lettervalue = MAX_PRIO - grid[y][x] prio_pathlen = (gridX * gridY) - len(visited) path = PossiblePath(y, x, visited) q.put((prio_valuediff, prio_distance, path)) def findPath(): global fewestSteps global n_solutions while not q.empty(): _, _, path = q.get() if (path.y, path.x) in point_cost and point_cost[(path.y, path.x)] < len(path.visited): # We already have a better path to the current point. continue log_every_n('Inspecting: %dx%d, visited %d points, %d solutions' % (path.x, path.y, len(path.visited), n_solutions)) visited = list(path.visited) if (path.y, path.x) in visited: continue visited.append((path.y, path.x)) if (not (fewestSteps == None)) and (len(visited) - 1 >= fewestSteps): continue if [path.x, path.y] == End: print('Visited: ', visited) print('Steps: ', len(visited) - 1) fewestSteps = len(visited) - 1 n_solutions += 1 continue if path.x > 0: if grid[path.y][path.x - 1] <= grid[path.y][path.x] + 1: valDiff = grid[path.y][path.x - 1] - grid[path.y][path.x] MakeCandidate(path.x - 1, path.y, visited, valDiff) if path.x < gridX: if grid[path.y][path.x + 1] <= grid[path.y][path.x] + 1: valDiff = grid[path.y][path.x + 1] - grid[path.y][path.x] MakeCandidate(path.x + 1, path.y, visited, valDiff) if path.y > 0: if grid[path.y - 1][path.x] <= grid[path.y][path.x] + 1: valDiff = grid[path.y - 1][path.x] - grid[path.y][path.x] MakeCandidate(path.x, path.y - 1, visited, valDiff) if path.y < gridY: if grid[path.y + 1][path.x] <= grid[path.y][path.x] + 1: valDiff = grid[path.y + 1][path.x] - grid[path.y][path.x] MakeCandidate(path.x, path.y + 1, visited, valDiff) with open('input12.txt','r') as f: inp = f.read().splitlines(keepends=False) grid = [] fewestSteps = None for i in range(len(inp)): grid.append([]) for j in range(len(inp[i])): if inp[i][j] == 'S': Start = [j, i] grid[i].append(0) elif inp[i][j] == 'E': End = [j, i] grid[i].append(ord('z') - ord('a')) else: grid[i].append(ord(inp[i][j])-ord('a')) gridX = len(grid[0]) - 1 gridY = len(grid) - 1 _x = Start[0] _y = Start[1] if Start[0] > 0: if grid[_y][_x - 1] <= 1: MakeCandidate(_x - 1, _y, [(_y, _x)], grid[_y][_x - 1]) if Start[0] < gridX: if grid[_y][_x + 1] <= 1: MakeCandidate(_x + 1, _y, [(_y, _x)], grid[_y][_x + 1]) if Start[1] > 0: if grid[_y - 1][_x] <= 1: MakeCandidate(_x, _y - 1, [(_y, _x)], grid[_y - 1][_x]) if Start[1] < gridY: if grid[_y + 1][_x] <= 1: MakeCandidate(_x, _y + 1, [(_y, _x)], grid[_y + 1][_x]) findPath() print(fewestSteps) #for x in grid: # tempa = '' # for y in x: # tempa += chr(y + 97) # print(tempa)