A*算法理解(unity C#)

最近发现A*算法忘的一干二净啊,记忆是个好东西,可惜吾没有啊,只能整理一篇文章以备日后翻看
这里只谈A*算法的实现,不谈A算法的优化*
这里的工程是unity版本的,当然理解A*算法是通用的

这里先放上A*算法的unity工程(unity2017.3.1) unity工程(github)

0X01 A*算法基本概念

启发式搜索: 启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,得到最好的位置,再从这个位置进行搜索直到目标。这样可以省略大量无畏的搜索路径,提到了效率。在启发式搜索中,对位置的估价是十分重要的。采用了不同的估价可以有不同的效果。
IDA*算法: 这种算法被称为迭代加深A算法,可以有效的解决A空间增长带来的问题,甚至可以不用到优先级队列。如果要知道详细:google一下。
搜索区域(The Search Area): 图中的搜索区域被划分为了简单的二维数组,数组每个元素对应一个小方格,当然我们也可以将区域等分成是五角星,矩形等,通常将一个单位的中心点称之为搜索区域节点(Node)。  
开放列表(Open List): 我们将路径规划过程中待检测的节点存放于Open List中,而已检测过的格子则存放于Close List中。
关闭列表(Close List): 我们将路径规划过程中已经检查过的节点放在Close List。
启发函数(Heuristics Function)(估价函数): H为启发函数,也被认为是一种试探,由于在找到唯一路径前,我们不确定在前面会出现什么障碍物,因此用了一种计算H的算法,具体根据实际场景决定。在我们简化的模型中,H采用的是传统的曼哈顿距离(Manhattan Distance)估价函数,也就是横纵向走的距离之和。
F(n) = G + H。F代表当前检查点的总花费,G代表起点到当前检查点的花费,H代表当前检查点到终点的预估花费。
父节点(parent): 在路径规划中用于回溯的节点。
A*算法的特点: A*算法在理论上是时间最优的,但是也有缺点:它的空间增长是指数级别的。

0X02 A*算法寻路过程

  1. 将起点A添加到open列表中(A没有计算花费F是因为当前open列表只有这一个节点)。
  2. 检查open列表,选取花费F最小的节点M(检查M如果为终点是则结束寻路,如果open列表没有则寻路失败,直接结束)。
  3. 对于与M相邻的每一节点N:(下面本来没有序号的,csdn markdown的bug)
    • 如果N是阻挡障碍,那么不管它。
    • 如果N在closed列表中,那么不管它。
    • 如果N不在open列表中:添加它然后计算出它的花费F(n)=G+H。
    • 如果N已在open列表中:当我们使用当前生成的路径时,检查F花费是否更小。如果是,更新它的花费F和它的父节点。
  4. 重复2,3步。

0X03 A*算法寻路详细描述

寻路关键代码:

    /// <summary>
    /// 使用A*算法寻路
    /// </summary>
    /// <param name="start"></param>
    /// <param name="end"></param>
    void FindPath(Vector2 start,Vector2 end)
    {
        //和A*算法无关,只是为了显示使用
        int showFindNum=1;

        //开启列表
        List<Cell> openLs = new List<Cell>();
        //关闭列表
        List<Cell> closeLs = new List<Cell>();

        //起点
        Cell startCell = grid.GetCell(start);
        //终点
        Cell endCell = grid.GetCell(end);
        Debug.LogFormat("寻路开始,start({0}),end({1})!",start,end);

        //将起点作为待处理的点放入开启列表,
        openLs.Add(startCell);

        //如果开启列表没有待处理点表示寻路失败,此路不通
        while(openLs.Count>0)
        {
            //遍历开启列表,找到消费最小的点作为检查点
            Cell cur = openLs[0];
            for (int i = 0; i < openLs.Count; i++)
            {
                if(openLs[i].fCost<cur.fCost&&openLs[i].hCost<cur.hCost)
                {
                    cur = openLs[i];
                }
            }
            Debug.Log("当前检查点:" + cur.ToString()+" 编号:"+showFindNum+"  open列表节点数量:"+openLs.Count);
            //显示在界面,和A*算法无关
            cur.obj.transform.Find("Num").GetComponent<Text>().text=showFindNum.ToString();
            showFindNum++;

            //从开启列表中删除检查点,把它加入到一个“关闭列表”,列表中保存所有不需要再次检查的方格。
            openLs.Remove(cur);
            closeLs.Add(cur);

            //检查是否找到终点
            if(cur==endCell)
            {
                Debug.Log("寻路结束!");
                grid.CreatePath(cur);
                return;
            }

            //根据检查点来找到周围可行走的点
            //1.如果是墙或者在关闭列表中则跳过
            //2.如果点不在开启列表中则添加
            //3.如果点在开启列表中且当前的总花费比之前的总花费小,则更新该点信息
            List<Cell> aroundCells = GetAllAroundCells(cur);
            foreach (var cell in aroundCells)
            {
                
                if (cell.isWall || closeLs.Contains(cell))
                    continue;

                int cost= cur.gCost+ GetDistanceCost(cell, cur);

                if(cost<cell.gCost||!openLs.Contains(cell))
                {
                    cell.gCost = cost;
                    cell.hCost = GetDistanceCost(cell,endCell);
                    cell.parent = cur;
                    Debug.Log("cell:" + cell.ToString() + "  parent:" + cur.ToString() + "  " + cell.PrintCost());
                    if(!openLs.Contains(cell))
                    {
                        openLs.Add(cell);
                    }

                    //显示在界面,和A*算法无关
                    cell.obj.transform.Find("Cost").GetComponent<Text>().text = cell.fCost.ToString();
                }


            }

        }

        Debug.Log("寻路失败!");
    }

根据上面的工程得到这个图:
在这里插入图片描述
圆点说明:黑色是障碍物体,红色是起点,绿色是终点,浅紫色是寻路路径
红色数字:总花费F
蓝色数字:寻路的过程描述

过程描述:

  • 将起点(3,6)放到open列表中。

  • 选择open列表中花费最小的点M(3,6),将M从open中移除,添加到closed列表中,后面检查时不再检查该点。

  • 计算(3,6)相邻的点,一共8个点,并且分别计算花费F(红色数字),都添加到open中
    +在这里插入图片描述

  • 选择open列表中花费最小的点M(4,6),将M从open中移除,添加到closed列表中,后面检查时不再检查该点。

  • 计算(4,6)相邻的点,一共8个点,右侧是障碍物,其它5个点都在open中,分别计算当前路径花费和原来对比,都大,所以没有更新花费和父节点

  • 选择open列表中花费最小的点M(4,5),将M从open中移除,添加到closed列表中,后面检查时不再检查该点。

  • 计算M相邻的点,在下面有三个新节点添加open中,其它五个点要么是障碍要么是已经在open中且花费比原来大,
    在这里插入图片描述

  • 选择open列表中花费最小的点M(4,7),将M从open中移除,添加到closed列表中,后面检查时不再检查该点。

  • 计算M相邻的点,在上面有三个新节点添加open中,其它五个点要么是障碍要么是已经在open中且花费比原来大,
    在这里插入图片描述

  • 选择open列表中花费最小的点M(3,5),将M从open中移除,添加到closed列表中,后面检查时不再检查该点。

  • 计算M相邻的点,在左下有一个新节点添加open中,在正下面有一个点(3,4)的花费比原来小,更新该节点信息,其它的点已经在open中且花费比原来大,
    在这里插入图片描述

  • 选择open列表中花费最小的点M(3,7),将M从open中移除,添加到closed列表中,后面检查时不再检查该点。

  • 计算M相邻的点,在左下有一个新节点添加open中,在正下面有一个点(3,8)的花费比原来小,更新该节点信息,其它的点已经在open中且花费比原来大,
    在这里插入图片描述

  • 选择open列表中花费最小的点M(5,4),将M从open中移除,添加到closed列表中,后面检查时不再检查该点。

  • 计算M相邻的点,有五个新节点添加open中,其它三个点要么是障碍要么是已经在open中且花费比原来大,
    在这里插入图片描述

  • 选择open列表中花费最小的点M(5,8),将M从open中移除,添加到closed列表中,后面检查时不再检查该点。

  • 计算M相邻的点,有五个新节点添加open中,其它三个点要么是障碍要么是已经在open中且花费比原来大,
    在这里插入图片描述

  • 选择open列表中花费最小的点M(6,5),将M从open中移除,添加到closed列表中,后面检查时不再检查该点。

  • 计算M相邻的点,有四个新节点添加open中,其它四个点要么是障碍要么是已经在open中且花费比原来大或者相等,
    在这里插入图片描述

  • 选择open列表中花费最小的点M(6,7),将M从open中移除,添加到closed列表中,后面检查时不再检查该点。

  • 计算M相邻的点,有两个新节点添加open中,其它六个点要么是障碍要么是已经在open中且花费比原来大或者相等,
    在这里插入图片描述

  • 选择open列表中花费最小的点M(7,6),将M从open中移除,添加到closed列表中,和终点对比相等,寻路结束。
    在这里插入图片描述

根据当前代码寻路有个情况就是寻路到终点前临近终点时,可以提前一步结束,这里没有结束,是为了方便演示

参考文章:
A算法完全理解
堪称最好最全的A算法详解(译文)
A星寻路算法介绍
这里的unity工程是参考一篇文章的,是两年前的文章,没有找到,就不放参考链接了

【为什么学习数据挖掘】       人工智能、大数据时代有什么技能是可以运用在各种行业的?数据分析就是。       从海量数据中获得别人看不见的信息,创业者可以通过数据分析来优化产品,营销人员可以通过数据分析改进营销策略,产品经理可以通过数据分析洞察用户习惯,金融从业者可以通过数据分析规避投资风险,程序员可以通过数据分析进一步挖掘出数据价值,它和编程一样,本质上也是一个工具,通过数据来对现实事物进行分析和识别的能力。不管你从事什么行业,掌握了数据分析能力,往往在其岗位上更有竞争力。 【超实用的课程内容】      本课程为Python数据挖掘方向的入门课程,课程主要以真实数据为基础,详细介绍数据挖掘入门的流程和使用Python实现pandas与numpy在数据挖掘方向的运用,并深入学习如何运用scikit-learn调用常用的数据挖掘算法解决数据挖掘问题,为进一步深入学习数据挖掘打下扎实的基础。 本课程分为三大部分: 基础知识篇:主要讲解数据挖掘这项技能的基本工作流程和介绍和入门必须的基本技能Python语言的入门,带领大家了解数据挖掘常见操作和基础知识。 数据采集篇:学习如何解决数据挖掘的数据来源问题,读取各类型不同的数据包括CSV,excel,MySQL进行数据采集的交互。 数据探索篇:本篇主要解决数据的预处理保证数据的质量并用常见数据挖掘算法进行特征提取,分析数据背后隐含的信息。 【报名须知】 课程采取录播模式,课程永久有效,可无限次观看 课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化 【如何开始学习?】 PC端:报名成功后可以直接进入课程学习 移动端:下载CSDN学院或CSDN
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页