AStar算法()
把网上的AStar算法的论述自己实现了一遍,一开始只是最基础的实现。当然,现在AStar算法已经演变出了各种优化的版本,这篇也会基于各种优化不断的更新。
如果对算法不熟悉可以看下Stanford的这篇文章,我觉得是讲解的十分仔细的了:http://theory.stanford.edu/~amitp/GameProgramming/,也附上国内的翻译:http://blog.csdn.net/coutamg/article/details/53923717
讲讲我对上面这篇文章的理解:
(1)AStar算法的核心就在于这个公式了f(n) = g(n) + h(n),算法的效果如何也都取决于这个公式。就如文章中说的,g(n)可以看做从start到current所花费的cost,h(n)从current到end的花费。
很多人会直接将这两个当做距离来计算,这是在忽略地形等条件影响下最简单的模型。对于每一步,我们可以确定g(n)的准确值,但是h(n)很难预估正确的值(特别是在复杂且大型的场景中)。文章中也提供了几种解决方案比如waypoint等。
(2)算法维护着两张表openlist和closelist,openlist初始化时将start加入。
在循环寻找路径时,将openlist中优先级最高的元素取出,移入closelist中,表示该点已经“探测”过。对该点的周围N个neighbor进行检测,符合条件将其加入openlist中,并对openlist进行优先级排序。
既然是对基础的简单理解,就不多说直接贴上代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class AStar { public enum POINT_TYPE
{
normal,
obstacle,
} public class POINT:System.IComparable
{
float _gValue, _hValue;
public float gValue
{
get
{
return _gValue;
}
set
{
_gValue = value;
fValue = AStar.GetFValue(pos,gValue,hValue);
}
} public float hValue
{
get
{
return _hValue;
}
set
{
_hValue = value;
fValue = AStar.GetFValue(pos, gValue, hValue);
}
}
public float fValue
{
get;
private set;
}
public Vector2 pos, parent;
public POINT_TYPE type; public int CompareTo(object obj)
{
POINT pt = obj as POINT;
if (fValue < pt.fValue)
return -;
else if (fValue == pt.fValue)
return ;
else
return ;
} } public Dictionary<Vector2, POINT> points = new Dictionary<Vector2, POINT>();
public static Vector2 startPt, endPt; public List<POINT> openList = new List<POINT>();
public List<POINT> closeList = new List<POINT>(); public bool finish = false; public static float GetFValue(Vector2 pt,float gValue,float hValue)
{
Vector2 vec1 = pt - startPt;
Vector2 vec2 = endPt - startPt;
float fac = Vector3.Cross(new Vector3(vec1.x, vec1.y, ), new Vector3(vec2.x, vec2.y, )).normalized.z > ? 0.01f : -0.01f;
return gValue + 2f * hValue + fac;
} float GetManhattanDistance(Vector2 pos1, Vector2 pos2)
{
return Mathf.Abs(pos1.x - pos2.x) + Mathf.Abs(pos1.y - pos2.y);
} List<POINT> GetNeighbours(Vector2 pt)
{
List<POINT> neighbouts = new List<POINT>();
if (points.ContainsKey(new Vector2(pt.x - , pt.y)))
neighbouts.Add(points[new Vector2(pt.x - , pt.y)]);
if (points.ContainsKey(new Vector2(pt.x + , pt.y)))
neighbouts.Add(points[new Vector2(pt.x + , pt.y)]);
if (points.ContainsKey(new Vector2(pt.x, pt.y +)))
neighbouts.Add(points[new Vector2(pt.x, pt.y +)]);
if (points.ContainsKey(new Vector2(pt.x, pt.y - )))
neighbouts.Add(points[new Vector2(pt.x, pt.y - )]);
return neighbouts;
} public void Init(List<POINT> pts,Vector2 start,Vector2 end)
{
foreach (POINT pt in pts)
{
points.Add(pt.pos, pt);
} startPt = start;
endPt = end; points[startPt].parent = start;
points[startPt].gValue = ;
points[startPt].hValue = Mathf.Abs(startPt.x - endPt.x) + Mathf.Abs(startPt.y - endPt.y); openList.Add(points[startPt]); finish = false;
} public void StepNext()
{
if (finish)
return; POINT current = openList[];
openList.Remove(current);
closeList.Add(current);
if (current.pos == endPt)
{
finish = true;
return;
} List<POINT> neighbours = GetNeighbours(current.pos);
for (int i = ; i < neighbours.Count; i++)
{
if (neighbours[i].type == POINT_TYPE.obstacle || closeList.Contains(neighbours[i]))
continue; bool needSort = false;
float gValue =GetManhattanDistance(neighbours[i].pos,startPt);
float hValue = GetManhattanDistance(neighbours[i].pos,endPt);
float fValue = AStar.GetFValue(neighbours[i].pos,gValue,hValue); if (openList.Contains(neighbours[i]))
{
if (neighbours[i].fValue > fValue)
{
neighbours[i].gValue = gValue;
neighbours[i].hValue = hValue;
needSort = true;
}
}
else
{
neighbours[i].gValue = gValue;
neighbours[i].hValue = hValue;
neighbours[i].parent = current.pos;
openList.Add(neighbours[i]);
needSort = true;
} if (needSort)
openList.Sort();
} } }
简单的标注这几行:
49-58 :继承于IComparable接口类,并且重写了CompareTo方法。这样就可以利用List<T>.Sort()来排序了。在CompareTo方法中,当fValue相等时,hValue值小具有更高的priority。关于fValue相同的情况在论文中有阐述。
71-77:根据g(n),h(n)计算f(n)。上面说的算法的核心公式是f(n) = g(n) + h(n),但是很多时候这样简单的相加并不能适应各种复杂的情况。考虑这样一种情况:
(请忽略这张图中坐标下的数值(f值),并不与代码相符)
蓝色为当前探测的点,黄色为待探测的点。若用公式f(n) = g(n) + h(n)此时有两种相等(f和h都相同)的情况,这样将增大计算的消耗。这里简单的用了cross函数使相等时总是能选择某一侧作为偏向。
138-139:g和h的值分别为n点到start和end点的曼哈顿距离(x,y轴上距离相加),这里其实只是近似值,并且g的值其实来说并不准确。上文说道g值对于每一步的计算来说都是可以确定的。在本例中暂且这样,下一例中改进。
来看一下算法的效果:
第一张图从(0,10)到(14,2),第二张图从(0,12)到(14,2)。绿色为算法最终输出的路径,黄色与蓝色为检测的范围。
而在实现过程中也法线了g和h对算法的影响。当g>>h时,算法偏向于全方位的检测,当h>>g时,算法偏向于向end点方向检测。
AStar算法()的更多相关文章
- [原创]南水之源A*(A-Star)算法
开发导航之前我看了一些A*(A-Star)算法的例子和讲解.没有求得甚解!不过也从A*(A-Star)算法中得到启发,写了一套自己的A*(A-Star)算法.当然,这不是真正(我也不知道)的A*(A- ...
- 启发式搜索A-Star算法 【寻找 最短路径 算法】【地理几何位置 可利用的情况】
在处理最短路径问题时,有一种启发式算法是我们应该了解的,由于其有着优秀的探索效率在各自现实项目中多有应用,它就是 A-star 算法,或 A* 算法. 个人观点: A* 算法并不保证找到的路径一 ...
- AStar算法的学习
摘自:http://www.cnblogs.com/hxsyl/p/3994730.html A*算法的java实现 import java.util.ArrayList; import java.u ...
- 【网络资料】Astar算法详解
关于A*算法,很早就想写点什么,可是貌似天天在忙活着什么,可事实又没有做什么,真是浮躁啊!所以今晚还是来写一下总结吧! A*算法是很经典的只能启发式搜索算法,关于只能搜索算法和一般的搜索算法(例如DF ...
- AStar算法(转载)
以下的文章来至http://blog.csdn.net/debugconsole/article/details/8165530,感激这位博主的翻译,可惜图片被和谐了,所以为方便阅读,我重新把图片贴上 ...
- aStar算法求第k短路
A*的概念主意在于估计函数,f(n)=g(n)+h(n),f(n)是估计函数,g(n)是n节点的当前代价,h(n)是n节点的估计代价:而实际中,存在最优的估计函数f'(n)=g'(n)+h'(n),那 ...
- poj 2449 Remmarguts' Date 求第k短路 Astar算法
=.=好菜 #include <iostream> #include <cstdio> #include <string.h> #include <cstri ...
- a-star算法
http://blog.csdn.net/shanshanpt/article/details/8977512 这篇文章讲得不错. 所谓的启发函数,所谓权值之类(此处所谓的权值就是路劲的长度).YES ...
- 算法:Astar寻路算法改进
早前写了一篇<RCP:gef智能寻路算法(A star)> 出现了一点问题. 在AStar算法中,默认寻路起点和终点都是N x N的方格,但如果用在路由上,就会出现问题. 如果,需要连线的 ...
随机推荐
- vs2013突然打不开项目,项目全部不兼容
转载:https://forum.cocos.com/t/vs2013/40931 转载:https://jingyan.baidu.com/article/cdddd41c7c6b5353cb00e ...
- 关于PHP5.6连接SqlServer
在做一个PHP报名系统的时候需要使用mssql来和winform结合起来使用, 但是发现我的php环境没有sqlsrv模块,于是乎,我就开始百度了 找到了微软官方下载地址,对照php版本,下载对应的模 ...
- 【HNOI 2018】毒瘤
Problem Description 从前有一名毒瘤. 毒瘤最近发现了量产毒瘤题的奥秘.考虑如下类型的数据结构题:给出一个数组,要求支持若干种奇奇怪怪的修改操作(例如给一个区间内的数同时加上 \(c ...
- aop (权限控制之功能权限)
在实际web开发过程中通常会存在功能权限的控制,不如这个角色只允许拥有查询权限,这个角色拥有CRUD权限,当然按钮权限显示控制上可以用button.tld来控制,本文就不说明. 具体控制流程就是通过登 ...
- kubernetes1.13.5安装部署
Kubernetes 一. Kubernetes介绍 各节点所需组件 Master:docker,kubeadm,kubelet, 组件 版本 备注 Kubelet 1.13.5 组件 Kube ...
- MySQL 存储过程返回多个值
MySQL 存储过程返回多个值 在本教程中,您将学习如何编写/开发返回多个值的存储过程. MySQL存储函数只返回一个值.要开发返回多个值的存储过程,需要使用带有INOUT或OUT参数的存储过程 ...
- 第 9 章 数据管理 - 076 - 使用 Rex-Ray volume
使用 Rex-Ray volume 在 docker1 或 docker2 上执行如下命令创建 volume: rexray volume create --size 2 'C:\share\myda ...
- 第 8 章 容器网络 - 072 - 一文搞懂各种 Docker 网络
Docker 起初只提供了简单的 single-host 网络,显然这不利于 Docker 构建容器集群并通过 scale-out 方式横向扩展到多个主机上. 跨主机网络方案: Docker Over ...
- 《R语言入门与实践》第一章:R基础
前言 本章介绍了 R 语言的基础知识 界面: 使用命令 “ R “进行命令行的实时编译 对象 定义: 用于储存数据的,设定一个名称 格式: a <- 1:6 命名规则: 规则1:不能以数字开头规 ...
- Batchnorm
Internal Covariate Shift:每一次参数迭代更新后,上一层网络的输出数据经过这一层网络计算后,数据的分布会发生变化,为下一层网络的学习带来困难(神经网络本来就是要学习数据的分布,要 ...