今天在整理自己的文档时,发现了一年前用C写的扫雷程序,要做出扫雷游戏其实原理很简单,在这里我不打算把整个代码贴出来,只是简单地描述一下我实现的方法,以及其中碰到的问题和大家讨论。
首先是初始化:
第一步是构造一个矩阵(int mat1[N][N]),初始化为全0,然后根据玩家希望雷的数目随机填入相应个1。
第二步,构造另一个矩阵(int
mat2[N][N])(当然,现在想想好像开辟两个矩阵有点浪费内存,不过,这倒是偷懒的一个好办法,反正现在计算机内存肯定够。),扫描第一个矩阵的每一格,如果该格为0,将该格周围8个值全部加起来(即无雷区周围的雷数)填到mat2相应的格中,否则,将9填到mat2中相应的格中。第一次做的时候,先初始化了一个(N+2)x(N+2)的矩阵,因为嫌讨论边界麻烦,就先空出周围一圈,其实也是大同小异。
这样一个可以玩的地图就构造好了。其中9代表雷,非9的值即周围雷的数目。到这个阶段,如果配上相应的图形显示和鼠标输入、判断胜出失败函数,就可以直接玩了。由于自己不会用MFC,更不会windows编程,只学过C,略懂C++,所以当时做的时候是用EASYX的graphics.h做出图形界面的。(如果想在VC下用控制台程序绘图,这是个相当不错的选择。它可以让你只关心算法而不必纠结申请窗口等琐事。这个绘图函数库详见:http://www.easyx.cn/)
这也是很久以前做这个程序时的效果。但是,在玩的时候就发现特别烦,就是每一个格子都必须亲自打开。所以第二次修改这个游戏的时候就发誓要做出windows扫雷中的可以点开一片的函数。经过多次实验,终于用迭代的搜索算法解决了这个问题。
仔细观察winmine,它的“自动打开”分为两类:
第一类:点击(左右同时点击)数字(事件是用户触发的)
第二类:程序自动打开格子(事件是由程序触发的)
========扫雷程序自动打开函数伪代码=====================================================
程序运行状态 自动打开(自动打开的位置,自动打开的类型)
{
如果是第一类:
首先统计周围插上红旗的数目
如果红旗数不等于该格的数字
返回继续(或提示该操作无效)
否则如果周围插红旗的位置无雷或有雷的地方未插红旗
返回终止(提示游戏失败)
否则按照第二类自动打开周围未插红旗的格子
如果是第二类:
如果该位置是无雷的并且还未打开
将该位置标记为打开
直接打开该格,并按照第二类自动打开周围8个格子
如果周围8格自动打开中有一个返回了终止,返回终止
否则返回继续
否则如果已经打开
直接返回继续
否则如果该位置是数字
即使周围插红旗的位置完全正确,也只打开自身这一格。
返回继续
}
==============================================================================================
做出来的效果:
图1 游戏中,点开一个空白区域,连续打开一串
图2 游戏获胜,用时261秒,是否继续?
当然,这个程序还存在很多问题,其中最重要的一个就是内存效率不高,其次,由于自己学程序比较杂,程序中用了C++构造的扫雷类结构,但是程序的主体却是C的味道,还用了windows编程的API函数,等自己学得比较系统后再修改。
在整个编程过程中,感觉颇有心得,在没有做出搜索算法之前,感觉非常难,实现的时候一头雾水,也曾失败过很多次:
图3 失败的截图,空白格周围应该全部打开
不过最终还是坚持下来了。后来成功的一个关键就是仔细地观察了windows扫雷的自动打开,然后定下心来将头绪理清楚。所以现在写这篇博客,也是提醒自己以后做任何事时都不能忘的这一点。