前段时间很喜欢玩"开心消消乐"这个休闲小游戏, 刚好大学的一位同学也在玩,后来就想着如果让自己来写这个逻辑要怎么写, 经过一天的构思, 找到一种利用深度优先搜索思想来实现的方式.
三消游戏的规则
- 一个m x n 的棋盘内, 初始状态下, 填满若干种不同类型的… 暂且叫Hero吧, 类型的数量根据游戏难度不同而不同, 一般有4~5种.
- 同种类型的Hero连着 >= 3时消除, 横着竖着都可以消, 斜着的不能消.
本文约定以下5种不同类型的Hero, 对应的值分别为1,2,3,4,5.
下面模拟一个5x5的棋盘, 说明一下规则,
消除前的棋盘:
1 1 2 4 5
5 1 1 1 4
5 2 1 5 4
4 3 3 3 4
消除后的棋盘:
1 1 2 4 5
5 0 0 0 0
5 2 1 5 0
4 0 0 0 0
算法实现
实现语言最早用的是C++, 后来因为要用Html绘制界面, 所以把代码编译成JavaScript的了, 而且因为现在过年回家了, C++的代码在公司, 只有Js的代码可以Po出来了.
算法其实很简单, 写一个函数ScanPos(pos), 这个函数用来扫描pos点的左、上、右、下四个邻近的点,如果某个邻近的点和当前扫描的点pos的类型一样,则递归调用ScanPos(newpos), 继续递归调用ScanPos, 直到所有方向的点都不匹配或者到达边界为止。
用上面那个例子说明一下扫描的过程:
----> x
|
| 坐标方向, 为了直观,原点为1, 1
V
y
假如我们初始扫描的点是(3, 2), HeroType = 1
1 1 2 4 5
5 1 1 1 4
5 2 1 5 4
4 3 3 3 4
Step.1
1 1 2 4 5
5 1 1 1 4
5 2 1 5 4
4 3 3 3 4
Step.2
1 1 2 4 5
5 1 1 1 4
5 2 1 5 4
4 3 3 3 4
Step.3
1 1 2 4 5
5 1 1 1 4
5 2 1 5 4
4 3 3 3 4
这里扫到5后发现5不匹配, 于是开始往上Scan
Step.4
1 1 2 4 5
5 1 1 1 4
5 2 1 5 4
4 3 3 3 4
Step.5
1 1 2 4 5
5 1 1 1 4
5 2 1 5 4
4 3 3 3 4
Scan到1,1这个点后,左、上、右、下都无效,左上到达边界,右边是来时的地方, 所以也不匹配,下边是5,也不匹配, 所以回退到1,2这个点的ScanPos函数,这个点的上、右也都不匹配, 所以继续往回退,…… 中间过程类似,不再描述。最后扫描后的棋盘状态:
1 1 2 4 5
5 1 1 1 4
5 2 1 5 4
4 3 3 3 4
可以发现这样扫描后,第一行和第三行的3个点,并不符合三消规则,但是也都被扫描到了。这就需要把这些点排除掉。
排除不符合的点
这一步做的比较粗暴,直接两层for循环遍历整个棋盘,在内层循环内对每一行Hero进行遍历时, 记录相邻的相同点的个数,然后把每个点的Match次数保存起来,最后只有Match >=3 的才会消除。
以上就是核心算法了,当然还有很多细节需要注意,比如抽象出Cell类,每个Cell有它的状态以及Match次数, 在每次ScanPos时,都要实时更新Cell的状态,等等。
JavaScript代码实现
function Grid (cols, rows) {
this.cols = cols;
this.rows = rows;
this.board = new Array();
this.lastClickPosX = -1;
this.lastClickPosY = -