纯lua版A*算法优化测试

写了个A*算法的lua版本,也参考了不少网上资料还有开源的代码,关于写这个的原因,只是在做一个rts的寻路,写了个lua版本也是图省事,想尽快看效果。出于程序员的好奇和执着,修改了好几个版本,优化算法,提高了一些效率,当然这里还有优化的余地,就不做进一步深入了,毕竟时间有限,优化的结果也是很明显的。

关于A*算法的基本原理,可以参考一个很好教程:http://www.policyalmanac.org/games/aStarTutorial.htm


优化

关于A*算法的优化,无非以下二点:

  • openlist、closelist的查找
  • openlist中获得最优节点

这里优化的方向有针对性,不同需要有不同的优化策略。这里我们研究的是针对2维地图的优化方案。
解决第一点,是要有好的查找效率,简单的可以用hash来加速查找。当然lua里直接map就可以提升不少速度:

  local idx = self:getIndex(row, col)
  local curNode = self:getNode(node, row, col, (row ~= node.row and col ~= node.col))
  local openNode = self.open_list[idx]
  local closeNode = self.close_list[idx]

  if not openNode and not closeNode then
      -- 不在OPEN表和CLOSE表中
      self.open_list[idx] = curNode
  elseif openNode then
      -- 在OPEN表
      if openNode.f > curNode.f then
          -- 更新OPEN表中的节点
          self.open_list[idx] = curNode
      end
  else
      -- 在CLOSE表中
      if closeNode.f > curNode.f then
          self.open_list[idx] = curNode
          self.close_list[idx] = nil
      end
  end

解决第二点,是要让openlist更快的查找最小f值节点,这里使用更快的heap,代码参考https://github.com/Yonaba/Binary-Heaps

  -- start node
  local idx = self:getIndex(self.startPoint.row, self.startPoint.col)
  self.open_list:push(self.nodes[idx])

  -- walkable 
  local check = function(row, col)
      ...
  end

  local dir = self.four_dir and four_dir or eight_dir
  while not self.open_list:empty() do
      -- check
      local node = self.open_list:pop()
      node.state = 2

      if node.row == self.endPoint.row and node.col == self.endPoint.col then
          -- found
      end

      for i = 1, #dir do
          local row = node.row + dir[i][1]
          local col = node.col + dir[i][2]
          local idx = self:getIndex(row, col)

          if check(row, col) then
              local g, h, f = self:getCost(node, row, col, ...)
              local newNode = self.nodes[idx]

              if newNode.state == 0 then
                  -- add new node
                  newNode.father = node
                  newNode.g = g
                  newNode.h = h
                  newNode.f = f
                  newNode.state = 1
                  self.open_list:push(newNode)
              elseif newNode.state == 1 then
                  -- alreay in openlist
                  if newNode.f > f then
                      -- a better way then update 
                      newNode.father = node
                      newNode.g = g
                      newNode.h = h
                      newNode.f = f
                  end
              else
                  -- in closelist
              end
          end
      end
  end

测试结果

测试环境使用cocos2dx2.2.6-lua,地图tilemap,大小50*50,地图信息如下:
地图信息

PC - Experiment1 实验结果:

Experiment1([1, 1] -> [1, 50]) time (s)
A* - array 0.0960~0.1030
A* - map 0.0290~0.0300
A* - map & heap sort 0.0020~0.0030

PC - Experiment2 实验结果:

Experiment2([1, 1] -> [6, 5]) time (s)
A* - array 0.1360~0.1450
A* - map 0.0420~0.0460
A* - map & heap sort 0.0020~0.0030

Mobile - Experiment1 实验结果:

Experiment1([1, 1] -> [1, 50]) time (s)
A* - array 1.050~1.110
A* - map 0.500~0.600
A* - map & heap sort 0.040~0.050

Mobile - Experiment2 实验结果:

Experiment2([1, 1] -> [6, 5]) time (s)
A* - array 1.260~1.300
A* - map 0.640~0.700
A* - map & heap sort 0.024~0.027

Repository

github:adamwu

往后可能写个c++版本的,毕竟lua效率要差些。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章