Advertisement
Guest User

Advent of Code 2021 Day 19

a guest
Dec 19th, 2021
316
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.94 KB | None | 0 0
  1. import numpy as np
  2. from itertools import combinations, product
  3.  
  4.  
  5. def input_parser(filepath):
  6.     output = []
  7.     with open(filepath, "r") as f:
  8.         for i, scanner in enumerate(f.read().split("\n\n")):
  9.             output.append(
  10.                 np.array(
  11.                     [
  12.                         [int(n) for n in row.split(",")]
  13.                         for row in scanner.split("\n")[1:]
  14.                     ]
  15.                 )
  16.             )
  17.     return output
  18.  
  19.  
  20. def rotate_around_x(arr: np.array) -> np.array:
  21.     x_rotation_matrix = np.array([[1, 0, 0], [0, 0, -1], [0, 1, 0]])
  22.     return np.matmul(arr, x_rotation_matrix)
  23.  
  24.  
  25. def rotate_around_y(arr: np.array) -> np.array:
  26.     y_rotation_matrix = np.array([[0, 0, 1], [0, 1, 0], [-1, 0, 0]])
  27.     return np.matmul(arr, y_rotation_matrix)
  28.  
  29.  
  30. def rotate_around_z(arr: np.array) -> np.array:
  31.     z_rotation_matrix = np.array([[0, -1, 0], [1, 0, 0], [0, 0, 1]])
  32.     return np.matmul(arr, z_rotation_matrix)
  33.  
  34.  
  35. def apply_translation(arr: np.array, distance: np.array) -> np.array:
  36.     return arr + distance
  37.  
  38.  
  39. def check_overlap(coords1, coords2):
  40.     coords1 = set(map(tuple, coords1))
  41.     coords2 = set(map(tuple, coords2))
  42.     overlap = coords1 & coords2
  43.     return overlap
  44.  
  45.  
  46. def generate_y_rotations(arr):
  47.     for _ in range(4):
  48.         arr = rotate_around_y(arr)
  49.         yield arr
  50.  
  51.  
  52. def generate_rotations(arr):
  53.     side_1 = np.copy(arr)
  54.     for rotation in generate_y_rotations(side_1):
  55.         yield rotation
  56.  
  57.     side_2 = rotate_around_z(arr)
  58.     for rotation in generate_y_rotations(side_2):
  59.         yield rotation
  60.  
  61.     side_3 = rotate_around_z(side_2)
  62.     for rotation in generate_y_rotations(side_3):
  63.         yield rotation
  64.  
  65.     side_4 = rotate_around_z(side_3)
  66.     for rotation in generate_y_rotations(side_4):
  67.         yield rotation
  68.  
  69.     side_5 = rotate_around_x(arr)
  70.     for rotation in generate_y_rotations(side_5):
  71.         yield rotation
  72.  
  73.     side_6a = rotate_around_x(arr)
  74.     side_6b = rotate_around_x(side_6a)
  75.     side_6 = rotate_around_x(side_6b)
  76.     for rotation in generate_y_rotations(side_6):
  77.         yield rotation
  78.  
  79.  
  80. def assemble_map(data):
  81.     scanner_positions = {(0, 0, 0)}
  82.     beacon_positions = set(map(tuple, data[0]))
  83.     oriented_positions = [False] * len(data)
  84.     oriented_positions[0] = True
  85.  
  86.     def find_adjacent_beacons(scanner, scanner_position):
  87.         nonlocal scanner_positions, beacon_positions, oriented_positions, data
  88.         for found_beacon in beacon_positions:
  89.             for rotation in generate_rotations(scanner):
  90.                 for beacon2 in rotation:
  91.                     offset = np.array(found_beacon) - beacon2
  92.                     arr_w_offset = apply_translation(rotation, offset)
  93.                     overlap = beacon_positions & set(map(tuple, arr_w_offset))
  94.                     if len(overlap) >= 12:
  95.                         beacon_positions.update(set(map(tuple, arr_w_offset)))
  96.                         scanner_positions.add(tuple(offset))
  97.                         oriented_positions[scanner_position] = True
  98.                         return
  99.  
  100.     while not all(oriented_positions):
  101.         for i, position_found in enumerate(oriented_positions):
  102.             if not position_found:
  103.                 find_adjacent_beacons(data[i], i)
  104.  
  105.     return scanner_positions, beacon_positions, oriented_positions
  106.  
  107.  
  108. def manhattan_distance(coord1, coord2):
  109.     return (
  110.         abs(coord1[0] - coord2[0])
  111.         + abs(coord1[1] - coord2[1])
  112.         + abs(coord1[2] - coord2[2])
  113.     )
  114.  
  115.  
  116. if __name__ == "__main__":
  117.  
  118.     fp = r"data/day19.txt"
  119.     data = input_parser(fp)
  120.  
  121.     scanner_positions, beacon_positions, _ = assemble_map(data)
  122.     print(f"Part A:  {len(beacon_positions)}")
  123.  
  124.     md_max = float("-inf")
  125.     for a, b in combinations(scanner_positions, 2):
  126.         md_max = (
  127.             md_max if md_max > manhattan_distance(a, b) else manhattan_distance(a, b)
  128.         )
  129.     print(f"Part B:  {md_max}")
  130.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement