扫雷小游戏的游戏规则是在雷区(一个表格)里面标记出雷,如果不小心将雷误认为是安全的将会被炸死,反之标记出雷区中所有的雷就会获得胜利!
思考
首先我们应该清楚我们将使用二维数组来模拟雷区,随机产生雷分布在雷区(二维数组)中,这需要一个二维数组。展示给玩家看的也是一个二维数组,这就是两个二维数组了。
分析到这里,我们需要两个二维数组,他们的大小一个一模一样。一个用于存储雷的信息,一个用于存储玩家玩的游戏的信息(就是他扫过了哪些地方,标记出了什么雷......)。
假如我们做的是一个9*9大小的雷区,那么我们应该将雷区大小声明为11*11。
为什么呢?我们玩扫雷游戏的过程中,点开一块坐标,假如这个坐标是安全的,那么它会显示在它周围8个方位的雷的个数。这就涉及在雷区的边界坐标中,要去访问它的周围坐标,这就会产生越界的问题。
那么我们想要9*9的雷区,声明11*11的雷区,在9*9的边界坐标去访问它周围坐标就不会越界,而我们展示给玩家或是对雷区进行操作时就可以通过控制坐标值访问。
构建框架
程序将从main函数开始。
main函数
调用test函数,然后返回0.
test函数
在开始游戏之前我们可以做一个菜单界面,让玩家可以选择进入游戏或退出程序。menu()实现菜单界面。通过获取玩家输入的值,在本程序中,玩家输入1进入游戏,调用game(),输入0退出程序,break跳出循环。输入其他的警告以后再次获取玩家的输入。这里用到一个do while循环,可以在一局游戏结束以后再次进入。
game函数
声明两个二维数组,一个用于存储雷的信息mine,一个用于存储玩家游戏的程度信息show。首先要用InitBoard()初始化二维数组。mine数组中要存储雷的信息,我们将'1'看做雷,将'0'看做安全的,所以要将mine数组中的值初始化为全是'0'。show中存储玩家游戏信息,我们设置为最开始全是'*',当玩家输入一个坐标时再展示该坐标周围的雷的个数。
初始化以后打印show数组展示给玩家看,使用DisplayBoard函数展示雷区。然后要在mine中随机布置雷,使用SetMine函数完成此操作。使用FindMine函数完成以下操作:在雷没有被全部找出来之前,不断请玩家输入坐标,然后判断该坐标是否安全。如果不安全,是雷则输出提示,展示mine数组,break跳出循环,结束本局游戏。如果是安全的则计算该坐标周围雷的个数,使用get_mine_count函数实现。使用"个数+'0'"的方法将int转为char设置到show数组的该坐标中去。
判定雷是否被完全找出的办法,设置一个win变量,大小为0。当玩家找到一个安全的坐标时win加1,9*9的雷区有81个坐标,其中有10个雷,则安全的坐标有71个,当win<71时证明还没有找出全部的雷,程序就不断请玩家输入坐标。当win=71时,跳出循环,输出提示并结束这局游戏。
进阶
以上实现了简易版的扫雷。我们玩过的扫雷,是当点击一个坐标后,假如是安全的并且它的周围坐标也是安全的,就可以打开一大片。而我们上面实现的不能完成这一操作。当玩家输入的坐标是安全的一行,还有判断它周围是不是有雷,如果没有雷就要挨个访问当前坐标周围的八个雷,判定他们周围有没有雷,并且将它周围雷的个数填入,这就要用到递归。
碰到的问题:当玩家输入一个坐标以后,这是一个安全的坐标,所以还有判断它周围坐标是否安全,周围坐标也是一个安全坐标,继续判断这个周围坐标的周围坐标,但是玩家输入的坐标也是周围坐标,最后就会进入玩家输入的坐标继续判断,这样就无法跳出递归,一直递归到计算机崩溃......
解决方法:声明一个字符类型的二维数组ju,假如这个坐标被判定过就设置ju中该坐标的值为1,以此来区分判定过的和没判定过的坐标。
代码实现
不足之处
有些时候玩家并没有完全找出所有雷的位置,但是在玩家排雷1的时候,将安全的坐标点出后,由此安全坐标开始,打开了一大片安全坐标,并且将雷的位置暴露出来,程序就自动确认游戏成功了。