Jps算法_JPS算法

Jps算法_JPS算法目录概念 强迫邻居(ForcedNeighbour) 跳点(JumpPoint) JPS寻路算法(JumpPointSearch) 实现原理 示例过程 JPS+(JumpPointSearchPlus) 预处理 示例过程 总结 参考概念JPS(jumppointsearch)算法实际上是对A*寻路算法的一个改进,因此在阅读本文之前需要先了解A*算法。A*算法在扩展节点时会把节点所有邻居都考虑进去,这样openlist中点的..

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

 

概念


JPS(jump point search)算法实际上是对A* 寻路算法的一个改进,因此在阅读本文之前需要先了解A*算法。A* 算法在扩展节点时会把节点所有邻居都考虑进去,这样openlist中点的数量会很多,搜索效率较慢。

若不了解A*算法,可以参考博主以前写的一篇文章 A* 寻路算法 – KillerAery – 博客园

例如在无遮挡情况下(往往会有多条等价路径),而我们希望起点到终点实际只取其中一条路径,而该路径外其它节点可以没必要放入openlist(不希望加入没必要的邻居)。

Jps算法_JPS算法

其次我们还希望直线方向上中途的点不用放入openlist,如果只放入每段直线子路径的起点和终点,那openlist又可以少放很多没必要的节点:

Jps算法_JPS算法

可以看到 JPS 算法搜到的节点总是“跳跃性”的,这是因为这些关键性的节点都是需要改变行走方向的拐点,因此这也是 Jump Point 命名的来历。

在介绍JPS等算法具体实现前,我们必须先掌握下面的概念。

强迫邻居(Forced Neighbour)

强迫邻居:节点 x 的8个邻居中有障碍,且 x 的父节点 p 经过x 到达 n 的距离代价比不经过 x 到达的 n 的任意路径的距离代价小,则称 n 是 x 的强迫邻居。

看定义也许十分晦涩难懂。直观来说,实际就是因为前进方向(父节点到 x 节点的方向为前进方向)的某一边的靠后位置有障碍物,因此想要到该边靠前的空位有最短的路径,就必须得经过过 x 节点。

可能的情况见图示,黑色为障碍,红圈即为强迫邻居:

Jps算法_JPS算法

(左图为直线方向情况下的强迫邻居,右图为斜方向情况下的强迫邻居)

跳点(Jump Point)

跳点:当前点 x 满足以下三个条件之一:

  • 节点 x 是起点/终点。
  • 节点 x 至少有一个强迫邻居。
  • 如果父节点在斜方向(意味着这是斜向搜索),节点x的水平或垂直方向上有满足条件a,b的点。

节点y的水平或垂直方向是斜向向量的拆解,比如向量d=(1,1),那么水平方向则是(1,0),并不会往左搜索,只会看右边,如果向量d=(-1,-1),那么水平方向是(-1,0),只会搜索左边,不看右边,其他同理。

下图举个例子,由于黄色节点的父节点是在斜方向,其对应分解成向上和向右两个方向,因为在右方向发现一个蓝色跳点,因此黄色节点也应被判断为跳点:

Jps算法_JPS算法

JPS 寻路算法(Jump Point Search)


实现原理

JPS 算法和A* 算法非常相似,步骤大概如下:

  1. openlist取一个权值最低的节点,然后开始搜索。(这些和A*是一样的)
  2. 搜索时,先进行 直线搜索(4/8个方向,跳跃搜索),然后再 斜向搜索(4个方向,只搜索一步)。如果期间某个方向搜索到跳点或者碰到障碍(或边界),则当前方向完成搜索,若有搜到跳点就添加进openlist。

跳跃搜索是指沿直线方向一直搜下去(可能会搜到很多格),直到搜到跳点或者障碍(边界)。一开始从起点搜索,会有4个直线方向(上下左右),要是4个斜方向都前进了一步,此时直线方向会有8个。

  1. 若斜方向没完成搜索,则斜方向前进一步,重复上述过程。

因为直线方向是跳跃式搜索,所以总是能完成搜索。

  1. 若所有方向已完成搜索,则认为当前节点搜索完毕,将当前节点移除于openlist,加入closelist。
  2. 重复取openlist权值最低节点搜索,直到openlist为空或者找到终点。

下面结合图片更好说明过程2和3:首先我们从openlist取出绿色的节点,作为搜索的开始,先进行直线搜索,再斜向搜索,没有找到任何跳点。

Jps算法_JPS算法

斜方向前进一步后,重复直线搜索和斜向搜索过程,仍没发现跳点。

Jps算法_JPS算法

斜方向前进两步后,重复直线搜索和斜向搜索过程,仍没发现跳点。

Jps算法_JPS算法

