曾经做过一个JavaScript版的网页迷宫游戏,从生成地图到操作全是用JavaScript在浏览器端完成的,有兴趣的同学可以右键查看网页源代码,最关键的代码为 mg.js ,近400行。
有不少朋友问我,这个迷宫是怎么实现的,考虑到自己去读源码是有点累,我就大概写一下这个迷宫游戏的实现思路。我的实现不是最高效的,仅供感兴趣的同学讨论研究。:-)
这一个迷宫是基于平面上的方格的,每一个格子有上、下、左、右四个方向,每个方向上可能有墙(不能通过),也可能没墙(可以通过)。这样,每个格子实际上就有16种可能的状态,我们用 0 ~ 15 来给每一种状态编一个号。如下图所示。
注意,上面的编号并不是随意的。由于每个格子有四条边,每个边有两种状态(可通过与不可通过),如果我们用0表示某一条边不可通过,1表示可通过,这样,四条边的状态就能组成一个四位的二进制数。我们把四条边按从上方开始按顺时针方向的上、右、下、左四个方向的状态分别代表二进制数的个、十、百、千位的话,得到的二进制数的十进制值就作为这个格子的编号。如下图所示。
这样做有什么好处呢?首先,我们只要用一个 0 ~ 15 之间的数字就能表示某个格子的状态了,便于地图数据的存储。另外,更重要的是,对于任意一个格子,我们要判断它的某个方向是否可通过时,只需要做一个简单的按位与,看结果是否为0就可以了。
如上面所说,我们的上、右、下、左四个方向分别代表这个二进制数的个、十、百、千位,即:
上:0001,即十进制 1
右:0010,即十进制 2
下:0100,即十进制 4
左:1000,即十进制 8
我们要判断某个格子(比如它的状态是6)的上方是否可通过时,只要计算:
6 & 1 = 0,可知上方不可通过,类似地,想知道它的右方是否可通过时,只要计算:
6 & 2 = 2,可知右方可以通过。
这样,当确定了迷宫地图的宽与高时,我们只需要一个简单的一维数组,每一项的值为 0 ~ 15 之间的整数,就足以记录这个迷宫的地图信息,并且能很方便高效地判断每个格子某个方向的可通过性。
确定了地图的表示方法,接下来的问题就是怎么生成地图。在这个游戏中,生成地图的方法比较简单:从某个格子开始,随机地遍历周边的未到达过的格子,如周边没有没到达过的格子了则后退一步,如地图上所有点都已到达则遍历完成,地图也就生成了。见下面的流程图。
这个过程,实际上就相当于一个人先随机地在地图上走一遍,并且把他走过的地方标记为可通过。这样就保证了地图上每一个格子都是连通的(任意一个格子总有某一条路能到达),并且保证有且仅有一条路可以从起点连到终点(事实上,地图上任意两个格子之间都有且仅有一条路相连)。
最终生成的迷宫就类似于下图的样子。当然,地图每次都是随机生成的,你看到的迷宫和我看到的会不一样。地图上的格子全是用 div + css 堆出来的,呵呵。
另外,这个算法生成的迷宫属于单连通迷宫,这类迷宫都有一个通用的简单解法“扶墙法”,即从起点开始,伸出一只手(左手右手都可以,看个人喜好)扶住墙壁,接下来就一直沿着这一边的墙走,无论转弯还是直走,都要保证这只手不要离开墙,这样虽然走的路线很可能不是最短的,但是能保证让你到达终点。
只生成地图,显然趣味性还不够,于是我又添加了一个小头像,再用了一个 jQuery 的键盘事件插件(js-hotkeys)接收按键事件控制小头像的移动,这样就差不多可以玩了。
然后,为了让游戏更加生动,我又为小头像加了一些状态,比如如果你进入页面几秒钟后还没有按方向键,它会弹出一个提示框告诉你操作方法,当你走到三面环墙的死胡同时它会说“哎呀……”,当你好一会儿没有操作了,它会说“Hello?”提醒你,走到终点时它会变成一个开心的笑脸并且欢呼。
最后,再贴一下这个迷宫游戏的游玩地址:http://oldj.net/static/maze/maze.html 。:-)