A*算法的C#实现

目录

1,概述

2,A *算法的基本原理

3,A *算法的实现步骤

4,A *算法的C#实现

5,测试


 

1,概述

        本文的主要内容是讲述A *寻路算法的基本原理,实现步骤以及对应的C#代码,适合读者用于学习A *算法或

使用此代码提供的接口完成游戏中的寻路功能。

        详细的A *算法的原理,请参照https://blog.csdn.net/denghecsdn/article/details/78778769

        详细的A *算法的实现,请参照:https://www.cnblogs.com/zhoug2020/p/3468167.html

2,A *算法的基本原理

        A *算法是一种经典的启发式算法,算法的核心是将节点n到目标点的代价定义为f(n)= g(n)+ h(n),其中 g(n)表示出发点到节点ñ的距离,h(n)是一种启发式函数,表示节点ñ到目标点的评估代价,通常为了简化我们采用曼哈顿距离来模拟。知道 f(n)如何计算后,A *算法还有两个重要的集合——open列表和closed列表,open列表用于存储当前可以选择移动的所有节点,closed列表用于存储走过的所有节点。首先,我们将出发点加入open列表中,然后每次从open列表中选择f(n)最小的节点,然后将该节点从open列表中移除,并加入到closed列表中,并将该节点周围没有走过的所有可达节点加入或更新到open列表中,重复选择节点直到目标点在closed列表中为止,再通过存储节点的parent回溯,这样就可以得到两个点之间的一条最短路径。

3,A *算法的实现步骤

①将出发点加入到open列表中。

②从open列表中选择 f(n)最小的节点k,将节点k从open列表中移除,并将其加入到closed列表中。

③对于节点ķ周围距离为1的每个可达节点t,执行以下操作:

        a.如果t在closed列表中,丢弃这个节点;

        b.如果t不在open列表中,将其加入open列表中;

        c.如果t在open列表中,计算其f(n)并和open列表中该节点的f(n)的对比,如果它的f(n)更小,则更新open列表中该节点的信息。

④重复②③直到目标点在closed列表中(表明求得最短路径)或open列表为空(表明终点不可达)。

4,A *算法的C#实现

文件名:

AStar.cs

算法执行接口:

AStar.Instance.Execute(int [,] map,int srcX,int srcY,int distX,int distY,int reachableVal = 0,bool allowDiagonal = false);

输出路径接口:

AStar.Instance.DisplayPath(ANode aNode);

完整代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

/******************************************************************************** 
** auth:    FengLinyi
** date:    2018/09/01
** desc:    A*算法的实现
** Ver.:     V1.0.0
*********************************************************************************/

namespace DeepCSharp
{
    class AStar
    {
        /// <summary>
        /// 二维坐标点
        /// </summary>
        public struct Point
        {
            public int x, y;
            public Point(int _x, int _y)
            {
                x = _x;
                y = _y;
            }
        }
        /// <summary>
        /// A*的每个节点
        /// </summary>
        public class ANode
        {
            public Point point;
            public ANode parent;
            public int fn, gn, hn;
        }
        private AStar() { }
        public static AStar Instance { get; } = new AStar();
        private int[,] map = null;
        private Dictionary<Point, ANode> openList = null;
        private HashSet<Point> closedList = null;
        private Point dist;
        private int reachableVal;

        /// <summary>
        /// 执行算法
        /// </summary>
        /// <param name="map">二维网格地图,边缘需要用不可达的值填充</param>
        /// <param name="srcX">当前点X坐标</param>
        /// <param name="srcY">当前点Y坐标</param>
        /// <param name="distX">目标点X坐标</param>
        /// <param name="distY">目标点Y坐标</param>
        public ANode Execute(int[,] map, int srcX, int srcY, int distX, int distY, int reachableVal = 0, bool allowDiagonal = false)
        {
            openList = new Dictionary<Point, ANode>();
            closedList = new HashSet<Point>();
            this.map = map;
            this.dist = new Point(distX, distY);
            this.reachableVal = reachableVal;
            //将初始节点加入到open列表中
            ANode aNode = new ANode();
            aNode.point = new Point(srcX, srcY);
            aNode.parent = null;
            aNode.gn = 0;
            aNode.hn = ManHattan(aNode.point, dist);
            aNode.fn = aNode.gn + aNode.hn;
            openList.Add(aNode.point, aNode);

            while (openList.Count > 0)
            {
                //从open列表中找到f(n)最小的结点
                ANode minFn = FindMinFn(openList);
                Point point = minFn.point;
                //判断是否到达终点
                if (point.x == dist.x && point.y == dist.y) return minFn;
                //去除minFn,加入到closed列表中
                openList.Remove(minFn.point);
                closedList.Add(minFn.point);
                //将minFn周围的节点加入到open列表中
                AddToOpenList(new Point(point.x - 1, point.y), minFn); //左
                AddToOpenList(new Point(point.x + 1, point.y), minFn); //右
                AddToOpenList(new Point(point.x, point.y - 1), minFn); //上
                AddToOpenList(new Point(point.x, point.y + 1), minFn); //下
                if(allowDiagonal)
                {
                    AddToOpenList(new Point(point.x - 1, point.y - 1), minFn); //左上
                    AddToOpenList(new Point(point.x + 1, point.y - 1), minFn); //右上
                    AddToOpenList(new Point(point.x - 1, point.y + 1), minFn); //左下
                    AddToOpenList(new Point(point.x + 1, point.y + 1), minFn); //右下
                }
            }
            return null;
        }

