如图这是我们常见的扫雷游戏的界面。为了实现扫雷游戏,我们借助一个二维的数组来实现,我们可以通过在二维数组里填充数字0来表示该处没有雷,填充1来表示该处有地雷。但是如图所示显示界面我们并不能看见此处到底是1或者0,一个数组我们不可能让其既填充0或1又让其填充别的字符来起到遮挡的作用,所以我们应该设计两个一样的数组;一个用来填充地雷应该在的位置,另一个用来显示界面。
当我们开始扫雷游戏时,点击一处就会统计出围绕该位置处其他几个位置雷的总的个数。此时又出现了一个问题:假设我们要创建一个9*9的棋盘,当我们点击中间部分如红框所示,我们需要统计八个格子;当时当我们选择了边界处,如黑框所示,我们只要统计三个格子。这在后面我们写统计一个坐标周围的地雷个数时会很麻烦,所以我们在创建棋盘的时候,我们就往外扩充两行两列,但是在设计地雷位置的时候还是将地雷放置在中间9*9的位置处,这样在统计所选位置周围地雷个数的时候并不会造成影响,而且每个位置都是统计八个元素中的地雷个数,极大方便了我们写函数。
在了解了一些基本设计原理后,现在让我们开始写程序。
由于该程序过程比较复杂,需要创建很多的函数,所以我们写的时候最好分成两个源文件,一个源文件用来写程序测试过程中的主体结构,另一个源文件用来写程序所需的函数,并且用一个头文件来引用。
函数的主题比较简单,首先我们进入游戏肯定是一个菜单选择页面,所以我们先创建一个menu函数来打印菜单,然后通过switch语句就可以实现具体的选择功能,此处比较简单,不过多赘述。具体代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include "game.h"
#include <time.h>
#include <stdlib.h>
menu()
{
printf("*************************\n");
printf("*********1.开始游戏******\n");
printf("*********0.退出游戏******\n");
printf("*************************\n");
}
test()
{
int flag = 0;
do
{
menu();
printf("请输入你想要的选项\n");
scanf("%d", &flag);
switch(flag)
{
case(1):
game();
break;
case(0):
printf("游戏已退出\n");
break;
default:
printf("重新输入\n");
break;
}
}
while (flag);
}
int main()
{
test();
return 0;
}
程序的主题内容就是我们的game()函数,所以我们现在来分析一下扫雷功能怎么实现。
首先,由上文可知我们需要两个二维数组,一个用来存放地雷,一个用来打印出来显示。这里为了方便,我把两个数组都设置成了char型。创建完了数组后我们肯定要对数组进行初始化,显示页面我们用“*”来填充,打印出来的界面就是一个只有“*”的棋盘,实现了遮挡的功能。在存放地雷的数组中我们先统一把每个位置设置为0,以便统计。初始化的方法也很简单,遍历数组,每个元素位置处设置值就行。以下就是数组的建立和初始化,因为我们要把遮挡的页面显示出来,所以这里需要写一个打印游戏界面的函数:
void Border_initialize(char arr[ROWS][COLS], int rows, int cols, char set)//初始化函数
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
arr[i][j] = set;
}
}
}
void Border_output(char arr[ROWS][COLS], int row, int col)//打印数组函数
{
printf("-------------------扫雷---------------------\n");
for (int i = 0; i <= row; i++)
{
printf("%d ", i);
}
printf("\n");
for (int i = 1; i <= row; i++)
{
printf("%d ", i);
for (int j = 1; j <= col; j++)
{
printf("%c ", arr[i][j]);
}
printf("\n");
}
printf("---------------------------------------------\n");
}
现在我们手里有一个初始化后的数组,现在我们就要来放置地雷,地雷的位置肯定是随机的,而且行和列的坐标都是1~9,只有中间9*9的棋盘才是有效的棋盘。假设此处我们要埋十个地雷,我们就要找十个数组的位置,将里面的元素从0改成1,就实现了地雷的布置。随机数的设置也很好实现,因为坐标只能是1~9,所以我们对9取模后加1就是1~9.此处还有一个容易被忽视的问题就是可能会有几次产生的随机坐标都是同一个,为了解决这一个问题,我们就还需再借助一个变量count,当我们每次进入循环时,判断产生的随机坐标处的元素是否为1,如果为0我们的count就减1,说明此次的设置地雷的操作是有效的,当count为0时,就跳出循环,这样子我们就可以得到一个埋藏着10个地雷的数组了。具体代码如下:
void Border_set(char arr[ROWS][COLS], int row, int col)//设置雷所在位置
{
//雷所在位置在数组中从一开始,到九结束
srand((unsigned int)time(NULL));
int x, y = 0;
//有十颗雷我们就应该将原来数组中的十个位置由0变为1来表示此处有雷
int count = 10;
do
{
x = rand() % row + 1;
y = rand() % col + 1;
if (arr[x][y] != '1')
{
arr[x][y] = '1';
count--;
}
}
while (count);
}
设置完地雷的值后我们就要开始实现扫雷操作了。我们此处肯定需要一个输入端来接受元素坐标,如果此处元素里的值为1,我们就提醒踩雷了,并退出游戏,返回主菜单界面。如果不为0的话,我们就需要在显示的数组处将那个地方的元素内容替换成周围八个位置处的地雷总数,于是在此处我们就要另外再设计一个Mine_count()函数来统计数字,已知ACSII码表中字符1和字符0差一,我们已知的元素坐标为(x,y),所以以(x,y)为中心的九个元素的行坐标范围是(x-1)~(x+1),列坐标范围是(y-1)~(y+1),我们将每个元素里面的存的字符减去字符0,然后再相加,用一个变量来存储并返回,我们就可以得到一个元素周围一圈位置所包含的地雷个数,此处我用循环来实现,一个位置一个位置相加也能实现。除此以外我们还要返回游戏成功的界面,因为一共由9*9个位置,由10个位置埋藏着地雷,所以我们只要猜出剩下的71个位置就能完成游戏,所以,我们再设置一个变量,用来统计成功次数,每次成功没有踩雷就减一,直至为0,跳出循环游戏成功。综上,代码如下:
int Mine_count(char arr[ROWS][COLS], int m, int n)//统计周围雷的个数
{
int count = 0;
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
count = count+(arr[m + i][n + j] - '0');//字符1和字符0在ASCII码表上差一,所以可以实现统计地雷出现的个数
}
}
return count;
}
void Border_function(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int row, int col)//实现扫雷功能
{
int x, y = 0;//实现我们要扫雷的位置
int d = 71;
while (d)
{
printf("请输入你想要扫的坐标\n");
scanf("%d %d", &x, &y);
if (x > row || x<0 || y>col || y < 0)
{
printf("输入坐标超出限制请重新输入\n");
continue;
}
else
{
if (arr1[x][y] == '1')
{
printf("哎呀,踩到雷了!游戏失败\n");
break;
}
else
{
int c = Mine_count(arr1, x, y);//此处需要一个功能来实现扫完某个位置会显示周围一圈雷的个数
arr2[x][y] = '0' + c;//字符0加上数字c就可以得到字符c
Border_output(arr2, row, col);//显示改变后的数组显示
d--;
}
}
}
if (d == 0)
{
printf("恭喜你扫雷成功!\n");
}
}
以上就是整个扫雷小游戏,注意记得拆开写,会更加简洁明了!
标签:count,地雷,int,C语言,扫雷,数组,printf,我们,游戏 From: https://blog.csdn.net/spikezqq/article/details/143926256