A*算法C#实现(界面是WinForm)

原文地址:https://blog.csdn.net/Isaac320/article/details/69400096

 源码CSDN下载(需2积分):https://download.csdn.net/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;
        }
    }

 

 源码CSDN下载(需2积分):https://download.csdn.net/download/sun_zeliang/10881332

 源码百度云(不需要积分):https://pan.baidu.com/s/1hyMVYsmP5xNXd5GQBFFlOQ   提取码:ifi9 

此为用C#写的A*算法源代码 using System; using System.Collections.Generic; using System.Text; using System.Drawing; namespace EtSoft.AStarLib { public class AStar { private StarNodeCollection openList = new StarNodeCollection(); private StarNodeCollection closeList = new StarNodeCollection(); public StarNode currentNode = null; #region 构造函数 /// <summary> /// 使用指定的地图对象、起点和终点初始化A算法 /// </summary> /// <param name="map">地图对象</param> public AStar(Map map) { this.map = map; } /// <summary> /// /// </summary> /// <param name="map">地图对象</param> /// <param name="start">起点坐标</param> /// <param name="end">终点坐标</param> public AStar(Map map, Point start, Point end) : this(map) { this.start = new StarNode(start); this.end = new StarNode(end); openList.Add(new StarNode(start)); //AddStartNodeToOpenList(this.start); } /// <summary> /// /// </summary> /// <param name="map">地图对象</param> /// <param name="startX">起点X坐标</param> /// <param name="startY">起点Y坐标</param> /// <param name="endX">终点X坐标</param> /// <param name="endY">终点Y坐标</param> public AStar(Map map, int startX, int startY, int endX, int endY) : this(map, new Point(startX, startY), new Point(endX, endY)) { } #endregion #region 属性 protected Map map; /// <summary> /// 地图数据 /// </summary> public Map Map { get { return map; } set { map = value; } } private StarNode start = null; /// <summary> /// 起点坐标,如果没有设置起点,返回null /// </summary> public StarNode Start { get { return start; } set { start = value; openList.Clear(); openList.Add(start); //AddNodeToOpenList(start); } } private StarNode end = null; /// <summary> /// 终点坐标,如果没有设置终点,返回null /// </summary> public StarNode End { get { return end; } set { end = value; } } private StarNodeCollection path; /// <summary> /// 返回路径节点集合,没有路径则返回null /// </summary> public StarNodeCollection Path { get { return path; } } private bool allDirection = false; /// <summary> /// true,允许八方向寻路 /// </summary> public bool AllDirection { get { return allDirection; } set { allDirection = value; } } #endregion /// <summary> /// 开始寻路 /// </summary> public void StartSearchPath() { if (start == null) throw new InvalidNodeException(InvalidNodeTypes.NoStart); if (end == null) throw new InvalidNodeException(InvalidNodeTypes.NoEnd); path = null; openList.Clear(); closeList.Clear(); currentNode = start; SearchPath(currentNode); } //寻路递归,受保护的虚方法,允许在子类重写寻路算法 protected virtual void SearchPath(StarNode starNode) { //currentNode = starNode; openList.Remove(starNode); closeList.Add(starNode); AddNodeToOpenList(); if (closeList.Contains(end)) { //如果终点在关闭列表中,找到路径 StarNode node=starNode.Parent; path = new StarNodeCollection(); do { path.Add(node); node = node.Parent; } while (node != null && !node.Equals(start)); path.Reverse(); return; } else if (openList.Count == 0) { //终点不在关闭列表,开放列表已空,没有可通行的路径 return; } currentNode = GetNextNode(); //迭代过程 SearchPath(currentNode); } /// <summary> /// 获得当前节点的下一个最佳节点 /// </summary> /// <returns></returns> public StarNode GetNextNode() { openList.SortByF(); return openList[0]; } /// <summary> /// 把当前点周围可通过的点加入到开放列表中 /// </summary>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值