斜方向前进了三步后(假设当前位置为 x),在水平直线搜索上发现了一个跳点(紫色节点为强迫邻居)。

Jps算法_JPS算法

于是 x 也被判断为跳点,添加进openlist。斜方向结束,绿色节点的搜索过程也就此结束,被移除于openlist,放入closelist。

Jps算法_JPS算法

示例过程

下面展示JPS算法更加完整的过程:
假设起点为绿色节点,终点为红色节点

Jps算法_JPS算法

重复直线搜索和斜向搜索过程,斜方向前进了3步。在第3步判断出黄色节点为跳点(依据是水平方向有其它跳点),将黄色跳点放入openlist,然后斜方向搜索完成,绿色节点移除于openlist,放入closelist。

Jps算法_JPS算法

对openlist下一个权值最低的节点(即黄色节点)开启搜索,在直线方向上发现了蓝色节点为跳点(依据是紫色节点为强迫邻居),类似地,放入openlist。

Jps算法_JPS算法

由于斜方向还没结束,继续前进一步。最后一次直线搜索和斜向搜索都碰到了边界,因此黄色节点搜索完成,移除于openlist,放入closelist。

Jps算法_JPS算法

对openlist下一个权值最低的节点(原为蓝色节点,下图变为黄色节点)开启搜索,直线搜索碰到边界,斜向搜索无果。斜方继续前进一步,仍然直线搜索碰到边界,斜向搜索无果。

Jps算法_JPS算法

由于斜方向还没结束,继续前进一步。

Jps算法_JPS算法

最终在直线方向上发现了红色节点为跳点,因此蓝色节点先被判断为跳点,只添加蓝色节点进openlist。斜方向完成,黄色节点搜索完成。

Jps算法_JPS算法

最后openlist取出的蓝色节点开启搜索,在水平方向上发现红色节点,判断为终点,算法完成。

回忆起跳点的第三个判断条件(如果父节点在斜方向,节点x的水平或垂直方向上有满足条件a,b的点),会发现这个条件判断是最复杂的。在寻路过程中,它使寻路多次在水平节点上搜到跳点,也只能先添加它本身。其次,这也是算法中需要使用到递归的地方,是JPS算法性能瓶颈所在。

JPS+(Jump Point Search Plus)


JPS+ 本质上也是 JPS寻路,只是加上了预处理来改进,从而使寻路更加快速。

预处理

我们首先对地图每个节点进行跳点判断,找出所有主要跳点:

Jps算法_JPS算法

然后对每个节点进行跳点的直线可达性判断,并记录好跳点直线可达性:

Jps算法_JPS算法

若可达还需记录号跳点直线距离:

Jps算法_JPS算法

类似地,我们对每个节点进行跳点斜向距离的记录:

Jps算法_JPS算法

剩余各个方向如果不可到达跳点的数据记为0或负数距离。如果在对应的方向上移动1步后碰到障碍(或边界)则记为0,如果移动n+1步后会碰到障碍(或边界)的数据记为负数距离-n

最后每个节点的8个方向都记录完毕,我们便完成了JPS+的预处理过程:

Jps算法_JPS算法

以上预处理过程需要有一个数据结构存储地图上每个格子8个方向距离碰撞或跳点的距离。

示例过程

做好了地图的预处理之后,我们就可以使用JPS+算法了。大致思路与JPS算法相同,不过这次有了预处理的数据,我们可以更快的进行直线搜索斜向搜索

在某个搜索方向上有:

  • 对于正数距离 n(意味着距离跳点 n 格),我们可以直接将n步远的节点作为跳点添加进openlist
  • 对于0距离(意味着一步都不可移动),我们无需在该方向搜索;
  • 对于负数距离 -n(意味着距离边界或障碍 n 格),我们直接将n步远的节点进行一次跳点判断(有可能满足跳点的第三条件,不过得益于预处理的数据,这步也可以很快完成)。

如下图示,起始节点通过已记录的向上距离,直接将3步远的跳点添加进openlist,而不再像以前需要迭代三步(还每步都要判断是否跳点):

Jps算法_JPS算法

其它过程也是类似的:

Jps算法_JPS算法Jps算法_JPS算法Jps算法_JPS算法Jps算法_JPS算法

总结


可以看到 JPS/JPS+ 算法里只有跳点才会被加入openlist里,排除了大量不必要的点,最后找出来的最短路径也是由跳点组成。这也是 JPS/JPS+ 高效的主要原因。

JPS

  • 绝大部分地图,使用 JPS 算法都会比 A* 算法更快,内存占用也更小(openlist里节点少了很多)。
  • JPS 在跳点判断上,要尽可能避免递归的深度过大(或者期待一下以后出现避免递归的算法),否则在超大型的地图里递归判断跳点可能会造成灾难。
  • JPS 也可以用于动态变化的地图,只是每次地图改变都需要再进行一次 JPS 搜索。
  • JPS 天生拥有合并节点(亦或者说是在一条直线里移除中间不必要节点)的功能,但是仍存在一些可以继续合并的地方。
  • JPS 只适用于 网格(grid)节点类型,不支持 Navmesh 或者路径点(Way Point)。

JPS+

  • JPS+ 相比 JPS 算法又是更快上一个档次(特别是避免了过多层递归判断跳点),内存占用则是每个格子需要额外记录8个方向的距离数据。
  • JPS+ 算法由于包含预处理过程,这让它面对动态变化的地图有天生的劣势(几乎是不可以接受动态地图的),因此更适合用于静态地图。
  • JPS+ 预处理的复杂度为 O(n)
  • ,n 代表地图格子数。
算法 性能 内存占用 支持动态地图 预处理 支持节点类型
A* 中等 支持 网格、Navmesh、路径点
JPS 偏小 支持 网格
JPS+ 非常快 中等 不支持 有,O(n)
  网格

综上,JPS/JPS+ 是A*算法的优秀替代者,绝大部分情况下更快和更小的内存占用已经足够诱人。在GDC 2015 关于 JPS+ 算法的演讲中,Steve Rabin 给出的数据甚至是比A* 算法快70~350倍。

参考


[1] 从头理解JPS寻路算法 – 简书 by ElephantKing

[2] JPS+: Over 100x Faster than A* | GDC 2015

[3] JPS+ with GoalBounding C++实现,和上面GDC2015的演讲人是同一个人 Steve Rabin。

[4] 一个在线可视化的JPS实现附说明 A Visual Explanation Of Jump Point Search

[5] JPS 算法原作者论文 github Harabor, Daniel Damir, and Alban Grastien. “Online Graph Pruning for Pathfinding On Grid Maps.” AAAI. 2011.

博主其它相关文章:
游戏AI 系列文章 – KillerAery – 博客园
游戏AI之路径规划 – KillerAery – 博客园

作者:KillerAery 出处:http://www.cnblogs.com/KillerAery/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/191577.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Mongo的morphia读取Map<String>>类型数据的问题「建议收藏」

    Mongo的morphia读取Map<String>>类型数据的问题「建议收藏」      最近一直使用morphia,给mongo数据查询带来很多遍历,但是最近项目遇到了一个严重的问题,在从Mongo数据库中查询Map&lt;String, List&lt;Object&gt;&gt;字段时,针对value值为空list时(即[ ]),竟然读到数据的严重问题,具体描述如下: 1.Entity数据结构:      import org.mongodb.morph…

  • php批量修改怎么实现,PinPHP购物分享系统2.2后台批量采集修改实现方法

    php批量修改怎么实现,PinPHP购物分享系统2.2后台批量采集修改实现方法因前段时间较忙,所以一直将这开发搁置了。今天看了一下新版的PinPHP,又心血来潮于是写了一下这个批量采集的实现,没想到写了差不多一两小时就实现了,虽然写得比较简单,也算是可以帮助一键采集一个分类。同时非常感谢PinPHP团队开发出如此好使的开源程序,哈,闲话先不多说,上代码。附源文件:下载源代码请猛击这里>>主要是对一个模板文件作了修改。/PinPHP_V2.21/admin/Tpl…

  • spss中进行单因素方差分析的操作步骤是_双因素方差分析交互作用判断

    spss中进行单因素方差分析的操作步骤是_双因素方差分析交互作用判断方差分析是检验多个总体均值是否相等的统计方法,本质上研究的是分类型自变量对数值型因变量的影响。一:分析-比较均值-单因素方差分析;二、对比-多项式;在此对话框是用于对组间平方和进行分解并确定均值的

  • 【PCIe】配置空间

    【PCIe】配置空间介绍PCI/PCIe配置空间。

  • sublime插件大全[通俗易懂]

    sublime插件大全[通俗易懂]1.PackageControl插件管理器1)在Sublime中打开View–&amp;gt;ShowConsole,将以下代码复制到输入框中后按回车键importurllib.request,os,hashlib;h=’6f4c264a24d933ce70df5dedcf1dcaee’+’ebe013ee18cced0ef93d5f746d80ef60′;…

  • getelementbyid属性与用法[通俗易懂]

    getelementbyid属性与用法[通俗易懂]语法:oElement=document.getElementById(sID)参数:sID――必选项。字符串 (String) 。返回值:oElemen――对象 (Element) 。说明:根据指定的 id 属性值得到对象。返回 id 属性值等于 sID 的第一个对象的引用。假如对应的为一组对象,则返回该组对象中的第一个。 如果无符合条件的对象,则返回 nul

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号