Advertisement
CloneTrooper1019

A* Pathfinder in Pure Lua.

Nov 11th, 2015
445
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.83 KB | None | 0 0
  1.  
  2. -------------------------------------------------------------------------------------------
  3. Vector2 = {}
  4.  
  5. local v2Meta = {}
  6.  
  7. function v2Meta.__tostring(v2)
  8.     return v2.X..", "..v2.Y
  9. end
  10.  
  11. function v2Meta.__eq(self,other)
  12.     return self.X == other.X and self.Y == other.Y
  13. end
  14.  
  15. local v2Methods =
  16. {
  17.     add = "+";
  18.     sub = "-";
  19.     mul = "*";
  20.     div = "/";
  21. }
  22.  
  23. local v2Format = "return Vector2.new(%d%s%d,%d%s%d)"
  24.  
  25. for key,met in pairs(v2Methods) do
  26.     v2Meta["__"..key] = function (self,other)
  27.         local x = self.X
  28.         local y = self.Y
  29.         local ox = other.X
  30.         local oy = other.Y
  31.         local result = v2Format:format(x,met,ox,y,met,oy)
  32.         return loadstring(result)()
  33.     end
  34. end
  35.  
  36. function Vector2.new(x,y)
  37.     local x = tonumber(x) and x or 0
  38.     local y = tonumber(y) and y or 0
  39.     local vec =
  40.     {
  41.         X = x;
  42.         Y = y;
  43.         magnitude = math.sqrt(x^2+y^2);
  44.     }
  45.     if vec.magnitude ~= 1 and vec.magnitude ~= 0 then
  46.         vec.unit = Vector2.new(x/vec.magnitude,y/vec.magnitude)
  47.     else
  48.         vec.unit = vec
  49.     end
  50.     setmetatable(vec,v2Meta)
  51.     return vec
  52.  
  53. end
  54.  
  55. -------------------------------------------------------------------------------------------
  56.  
  57. local maze =
  58. {
  59.     "##########################################";
  60.     "# # #       #     #       #         #   #";
  61.     "# # ### ### # ### ### ### ### # ### # # #";
  62.     "#       #   #   #   # # #   # # # #   # #";
  63.     "######### ##### ### # # ### ### # ##### #";
  64.     "#       # #       #   #   #     #   #   #";
  65.     "### ##### ####### ####### ####### ### ###";
  66.     "# #     #     #   #           #         #";
  67.     "# # ### ##### # ##### ##### # # #########";
  68.     "# # #       #   #     #     # #         #";
  69.     "# # # ### ####### ########### ######### #";
  70.     "#   #   # #               #     #   #   #";
  71.     "# ##### # # ############# ##### ### # ###";
  72.     "# #     # #         # # #     #     #   #";
  73.     "### ##### ######### # # ##### ######### #";
  74.     "#   #   #   #               #       #   #";
  75.     "# ### # ##### ##################### # ###";
  76.     "#     #       #   # #         # #   #   #";
  77.     "# ############# # # ######### # # ### ###";
  78.     "# #       #     #               #   #   #";
  79.     "S # ##### # ################### ### # ###";
  80.     "# #     #   #     #   #       # #   #   #";
  81.     "# ##### ##### ### # # # ##### # # ##### E";
  82.     "#       #       #   #       #   #       #";
  83.     "#########################################";
  84. }
  85.  
  86.  
  87. local data = {}
  88. local startPos
  89. local endPos
  90. local abs = math.abs
  91.  
  92. for y,row in pairs(maze) do
  93.     local x = 0
  94.     for char in row:gmatch(".") do
  95.         x = x + 1
  96.         if not data[x] then
  97.             data[x] = {}
  98.         end
  99.         if char == "S" then
  100.             startPos = Vector2.new(x,y)
  101.             data[x][y] = " "
  102.         elseif char == "E" then
  103.             endPos = Vector2.new(x,y)
  104.             data[x][y] = " "
  105.         else
  106.             data[x][y] = char
  107.         end
  108.     end
  109. end
  110.  
  111. local function aStar(start_,end_)
  112.     local closedCache = {}
  113.     local closedList = {}
  114.  
  115.     local function addToClosedList(pos)
  116.         closedList[#closedList+1] = pos
  117.         local x,y = pos.X,pos.Y
  118.         if not closedCache[x] then
  119.             closedCache[x] = {}
  120.         end
  121.         if not closedCache[x][y] then
  122.             closedCache[x][y] = true
  123.         end
  124.     end
  125.  
  126.  
  127.     addToClosedList(start_)
  128.  
  129.     local function getOpenList(pos)
  130.         local openList = {}
  131.         local function processCell(cx,cy)
  132.             if data[cx] then
  133.                 local cell = data[cx][cy]
  134.                 if cell and cell == " " then
  135.                     if not closedCache[cx] then
  136.                         closedCache[cx] = {}
  137.                     end
  138.                     if not closedCache[cx][cy] then
  139.                         local openPos = Vector2.new(cx,cy)
  140.                         table.insert(openList,openPos)
  141.                     end
  142.                 end
  143.             end
  144.         end
  145.         for x = -1,1 do
  146.             for y = -1,1 do
  147.                 local isSame = (x+y == 0)
  148.                 local isDiagonal = (abs(x)+abs(y) == 2)
  149.                 if not (isSame or isDiagonal) then
  150.                     local cx = pos.X + x
  151.                     local cy = pos.Y + y
  152.                     processCell(cx,cy)
  153.                 end
  154.             end
  155.         end
  156.         return openList
  157.     end
  158.  
  159.     local foundPath = false
  160.  
  161.     while not foundPath do
  162.         local g = #closedList-1
  163.         local lastPos = closedList[g+1]
  164.         local openList = getOpenList(lastPos)
  165.         if #openList > 0 then
  166.             local lowestF,bestPos = math.huge,Vector2.new()
  167.             for _,pos in pairs(openList) do
  168.                 local h = (endPos-pos).magnitude
  169.                 if h == 0 then
  170.                     addToClosedList(end_)
  171.                     foundPath = true
  172.                     print("Path found!")
  173.                     break
  174.                 end
  175.                 local f = g + h
  176.                 if f < lowestF then
  177.                     lowestF = f
  178.                     bestPos = pos
  179.                 end
  180.             end
  181.             if not foundPath then
  182.                 addToClosedList(bestPos)
  183.             end
  184.         else
  185.             break
  186.         end
  187.     end
  188.    
  189.     return foundPath,closedList
  190. end
  191.  
  192. local findingPath = true
  193. local currentStartPos = startPos
  194.  
  195. local function deepCopy(t)
  196.     local new = {}
  197.     for k,v in pairs(t) do
  198.         if type(v) == "table" then
  199.             new[k] = deepCopy(v)
  200.         else
  201.             new[k] = v
  202.         end
  203.     end
  204.     return new
  205. end
  206.  
  207. local arrowKeys =
  208. {
  209.     ["-1, 0"] = "<";
  210.     ["1, 0"] = ">";
  211.     ["0, -1"] = "^";
  212.     ["0, 1"] = "v";
  213. }
  214.  
  215. local function printMaze(closedList)
  216.     print()
  217.     local dataCopy = deepCopy(data)
  218.  
  219.     local startPos = closedList[1]
  220.     local endPos = closedList[#closedList]
  221.     for index,node in pairs(closedList) do
  222.         if startPos == node then
  223.             dataCopy[node.X][node.Y] = "S"
  224.         elseif endPos == node then
  225.             dataCopy[node.X][node.Y] = "E"
  226.         else
  227.             local nextNode = closedList[index+1]
  228.             if nextNode then
  229.                 local movement = (nextNode-node).unit
  230.                 dataCopy[node.X][node.Y] = arrowKeys[tostring(movement)]
  231.             end
  232.             --dataCopy[node.X][node.Y] = string.char(165)
  233.            
  234.         end
  235.     end
  236.  
  237.     local finalData = {}
  238.  
  239.     for y,row in pairs(dataCopy) do
  240.         for x,char in pairs(row) do
  241.             if not finalData[x] then
  242.                 finalData[x] = {}
  243.             end
  244.             if char == "B" then
  245.                 char = " "
  246.             end
  247.             finalData[x][y] = char
  248.         end
  249.     end
  250.  
  251.     for _,column in pairs(finalData) do
  252.         print(table.concat(column,""))
  253.     end
  254.     print()
  255. end
  256.  
  257. local function block(pos)
  258.     data[pos.X][pos.Y] = "B"
  259. end
  260.  
  261. while findingPath do
  262.     local foundPath,nodes = aStar(currentStartPos,endPos)
  263.     if foundPath then
  264.         findingPath = false
  265.         printMaze(nodes)
  266.     else
  267.         block(nodes[#nodes])
  268.     end
  269. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement