Advertisement
Guest User

aoc_2021_19

a guest
Dec 19th, 2021
216
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.49 KB | None | 0 0
  1. # Day 19
  2. # Finding overlapped scanners and beacons
  3. # Try minimizing the cost function (parameters = x, y, z and theta phi?)
  4.  
  5. with open('input_day19.txt') as f:
  6.     report = f.readlines()
  7.     beacons = []
  8.     for i, l in enumerate(report):
  9.         report[i] = l.strip().split(',')
  10.         if '---' in report[i][0]:
  11.             beacons.append([])
  12.         elif len(report[i])==3:
  13.             beacons[-1].append(tuple([int(v) for v in report[i]]))
  14.            
  15. '''
  16. Distances between points are translational and rotational invariant,
  17. thus a good clue to identify overlapping - what if there are points
  18. with equal distance? --> checked, no biggie
  19.  
  20. After getting the 12 overlapping beacons, we can work out the
  21. alignment and positions of sensors...by the wonderful work of
  22. minization
  23.  
  24. Then rotate the coordinates of the beacons..
  25. '''
  26.  
  27. def dist(arr1, arr2):
  28.     total = 0.
  29.     for i in range(3):
  30.         total += (arr1[i]-arr2[i])**2
  31.     return total**0.5
  32.  
  33.  
  34. # for each sensor, calculate the distance between each
  35. # pair of beacons, save as set and dict
  36. b_dist_set = [[] for _ in beacons]
  37. b_dist_dict = [{} for _ in beacons]
  38. for k in range(len(beacons)):
  39.     for i in range(len(beacons[k])-1):
  40.         for j in range(i+1, len(beacons[k])):
  41.             d = dist(beacons[k][i], beacons[k][j])
  42.             b_dist_set[k].append(d)
  43.             if d not in b_dist_dict[k]:
  44.                 b_dist_dict[k][d] = [beacons[k][i], beacons[k][j]]
  45.             else:
  46.                 print('Warning', k, i, j)
  47.                 print(b_dist_dict[k][d])
  48.                 print(beacons[k][i], beacons[k][j])
  49.                 b_dist_dict[k][d] += [beacons[k][i], beacons[k][j]]
  50.                
  51. # turn it to a set for easier comparison
  52. for k in range(len(beacons)):
  53.     b_dist_set[k] = set(b_dist_set[k])      
  54.    
  55. from scipy.spatial.transform import Rotation as R
  56. from scipy.optimize import minimize
  57.  
  58. def transform(coor, alpha, beta, gamma, center):
  59.     # align the axis rot()*coor
  60.     # Please specify degrees
  61.     # then perform translation
  62.     r_a = R.from_euler('z', [alpha], degrees=True)
  63.     r_b = R.from_euler('x', [beta], degrees=True)
  64.     r_g = R.from_euler('z', [gamma], degrees=True)
  65.     coor = r_a.apply(coor)
  66.     coor = r_b.apply(coor)
  67.     coor = r_g.apply(coor)
  68.    
  69.     return tuple([coor[0][i] + center[i] for i in range(3)])
  70.  
  71. # create a dict to store the transformed sensors
  72. checked = {0:True}
  73. # a list to store the location of the sensors
  74. sensor = [[0,0,0] for _ in range(len(beacons))]
  75.  
  76. # check until all sensors are checked
  77. while len(checked) != 25:
  78.     for k in range(len(beacons)-1):
  79.         for l in range(1, len(beacons)):
  80.             if k == l:
  81.                 continue
  82.             if k in checked and l in checked:
  83.                 continue
  84.             if k not in checked and l not in checked:
  85.                 continue
  86.             # compare the distance set
  87.             overlap = b_dist_set[k].intersection(b_dist_set[l])
  88.             # if 12 overlap, there will be exactly 66 distances
  89.             # present in both sets
  90.             if len(overlap) >= 66:
  91.                 # find the 1 to 1 correspondence for each point
  92.                 corr_map = {}
  93.                 if k in checked:
  94.                     base = k
  95.                     target = l
  96.                 else:
  97.                     base = l
  98.                     target = k
  99.                 print(base, target)
  100.                 for d in overlap:
  101.                     for pt in b_dist_dict[base][d]:
  102.                         if pt not in corr_map:
  103.                             corr_map[pt] = set(b_dist_dict[target][d])
  104.                         else:
  105.                             corr_map[pt] = corr_map[pt].intersection(b_dist_dict[target][d])
  106.  
  107.                 for pt in corr_map:
  108.                     corr_map[pt] = list(corr_map[pt])[0]
  109.  
  110.                 #print(corr_map)
  111.  
  112.                 def cost_dist(par):
  113.                     cost = 0.
  114.                     for k in corr_map:
  115.                         cost += dist(k, transform(corr_map[k], par[0], par[1], par[2], par[3:]))
  116.                     return cost
  117.  
  118.                 # find the transformation that minimize the cost
  119.                 result = minimize(cost_dist, [0.,0.,0.,0.,0.,0.])
  120.                 #print(result)
  121.                 par = result['x']
  122.                 sensor[target] = [int(np.rint(v)) for v in par[3:]]
  123.                
  124.                 # align the target coordinates
  125.                 aligned = []
  126.                 for b in beacons[target]:
  127.                     coor = [int(np.rint(v)) for v in transform(b, par[0], par[1], par[2], par[3:])]
  128.                     aligned.append(tuple(coor))
  129.                 beacons[target] = aligned
  130.  
  131.                 # update the key of the b_dist_dict
  132.                 for d in b_dist_dict[target]:
  133.                     new_coor = []
  134.                     for coor in b_dist_dict[target][d]:
  135.                         nc = [int(np.rint(v)) for v in transform(coor, par[0], par[1], par[2], par[3:])]
  136.                         new_coor.append(tuple(nc))
  137.                     b_dist_dict[target][d] = new_coor
  138.  
  139.                 checked[target] = True
  140.  
  141. # part 1, how many unique beacons
  142. unique_beacon = set(beacons[0])
  143. for bs in beacons:
  144.     unique_beacon = unique_beacon.union(bs)
  145.    
  146. print(len(unique_beacon))
  147.  
  148. # part 2, what is the largest distance apart
  149. max_dist = 0
  150. for i in range(len(sensor)-1):
  151.     for j in range(1, len(sensor)):
  152.         max_dist = max(max_dist, sum([abs(sensor[i][k]-sensor[j][k]) for k in range(3)]))
  153. print(max_dist)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement