-
Notifications
You must be signed in to change notification settings - Fork 0
/
19.py
67 lines (47 loc) · 1.76 KB
/
19.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
from lib import *
input = read_input(2021, 19)
ROT1 = [
np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]),
np.array([[-1, 0, 0], [0, -1, 0], [0, 0, 1]]),
np.array([[0, 1, 0], [-1, 0, 0], [0, 0, 1]]),
np.array([[0, -1, 0], [1, 0, 0], [0, 0, 1]]),
np.array([[0, 0, 1], [0, -1, 0], [1, 0, 0]]),
np.array([[0, 0, -1], [0, 1, 0], [1, 0, 0]]),
]
ROT2 = [
np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]),
np.array([[1, 0, 0], [0, 0, -1], [0, 1, 0]]),
np.array([[1, 0, 0], [0, -1, 0], [0, 0, -1]]),
np.array([[1, 0, 0], [0, 0, 1], [0, -1, 0]]),
]
def rotations():
for a in ROT1:
for b in ROT2:
yield lambda x: b @ (a @ x)
def match_scanner(beacons, scanner_positions, scanner):
for rot in rotations():
counter = Counter()
for rel in map(rot, scanner[0]):
for abs_ in map(np.array, beacons):
k = abs_ - rel
counter[kt := tuple(k)] += 1
if counter[kt] >= 12:
beacons.update([tuple(rot(x) + k) for x in scanner[0]])
scanner_positions.append(k)
return
remaining = []
for block in input.split("\n\n"):
positions = [np.array(tuple(map(int, line.split(",")))) for line in block.splitlines()[1:]]
distances = {int((x := a - b).dot(x)) for a in positions for b in positions}
remaining.append((positions, distances))
first = remaining.pop(0)
beacons = {*map(tuple, first[0])}
distances = first[1].copy()
scanners = []
while remaining:
i = max(range(len(remaining)), key=lambda j: len(remaining[j][1] & distances))
s = remaining.pop(i)
match_scanner(beacons, scanners, s)
distances.update(s[1])
print(len(beacons))
print(max(sum(np.abs(a - b)) for a in scanners for b in scanners))