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 2022/22

+160
+160
2022/day22.py
··· 1 + import re, fileinput 2 + 3 + from utils import min_max_xy 4 + from utils import firsts, lasts 5 + from utils import Point, DIRS 6 + 7 + 8 + # Read problem input. 9 + graph = {} 10 + in_maze = True 11 + start = None 12 + for y, line in enumerate(fileinput.input()): 13 + if not line.strip(): 14 + in_maze = False 15 + if in_maze: 16 + for x, c in enumerate(line.strip("\n")): 17 + if c != ' ': 18 + if start is None and c == '.': 19 + start = Point(x, -y) 20 + graph[Point(x, -y)] = c 21 + else: 22 + instructions = re.findall(r'(\d+|[LR])', line) 23 + 24 + 25 + def wrapped_links(graph): 26 + """Compute link dictionary for part 1.""" 27 + links = {} 28 + min_x, max_x, min_y, max_y = min_max_xy(list(graph.keys())) 29 + 30 + # Construct the left-to-right wrap-around links. 31 + for y in range(min_y, max_y + 1): 32 + first = None 33 + for x in range(min_x, max_x + 1): 34 + p = Point(x, y) 35 + if first is None and p in graph: 36 + first = p 37 + elif p in graph: 38 + last = p 39 + 40 + links[last, 1] = (first, 1) 41 + links[first, 3] = (last, 3) 42 + 43 + # Construct the top-to-bottom wrap-around links. 44 + for x in range(min_x, max_x + 1): 45 + first = None 46 + for y in range(min_y, max_y + 1): 47 + p = Point(x, y) 48 + if first is None and p in graph: 49 + first = p 50 + elif p in graph: 51 + last = p 52 + 53 + links[last, 0] = (first, 0) 54 + links[first, 2] = (last, 2) 55 + 56 + return links 57 + 58 + 59 + def cube_links(): 60 + """ 61 + This works specifically for my cube, which is shaped as follows: 62 + 63 + 1122 64 + 1122 65 + 33 66 + 33 67 + 4455 68 + 4455 69 + 66 70 + 66 71 + 72 + """ 73 + links = {} 74 + 75 + # Define 2D arrays representing the 6 different faces of the cube, as numbered 76 + # above, in the orientation given by the problem input. 77 + FS = 50 78 + f1 = [[Point(x, -y) for x in range(FS*1, FS*2)] for y in range(FS*0, FS*1)] 79 + f2 = [[Point(x, -y) for x in range(FS*2, FS*3)] for y in range(FS*0, FS*1)] 80 + f3 = [[Point(x, -y) for x in range(FS*1, FS*2)] for y in range(FS*1, FS*2)] 81 + f4 = [[Point(x, -y) for x in range(FS*0, FS*1)] for y in range(FS*2, FS*3)] 82 + f5 = [[Point(x, -y) for x in range(FS*1, FS*2)] for y in range(FS*2, FS*3)] 83 + f6 = [[Point(x, -y) for x in range(FS*0, FS*1)] for y in range(FS*3, FS*4)] 84 + 85 + # "Glue together" the appropriate edges of each of the face pairs that will 86 + # be touching when the cube is formed. The "facing" direction changes depending 87 + # on which direction you're coming into the point from. 88 + for p, np in zip(f1[0], reversed(firsts(f6))): 89 + links[(p, 0)] = (np, 1) 90 + links[(np, 3)] = (p, 2) 91 + 92 + for p, np in zip(firsts(f1), reversed(firsts(f4))): 93 + links[(p, 3)] = (np, 1) 94 + links[(np, 3)] = (p, 1) 95 + 96 + for p, np in zip(f2[0], f6[-1]): 97 + links[(p, 0)] = (np, 0) 98 + links[(np, 2)] = (p, 2) 99 + 100 + for p, np in zip(reversed(lasts(f2)), lasts(f5)): 101 + links[(p, 1)] = (np, 3) 102 + links[(np, 1)] = (p, 3) 103 + 104 + for p, np in zip(f2[-1], reversed(lasts(f3))): 105 + links[(p, 2)] = (np, 3) 106 + links[(np, 1)] = (p, 0) 107 + 108 + for p, np in zip(firsts(f3), reversed(f4[0])): 109 + links[(p, 3)] = (np, 2) 110 + links[(np, 0)] = (p, 1) 111 + 112 + for p, np in zip(f5[-1], reversed(lasts(f6))): 113 + links[(p, 2)] = (np, 3) 114 + links[(np, 1)] = (p, 0) 115 + 116 + return links 117 + 118 + 119 + def simulate(graph, start, instructions, links): 120 + pos = start 121 + dir = 1 122 + for ins in instructions: 123 + # Turn clockwise or counterclockwise. 124 + if not ins.isnumeric(): 125 + if ins == 'L': 126 + dir = (dir - 1) % 4 127 + else: 128 + dir = (dir + 1) % 4 129 + continue 130 + 131 + # Move some number of steps (or stop at a wall). 132 + for _ in range(int(ins)): 133 + np = pos + DIRS[dir] 134 + 135 + # Bump into a wall, stop going forward. 136 + if graph.get(np) == '#': 137 + break 138 + elif graph.get(np) == '.': 139 + pos = np 140 + continue 141 + else: 142 + # We need to wrap around to another spot. The link mapping 143 + # tells us what the new position is, and what our new facing is. 144 + np, nf = links[pos, dir] 145 + 146 + if graph.get(np) == '#': 147 + break 148 + elif graph.get(np) == '.': 149 + pos = np 150 + dir = nf 151 + continue 152 + 153 + row = -pos.y + 1 154 + col = pos.x + 1 155 + facing = (dir - 1) % 4 156 + 157 + return (1000 * row) + (4 * col) + facing 158 + 159 + print("Part 1:", simulate(graph, start, instructions, wrapped_links(graph))) 160 + print("Part 2:", simulate(graph, start, instructions, cube_links()))