text = open(0).read() graph = { complex(x, y): int({'.': 1, '#': 10000}.get(val, val)) for y, row in enumerate(text.splitlines()) for x, val in enumerate(row) } xmax = max(int(p.real) for p in graph) ymax = max(int(p.imag) for p in graph) end = complex(xmax, ymax) mapping = {1: '>', -1: '<', 1j: 'v', -1j: '^'} # a position mapped to the lowest effort taken to reach it edge = {(0, ''): (0, '')} exhausted = {} while end not in exhausted: pos = min(edge, key=edge.get) parent = edge.pop(pos) if pos[0] == end: break exhausted[pos] = parent for step in [1, -1, 1j, -1j]: # no reverse if pos[1] and pos[1][-1] == mapping[-step]: continue # turn condition bop = pos[1] + mapping[step] if len(bop) == 4 and len(set(bop)) == 1: continue adj = pos[0] + step, bop[-3:] # out of bounds check if adj[0] not in graph: continue # some positions are truly dead if adj in exhausted: continue score = parent[0] + graph[adj[0]], parent[1] + mapping[step] if adj not in edge: edge[adj] = score else: edge[adj] = min(edge[adj], score) def scorer(seq): pos = 0 out = 0 for char in seq: pos += {'>': 1, '<': -1, '^': -1j, 'v': 1j}[char] out += graph[pos] return out print(parent[1], scorer(parent[1])) test = '>>>v>>>^>>>vv>vv>vvv>vvv' print(test, scorer(test))