A(A-star)寻路算法是一种基于启发式搜索的路径规划算法,常用于游戏开发和人工智能领域,JPS是A  算法的一个优化算法,咱们就先做一段简单的A* 算法介绍,后续再进行JPS算法的进一步探讨。
 
A* 要素说明: 开启节点列表(OpenList):存放待检测的节点。
关闭节点列表(ClosedList):存放不会被检测的节点。
G 值:从初始节点到任意节点的代价。
H 值:从节点到目标点的启发式评估代价。
F 值:G 值和 H 值之和。
A* 算法通过在二维数组或网格中寻找两点之间的最短路径,结合启发式评估来快速确定路径,算法核心是选择 F 值最小的节点进行扩展,直到找到终点或遍历完所有节点。
实现步骤: 从 OpenList 中选择 F 值最小的节点(如果 F 相同,选取 H 最小的)。
遍历该节点周围的相邻节点:
如果没有找到终点,继续循环。
如果相邻节点不在 OpenList 中,计算其 G 值和 H 值,并设置父节点为当前节点,加入 OpenList。
如果相邻节点已在 OpenList 中,更新其 G 值为较小的值,重新设置父节点。
如果遍历到终点,回溯路径,找到最终路径。
创建一个节点类,包含节点是否可通过、世界坐标、网格坐标、G 值、H 值和父节点信息。
创建网格,初始化节点列表,设置节点是否可通过。
将起点放入 OpenList 中。
循环执行以上步骤
可参考下面的C#代码案例:
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 public  List<Node> FindPath (Node start, Node end ){     List<Node> openList = new  List<Node>();     HashSet<Node> closedList = new  HashSet<Node>();     openList.Add(start);     while  (openList.Count > 0 )     {         Node currentNode = openList[0 ];         for  (int  i = 1 ; i < openList.Count; i++)         {             if  (openList[i].f < currentNode.f || (openList[i].f == currentNode.f && openList[i].h < currentNode.h))             {                 currentNode = openList[i];             }         }         openList.Remove(currentNode);         closedList.Add(currentNode);         if  (currentNode.x == end.x && currentNode.y == end.y)         {             return  GetPath(currentNode);         }                  List<Node> neighbors = GetNeighbors8(currentNode);         foreach  (Node neighbor in  neighbors)         {             if  (closedList.Contains(neighbor) || map[neighbor.x, neighbor.y] == 1 )                 continue ;             float  newCost = currentNode.g + GetMoveCost(currentNode, neighbor);              if  (newCost < neighbor.g || !openList.Contains(neighbor))             {                 neighbor.g = newCost;                 neighbor.h = Heuristic(neighbor, end);                 neighbor.parent = currentNode;                 if  (!openList.Contains(neighbor))                     openList.Add(neighbor);             }         }     }     return  null ; } private  List<Node> GetNeighbors (Node node, Node end ){     List<Node> neighbors = new  List<Node>();     for  (int  dx = -1 ; dx <= 1 ; dx++)     {         for  (int  dy = -1 ; dy <= 1 ; dy++)         {                          if  (dx == 0  && dy == 0 )                 continue ;                          if  (dx != 0  && dy != 0 )             {                 int  nx = node.x + dx;                 int  ny = node.y + dy;                 if  (nx >= 0  && nx < width && ny >= 0  && ny < height && map[nx, ny] != 1 )                 {                     neighbors.Add(new  Node(nx, ny));                 }             }                          else              {                 int  nx = node.x + dx;                 int  ny = node.y + dy;                 if  (nx >= 0  && nx < width && ny >= 0  && ny < height && map[nx, ny] != 1 )                 {                     neighbors.Add(new  Node(nx, ny));                 }             }         }     }     return  neighbors; } private  float  GetMoveCost (Node fromNode, Node toNode ){          if  (Math.Abs(fromNode.x - toNode.x) + Math.Abs(fromNode.y - toNode.y) == 1 )      {         return  1f ;     }     else       {         return  1.414f ;      } } 
 
咱们看完了A*的原理,回到主题再来讨论下JPS算法,下面这段介绍来自维基百科: Jump Point Search (JPS) 是对 A* 搜索算法在均匀代价网格上的一种优化。它通过图剪枝来减少搜索过程中的对称性,从而消除了网格中某些节点,前提是满足与网格相关的某些条件。因此,该算法可以考虑沿着网格的直线(水平、垂直和对角线)进行较长的“跳跃”,而不是普通 A* 考虑的从一个网格位置到下一个网格位置的小步。JPS 保持了 A* 的最优性,同时可能将其运行时间缩短一个数量级。
下面的参考图(直跳a和斜跳b)来自 Harabor, Daniel; Grastien, Alban. “Improving Jump Point Search” (PDF). Australian National University College of Engineering and Computer Science. Association for the Advancement of Artificial Intelligence (www.aaai.org ). Retrieved 11 July 2015.
A* 算法回顾: A* 算法是一种启发式搜索算法,用于在图或网格上寻找最短路径。
它通过估计每个节点到目标的代价(通常使用启发式函数)来选择下一个节点进行扩展。
A* 算法维护一个开放列表(Open List)和一个关闭列表(Closed List),其中存储了待扩展的节点和已经处理过的节点。
JPS 算法的优化: 只关注所谓的“跳跃点”,而不是所有邻居点,在每个搜索步骤中,通过跳过中间的空白节点,直接跳到可能是最优解的位置(Jump Point)。这样可以减少搜索空间,提高搜索效率。
在每个节点处进行跳跃,以确定是否存在“强制邻居”(forced neighbors)。如果存在强制邻居,则在这些强制邻居之间不需要再次搜索,可以直接跳到下一个强制邻居,从而减少搜索量。
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 private  List<Node> GetNeighbors (Node node, Node end ){          List<Node> neighbors = new  List<Node>();          int  dx = Math.Sign(end.x - node.x);     int  dy = Math.Sign(end.y - node.y);                                    if  (dx == 0  && dy == 0 )         return  neighbors;          if  (dx == 0  || dy == 0 )     {                  if  (dx != 0 )         {             int  nx = node.x + dx;             int  ny = node.y;                          if  (nx >= 0  && nx < width && map[nx, ny] != 1 )             {                 neighbors.Add(new  Node(nx, ny));             }         }                  else          {             int  nx = node.x;             int  ny = node.y + dy;                          if  (ny >= 0  && ny < height && map[nx, ny] != 1 )             {                 neighbors.Add(new  Node(nx, ny));             }         }     }          else      {         int  nx = node.x + dx;         int  ny = node.y + dy;                  if  (nx >= 0  && nx < width && ny >= 0  && ny < height && map[nx, ny] != 1 )         {             neighbors.Add(new  Node(nx, ny));         }                  if  (map[node.x, ny] != 1 )         {             neighbors.Add(new  Node(node.x, ny));         }         if  (map[nx, node.y] != 1 )         {             neighbors.Add(new  Node(nx, node.y));         }     }          return  neighbors; } 
 
本文标题: A* JPS寻路算法的探讨
文章作者: Keyle
发布时间: 2024-05-08
最后更新: 2024-05-09
原始链接: https://vrast.cn/posts/10991/ 
版权声明: ©Keyle's Blog. 本站采用署名-非商业性使用-相同方式共享 4.0 国际进行许可