-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathd19.py
99 lines (78 loc) · 2.55 KB
/
d19.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
from collections import Counter
from itertools import starmap
from operator import add, sub
scanners = open("input.txt").read().strip().split('\n\n')
scanners = list(map(lambda d: list(map(lambda t: tuple(map(int, t.split(','))), d.split('\n')[1:])), scanners))
def identity(x, y, z): return x, y, z
def rot90z(x, y, z): return y, -x, z
def rot90y(x, y, z): return z, y, -x
def rot90x(x, y, z): return x, z, -y
rotation_scheme = [
identity,
rot90z, rot90z, rot90z, rot90z,
rot90y,
rot90z, rot90z, rot90z, rot90z,
rot90y,
rot90z, rot90z, rot90z, rot90z,
rot90y,
rot90z, rot90z, rot90z, rot90z,
rot90y,
rot90x,
rot90z, rot90z, rot90z, rot90z,
rot90x, rot90x,
rot90z, rot90z, rot90z, rot90z,
]
class Scanner:
id = 0
def __init__(self, beacons):
self.id = Scanner.id
self.beacons = beacons
self.possibs = self.generate_possibilities()
Scanner.id += 1
self.pos = (0, 0, 0)
def __repr__(self):
return f's{self.id} {self.pos}'
def generate_possibilities(self):
out = []
pos = self.beacons
for r in rotation_scheme:
pos = list(starmap(r, pos))
out.append(pos)
return out
def tuple_sub(t1, t2): return tuple(map(sub, t1, t2))
def tuple_add(t1, t2): return tuple(map(add, t1, t2))
def dist(t1, t2): return sum([abs(p1 - p2) for p1, p2 in zip(t1, t2)])
beacons = set()
def pair_scanners(scanner):
for possib in scanner.possibs:
c = Counter()
for ps1 in beacons:
for ps2 in possib:
diff = tuple_sub(ps1, ps2)
c.update([diff])
[(recovered_pos, count)] = c.most_common(1)
if count < 12: continue
new_beacons = list(map(lambda t: tuple_add(recovered_pos, t), possib))
scanner.beacons = new_beacons
scanner.pos = recovered_pos
beacons.update(new_beacons)
return scanner
scanners = list(map(Scanner, scanners))
unmatched = scanners[1:]
found_scanners = [scanners[0]]
beacons.update(scanners[0].beacons)
while unmatched:
for un in unmatched:
found_scanner = pair_scanners(un)
if found_scanner:
found_scanners.append(found_scanner)
unmatched.remove(un)
# one star
print(len(beacons))
# two stars
max_dist = -1
for s1 in found_scanners:
for s2 in found_scanners:
if s1.id == s2.id: continue
max_dist = max(max_dist, dist(s1.pos, s2.pos))
print(max_dist)