Advertisement
Guest User

Day 19

a guest
Dec 20th, 2021
827
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.24 KB | None | 0 0
  1. from collections import defaultdict
  2. from itertools import permutations, product
  3.  
  4.  
  5. class Point():
  6. def __init__(self, x, y, z):
  7. self.x, self.y, self.z = x, y, z
  8.  
  9. def __sub__(self, other):
  10. return (self.x - other.x, self.y - other.y, self.z - other.z)
  11.  
  12. def __eq__(self, other):
  13. return self.x == other.x and self.y == other.y and self.z == other.z
  14.  
  15. def __str__(self):
  16. return f'({self.x}, {self.y}, {self.z})'
  17.  
  18. def __repr__(self):
  19. return f'({self.x}, {self.y}, {self.z})'
  20.  
  21. def __hash__(self):
  22. return hash(str(self))
  23.  
  24. def manhattan_dist(self, other):
  25. return abs(self.x - other.x) + abs(self.y - other.y) + abs(self.z - other.z)
  26.  
  27.  
  28. class Scanner():
  29. def __init__(self, detected_points=[], location=None):
  30. self.detected_points = detected_points
  31. self.location = location
  32.  
  33.  
  34. def generate_rotations(points):
  35. rotations = []
  36.  
  37. for rotation in permutations(['x', 'y', 'z']):
  38. for signs in product([-1, 1], repeat=3):
  39. single_rotation = []
  40.  
  41. for point in points:
  42. axes = {'x': point.x, 'y': point.y, 'z': point.z}
  43. single_rotation.append(
  44. Point(axes[rotation[0]] * signs[0], axes[rotation[1]] * signs[1], axes[rotation[2]] * signs[2]))
  45.  
  46. rotations.append(single_rotation)
  47.  
  48. return rotations
  49.  
  50.  
  51. def check_same_shape(located_scanner, unlocated_scanner):
  52. for rotation in generate_rotations(unlocated_scanner.detected_points):
  53. counts = defaultdict(int)
  54.  
  55. for point_1 in rotation:
  56. for point_2 in located_scanner.detected_points:
  57. counts[point_2 - point_1] += 1
  58.  
  59. for k in counts:
  60. if counts[k] == 12:
  61. return True, Point(k[0], k[1], k[2]), rotation
  62.  
  63. return False, None, None
  64.  
  65.  
  66. def convert_to_absolute(scanner_location, points):
  67. new = []
  68.  
  69. for point in points:
  70. new.append(Point(point.x + scanner_location.x, point.y +
  71. scanner_location.y, point.z + scanner_location.z))
  72.  
  73. return new
  74.  
  75.  
  76. def locate_scanners(scanners):
  77. n = len(scanners)
  78. located_scanners = {
  79. 0: Scanner(scanners[0].detected_points, Point(0, 0, 0))
  80. }
  81.  
  82. while len(located_scanners) != n:
  83. for i in range(n):
  84. if i in located_scanners:
  85. continue
  86.  
  87. unlocated_scanner = scanners[i]
  88.  
  89. for j in located_scanners:
  90. located_scanner = located_scanners[j]
  91.  
  92. valid, scanner_location, rotation = check_same_shape(
  93. located_scanner, unlocated_scanner)
  94.  
  95. if not valid:
  96. continue
  97.  
  98. newly_located_scanner = Scanner(
  99. convert_to_absolute(
  100. scanner_location, rotation
  101. ),
  102. scanner_location
  103. )
  104.  
  105. located_scanners[i] = newly_located_scanner
  106.  
  107. break
  108.  
  109. res = [None] * n
  110.  
  111. for i in located_scanners:
  112. res[i] = located_scanners[i]
  113.  
  114. return res
  115.  
  116.  
  117. def solve_part_1(scanners):
  118. located_scanners = locate_scanners(scanners)
  119.  
  120. points = set()
  121.  
  122. for scanner in located_scanners:
  123. points.update(scanner.detected_points)
  124.  
  125. return len(points)
  126.  
  127.  
  128. def solve_part_2(scanners):
  129. located_scanners = locate_scanners(scanners)
  130.  
  131. res = float('-inf')
  132. for i in range(len(located_scanners)):
  133. for j in range(i+1, len(located_scanners)):
  134. scanner_1 = located_scanners[i]
  135. scanner_2 = located_scanners[j]
  136.  
  137. res = max(res, scanner_1.location.manhattan_dist(
  138. scanner_2.location))
  139.  
  140. return res
  141.  
  142.  
  143. if __name__ == '__main__':
  144. with open('input_01.txt') as f:
  145. scanners = []
  146.  
  147. for scanner in f.read().split('\n\n'):
  148. detected_points = []
  149.  
  150. for coords in scanner.split('\n')[1:]:
  151. x, y, z = [int(coord) for coord in coords.split(',')]
  152. detected_points.append(Point(x, y, z))
  153.  
  154. scanners.append(Scanner(detected_points))
  155.  
  156. print(solve_part_1(scanners))
  157. print(solve_part_2(scanners))
  158.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement