原文地址:https://blog.youkuaiyun.com/Isaac320/article/details/69400096
源码优快云下载(需2积分):https://download.youkuaiyun.com/download/sun_zeliang/10881332
源码百度云(不需要积分):https://pan.baidu.com/s/1OEwCex9mpBLS1z3iPoem1w 提取码:do1m
翻了翻别人写的博客,我看到一个A星算法,只怪自己见识太少,竟然没听过这个算法。网上查了好些资料,自己对这算法理解了些,并用C#实现出来。
A星算法,也叫A*算法。这是一种在图形平面上,有多个节点的路径,求出最低通过成本的算法。 如在一张dota地图上,英雄从一个地方走动到地图上另一个点,它选择最优路线的算法。
如上图,绿点是开始点,红点是目的地,黑色区域是不可通过区域。 通过A*算法,黄色线段就是找到的最优路线。
我想了想,其实用漫水算法也能找这路线啊。这A星算法优点在于处理速度快,并不是像漫水一样,各个方向都在寻找。
A*算法原理。就以上面那种情况说明吧, 从绿色点开始,你想去红色点,你下一步有八个方向选择。
八个方向选择,你肯定想往右边走,这样才能离目的地近。横竖走,还是斜着走,更倾向横竖走,距离短。
用G表示你从起始点走的距离。横或竖一格G=10,斜着G=14。
用H表示你离目的地的距离,这里就是个估算,就像你老远看下,在那个方向,估算下距离。用曼哈顿距离表示就可以了。 比如你在(1,1),要去(5,5).距离就当你竖着走4格,横着走4个,八格就到了。估算,别管障碍物。八格那么,H=80.变大十倍(因为G变大10倍了)。
那么用F=G+H表示你周围的格子,你要去目的地花的代价。 越小越好。
然后你建两个表,存放一些东西。你要探索的格子存在OpenList里去,你找到最好的存到CloseList去。你存的不仅仅是这个格子的F值,还有它指向的方向,不然你的G有什么意义。
然后你就有F的值了,你周围的八个格子F都有了,加入到你的OpenList里去。选个F最小的格子,移出OpenList,存到CloseList去。走到这个格子,探索这个格子周围的格子忽略障碍物和边界,忽略CloseList里的格子,其他统统加入到Openlist里。如果有格子在OpenList里,看看他们原来的G值和你走过去的G值大小比较下,如果你的G大,就让那个格子以前那样,你的G小,更新它。
然后在OpenList找最小F那个格子,移出OpenList,加入CloseList,走到这个格子,打开周围格子,循环下去,直到你哪天一不小心打开了目的地的格子。就停止吧。
最后,从目的地这个格子的指向,一路指向你开始的格子!
A*算法
/// <summary>
/// A*主要类
/// </summary>
public class AStarAlgorithm
{
private List<Point> openList = new List<Point>(); //开启列表
private List<Point> closeList = new List<Point>(); //关闭列表
private byte[,] map; //地图
public AStarAlgorithm(byte[,] map)
{
this.map = map;
}
/// <summary>
/// 计算当前点到下一个点的G值
/// </summary>
/// <param name="tempPoint"></param>
/// <returns></returns>
private int CalcG(Point tempPoint)
{
if (tempPoint.ParentPoint == null) return 0;
//如果横向或者纵向 G+10
if (tempPoint.X == tempPoint.ParentPoint.X || tempPoint.Y == tempPoint.ParentPoint.Y)
return tempPoint.ParentPoint.G + 10;
else //斜角 G+14
return tempPoint.ParentPoint.G + 14;
}
/// <summary>
/// 计算当前点到终点的H值
/// </summary>
/// <param name="tempPoint">当前点</param>
/// <param name="endPoint">终点</param>
/// <returns></returns>
private int CalcH(Point tempPoint, Point endPoint)
{
//两者之间的距离*10
return (Math.Abs(endPoint.Y - tempPoint.Y) + Math.Abs(endPoint.X - tempPoint.X)) * 10;
}
/// <summary>
/// 获取周围的点
/// </summary>
/// <param name="point"></param>
/// <param name="startPoint"></param>
/// <param name="endPoint"></param>
private void SurroundPoints(Point point, Point startPoint,ref Point endPoint)
{
var surroundPoints = new List<Point>(9);
for ( int x = point.X - 1; x <= point.X + 1; x++)
{
for (int y = point.Y - 1; y <= point.Y + 1; y++)
{
//排除超过边界和关闭自身的点
if ((x >= 0 && x < map.GetLength(0) && y >= 0 && y < map.GetLength(1)) && !(x == point.X && y == point.Y))
{
//排除障碍点和关闭列表中的点
if (map[x, y] != 0 && !closeList.ExistPoint(x, y))
{
//在开启列表中 求得该点和当前点的G值,和当前点保存点的G值比较
if (openList.ExistPoint(x, y))
{
Point p = openList.GetPoint(x, y);
int g = 0;
//g = point.G + (point.X == p.X || point.Y == p.Y ? 10 : 14);
g = point.X == p.X || point.Y == p.Y ? 10 : 14;
if (g < point.G)
{
openList.Remove(p);
p.ParentPoint = point;
p.G = g;
openList.Add(p);
}
}
else
{
//不在开启列表中
Point p = new Point();
p.X = x;
p.Y = y;
p.ParentPoint = point;
p.G = CalcG(point);
p.H = CalcH(startPoint,endPoint);
openList.Add(p);
}
}
}
}
}
}
/// <summary>
/// 查找路径
/// </summary>
/// <param name="startPoint">起点</param>
/// <param name="endPoint">终点</param>
/// <returns></returns>
public List<Point> FindPath(Point startPoint,Point endPoint)
{
List<Point> result = new List<Point>();
openList.Add(startPoint);
while (!(openList.ExistPoint(endPoint.X, endPoint.Y) || openList.Count == 0))
{
Point point = openList.MinPoint();
if (point == null) return null;
openList.Remove(point);
closeList.Add(point);
SurroundPoints(point, startPoint,ref endPoint);
}
Point p = openList.GetPoint(endPoint.X, endPoint.Y);
while (p.ParentPoint != null)
{
result.Add(p);
p = p.ParentPoint;
}
return result;
}
}
帮助类
/// <summary>
/// List<Point>的帮助类
/// </summary>
public static class ListHelper
{
public static bool ExistPoint(this List<Point> points, int x, int y)
{
foreach (var item in points)
{
if (x == item.X && y == item.Y)
return true;
}
return false;
}
public static void AddPoint(this List<Point> points,int x,int y)
{
Point point = new Point(x, y);
points.Add(point);
}
public static Point GetPoint(this List<Point> points, int x, int y)
{
foreach (var item in points)
{
if (x == item.X && y == item.Y)
return item;
}
return null;
}
public static Point MinPoint(this List<Point> points)
{
Point point = null;
foreach (var item in points)
{
if (point == null || point.G + point.H > item.G + item.H)
point = item;
}
return point;
}
}
public class Point
{
public int X { get; set; }
public int Y { get; set; }
public int G { get; set; }
public int H { get; set; }
public Point ParentPoint { get; set; }
public Point()
{
}
public Point(int x,int y)
{
this.X = x;
this.Y = y;
}
public Point(int x,int y,int g,int h,Point point)
{
this.X = x;
this.Y = y;
this.G = g;
this.H = h;
this.ParentPoint = point;
}
public int CalcF()
{
return this.G + this.H;
}
}
源码优快云下载(需2积分):https://download.youkuaiyun.com/download/sun_zeliang/10881332
源码百度云(不需要积分):https://pan.baidu.com/s/1hyMVYsmP5xNXd5GQBFFlOQ 提取码:ifi9