c#实现迷宫寻路算法

一、解决问题:

在Unity3d的一些2d游戏制作上,有时需要敌人在众多箱子(障碍物)中向主角移动,如果是简单的移动ai代码实现,敌人有可能陷入死胡同然后左右移动,卡死在胡同上,为了一个智能的ai实现,比较常用的是A*算法,但这里为了简便,我们使用了深度搜索的方式进行判断。所谓深度搜索,一位博主总结得很好,就是“不见棺材不回头。算法会朝一个方向进发,直到遇到边界或者障碍物,才回溯。一般在实现的时候,我们采用递归的方式来进行,也可以采用模拟压栈的方式来实现。

在这里的代码中,是利用c#的栈,保存了名为Cell的宫格类,Cell类中包含了周围四个方向是否有路的信息,Maze迷宫类中将对每个能走的方向都进行尝试行走,将能走的路一直走下去,直到走不通为止,此时开始回溯,即使用stack.Pop(),一直退回分支,走下一条路线。举个例子:当前宫格的北方向【有路】,那么尝试向北走一步,走完后把设置此宫格的北方向为【无路】,并把走到的那个宫格的南方向设置为【无路】(都是相对的),就这样一直走下去,当发现无法到达终点时,开始退回,再次判断当前宫格的四个方向是否有路,直到退回到最后的分支上,进行下一条路的尝试行走。

该算法虽然简单,但却在不少地方都需要用到,比如游戏按键刷图脚本的地图判断的处理部分:例如找色判断dnf、手游《永远的7日之都》的万神殿地图部分,只要能直到当前揭示的地图,就可以算出一条通向boss的道路,然后自动刷图就完成了一个核心功能。


二、演示效果:

控制台程序代码Program.cs中输入:

 int[,] maps = new int[,] {
                { 0, 0, 0, 0, 0 },
                { 1, 0, 0, 1, 1 },
                { 0, 0, 0, 1, 0 },
                { 0, 1, 1, 1, 1 },

                { 0, 0, 0, 0, 0 } };

注释:0代表可通过,1代表不可通过。

运行程序,输出如下:

2 2 2 0 0
1 2 2 1 1
2 2 2 1 0
2 1 1 1 1
2 2 2 2 2

注释:2代表为走出的路径

三、上代码:


创建控制台程序:

Program.cs:

using System;

namespace MazePath
{
    class Program
    {
        static void Main(string[] args)
        {
            //0表示可走,1表示不可走
            int[,] maps = new int[,] {
                { 0, 0, 0, 0, 0 },
                { 1, 0, 0, 1, 1 },
                { 0, 0, 0, 1, 0 },
                { 0, 1, 1, 1, 1 },
                { 0, 0, 0, 0, 0 } };


            Maze maze = new Maze(maps);           
            Console.ReadLine();
        }
    }
}

Maze.cs:

using System;
using System.Collections.Generic;


namespace MazePath
{
    class Maze
    {
        Cell[,] cells;
        Stack<Cell> cellStack = new Stack<Cell>();
        int[,] maps;
        int rows;
        int length;

        public Maze(int[,] maps)
        {
            this.maps = maps;
            length = maps.GetLength(1);
            rows = maps.GetLength(0);
            cells = new Cell[rows, length];
            InitCells();
            GetValidPath();
            ConsoleResult();
        }

        public void InitCells()
        {
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < length; j++)
                {
                    //设置每个格子自身的位置属性
                    Cell cell = new Cell();
                    cell.SetPos(i, j);

                    cells[i, j] = cell;

                    //-----设置格子的周围方向属性---------------
                    //西
                    if ((j - 1) >= 0)
                    {
                        if (maps[i, j - 1] == 0)
                            cells[i, j].SetDirection(Const.WEST, Const.ENABLE);
                        else
                            cells[i, j].SetDirection(Const.WEST, Const.DISABLE);
                    }

                    //东
                    if ((j + 1) < length)
                    {
                        if (maps[i, j + 1] == 0)
                            cells[i, j].SetDirection(Const.EAST, Const.ENABLE);
                        else
                            cells[i, j].SetDirection(Const.EAST, Const.DISABLE);
                    }

                    //北
                    if ((i - 1) >= 0)
                    {
                        if (maps[i - 1, j] == 0)
                            cells[i, j].SetDirection(Const.NORTH, Const.ENABLE);
                        else
                            cells[i, j].SetDirection(Const.NORTH, Const.DISABLE);
                    }

                    //南
                    if ((i + 1) < rows)
                    {
                        if (maps[i + 1, j] == 0)
                            cells[i, j].SetDirection(Const.SOUTH, Const.ENABLE);
                        else
                            cells[i, j].SetDirection(Const.SOUTH, Const.DISABLE);
                    }

                }
            }
        }

        public void GetValidPath()
        {
            int i = 0;int j = 0;
            cellStack.Push(cells[i, j]);
            while (true)
            {
                i = cellStack.Peek().x; j = cellStack.Peek().y;
                if (i == (rows - 1) && j == (length - 1))
                {
                    return;
                }

                //东
                if (cellStack.Peek().GetDirection(Const.EAST)==Const.ENABLE)
                {
                    cells[i, j].SetDirection(Const.EAST, Const.DISABLE);
                    cells[i, j+1].SetDirection(Const.WEST, Const.DISABLE);
                    cellStack.Push(cells[i, j + 1]);
                    continue;
                }
                //西
                if (cellStack.Peek().GetDirection(Const.WEST) == Const.ENABLE)
                {
                    cells[i, j].SetDirection(Const.WEST, Const.DISABLE);
                    cells[i, j + 1].SetDirection(Const.EAST, Const.DISABLE);
                    cellStack.Push(cells[i, j - 1]);
                    continue;
                }
                //北
                if (cellStack.Peek().GetDirection(Const.NORTH) == Const.ENABLE)
                {
                    cells[i, j].SetDirection(Const.NORTH, Const.DISABLE);
                    cells[i - 1, j].SetDirection(Const.SOUTH, Const.DISABLE);
                    cellStack.Push(cells[i-1, j]);
                    continue;
                }
                //南
                if (cellStack.Peek().GetDirection(Const.SOUTH) == Const.ENABLE)
                {
                    cells[i, j].SetDirection(Const.SOUTH, Const.DISABLE);
                    cells[i + 1, j].SetDirection(Const.NORTH, Const.DISABLE);
                    cellStack.Push(cells[i+1, j]);
                    continue;
                }

                cellStack.Pop();

                if (cellStack.Count == 0)
                {
                    Console.WriteLine("根本没有这个路径");
                    return;
                }
            }
        }

        public void ConsoleResult()
        {
            while (cellStack.Count != 0)
            {
                int i = cellStack.Peek().x;
                int j = cellStack.Peek().y;
                cellStack.Pop();
                maps[i, j] = 2;
            }

            string s = "";
            for(int i = 0; i < maps.GetLength(0); i++)
            {
                for(int j = 0; j < maps.GetLength(1); j++)
                {
                    s += maps[i, j].ToString()+" ";
                }
                s += "\r\n";
            }
            Console.WriteLine(s);
        }
    }
}

Cell.cs:

namespace MazePath
{
    class Cell
    {
        public int x;
        public int y;
        //directon 索引0-3分别是东西南北,默认为0表示不可走,1则表示可走
        private int[] directions = new int[4];

        public void SetPos(int x,int y)
        {
            this.x = x;
            this.y = y;
        }

        public bool IsEnable(int index)
        {
            return directions[index]==1;
        }
        public void SetDirection(int index,int result)
        {
            directions[index] = result;
        }
        public int GetDirection(int index)
        {
            return directions[index];
        }
    }
}

Const.cs:

namespace MazePath
{
    public static class Const
    {
        public const int EAST = 0;   //东
        public const int WEST = 1;   //西
        public const int SOUTH = 2;  //南
        public const int NORTH = 3;  //北

        public const int ENABLE = 1;
        public const int DISABLE = 0;

    }
}

猜你喜欢

转载自blog.csdn.net/qq_36927190/article/details/79533499