/ Python / 2021 / 19.py
19.py
 1  from lib import *
 2  
 3  input = read_input(2021, 19)
 4  
 5  ROT1 = [
 6      np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]),
 7      np.array([[-1, 0, 0], [0, -1, 0], [0, 0, 1]]),
 8      np.array([[0, 1, 0], [-1, 0, 0], [0, 0, 1]]),
 9      np.array([[0, -1, 0], [1, 0, 0], [0, 0, 1]]),
10      np.array([[0, 0, 1], [0, -1, 0], [1, 0, 0]]),
11      np.array([[0, 0, -1], [0, 1, 0], [1, 0, 0]]),
12  ]
13  
14  
15  ROT2 = [
16      np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]),
17      np.array([[1, 0, 0], [0, 0, -1], [0, 1, 0]]),
18      np.array([[1, 0, 0], [0, -1, 0], [0, 0, -1]]),
19      np.array([[1, 0, 0], [0, 0, 1], [0, -1, 0]]),
20  ]
21  
22  
23  def rotations():
24      for a in ROT1:
25          for b in ROT2:
26              yield lambda x: b @ (a @ x)
27  
28  
29  def match_scanner(beacons, scanner_positions, scanner):
30      for rot in rotations():
31          counter = Counter()
32  
33          for rel in map(rot, scanner[0]):
34              for abs_ in map(np.array, beacons):
35                  k = abs_ - rel
36  
37                  counter[kt := tuple(k)] += 1
38  
39                  if counter[kt] >= 12:
40                      beacons.update([tuple(rot(x) + k) for x in scanner[0]])
41  
42                      scanner_positions.append(k)
43  
44                      return
45  
46  
47  remaining = []
48  for block in input.split("\n\n"):
49      positions = [np.array(tuple(map(int, line.split(",")))) for line in block.splitlines()[1:]]
50      distances = {int((x := a - b).dot(x)) for a in positions for b in positions}
51      remaining.append((positions, distances))
52  
53  first = remaining.pop(0)
54  beacons = {*map(tuple, first[0])}
55  distances = first[1].copy()
56  scanners = []
57  while remaining:
58      i = max(range(len(remaining)), key=lambda j: len(remaining[j][1] & distances))
59      s = remaining.pop(i)
60  
61      match_scanner(beacons, scanners, s)
62  
63      distances.update(s[1])
64  
65  
66  print(len(beacons))
67  print(max(sum(np.abs(a - b)) for a in scanners for b in scanners))