        /// <summary>
        /// 输出最短路径
        /// </summary>
        /// <param name="aNode"></param>
        public void DisplayPath(ANode aNode)
        {
            while(aNode != null)
            {
                Console.WriteLine(aNode.point.x + "," + aNode.point.y);
                aNode = aNode.parent;
            }
        }

        /// <summary>
        /// 判断节点是否可达,可达则将节点加入到open列表中
        /// </summary>
        /// <param name="a"></param>
        /// <param name="parent"></param>
        private void AddToOpenList(Point point, ANode parent)
        {
            if(IsReachable(point) && !closedList.Contains(point))
            {
                ANode aNode = new ANode();
                aNode.point = point;
                aNode.parent = parent;
                aNode.gn = parent.gn + 1;
                aNode.hn = ManHattan(point, dist);
                aNode.fn = aNode.gn + aNode.hn;
                if (openList.ContainsKey(aNode.point))
                {
                    if (aNode.fn < openList[aNode.point].fn)
                    {
                        openList[aNode.point] = aNode;
                    }
                }
                else
                    openList.Add(aNode.point, aNode);
            }
        }

        /// <summary>
        /// 判定该点是否可达
        /// </summary>
        /// <param name="a"></param>
        /// <returns></returns>
        private bool IsReachable(Point a)
        {
            return map[a.y, a.x] == this.reachableVal;
        }

        /// <summary>
        /// 计算两个点之间的曼哈顿距离
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        private int ManHattan(Point a, Point b)
        {
            return Math.Abs(a.x - b.x) + Math.Abs(a.y - b.y);
        }

        /// <summary>
        /// 从open列表中获取最小f(n)的节点
        /// </summary>
        /// <param name="aNodes"></param>
        /// <returns></returns>
        private ANode FindMinFn(Dictionary<Point, ANode> aNodes)
        {
            ANode minANode = null;
            foreach(var e in aNodes)
            {
                if(minANode == null || e.Value.fn < minANode.fn)
                {
                    minANode = e.Value;
                }
            }
            return minANode;
        }
    }
}

5,测试

主函数中的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DeepCSharp
{
    class Program
    {
        static void Main(string[] args)
        {
            int[,] map =
            {
                {1,1,1,1,1,1,1,1 },
                {1,0,0,0,1,1,1,1 },
                {1,1,1,0,1,1,1,1 },
                {1,1,0,0,1,0,0,1 },
                {1,1,0,0,0,0,0,1 },
                {1,1,1,1,1,1,1,1 },
            };
            var node = AStar.Instance.Execute(map, 1, 1, 6, 4);
            AStar.Instance.DisplayPath(node);
        }
    }
}

测试结果:

  • 5
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 非常感谢您的问题,C 语言是一种通用的、面向过程的计算机编程语言,它由计算机科学家美国计算机科学家贝尔·约翰逊(Bell Johnson)和美国计算机科学家丹尼斯·里奇(Dennis Ritchie)开发,并以1969年发布的“编译程序设计语言”(CPL)为基础。它是一种可移植的语言,可以用于多种不同的硬件平台和操作系统,并且功能强大。 ### 回答2: C语言是一种通用的高级编程语言,广泛应用于嵌入式系统、操作系统和应用程序的开发中。它具有简洁、高效、可移植等特点,适合用于开发一些对性能要求较高的应用。 与其他高级语言相比,C语言的语法较为简单,便于学习和理解。它提供了丰富的基本数据类型和运算符,可以方便地进行各种数学计算和逻辑操作。同时,C语言还提供了强大的控制结构,如条件语句、循环结构和函数,使得程序的编写更加灵活和高效。 C语言的可移植性也是它的一个重要特点。通过使用标准库和标准头文件,可以实现对不同平台上的应用程序的开发。而且C语言的编译器也非常丰富,可以运行在各种操作系统上,如Windows、Linux、Mac OS等。 在嵌入式系统和操作系统的开发中,C语言是首选的开发语言。由于它具有较低的层次感和较高的执行效率,可以更好地控制底层硬件和操作系统资源。此外,C语言还提供了指针操作和内存管理功能,可以更好地处理底层系统的内存布局和访问问题。 总之,C语言作为一种通用的高级编程语言,具有简洁、高效、可移植等优点,适用于各种开发场景。无论是开发嵌入式系统、操作系统还是应用程序,都可以选择C语言作为开发语言,以实现高效、可靠的程序编写。 ### 回答3: 语言编程的好处和挑战。 使用C语言进行编程有许多好处。首先,C语言是一种通用的编程语言,广泛应用于系统开发、嵌入式系统、游戏开发等领域。其简单而高效的语法使得编写代码更加容易,C语言也具备了底层的硬件和内存控制能力,使得程序开发者可以更好地控制程序的性能和效率。此外,C语言具备了丰富的标准库和函数,方便程序员利用已有的资源进行开发。 然而,使用C语言进行编程也面临一些挑战。首先,C语言是一种底层的编程语言,需要程序员对计算机底层的原理和机器语言有一定的了解。这对于一些新手来说可能会造成困扰。其次,C语言的代码相对较长,需要较多的代码行数来完成一些任务。这增加了程序的复杂性和容错难度。此外,由于C语言没有自动内存管理的机制,程序员需要手动管理内存的分配和释放,这可能导致内存泄漏和崩溃等问题。 在总体来说,使用C语言进行编程具有许多优点和挑战。对于有一定编程基础的开发者来说,C语言是一个强大的工具,可以实现高性能的程序。然而,对于新手和初学者来说,可能需要一些时间和经验来适应C语言的语法和特点。总之,C语言作为一种经典的编程语言,在编程领域仍然具有重要的地位。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值