C#迷宫的实现(1)



迷宫的基础算法在严蔚敏老师写的数据结构(C语言版)已经描述过了。主要是用栈的特性来保存在迷宫之中走过的路径,走到死胡同后再用栈弹出栈顶,再将指针指到栈顶。这种穷尽的算法有点笨(额  电脑就是这样),貌似也有一些更好的搜索路径,不过现在俺还没接触学习到0 0 ,比如A*算法。记得老师讲过,不过很快就还给老师了。哈哈~~废话少说,现在就是用面向对象的思想来完成走迷宫的这样一个程序。(第一次写,不好勿怪,纯属菜鸟交流~~)

 首先可以认为迷宫分为许多个划分为许多个小格子的有序集合(乱扯的。。。),迷宫就是这些小格子组成的。可以认为它们有坐标,x,y;给一个标记Flag来指示该格子是否已经走过(默认为false);因为迷宫之间还应该有一些不能走的地方,称之为墙,那么在用一个IsWall来标识该格子是否是墙。哦,还应该给这个格子标记上行走的方向(这个方向我想应该做为一个枚举)。下面是代码:

 

  1. <p>    //迷宫中的一个小格子  
  2.     public class MazeElem  
  3.     {  
  4.         //这是方向,初始的方向应该是None~木有方向~  
  5.         public Direction dir = Direction.None;  
  6.         //构造函数  
  7.         public MazeElem(int x,int y,bool isWall)  
  8.         {  
  9.             _x=x;  
  10.             _y=y;  
  11.             _isWall=isWall;  
  12.         }</p><p>        private int _x;  
  13.         private int _y;</p><p>        //flag的默认值应该是false,假定所有的格子都没有走过  
  14.         private bool _flag=false;  
  15.         private bool _isWall;  
  16.         //X坐标,作为属性了  
  17.         public int X  
  18.         {  
  19.             get { return _x; }  
  20.             set { _x = value; }  
  21.         }  
  22.         //Y坐标,也成属性了0 0  
  23.         public int Y  
  24.         {  
  25.             get { return _y; }  
  26.             set { _y = value; }  
  27.         }  
  28.         //是否墙  
  29.         public bool IsWall  
  30.         {  
  31.             get{return _isWall;}  
  32.             set{_isWall=value;}  
  33.         }  
  34.         //是否走过  
  35.         public bool Flag  
  36.         {  
  37.             get { return _flag; }  
  38.             set { _flag = value; }  
  39.         }  
  40.     }</p>   

    //迷宫中的一个小格子     public class MazeElem     {         //这是方向,初始的方向应该是None~木有方向~         public Direction dir = Direction.None;         //构造函数         public MazeElem(int x,int y,bool isWall)         {             _x=x;             _y=y;             _isWall=isWall;         }

        private int _x;         private int _y;

//flag的默认值应该是false,假定所有的格子都没有走过         private bool _flag=false;         private bool _isWall;         //X坐标,作为属性了         public int X         {             get { return _x; }             set { _x = value; }         }         //Y坐标,也成属性了0 0         public int Y         {             get { return _y; }             set { _y = value; }         }         //是否墙         public bool IsWall         {             get{return _isWall;}             set{_isWall=value;}         }         //是否走过         public bool Flag         {             get { return _flag; }             set { _flag = value; }         }     }

 好了,格子类写好了。应该挺容易理解的把。这些都是基础,俺只是想打一下自己的基础~我们再写一个方向的枚举。一个格子的方向很容易想到:东西南北对应(右左下上),除了这些,还应该有这两个:一个是初始的方向,(一开始方向的初始值我想设置为null的,结果报错了。。。。切记。。枚举是值类型。。)还有当这个格子各个方面都无路可走的时候(人若如此只能感叹悲催...),我以为要做一个标记,那就设置NoDir。

  1. //方向枚举  
  2. public enum Direction  
  3. {   
  4.     /// <summary>  
  5.     /// 初始值,木有方向  
  6.     /// </summary>  
  7.     None,  
  8.     /// <summary>  
  9.     /// 北/上  
  10.     /// </summary>  
  11.     North,  
  12.     /// <summary>  
  13.     /// 南/下  
  14.     /// </summary>  
  15.     South,  
  16.     /// <summary>  
  17.     /// 西/左  
  18.     /// </summary>  
  19.     West,  
  20.     /// <summary>  
  21.     /// 东/右  
  22.     /// </summary>  
  23.     East,  
  24.     /// <summary>  
  25.     /// 无放向可走  
  26.     /// </summary>  
  27.     NoDir  
  28. }  
    //方向枚举
    public enum Direction
    { 
        /// <summary>
        /// 初始值,木有方向
        /// </summary>
        None,
        /// <summary>
        /// 北/上
        /// </summary>
        North,
        /// <summary>
        /// 南/下
        /// </summary>
        South,
        /// <summary>
        /// 西/左
        /// </summary>
        West,
        /// <summary>
        /// 东/右
        /// </summary>
        East,
        /// <summary>
        /// 无放向可走
        /// </summary>
        NoDir
    }


接下来开始写这个迷宫类。可以认为迷宫是一个n X n 个迷宫格子的集合,所以设置一个迷宫格子的的二维数组MazeElem[,];为了指示当前行走的迷宫格子,设置一个MazeElem类型cur变量;当然还要设置一个迷宫的出口end(这里简化一下吧,默认出口就是这个迷宫右下角的那个小格子,入口就是迷宫左上角的格子。。。cur初始值为入口处。。。)。还有栈是必须的,主要是用来保存走过的路径,.NET已经提供一个Stack类,不需要我们自己写(想想用List来写栈好像也不是很难,这是看到某位大神的思路的)。嗯,还要用一对xy变量来保存这个迷宫的大小,方便后面的比较。

 

  1. public class Maze  
  2. {  
  3.     //很多的格子  
  4.     public MazeElem[,] maze;  
  5.     //当前格子  
  6.     MazeElem cur;  
  7.     //这是出口的那个格子  
  8.     MazeElem end;  
  9.     //用来保存路径的栈  
  10.     Stack<MazeElem> path = new Stack<MazeElem>();  
  11.     //这两个变量是用来保存迷宫的大小的  
  12.     int x, y;  
  13.     public Maze()  
  14.     {  
  15.       
  16.     }  
  17.     //构造函数,这个是最简单木有任何墙出现的空白迷宫。。  
  18.     public Maze(int x,int y)  
  19.     {  
  20.         x = x;  
  21.         y = y;  
  22.         maze=new MazeElem[x,y];  
  23.         //初始化  
  24.         for(int i=0;i<x;i++)  
  25.             for(int j=0;j<y;j++)  
  26.                 maze[i,j]=new MazeElem(i,j,false);  
  27.     }  
  28.     //用一个二维数组来初始化的构造函数- -  
  29.     public Maze(int[,] mazeArray)  
  30.     {  
  31.         //获取数组mazeArray0维中的个数  
  32.         x = (int)mazeArray.GetLongLength(0);  
  33.         //获取数组mazeArray1维中的个数  
  34.         y = (int)mazeArray.GetLongLength(1);  
  35.         //初始化maze  
  36.         maze = new MazeElem[x, y];  
  37.         for (int i = 0; i < x; i++)  
  38.             for(int j=0;j<y;j++)  
  39.                 maze[i, j] = new MazeElem(i, j, mazeArray[i,j]>0?true:false);  
  40.         //cur默认为左上角的格子,出口默认为右下角的格子  
  41.         cur=maze[0, 0];  
  42.         end = maze[x - 1, y - 1];  
  43.     }  
    public class Maze
    {
        //很多的格子
        public MazeElem[,] maze;
        //当前格子
        MazeElem cur;
        //这是出口的那个格子
        MazeElem end;
        //用来保存路径的栈
        Stack<MazeElem> path = new Stack<MazeElem>();
        //这两个变量是用来保存迷宫的大小的
        int x, y;
        public Maze()
        {
        
        }
        //构造函数,这个是最简单木有任何墙出现的空白迷宫。。
        public Maze(int x,int y)
        {
            x = x;
            y = y;
            maze=new MazeElem[x,y];
            //初始化
            for(int i=0;i<x;i++)
                for(int j=0;j<y;j++)
                    maze[i,j]=new MazeElem(i,j,false);
        }
        //用一个二维数组来初始化的构造函数- -
        public Maze(int[,] mazeArray)
        {
            //获取数组mazeArray0维中的个数
            x = (int)mazeArray.GetLongLength(0);
            //获取数组mazeArray1维中的个数
            y = (int)mazeArray.GetLongLength(1);
            //初始化maze
            maze = new MazeElem[x, y];
            for (int i = 0; i < x; i++)
                for(int j=0;j<y;j++)
                    maze[i, j] = new MazeElem(i, j, mazeArray[i,j]>0?true:false);
            //cur默认为左上角的格子,出口默认为右下角的格子
            cur=maze[0, 0];
            end = maze[x - 1, y - 1];
        }


 有一些方法还没写出来。先理清一下走迷宫的算法:

判断当前格子是否已经走过,如果没走过(flag=false):设置为已经走过flag=true,该格子入栈,然后选定一个方向尝试走其他格子;如果走过了:检查该格子的方向,如果不是NoDir(NoDir说明四个方向都尝试过了),选定一个方向尝试走其他格子如果是NoDir,那么将栈顶弹出,并将cur指向栈顶的格子。重复操作直道格当前格子指向迷宫的出口。选定一个方向尝试走其他格子的方法流程是这样的:先切换这个格子的方向,然后根据切换后的方向进行尝试,如果该方向的格子无法走过,那么继续选定一个方向尝试走其他格子,如果可以走过,那么将cur指向该格子。切换这个格子的方向,这个就比较简单~我们顺时针方向切换,开始的是East,向右走(dir为None,我就返回East;如果是East,那我返回South;如果是South,那返回West;如果是West,返回North;如果是North,那返回NoDir)。额,应该说得稍微清楚些把?具体看代码~一下都是Maze里面的方法,想复制的童鞋别复制错地方了0 0

  1. private  void CurGoNextStep(MazeElem me)  
  2. {  
  3.     switch (SwitchDirection(me))  
  4.     {   
  5.         case Direction.East:  
  6.             if (me.Y + 1 < y)  
  7.             {  
  8.                 MazeElem next = maze[me.X, me.Y+1];  
  9.                 //不能为墙,是墙你会走过去么?而且也不能是已经走过的,好马不吃回头草  
  10.                 if (!next.IsWall && !next.Flag)  
  11.                 {  
  12.                     //next.Flag = true;  
  13.                     cur = next;  
  14.                 }  
  15.                  //不行就换个方向把.  
  16.                 else  
  17.                 {  
  18.                     CurGoNextStep(me);  
  19.                 }  
  20.             }  
  21.             else  
  22.             {  
  23.                 CurGoNextStep(me);  
  24.             }  
  25.             break;  
  26.         case Direction.South:  
  27.             if (me.X + 1 <x)  
  28.             {  
  29.                 MazeElem next = maze[me.X+1, me.Y];  
  30.                 if (!next.IsWall && !next.Flag)  
  31.                 {  
  32.                     //next.Flag = true;  
  33.                     cur = next;  
  34.                 }  
  35.                 else  
  36.                 {  
  37.                     CurGoNextStep(me);  
  38.                 }  
  39.             }  
  40.             else  
  41.             {  
  42.                 CurGoNextStep(me);  
  43.             }  
  44.             break;  
  45.         case Direction.West:  
  46.             if (me.Y - 1>0)  
  47.             {  
  48.                 MazeElem next = maze[me.X, me.Y - 1];  
  49.                 if (!next.IsWall && !next.Flag)  
  50.                 {  
  51.                     //next.Flag = true;  
  52.                     cur = next;  
  53.                 }  
  54.                 else  
  55.                 {  
  56.                     CurGoNextStep(me);  
  57.                 }  
  58.             }  
  59.             else  
  60.             {  
  61.                 CurGoNextStep(me);  
  62.             }  
  63.             break;  
  64.         case Direction.North:  
  65.             if (me.X - 1 >0)  
  66.             {  
  67.                 MazeElem next = maze[me.X - 1, me.Y];  
  68.                 if (!next.IsWall && !next.Flag)  
  69.                 {  
  70.                     //next.Flag = true;  
  71.                     cur = next;  
  72.                 }  
  73.                 else  
  74.                 {  
  75.                     CurGoNextStep(me);  
  76.                 }  
  77.             }  
  78.             else  
  79.             {  
  80.                 CurGoNextStep(me);  
  81.             }  
  82.             break;  
  83.         case Direction.NoDir:  
  84.             //无路可走了已经  
  85.             break;  
  86.     }  
  87. }  
  88.   
  89. //转换方向  
  90. private  Direction SwitchDirection(MazeElem me)  
  91. {  
  92.     switch (me.dir)  
  93.     {   
  94.         case Direction .None:  
  95.             me.dir = Direction.East;  
  96.             return Direction.East;  
  97.             break;  
  98.         case Direction.East:  
  99.             me.dir = Direction.South;  
  100.             return Direction.South;  
  101.             break;  
  102.         case Direction.South:  
  103.             me.dir = Direction.West;  
  104.             return Direction.West;  
  105.             break;  
  106.         case Direction.West:  
  107.             me.dir = Direction.North;  
  108.             return Direction.North;  
  109.             break;  
  110.         case Direction.North:  
  111.             me.dir = Direction.NoDir;  
  112.             return Direction.NoDir;  
  113.             break;  
  114.     }  
  115.     return Direction.None;  
  116. }  
        private  void CurGoNextStep(MazeElem me)
        {
            switch (SwitchDirection(me))
            { 
                case Direction.East:
                    if (me.Y + 1 < y)
                    {
                        MazeElem next = maze[me.X, me.Y+1];
                        //不能为墙,是墙你会走过去么?而且也不能是已经走过的,好马不吃回头草
                        if (!next.IsWall && !next.Flag)
                        {
                            //next.Flag = true;
                            cur = next;
                        }
                         //不行就换个方向把.
                        else
                        {
                            CurGoNextStep(me);
                        }
                    }
                    else
                    {
                        CurGoNextStep(me);
                    }
                    break;
                case Direction.South:
                    if (me.X + 1 <x)
                    {
                        MazeElem next = maze[me.X+1, me.Y];
                        if (!next.IsWall && !next.Flag)
                        {
                            //next.Flag = true;
                            cur = next;
                        }
                        else
                        {
                            CurGoNextStep(me);
                        }
                    }
                    else
                    {
                        CurGoNextStep(me);
                    }
                    break;
                case Direction.West:
                    if (me.Y - 1>0)
                    {
                        MazeElem next = maze[me.X, me.Y - 1];
                        if (!next.IsWall && !next.Flag)
                        {
                            //next.Flag = true;
                            cur = next;
                        }
                        else
                        {
                            CurGoNextStep(me);
                        }
                    }
                    else
                    {
                        CurGoNextStep(me);
                    }
                    break;
                case Direction.North:
                    if (me.X - 1 >0)
                    {
                        MazeElem next = maze[me.X - 1, me.Y];
                        if (!next.IsWall && !next.Flag)
                        {
                            //next.Flag = true;
                            cur = next;
                        }
                        else
                        {
                            CurGoNextStep(me);
                        }
                    }
                    else
                    {
                        CurGoNextStep(me);
                    }
                    break;
                case Direction.NoDir:
                    //无路可走了已经
                    break;
            }
        }

        //转换方向
        private  Direction SwitchDirection(MazeElem me)
        {
            switch (me.dir)
            { 
                case Direction .None:
                    me.dir = Direction.East;
                    return Direction.East;
                    break;
                case Direction.East:
                    me.dir = Direction.South;
                    return Direction.South;
                    break;
                case Direction.South:
                    me.dir = Direction.West;
                    return Direction.West;
                    break;
                case Direction.West:
                    me.dir = Direction.North;
                    return Direction.North;
                    break;
                case Direction.North:
                    me.dir = Direction.NoDir;
                    return Direction.NoDir;
                    break;
            }
            return Direction.None;
        }
  1. //开始走迷宫  
  2. public void Start()  
  3. {  
  4.   
  5.     while (cur != end)  
  6.     {     
        //开始走迷宫
        public void Start()
        {

            while (cur != end)
            {   
  1. //如果没走过  
  2. if (!cur.Flag)  
  3. {  
  4.     //留下痕迹  
  5.     cur.Flag = true;  
  6.     //节点入栈  
  7.     path.Push(maze[cur.X,cur.Y]);  
  8.  //换方向走     
                //如果没走过
                if (!cur.Flag)
                {
                    //留下痕迹
                    cur.Flag = true;
                    //节点入栈
                    path.Push(maze[cur.X,cur.Y]);
                 //换方向走   
  1.  CurGoNextStep(cur);  
  2. }  
  3. else  
  4. {  
                 CurGoNextStep(cur);
                }
                else
                {
  1.             //如果不是无路可走的情况  
  2.             if (cur.dir != Direction.NoDir)  
  3.                 CurGoNextStep(cur);  
  4.             else//无路可走了~~那就回头...  
  5.             {  
  6.                 if (path.Count != 0)  
  7.                 //栈顶弹出  
  8.                      path.Pop();  
  9.                 if (path.Count != 0)  
  10.                 {  
  11.                     //更新cur  
  12.                     cur = path.Peek();  
  13.                 }  
  14.             }  
  15.         }  
  16.     }  
  17. }  
                    //如果不是无路可走的情况
                    if (cur.dir != Direction.NoDir)
                        CurGoNextStep(cur);
                    else//无路可走了~~那就回头...
                    {
                        if (path.Count != 0)
                        //栈顶弹出
                             path.Pop();
                        if (path.Count != 0)
                        {
                            //更新cur
                            cur = path.Peek();
                        }
                    }
                }
            }
        }


 

就这么多吧。可以测试一下:

 
  1. //用数组简单表示一个迷宫,大于0则表示该格子为墙  
  2. int[,] array = new int[5, 5] { {0,0,1,0,0 }, {0,1,0,0,0}, {0,1,0,0,0},{ 0,1,0,0,0},{0,0,0,1,0}};  
//用数组简单表示一个迷宫,大于0则表示该格子为墙
int[,] array = new int[5, 5] { {0,0,1,0,0 }, {0,1,0,0,0}, {0,1,0,0,0},{ 0,1,0,0,0},{0,0,0,1,0}};


大概是下面这样的图~~这编辑器有点蛋疼,直接用表格画了(黑色表示墙),左上角和右下角分别为入口和出口(黄色的....)

     
     
     
     
     

  1. //构造迷宫  
  2. Maze m = new Maze(array);  
  3. //开始走迷宫  
  4. m.Start();  
  5. //打印出迷宫中走的方向  
  6. if (m.maze != null)  
  7. {  
  8.     int tmp = 0;  
  9.     foreach (MazeElem me in m.maze)  
  10.     {  
  11.         tmp++;  
  12.         Console.Write(me.dir +" ");  
  13.         if (tmp % 5 == 0)  
  14.             Console.WriteLine();  
  15.     }  
  16. }  
            //构造迷宫
            Maze m = new Maze(array);
            //开始走迷宫
            m.Start();
            //打印出迷宫中走的方向
            if (m.maze != null)
            {
                int tmp = 0;
                foreach (MazeElem me in m.maze)
                {
                    tmp++;
                    Console.Write(me.dir +" ");
                    if (tmp % 5 == 0)
                        Console.WriteLine();
                }
            }


结果如下:

感觉面向对象是好理解些,不过我不是很能够体现出面向对象的好处

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值