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