Waffle3z

aoc2021 day 19

Dec 19th, 2021 (edited)
766
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 3.92 KB | None | 0 0
  1. local meta = {}
  2. local function wrap(v) return setmetatable(v, meta) end
  3. meta.__sub = function(a, b) return wrap({x = a.x - b.x, y = a.y - b.y, z = a.z - b.z}) end
  4. meta.__add = function(a, b) return wrap({x = a.x + b.x, y = a.y + b.y, z = a.z + b.z}) end
  5. meta.__eq = function(a, b) return a.x == b.x and a.y == b.y and a.z == b.z end
  6.  
  7. local orientations = {}
  8. local directions = {
  9.     wrap({x=1, y=0, z=0}), wrap({x=0, y=1, z=0}), wrap({x=0, y=0, z=1}),
  10.     wrap({x=-1, y=0, z=0}), wrap({x=0, y=-1, z=0}), wrap({x=0, y=0, z=-1})
  11. }
  12. local function cross(a, b)
  13.     return wrap({x = a.y*b.z - a.z*b.y, y = -a.x*b.z + a.z*b.x, z = a.x*b.y - a.y*b.x})
  14. end
  15. local function dot(a, b)
  16.     return a.x*b.x + a.y*b.y + a.z*b.z
  17. end
  18. for i = 1, 6 do
  19.     for j = 1, 6 do
  20.         local a, b = directions[i], directions[j]
  21.         local c = cross(a, b)
  22.         if c ~= wrap({x=0, y=0, z=0}) then
  23.             orientations[#orientations+1] = {a, b, c}
  24.         end
  25.     end
  26. end
  27.  
  28. local function orient(v, i)
  29.     local o = orientations[i]
  30.     return wrap({x = dot(v, o[1]), y = dot(v, o[2]), z = dot(v, o[3])})
  31. end
  32.  
  33. local scanners = {}
  34. local results
  35. local input = getinput()
  36.  
  37. for v in input:gmatch("[^\n]+") do
  38.     local n = v:match("scanner (%d+)")
  39.     if n then
  40.         results = {}
  41.         scanners[tonumber(n)] = results
  42.     else
  43.         local x, y, z = v:match("(.+),(.+),(.+)")
  44.         results[#results+1] = wrap({x = tonumber(x), y = tonumber(y), z = tonumber(z)})
  45.     end
  46. end
  47.  
  48. local function hash(v)
  49.     return v.x..","..v.y..","..v.z
  50. end
  51.  
  52. local set = {}
  53. local overlaps = {}
  54. local connections = {}
  55. for i = 0, #scanners do
  56.     connections[i] = {}
  57.     overlaps[i] = {}
  58.     for o = 1, 24 do
  59.         overlaps[i][o] = {}
  60.         for a = 1, #scanners[i] do
  61.             overlaps[i][o][a] = {}
  62.             for j = 0, #scanners do
  63.                 overlaps[i][o][a][j] = {}
  64.                 for b = 1, #scanners[j] do
  65.                     overlaps[i][o][a][j][b] = 0
  66.                 end
  67.             end
  68.         end
  69.     end
  70. end
  71.  
  72. for i = 0, #scanners do
  73.     local scanner = scanners[i]
  74.     for o = 1, 24 do
  75.         for a = 12, #scanner do
  76.             for A = 1, #scanner do
  77.                 local h = hash(orient(scanner[A] - scanner[a], o))
  78.                 set[h] = set[h] or {}
  79.                 if o == 1 then
  80.                     set[h][#set[h]+1] = {i, a}
  81.                 end
  82.                 for _, m in pairs(set[h]) do
  83.                     local j, b = m[1], m[2]
  84.                     if j ~= i then
  85.                         overlaps[i][o][a][j][b] = overlaps[i][o][a][j][b] + 1
  86.                         if overlaps[i][o][a][j][b] == 12 then
  87.                             if not connections[i][j] then
  88.                                 connections[i][j] = {a, b}
  89.                                 connections[j][i] = {b, a}
  90.                                 print("connected", i, j)
  91.                             end
  92.                         end
  93.                     end
  94.                 end
  95.             end
  96.         end
  97.     end
  98. end
  99.  
  100. local points = {}
  101. local numpoints = #scanners[0]
  102. for i = 1, #scanners[0] do
  103.     points[hash(scanners[0][i])] = true
  104. end
  105. local positions = {[0] = wrap({x=0, y=0, z=0})}
  106. local queue = {0}
  107. while queue[1] do
  108.     local i = table.remove(queue, 1)
  109.     for j, link in pairs(connections[i]) do
  110.         if not positions[j] then
  111.             print("scanners", i, j)
  112.             local scanner0, scanner1 = scanners[i], scanners[j]
  113.             local a, b = link[1], link[2]
  114.             local set = {}
  115.             for A = 1, #scanner0 do
  116.                 set[hash(scanner0[A])] = true
  117.             end
  118.             for o = 1, 24 do
  119.                 local oriented = {}
  120.                 for B = 1, #scanner1 do
  121.                     oriented[B] = orient(scanner1[B], o)
  122.                 end
  123.                 local matches = 0
  124.                 for B = 1, #scanner1 do
  125.                     if set[hash(oriented[B] - oriented[b] + scanner0[a])] then
  126.                         matches = matches + 1
  127.                         if matches == 12 then break end
  128.                     end
  129.                 end
  130.                 if matches == 12 then
  131.                     positions[j] = positions[i] + oriented[b] - scanner0[a]
  132.                     for B = 1, #scanner1 do
  133.                         scanner1[B] = oriented[B]
  134.                         local h = hash(scanner1[B] - positions[j])
  135.                         if not points[h] then
  136.                             points[h] = true
  137.                             numpoints = numpoints + 1
  138.                         end
  139.                     end
  140.                     queue[#queue+1] = j
  141.                     break
  142.                 end
  143.             end
  144.         end
  145.     end
  146. end
  147. print(numpoints)
  148.  
  149. local highest = 0
  150. for i = 0, #scanners do
  151.     for j = i+1, #scanners do
  152.         local d = positions[i] - positions[j]
  153.         highest = math.max(highest, math.abs(d.x) + math.abs(d.y) + math.abs(d.z))
  154.     end
  155. end
  156. print(highest)
Add Comment
Please, Sign In to add comment