Advertisement
Guest User

Untitled

a guest
Dec 18th, 2022
353
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.14 KB | Source Code | 0 0
  1. # %%
  2. import numpy as np
  3. from time import perf_counter
  4.  
  5. t1 = perf_counter()
  6. with open('./data/01.txt', 'r') as f:
  7.     data = [line.strip() for line in f.readlines()]
  8.  
  9. # %%
  10. data = np.array([[int(i) for i in d.split(',')] for d in data])
  11. # %%
  12. # find smallest and largest voxel positions in data
  13. dim_mins = np.amin(data, axis=0)
  14. dim_maxs = np.amax(data, axis=0)
  15. # %%
  16. # create grid with padding according to maximum values of voxel positions
  17. grid = np.zeros(dim_maxs+2, dtype=np.int32)
  18. grid[data[:, 0], data[:, 1], data[:, 2]] = 1
  19.  
  20.  
  21. # %%
  22. # define a shift function that shifts the whole array by value val along
  23. # axis axis and pads the other side with zeros to keep array size
  24. # uses np.roll for speed
  25. def shift(arr: np.ndarray, axis: int, val: int) -> np.ndarray:
  26.     if val == 0:
  27.         return arr
  28.     t = np.roll(arr, val, axis)
  29.     if axis == 0:
  30.         if val > 0:
  31.             t[:val, :, :] = 0
  32.             return t
  33.         elif val < 0:
  34.             t[val:, :, :] = 0
  35.             return t
  36.         else:
  37.             raise TypeError
  38.     elif axis == 1:
  39.         if val > 0:
  40.             t[:, :val, :] = 0
  41.             return t
  42.         elif val < 0:
  43.             t[:, val:, :] = 0
  44.             return t
  45.         else:
  46.             raise TypeError
  47.     elif axis == 2:
  48.         if val > 0:
  49.             t[:, :, :val] = 0
  50.             return t
  51.         elif val < 0:
  52.             t[:, :, val:] = 0
  53.             return t
  54.         else:
  55.             raise TypeError
  56.     else:
  57.         raise IndexError
  58.  
  59.  
  60. # %%
  61. # ------ PUZZLE 18-01 ------
  62.  
  63. # neighbor from left:
  64. t = grid + shift(grid, 0, 1)
  65. left = np.zeros(t.shape, dtype=grid.dtype)
  66. left[t == 2] = 1
  67.  
  68. # neighbor from right:
  69. t = grid + shift(grid, 0, -1)
  70. right = np.zeros(t.shape, dtype=grid.dtype)
  71. right[t == 2] = 1
  72.  
  73. # neighbor from behind:
  74. t = grid + shift(grid, 1, 1)
  75. behind = np.zeros(t.shape, dtype=grid.dtype)
  76. behind[t == 2] = 1
  77.  
  78. # neighbor from front:
  79. t = grid + shift(grid, 1, -1)
  80. front = np.zeros(t.shape, dtype=grid.dtype)
  81. front[t == 2] = 1
  82.  
  83. # neighbor from below:
  84. t = grid + shift(grid, 2, 1)
  85. below = np.zeros(t.shape, dtype=grid.dtype)
  86. below[t == 2] = 1
  87.  
  88. # neighbor from top:
  89. t = grid + shift(grid, 2, -1)
  90. top = np.zeros(t.shape, dtype=grid.dtype)
  91. top[t == 2] = 1
  92. # %%
  93. # calculate all faces
  94. faces = np.zeros(grid.shape, dtype=grid.dtype)
  95. faces[grid != 0] = 6  # every cube has 6 faces
  96.  
  97. # subtract faces that are facing other cubes from any direction
  98. faces -= top
  99. faces -= below
  100. faces -= left
  101. faces -= right
  102. faces -= front
  103. faces -= behind
  104. t2 = perf_counter()
  105. print("Surface Area Puzzle 1:", np.sum(faces[faces != 0]), t2-t1)
  106.  
  107.  
  108. # %%
  109. # ------ PUZZLE 18-02 ------
  110. t3 = perf_counter()
  111.  
  112.  
  113. # find outside by recursively propagating the "outside"
  114. # returns a np.ndarray of same size as arr with value 2
  115. # meaning outside, value 1 meaning droplets of the grid
  116. # value 0 meaning inside
  117. def propagate_outside(arr: np.ndarray) -> np.ndarray:
  118.     arr = arr.copy()
  119.     old_arr = arr.copy()
  120.     arr[0, 0, 0] = 2
  121.     t01 = shift(arr, 0, 1)
  122.     t0n1 = shift(arr, 0, -1)
  123.     t11 = shift(arr, 1, 1)
  124.     t1n1 = shift(arr, 1, -1)
  125.     t21 = shift(arr, 2, 1)
  126.     t2n1 = shift(arr, 2, -1)
  127.     arr[(t01 == 2) & (arr != 1)] = 2
  128.     arr[(t0n1 == 2) & (arr != 1)] = 2
  129.     arr[(t11 == 2) & (arr != 1)] = 2
  130.     arr[(t1n1 == 2) & (arr != 1)] = 2
  131.     arr[(t21 == 2) & (arr != 1)] = 2
  132.     arr[(t2n1 == 2) & (arr != 1)] = 2
  133.     if np.all(old_arr == arr):
  134.         return arr
  135.     else:
  136.         return propagate_outside(arr)
  137.  
  138.  
  139. # %%
  140. outside = propagate_outside(grid)  # outside: 2, cubes: 1, inside: 0
  141.  
  142. is_inside = np.zeros(outside.shape, dtype=grid.dtype)
  143. is_inside[outside == 0] = 1
  144. # %%
  145. # subtract inside faces from cube faces left after Puzzle 1
  146. faces -= shift(is_inside, 0, 1)  # left
  147. faces -= shift(is_inside, 0, -1)  # right
  148. faces -= shift(is_inside, 1, 1)  # behind
  149. faces -= shift(is_inside, 1, -1)  # front
  150. faces -= shift(is_inside, 2, 1)  # bottom
  151. faces -= shift(is_inside, 2, -1)  # top
  152.  
  153. t4 = perf_counter()
  154. # only sum the faces > 0 because all interior values without cubes will
  155. # accumulate negative vals
  156. print("Exterior Surface Area:", np.sum(faces[faces > 0]), t4-t3)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement