Advertisement
Larvix

mappedPathfinding

Feb 4th, 2024 (edited)
773
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.91 KB | None | 0 0
  1. local isDead = function(node)
  2.     for _,dead in pairs(deadNodes) do
  3.         if node.y == dead.y and node.x == dead.x and node.z == dead.z then
  4.             return true
  5.         end
  6.     end
  7.     return false
  8. end
  9.  
  10. local isVisited = function(node)
  11.     for _,existing in pairs(path) do
  12.         if node.y == existing.y and node.x == existing.x and node.z == existing.z then
  13.             return true
  14.         end
  15.     end
  16.     return false
  17. end
  18.  
  19. local heuristic = function(node, goal)
  20.     return math.abs(goal.x - node.x) + math.abs(goal.y - node.y) + math.abs(goal.z - node.z)
  21. end
  22.  
  23. local findNext = function(current, goal, previous)
  24.     local pNeighbours = {
  25.         {x = current.x + 1, y = current.y, z = current.z},
  26.         {x = current.x - 1, y = current.y, z = current.z},
  27.         {x = current.x, y = current.y, z = current.z + 1},
  28.         {x = current.x, y = current.y, z = current.z - 1},
  29.         {x = current.x, y = current.y + 1, z = current.z},
  30.         {x = current.x, y = current.y - 1, z = current.z},
  31.     }
  32.     local neighbours = {}
  33.  
  34.     for k, v in pairs(pNeighbours) do
  35.         if mapData[v.y] and mapData[v.y][v.x] and mapData[v.y][v.x][v.z] == "" then
  36.             local cost = 1 -- Assuming each movement has a cost of 1 for simplicity
  37.             table.insert(neighbours, {x = v.x, y = v.y, z = v.z, cost = cost})
  38.         end
  39.     end
  40.  
  41.     table.sort(neighbours, function(a, b)
  42.         return (a.cost + heuristic(a, goal)) < (b.cost + heuristic(b, goal))
  43.     end)
  44.  
  45.     if #neighbours == 0 then
  46.         table.insert(deadNodes, current)
  47.     end
  48.  
  49.     return neighbours
  50. end
  51.  
  52. local isValid = function(start,goal)
  53.     if mapData[goal.y] and mapData[goal.y][goal.x] and mapData[goal.y][goal.x][goal.z] == "" then
  54.         if #findNext(goal,start) > 0 and #findNext(start,goal) > 0 then
  55.             --textutils.slowPrint(textutils.serialise(findNext(start,goal)))
  56.             return true
  57.         end
  58.     end
  59.     return false
  60. end
  61.  
  62. local findPath = function(start, goal, timeout)
  63.     local time = os.clock() + timeout
  64.     local found = false
  65.     local exploredNodesCount = 0
  66.     local maxStaleIterations = 10 -- Adjust this value based on your needs
  67.  
  68.     if isValid(start, goal) then
  69.         while not isDead(start) and not found and os.clock() < time do
  70.             if (path[#path].x == goal.x and path[#path].y == goal.y and path[#path].z == goal.z) then
  71.                 found = true
  72.                 break
  73.             end
  74.  
  75.             os.queueEvent("yield")
  76.             os.pullEvent("yield")
  77.             local next = findNext(path[#path], goal, path[#path - 1])
  78.  
  79.             if #next == 0 then
  80.                 table.remove(path, #path)
  81.             else
  82.                 local newNode = false
  83.  
  84.                 for k, v in pairs(next) do
  85.                     if not isVisited(v) then
  86.                         newNode = true
  87.                         table.insert(path, v)
  88.                         exploredNodesCount = exploredNodesCount + 1
  89.                         break
  90.                     end
  91.                 end
  92.  
  93.                 if not newNode then
  94.                     table.insert(deadNodes, path[#path])
  95.                     table.remove(path, #path)
  96.                 end
  97.             end
  98.  
  99.             -- Check for staleness and break out of the loop if no progress is made
  100.             if exploredNodesCount > 0 then
  101.                 exploredNodesCount = 0
  102.             else
  103.                 maxStaleIterations = maxStaleIterations - 1
  104.                 if maxStaleIterations <= 0 then
  105.                     break
  106.                 end
  107.             end
  108.         end
  109.     end
  110.  
  111.     return found
  112. end
  113.  
  114. local function isNeighbor(node1, node2)
  115.     local dx = math.abs(node2.x - node1.x)
  116.     local dy = math.abs(node2.y - node1.y)
  117.     local dz = math.abs(node2.z - node1.z)
  118.  
  119.     return (dx == 1 and dy == 0 and dz == 0) or
  120.            (dx == 0 and dy == 1 and dz == 0) or
  121.            (dx == 0 and dy == 0 and dz == 1)
  122. end
  123.  
  124. local function smoothPath(path)
  125.     local smoothPath = {path[1]}
  126.     local i = 1
  127.  
  128.     while i < #path - 1 do
  129.         local j = i + 1
  130.         local straightLine = isNeighbor(path[i], path[j])
  131.  
  132.         while j <= #path do
  133.             if not mapData[path[j].y] or not mapData[path[j].y][path[j].x] or not mapData[path[j].y][path[j].x][path[j].z] == "" then
  134.                 break
  135.             end
  136.  
  137.             local canSee = true
  138.  
  139.             for k = i + 1, j - 1 do
  140.                 if not isDead(path[k]) then
  141.                     canSee = false
  142.                     break
  143.                 end
  144.             end
  145.  
  146.             if canSee then
  147.                 if not straightLine or isNeighbor(path[j - 1], path[j]) then
  148.                     smoothPath[#smoothPath + 1] = path[j]
  149.                 end
  150.                 i = j - 1
  151.                 break
  152.             end
  153.  
  154.             j = j + 1
  155.             straightLine = isNeighbor(path[i], path[j])
  156.         end
  157.  
  158.         i = i + 1
  159.     end
  160.  
  161.     -- Ensure the smoothed path includes the end point
  162.     smoothPath[#smoothPath + 1] = path[#path]
  163.  
  164.     return smoothPath
  165. end
  166.  
  167. local function removeDetours(path)
  168.     local i = 1
  169.  
  170.     while i <= #path - 2 do
  171.         local j = #path
  172.  
  173.         while j > i + 1 do
  174.             if isNeighbor(path[i], path[j]) then
  175.                 -- Nodes i and j are neighbors, remove the intermediate nodes
  176.                 for k = i + 1, j - 1 do
  177.                     table.remove(path, i + 1)
  178.                 end
  179.                 j = i + 2
  180.             else
  181.                 j = j - 1
  182.             end
  183.         end
  184.  
  185.         i = i + 1
  186.     end
  187.  
  188.     return path
  189. end
  190.  
  191. local find = function(mappedBlocks,myX,myY,myZ,gX,gY,gZ,timeout)
  192.     mapData = mappedBlocks
  193.     local start = {x = tonumber(myX), y = tonumber(myY), z = tonumber(myZ)}
  194.     local goal = {x = tonumber(gX), y = tonumber(gY), z = tonumber(gZ)}
  195.     local timer = tonumber(timeout) or 5
  196.     path = {start}
  197.     deadNodes = {}
  198.     local hasPath = findPath(start,goal,timer)
  199.     if hasPath then
  200.         existingPath = path
  201.         path = {goal}
  202.         findPath(goal,start,timer)
  203.         path = removeDetours(path)
  204.         path = smoothPath(path)
  205.         existingPath = removeDetours(existingPath)
  206.         existingPath = smoothPath(existingPath)
  207.         if #existingPath < #path then
  208.             path = existingPath
  209.             loopStart = 2
  210.             loopEnd = #path
  211.             loopD = 1
  212.         else
  213.             loopStart = #path - 1
  214.             loopEnd = 1
  215.             loopD = -1
  216.         end
  217.         foundPath = ""
  218.         for i = loopStart,loopEnd,loopD do
  219.             local x = path[i].x - path[i-loopD].x
  220.             local y = path[i].y - path[i-loopD].y
  221.             local z = path[i].z - path[i-loopD].z
  222.             if x > 0 then foundPath = foundPath.."e"
  223.             elseif x < 0 then foundPath = foundPath.."w"
  224.             elseif z > 0 then foundPath = foundPath.."s"
  225.             elseif z < 0 then foundPath = foundPath.."n"
  226.             elseif y > 0 then foundPath = foundPath.."u"
  227.             elseif y < 0 then foundPath = foundPath.."d" end
  228.         end
  229.         return foundPath
  230.     end
  231.     return hasPath
  232. end
  233.  
  234. return {find = find}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement