1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
| local removeFromList = function(nodeList, element) for i = 1, #nodeList do if nodeList[i] == element then table.remove(nodeList, i) break end end end
local findNodeByIndex = function(nodeList, nodeIndex) for i = 1, #nodeList do if nodeList[i].index == nodeIndex then return nodeList[i] end end return nil end
local contains = function(nodeList, nodeIndex) return findNodeByIndex(nodeList, nodeIndex) ~= nil end
local findMinFNode = function(nodeList) local minF = math.maxinteger local minFNode = nil for i = 1, #nodeList do local n = nodeList[i] local F = n.G + n.H if F < minF then minF = F minFNode = n end end return minFNode end
local node = function(index, preNodeIndex, G, H) if index == nil then index = 0 end if preNodeIndex == nil then preNodeIndex = 0 end if G == nil then G = 0 end if H == nil then H = 0 end local n = { index = index, preNodeIndex = preNodeIndex, G = G, H = H, } return n end
local map = { 1,0,1,1,1,0,1,1,1, 1,0,1,0,1,1,1,0,1, 1,1,1,0,1,1,0,1,1, 1,1,0,0,0,0,0,1,1, 1,1,1,1,1,1,0,1,1, 1,1,0,1,0,1,0,1,1, 1,1,0,1,0,1,1,0,1, 1,0,0,1,1,0,0,1,1, 1,1,1,1,1,1,1,1,1, }
local mapH = 9 local mapV = #map / mapH local mapDataLength = #map
local openList = {} local closeList = {}
local startNodeIndex = 37 local endNodeIndex = 45 local openObliqueCheck = true local minFNode = nil
local calculateH = function(nodeIndex) local projectedXEnd = (endNodeIndex - 1) % mapH + 1 local projectedXNode = (nodeIndex - 1) % mapH + 1 local projectedYEnd = endNodeIndex - (endNodeIndex - 1) % mapH local projectedYNode = nodeIndex - (nodeIndex - 1) % mapH local xDis = math.abs(projectedXEnd - projectedXNode) local yDis = math.abs(projectedYEnd - projectedYNode) / mapH return xDis + yDis end
local isReachable = function(nodeIndex) return nodeIndex > 0 and nodeIndex <= mapDataLength and map[nodeIndex] > 0 end
table.insert(openList, node(startNodeIndex, -1, 0, calculateH(startNodeIndex)))
repeat minFNode = findMinFNode(openList) local upLeft = minFNode.index - mapH - 1 if upLeft % mapH == 0 then upLeft = -1 end local up = minFNode.index - mapH local upRight = minFNode.index - mapH + 1 if upRight % mapH == 1 then upRight = -1 end local left = minFNode.index - 1 if left % mapH == 0 then left = -1 end local right = minFNode.index + 1 if right % mapH == 1 then right = -1 end local bottomLeft = minFNode.index + mapH - 1 if bottomLeft % mapH == 0 then bottomLeft = -1 end local bottom = minFNode.index + mapH local bottomRight = minFNode.index + mapH + 1 if bottomRight % mapH == 1 then bottomRight = -1 end
local neighborList = {upLeft, up, upRight, left, right, bottomLeft, bottom, bottomRight}
local obliqueReachableList = {1,1,1,1,1,1,1,1} if openObliqueCheck then local isReachable_up = isReachable(up) local isReachable_left = isReachable(left) local isReachable_right = isReachable(right) local isReachable_bottom = isReachable(bottom) if (not isReachable_left) and (not isReachable_up) then obliqueReachableList[1] = 0 end if (not isReachable_up) and (not isReachable_right) then obliqueReachableList[3] = 0 end if (not isReachable_left) and (not isReachable_bottom) then obliqueReachableList[6] = 0 end if (not isReachable_bottom) and (not isReachable_right) then obliqueReachableList[8] = 0 end end
for i = #neighborList, 1, -1 do local n = neighborList[i] local reachable = isReachable(n) if (not reachable) or obliqueReachableList[i] == 0 or contains(openList, n) or contains(closeList, n) then table.remove(neighborList, i) else local stepValue = 1 if i == 1 or i == 3 or i == 6 or i == 8 then stepValue = 1.414 end local node = node(n, minFNode.index, minFNode.G + stepValue, calculateH(n)) table.insert(openList, node) end end removeFromList(openList, minFNode) table.insert(closeList, minFNode)
until(minFNode.index == endNodeIndex or #openList == 0)
local nodeIndex = endNodeIndex local path = {} if contains(closeList, nodeIndex) then while true do node = findNodeByIndex(closeList, nodeIndex) table.insert(path, node) nodeIndex = node.preNodeIndex if nodeIndex == -1 then break end end
local toVectorFormat = function(index) local x = index%mapH if x == 0 then x = mapH end return "("..math.ceil(index/mapH)..", "..x..")" end local output = "A* path from "..toVectorFormat(startNodeIndex).." to "..toVectorFormat(endNodeIndex) .. " distance is "..findNodeByIndex(closeList, endNodeIndex).G.." \n" for i = #path, 1, -1 do local str = toVectorFormat(path[i].index) output = output .. str .. " -> " end print(string.sub(output, 1, #output - 4)) else print("no path found in map.") end
|