⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 astarpathfinder.cs

📁 两种AstarPathFinder 一种DijkstraPathfinder BFS
💻 CS
📖 第 1 页 / 共 2 页
字号:
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace PathFinder
{
    class AstarPathFinder:PathFinder
    {
        private int[,] areaMark;
        private static Point[] moves = new Point[] { new Point(0, 1), new Point(1, 0), new Point(0, -1), new Point(-1, 0) };
        //       下              右              上                  左
        private byte[,] parents;
        private int[,] whichList;
        int openMark, closeMark;

        //private int[,] openArrayID;
        private int[,] cost;
        private int[] openHeap;
        private Point[] openArray;
        private int[] gCost;
        private int[] fCost;
        private int[,] openPointToHeapID;
        private Map currentMap;

        int numberOfOpenListItems;
        int openID;
        double hValue;

        public double HValue
        {
            get { return hValue; }
            set { hValue = value; }
        }


        public AstarPathFinder(Map myMap)
        {
            currentMap = myMap;
            cost = new int[myMap.Width, myMap.Height];
            areaMark = new int[myMap.Width, myMap.Height];       //标记区域,用来预判能否到达目标
            parents = new byte[myMap.Width, myMap.Height];      //父结点方向
            whichList = new int[myMap.Width, myMap.Height];    //标记在哪个队列
            openMark = 1; closeMark = 2;                //队列标志,每次寻路之前更新
            //openArrayID = new int[Map.width, Map.height];    //标记在OPEN队列里的编号,位置映射到编号,方便更新OPEN队列中的结点

            openPointToHeapID = new int[myMap.Width, myMap.Height];         //位置映射到在堆中的ID,区别于openArrayID
            HValue = 1;
            openHeap = new int[myMap.Width * myMap.Height];    //二叉堆的open队列,只存在openArray中的下标
            openArray = new Point[myMap.Width * myMap.Height + 1];    //open队列中存的结点,编号映射到位置
            gCost = new int[myMap.Width * myMap.Height + 1];    //open队列的当前实际代价
            fCost = new int[myMap.Width * myMap.Height + 1];    //open队列的估计代价
            numberOfOpenListItems = 0;                      //二叉堆的大小,从1开始计数,每次寻路之前归零
            openID = 0;                                     //编号,每次寻路之前归零
            iniAreaMark();
        }

        public void iniAreaMark()
        {
            int nodeNumber = currentMap.Width * currentMap.Height;
            //Console.WriteLine("nodeNumber is {0}", nodeNumber);
            for (int i = 0; i < currentMap.Width; i++)               //标记,-1表示没走过,0表示在check队列里等待检查
            {
                for (int j = 0; j < currentMap.Height; j++)
                {
                    areaMark[i, j] = -1;
                }
            }

            int checkMark = 1;
            Point currentPoint = new Point(0, 0);
            List<Point> checkList = new List<Point>();


            Point nowCheckPoint = new Point();
            while (nodeNumber > 0)
            {
                if (areaMark[currentPoint.X, currentPoint.Y] > -1)
                {
                    do
                    {
                        if (currentPoint.X == currentMap.Width - 1)
                        {
                            currentPoint.X = 0;
                            currentPoint.Y++;
                        }
                        else
                        {
                            currentPoint.X++;
                        }
                    } while (areaMark[currentPoint.X, currentPoint.Y] > -1);
                }
                //Console.WriteLine(currentPoint);

                checkList.Add(new Point(currentPoint.X, currentPoint.Y));

                while (checkList.Count > 0)
                {
                    nowCheckPoint = checkList[checkList.Count - 1];
                    checkList.RemoveAt(checkList.Count - 1);
                    if (currentMap.map[nowCheckPoint.X, nowCheckPoint.Y] > 3)
                    {
                        areaMark[nowCheckPoint.X, nowCheckPoint.Y] = int.MaxValue;
                    }
                    else
                    {
                        areaMark[nowCheckPoint.X, nowCheckPoint.Y] = checkMark;
                        for (int i = 0; i < moves.Length; i++)
                        {
                            Point nextCheckPoint = new Point(nowCheckPoint.X + moves[i].X, nowCheckPoint.Y + moves[i].Y);
                            if (currentMap.isIn(nextCheckPoint) && (areaMark[nextCheckPoint.X, nextCheckPoint.Y] < 0))
                            {
                                checkList.Add(nextCheckPoint);
                                areaMark[nextCheckPoint.X, nextCheckPoint.Y] = 0;
                                //Console.WriteLine(new Point(nowCheckPoint.X + moves[i].X, nowCheckPoint.Y + moves[i].Y));
                            }
                        }
                    }
                    nodeNumber--;
                }

                //Console.WriteLine("nodeNumber is {0}", nodeNumber);

                checkMark++;
            }

            //for (int i = 0; i < Map.width; i++)
            //{
            //    for (int j = 0; j < Map.height; j++)
            //    {
            //        if (areaMark[j, i] == int.MaxValue)
            //        {
            //            Console.Write(" .");
            //        }
            //        else
            //        {
            //            Console.Write(" " + areaMark[j, i]);
            //        }
            //    }
            //    Console.WriteLine();
            //}
        }

        private void heapSwap(int p, int q)
        {
            openPointToHeapID[openArray[openHeap[p]].X, openArray[openHeap[p]].Y] = q;
            openPointToHeapID[openArray[openHeap[q]].X, openArray[openHeap[q]].Y] = p;
            int temp = openHeap[p];
            openHeap[p] = openHeap[q];
            openHeap[q] = temp;

            //totalSwapNumber++;
        }

        private int getHCost(Point currentPoint, Point to)
        {
            // return Convert.ToInt32(Math.Floor(Math.Abs(currentPoint.X - to.X) + Math.Abs(currentPoint.Y - to.Y) * 2.1)) ;
            return Convert.ToInt32(Math.Abs(currentPoint.X - to.X) + Math.Abs(currentPoint.Y - to.Y) * HValue);
        }

        /// <summary>
        /// 插入OPEN队列的二叉树,为其分配OPEN队列的编号唯一标记,二叉树中只存编号,用数组存下各项代价
        /// </summary>
        /// <param name="currentPoint"></param>
        /// <param name="to"></param>
        /// <param name="currentGCost"></param>
        private void insertOpenHeap(Point currentPoint, Point to, int currentGCost)
        {
            whichList[currentPoint.X, currentPoint.Y] = openMark;   //标记进入OPEN队列
            openID++;                            //分配编号
            //openArrayID[currentPoint.X, currentPoint.Y] = openID;       //位置映射到编号

            numberOfOpenListItems++;                //加入堆
            openArray[openID] = currentPoint;        //加入OPEN队列
            openPointToHeapID[currentPoint.X, currentPoint.Y] = numberOfOpenListItems;
            gCost[openID] = currentGCost;        //求实际值
            fCost[openID] = currentGCost + getHCost(currentPoint, to);    //求估价后的值

            openHeap[numberOfOpenListItems] = openID;        //插入二叉堆
            int m = numberOfOpenListItems;                                  //排序
            while (m != 1)
            {
                if (fCost[openHeap[m]] <= fCost[openHeap[m >> 1]])
                {
                    heapSwap(m, m >> 1);
                    m = m >> 1;
                }
                else break;
            }

            //heapDepth = Math.Max(heapDepth, numberOfOpenListItems);
        }

        private int getMin()                    //返回当前fCost最小的结点的ID,调整二叉堆
        {
            int minPointID = openHeap[1];
            openHeap[1] = openHeap[numberOfOpenListItems];
            numberOfOpenListItems--;

            int m = 1;
            int smallest = 1;
            do
            {
                m = smallest;
                if (((m << 1) <= numberOfOpenListItems) && (fCost[openHeap[smallest]] > fCost[openHeap[m << 1]]))
                {
                    smallest = (m << 1);
                }
                if (((m << 1) + 1 <= numberOfOpenListItems) && (fCost[openHeap[smallest]] > fCost[openHeap[(m << 1) + 1]]))
                {
                    smallest = (m << 1) + 1;
                }
                if (m != smallest)
                {
                    heapSwap(m, smallest);
                }
            } while (m != smallest);


            return minPointID;

        }

        /// <summary>
        /// 更新OPEN队列中ID为changePointID的结点的G, F, Parent,调整二叉堆
        /// </summary>
        /// <param name="changePointID"></param>
        /// <param name="changePointGCost"></param>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -