My Advent of Code solutions in Python. kevinyap.ca/2019/12/going-fast-in-advent-of-code/
advent-of-code python
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add solution for 2023/23

+118
+118
2023/day23.py
··· 1 + import fileinput 2 + from collections import deque, defaultdict 3 + 4 + from utils import Point, N, S, E, W, DIRS 5 + 6 + 7 + SLOPES = { 8 + '^': S, 9 + 'v': N, 10 + '<': W, 11 + '>': E, 12 + } 13 + 14 + 15 + def get_neighbours(graph, node, part_2=False): 16 + """In part 2, we ignore slopes.""" 17 + if graph.get(node) == '#': 18 + return 19 + 20 + if not part_2: 21 + if graph.get(node) in SLOPES: 22 + yield node + SLOPES[graph.get(node)] 23 + return 24 + 25 + for d in DIRS: 26 + np = node + d 27 + if np not in graph: 28 + continue 29 + 30 + neighbour = graph.get(np) 31 + 32 + if neighbour == '#': 33 + continue 34 + 35 + if not part_2 and neighbour in SLOPES and d != SLOPES[neighbour]: 36 + continue 37 + 38 + yield np 39 + 40 + 41 + def longest_path(graph, start, end, part_2=False): 42 + horizon = [(start, 0, set())] 43 + best = 0 44 + 45 + while horizon: 46 + curr, dist, seen = horizon.pop() 47 + 48 + if curr == end: 49 + best = max(best, dist) 50 + continue 51 + 52 + if curr in seen: 53 + continue 54 + 55 + for neighbour, weight in graph[curr]: 56 + horizon.append((neighbour, dist + weight, seen | set([curr]))) 57 + 58 + return best 59 + 60 + 61 + def compress_graph(graph, part_2=False): 62 + # Sort all points in graph by their degree. 63 + degrees = defaultdict(set) 64 + for node in graph: 65 + degrees[len(list(get_neighbours(graph, node, part_2)))].add(node) 66 + 67 + key_points = degrees[1] | degrees[3] | degrees[4] 68 + 69 + 70 + # Find the distance from node to all other "key points" it can reach. 71 + def bfs(start): 72 + horizon = deque([(start, 0)]) 73 + seen = set() 74 + 75 + while horizon: 76 + curr, dist = horizon.pop() 77 + 78 + if curr != start and curr in key_points: 79 + yield curr, dist 80 + continue 81 + 82 + if curr in seen: 83 + continue 84 + 85 + seen.add(curr) 86 + 87 + for neighbour in get_neighbours(graph, curr, part_2): 88 + horizon.appendleft((neighbour, dist + 1)) 89 + 90 + 91 + # Create the compressed weighted graph. 92 + compressed = defaultdict(list) 93 + 94 + for node in key_points: 95 + for neighbour, weight in bfs(node): 96 + compressed[node].append((neighbour, weight)) 97 + 98 + return compressed 99 + 100 + 101 + # Parse problem input. 102 + GRAPH = {} 103 + START = None 104 + END = None 105 + for y, line in enumerate(fileinput.input()): 106 + for x, c in enumerate(line.strip()): 107 + p = Point(x, y) 108 + if c == '.': 109 + if y == 0: 110 + START = p 111 + 112 + END = p 113 + 114 + GRAPH[p] = c 115 + 116 + print("Part 1:", longest_path(compress_graph(GRAPH), START, END)) 117 + print("Part 2:", longest_path(compress_graph(GRAPH, part_2=True), START, END, part_2=True)) 118 +