A*算法lua实现

来源:互联网 发布:淘宝尺码怎么设置 编辑:程序博客网 时间:2024/06/15 11:26

转自:http://www.cocoachina.com/bbs/read.php?tid-279162.html
加了点注释方便理解

--[[    A*寻路算法,估价值代表估计代价值--]]-- 行走的4个方向local four_dir = {    {1, 0},    {0, 1},    {0, -1},    {-1, 0},}-- 行走的8个方向local eight_dir = {    {1, 1},    {1, 0},    {1, -1},    {0, 1},    {0, -1},    {-1, 1},    {-1, 0},    {-1, -1}}local AStar = {}-- 地图、起始点、终点-- map 是一个二维数组,对应值为0表示可以通行,1表示障碍物AStar.init = function(self, map, startPoint, endPoint, four_dir)    self.startPoint = startPoint    self.endPoint   = endPoint    self.map        = map    self.cost       = 10  -- 单位花费    self.diag       = 1.4 -- 对角线长, 根号2 一位小数    self.open_list  = {}  -- open_list表保存了所有已生成而未考察的节点     self.close_list = {}  -- close_list表中记录已访问过的节点    self.mapRows    = #map    self.mapCols    = #map[1]    self.four_dir   = four_dir -- 使用4方向的寻路还是八方向的寻路end-- 搜索路径,核心代码AStar.searchPath = function(self)    -- 验证终点是否为阻挡,如果为阻挡,则直接返回空路径    if self.map[self.endPoint.row][self.endPoint.col] ~= 0 then        logf("(", self.endPoint.row, ",", self.endPoint.col, ") 是阻挡!!!无法寻路")        return nil    end    -- 把出发节点加入open_list中    local startNode = {}      startNode.row = self.startPoint.row    startNode.col = self.startPoint.col    startNode.g = 0    startNode.h = 0    startNode.f = 0    table.insert(self.open_list, startNode)    -- 检查边界、障碍点     local check = function(row, col)        if 1 <= row and row <= self.mapRows and 1 <= col and col <= self.mapCols then            if self.map[row][col] == 0 or (row == self.endPoint.row and col == self.endPoint.col) then                return true            end        end        return false    end    local dir = self.four_dir and four_dir or eight_dir    while #self.open_list > 0 do        local node = self:getMinNode()        if node.row == self.endPoint.row and node.col == self.endPoint.col then            -- 找到路径            return self:buildPath(node)        end        for i = 1, #dir do            local row = node.row + dir<i>[1]            local col = node.col + dir<i>[2]            if check(row, col) then                local curNode = self:getNodeWithFGH(node, row, col, (row ~= node.row and col ~= node.col))                local openNode, openIndex = self:findNodeInOpenList(row, col)                local closeNode, closeIndex = self:findNodeInCloseList(row, col)                if not openNode and not closeNode then                    -- 不在OPEN表和CLOSE表中                    -- 求出估价值并把节点加到 open list                    table.insert(self.open_list, curNode)                --根据估价函数重排OPEN表                --这样循环中的每一步只考虑OPEN表中状态最好的节点。                elseif openNode then                    -- 已经在OPEN表中,且估价值小于OPEN表中的估价值                    -- 更新OPEN表中的估价值                    if openNode.f > curNode.f then                        self.open_list[openIndex] = curNode                    end                else                    -- 在CLOSE表中,且估价值小于CLOSE表中的估价值                    -- 从CLOSE表中移除节点,并且加入OPEN表中                    if closeNode.f > curNode.f then                        table.insert(self.open_list, curNode)                        table.remove(self.close_list, closeIndex)                    end                end            end        end        -- 节点放入到 close list 里面        table.insert(self.close_list, node)    end    -- 不存在路径    return nilend-- 获取 f ,g ,h, 最后一个参数代表是否允许沿着对角线走AStar.getNodeWithFGH = function(self, father, row, col, isdiag)    local node = {}    local cost = self.cost    if isdiag then        cost = cost * self.diag    end    node.father = father    node.row = row    node.col = col    node.g = father.g + cost    -- 估价值h    if self.four_dir then        node.h = self:manhattan(row, col)    else        node.h = self:diagonal(row, col)    end    node.f = node.g + node.h  -- f = g + h     return nodeend-- 判断节点是否已经存在 open list 里面AStar.findNodeInOpenList = function(self, row, col)    for i = 1, #self.open_list do        local node = self.open_list<i>        if node.row == row and node.col == col then            return node, i   -- 返回节点和下标        end    end    return nilend-- 判断节点是否已经存在 close list 里面AStar.findNodeInCloseList = function(self, row, col)    for i = 1, #self.close_list do        local node = self.close_list<i>        if node.row == row and node.col == col then            return node, i        end    end    return nilend-- 在open_list中找到最佳点,并删除AStar.getMinNode = function(self)    if #self.open_list < 1 then        return nil    end    local min_node = self.open_list[1]    local min_i = 1    for i,v in ipairs(self.open_list) do        if min_node.f > v.f then            min_node = v            min_i = i        end    end    table.remove(self.open_list, min_i)    return min_nodeend-- 计算路径AStar.buildPath = function(self, node)    local path = {}    local sumCost = node.f -- 路径的总花费    while node do        path[#path + 1] = {row = node.row, col = node.col}        node = node.father    end    return path, sumCostend-- 估价h函数-- 曼哈顿估价法(用于不能对角行走)AStar.manhattan = function(self, row, col)      local h = math.abs(row - self.endPoint.row) + math.abs(col - self.endPoint.col)    return h * self.costend-- 对角线估价法,先按对角线走,一直走到与终点水平或垂直平行后,再笔直的走AStar.diagonal = function(self, row, col)    local dx = math.abs(row - self.endPoint.row)    local dy = math.abs(col - self.endPoint.col)    local minD = math.min(dx, dy)    local h = minD * self.diag + dx + dy - 2 * minD    return h * self.costendreturn AStar
0 0
原创粉丝点击