2022-12-12 07:41:14 +00:00
|
|
|
import shared
|
|
|
|
import matrix
|
|
|
|
from dijkstar import Graph, find_path, algorithm
|
|
|
|
|
|
|
|
|
|
|
|
criteria = lambda _cur, _neighbor: _neighbor - _cur <= 1
|
2022-12-12 16:44:03 +00:00
|
|
|
|
|
|
|
|
2022-12-12 07:41:14 +00:00
|
|
|
def build_graph(mx):
|
2022-12-12 17:09:28 +00:00
|
|
|
"""
|
|
|
|
This is the meat of the solution,
|
|
|
|
getting the valid neighbors - and then weighing those neighbors as pathable
|
|
|
|
- loop through each row/col and then find who that cell can navigate to, ULDR
|
|
|
|
- if it can navigate, add an edge
|
|
|
|
"""
|
2022-12-12 07:41:14 +00:00
|
|
|
graph = Graph()
|
|
|
|
for y, row in enumerate(mx):
|
|
|
|
for x, _ in enumerate(row):
|
|
|
|
neighbors = matrix.valid_neighbors(mx, x=x, y=y, criteria=criteria)
|
|
|
|
for neighbor in neighbors:
|
2022-12-12 16:44:03 +00:00
|
|
|
graph.add_edge((y, x), (neighbor["y"], neighbor["x"]), 1)
|
2022-12-12 07:41:14 +00:00
|
|
|
return graph
|
|
|
|
|
|
|
|
|
|
|
|
def part1(mx):
|
|
|
|
start = matrix.find_in_matrix(mx, "S")
|
|
|
|
end = matrix.find_in_matrix(mx, "E")
|
2022-12-12 17:09:28 +00:00
|
|
|
# Now that we got the start/end, fix those to 'a' and 'z' like the instructions said
|
2022-12-12 07:41:14 +00:00
|
|
|
mx[start[0]][start[1]] = "a"
|
|
|
|
mx[end[0]][end[1]] = "z"
|
2022-12-12 17:09:28 +00:00
|
|
|
# Turn the a-z into numbers 0-25
|
2022-12-12 16:44:03 +00:00
|
|
|
matrix.apply_to_all(mx, lambda x: ord(x) - ord("a"))
|
2022-12-12 07:41:14 +00:00
|
|
|
|
|
|
|
graph = build_graph(mx)
|
|
|
|
path = find_path(graph, start, end)
|
2022-12-13 05:47:25 +00:00
|
|
|
print(len(path.nodes) - 1)
|
2022-12-12 07:41:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
def part2(mx):
|
|
|
|
end = matrix.find_in_matrix(mx, "E")
|
2022-12-12 17:09:28 +00:00
|
|
|
# don't NEED this, because we go from all 'a', but need to replace it still
|
2022-12-12 07:41:14 +00:00
|
|
|
s = matrix.find_in_matrix(mx, "S")
|
2022-12-12 17:09:28 +00:00
|
|
|
# Now that we got the start/end, fix those to 'a' and 'z' like the instructions said
|
2022-12-12 07:41:14 +00:00
|
|
|
mx[s[0]][s[1]] = "a"
|
|
|
|
mx[end[0]][end[1]] = "z"
|
2022-12-12 16:44:03 +00:00
|
|
|
starts = matrix.find_in_matrix(mx, "a", one=False)
|
2022-12-12 17:09:28 +00:00
|
|
|
|
|
|
|
# Turn the a-z into numbers 0-25
|
2022-12-12 16:44:03 +00:00
|
|
|
matrix.apply_to_all(mx, lambda x: ord(x) - ord("a"))
|
2022-12-12 07:41:14 +00:00
|
|
|
graph = build_graph(mx)
|
|
|
|
|
2022-12-12 17:09:28 +00:00
|
|
|
paths = []
|
|
|
|
# Find the yx of all 'a'
|
2022-12-12 07:41:14 +00:00
|
|
|
for start in starts:
|
|
|
|
try:
|
|
|
|
path = find_path(graph, start, end)
|
2022-12-12 17:09:28 +00:00
|
|
|
paths.append(path)
|
2022-12-12 07:41:14 +00:00
|
|
|
except algorithm.NoPathError:
|
2022-12-12 17:09:28 +00:00
|
|
|
# This 'a' is in a puddle of 'c's, so it's not pathable
|
2022-12-12 07:41:14 +00:00
|
|
|
pass
|
2022-12-13 05:47:25 +00:00
|
|
|
shortest = min(paths, key=lambda x: x.total_cost)
|
|
|
|
# matrix.apply_to_all(mx, lambda x: chr(x+ord('a'))) # Back to letters, single char prettier
|
|
|
|
# all_visited = []
|
|
|
|
# for p in paths:
|
|
|
|
# all_visited.extend(p.nodes)
|
|
|
|
# all_visited = list(set(all_visited))
|
|
|
|
# matrix.highlight(mx, red=all_visited, blink_green=shortest.nodes)
|
2022-12-12 17:09:28 +00:00
|
|
|
print(shortest.total_cost)
|
2022-12-12 07:41:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
mx = matrix.load_matrix_file(shared.get_fname(12), matrix.split_word_to_chr_list)
|
2022-12-13 05:47:25 +00:00
|
|
|
with shared.elapsed_timer() as elapsed:
|
|
|
|
part1(mx)
|
|
|
|
print(elapsed())
|
2022-12-12 17:09:28 +00:00
|
|
|
mx = matrix.load_matrix_file(shared.get_fname(12), matrix.split_word_to_chr_list)
|
2022-12-13 05:47:25 +00:00
|
|
|
with shared.elapsed_timer() as elapsed:
|
|
|
|
part2(mx)
|
|
|
|
print(elapsed())
|
2022-12-12 07:41:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|