Advertisement
Guest User

Fast surface area counting (optimized)

a guest
Dec 18th, 2022
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 1.76 KB | None | 0 0
  1. import collections
  2. import functools
  3.  
  4. lines = [l.strip() for l in open('day18.txt', 'r') if l.strip()]
  5. P = set(map(eval, lines))
  6.  
  7. def adj(p):
  8.     for axis in range(3):
  9.         for d in (-1, 1):
  10.             q = list(p)
  11.             q[axis] += d
  12.             yield tuple(q)
  13.  
  14. P_adj = {q for p in P for q in adj(p) if q not in P}
  15.  
  16. lines = collections.defaultdict(lambda: [])
  17. indices = {}
  18. for p in P_adj:
  19.     for axis in range(3):
  20.         lines[(axis, p[:axis] + p[axis + 1:])].append(p)
  21. for (axis, _), l in lines.items():
  22.     l.sort(key=lambda p: p[axis])
  23.     for i, p in enumerate(l):
  24.         indices[(axis, p)] = i
  25.  
  26.  
  27. def get_line(p, axis):
  28.     l = lines[(axis, p[:axis] + p[axis + 1:])]
  29.     i = indices[(axis, p)]
  30.     return l, i
  31.  
  32. def neighbors(p):
  33.     #Try to jump across empty space
  34.     for axis in range(3):
  35.         l, i = get_line(p, axis)
  36.         if i == 0 or i == len(l) - 1:
  37.             continue
  38.         for d in (-1, 1):
  39.             if not (0 <= i + d < len(l)):
  40.                 continue
  41.             q = list(p)
  42.             q[axis] += d
  43.             q = tuple(q)
  44.             if q in P:
  45.                 continue
  46.             yield l[i + d]
  47.     #Crawl around the boundary
  48.     for q in adj(p):
  49.         if q in P:
  50.             continue
  51.         if q in P_adj:
  52.             yield q
  53.         for r in adj(q):
  54.             if r in P_adj:
  55.                 yield r
  56.  
  57. external = set()
  58.  
  59. #Find points which directly face the outside
  60. for l in lines.values():
  61.     external.add(l[0])
  62.     external.add(l[-1])
  63.  
  64. #Flood fill
  65. stack = list(external)
  66. while stack:
  67.     p = stack.pop()
  68.     for q in neighbors(p):
  69.         if q not in external:
  70.             external.add(q)
  71.             stack.append(q)
  72.  
  73. print(sum(1 for p in external for q in adj(p) if q in P))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement