最近在学习数据结构,写了这个小程序。
程序分为两个部分,一个用递归来生成迷宫,另一个是寻路,也是用递归的方法。下面介绍下思路。
递归就是程序调用自身的一个过程,要跳出递归,必须还有一个“出口”,用来停止递归。生成迷宫的递归的出口就是当前位置的上下左右没有空余的格子。
我用PictureBox作为迷宫的格子,将PictureBox存放在数组里:
假如以map[0,0]作为起始点来生成迷宫的话,程序会随机的选择上下左右中的一个方向来走,如果选中的一个方向中的格子没超出数组界限且没有被遍历过,就记录在位置,然后以该位置为起点,再次随机选择上下左右,这样重复下去,最终将整个格子遍历,其过程像一棵树,map[0,0]就是该数的根。
在该例子中,假如如生成如图所示的迷宫:
该迷宫的生成过程我记录了下来,可用如下的树状图表示:
程序遍历的顺序为:1-4-5-8-9-6-3-2,到2后发现周围没有可用的空格,结束递归,向上返回,一直返回到8这个位置,发现还有可用的空格于是向左递归,遍历了7这个位置,最终整个map都遍历了一遍,这样的算法的特点是:任何一个节点都有一条且唯一的一条通向根节点1的路径,所以任何一个节点都能以根节点为枢纽,通向另一个节点,因此这样遍历后一定会有一条且唯一一条从起点map[0,0]通向终点map[2,2]的路径。
下面要解决的就是如何表示pictureBox中迷宫的路径,这里我使用了oldj的写法(前人栽树,后人乘凉,哈哈):
http://oldj.net/article/javascript-maze/
不过我和他的表示方法有点不一样,思想都是一样的。迷宫的格子共有16种状态:
大家注意,每个格子下面的文件名,这不是随便定义的,是有规律的。每个格子有上下左右4条边,每条边都有通过与不通过两种状态,这里用0表示不通过,1表示可以通过,1.jpg的状态按上-右-下-左的顺序就是:0001,十进制就是1;3.jpg可以表示为0011,转换为十进制就是3,哈哈,大家看出来了吧,文件名就是格子状态的十进制表示方法。C#提供了二进制操作。
使用CreateNumMap(int m,int n,int o)这个方法来递归,m表示迷宫的行数,n表示迷宫的列数,o表示的是格子的状态,[1,2]表示的是第2行第3列,就是上例中的格子6,程序中的所有数组都是这样表示的。
在上面的例子中,该函数的初始值是CreateNumMap(0,0,0),就是从迷宫中的格子1开始遍历,格子1的初始状态为0.jpg,然后随机选择了向下遍历,第一个格子就变成了2.jpg,在下面方向开了一个口,这是怎么变成的呢?其实这里用了二进制的异或操作,异或操作的定义是:0异或0得0,0异或1得1,1异或1得0。程序选择了向下遍历,格子1的初始状态为0.jpg,这时要在格子1的下面打开通道,还要保证格子1其它几条边的状态不变,只要将图片2.jpg与格子1的0.jpg进行异或操作:2异或0就是0010异或0000得0010,就是十进制的2,这是就得到了正确的图片格式,C#的异或操作符是"^"。
在程序中先将格子的状态用数字表示,遍历完成后将格子中的图片替换为数字对应的图片。
至于怎么寻路的,如果你会了上面的方法,这就不是难题了,源代码中有,自己看吧。
用vs2010写的程序,用了3.5的framework。
源码下载地址:https://files.cnblogs.com/fmnisme/%E8%BF%B7%E5%AE%AB.rar