在基本掌握了分支、循环、数组、函数的前提下,我们基本就可以用c语言来实现一个扫雷游戏的编写了,其中只需要用到一个生疏的知识点——随机数的生成。在这之前我已经发布了一篇关于随机数生成的文章,可前往自取。在掌握了这些知识之后,便可以开始进行扫雷游戏的编写了。
在开始前,为了条理清晰一点,我们先创建一个头文件saolei.h来写游戏需要的数据类型和函数声明,和两个源文件saolei.c、test.c,分别进行游戏实现和写游戏的测试逻辑。
完整代码放在文章最后
1、主体设计及准备
首先我们需要在saolei.c、test.c两个源文件中对saolei.h进行引用,因为大多数据类型和函数声明都将写在saolei.h中
在saolei.h中需要引用的头文件
#include<stdio.h>
#include<stdlib.h>//随机数生成所需头文件
#include<time.h>//随机数生成所需头文件
这里我们同时也先在test.c中创建一个主体框架,后续进行内容填充
int main()
{
srand((unsigned int)time(NULL));//生成随机数
do
{
caidan();//菜单函数
scanf("%d", &a);//这里的a定义在saolei.h中,为int a,作为全局变量,方便在排雷失败或者成功后跳出循环
switch (a)
{
case 1:
saolei();//游戏的主体函数,后续进行填充
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
}
while (a);
}
为了美观和引导游戏进行,在这里我们在test.c中创建一个菜单函数
void caidan()
{
printf("*********************\n");
printf("**** 1、开始游戏 ****\n");
printf("**** 0、退出游戏 ****\n");
printf("*********************\n");
}
在test.c中的主体框架上面创建一个游戏的主体函数
void saolei()
{
}
2、布置棋盘
这里我们做两个99的棋盘,作为进行布置雷和扫雷的场地,但是我们如果只是创建两个99的数组便会面临一个问题
![对一个位置进行扫雷的范围]](https://img-blog.csdnimg.cn/3c2d04c72c914270ba202eb36bfa3cfc.png#pic_center =300x300)
在边缘时便可能超出范围,于是为了编写代码的方便,这里我们创建两个11*11的数组作为棋盘,最外围一圈只让他存在,不进行使用
为了使代码更灵活,我们在saolei.h中创建`
#define HANG 9//行数
#define LIE 9//列数
#define HANGS HANG+2//行数的扩展
#define LIES LIE+2//列数的扩展
#define M 10//雷的个数
上面的行数、列数、雷的个数均可以自己设置,只需要改变后面的数字即可。
将两个数组在test.c中创建为
char mine[HANGS][LIES];
char show[HANGS][LIES];`
如果想改变棋盘的大小,只需要改变HANG,LIE后面的值便可以了,现在使用9*9的棋盘作为示范。
3、初始化
在创建了棋盘后紧接着便需要棋盘进行初始化,对其中填入内容。其中char mine[HANGS][LIES]
中全部填入字符0,为显示雷的不可见的棋盘,内容为字符0的表示没有雷,后续将在char mine[HANGS][LIES]
填入雷,而char show[HANGS][LIES]
全部填入*,作为展示出来的棋盘。
首先,在游戏的主体函数saolei()中填入初始化函数
chushihua(mine, HANGS, LIES, '0');
chushihua(show, HANGS, LIES, '*');
再在saolei.h头文件里面申明初始化函数
void chushihua(char buzhi[HANGS][LIES], int hangs, int lies, char t);
最后在saolei.c中进行初始化函数的编写:运用两层循环分别将‘0’和‘*’填入数组mine和show
void chushihua(char buzhi[HANGS][LIES], int hangs, int lies, char t)
{
int i = 0;
for (int i = 0; i < hangs; i++)
{
for (int j = 1; j < lies; j++)
{
buzhi[i][j] = t;
}
}
}
到这里我们可以分别将两个数组打印出来,查看效果。这里我们又需要创建一个函数void chushi(char buzhi[HANGS][LIES], int hang, int lie)
同样也需要在saolei.h头文件里面申明函数。这里同样使用两层循环来打印出来,但是为了美观和后续输入排雷坐标的方便添加了行列的显示
void chushi(char buzhi[HANGS][LIES], int hang, int lie)
{
for (int i = 0; i <= hang; i++)//打印列数
{
printf("%d ", i);
}
printf("\n");
for (int i = 1; i <= hang; i++)
{
printf("%d ", i);//打印行数
for (int j = 1; j <= lie; j++)
{
printf("%c ", buzhi[i][j]);
}
printf("\n");
}
}
最后在游戏主题函数中初始化函数的后面填入chushi(mine, HANG, LIE);
和 chushi(show, HANG, LIE);
导入数组和数值进行打印
打印出来效果如下:
这里为了查看效果,两个都打印了出来,到后面数组mine将不会打印,隐藏起来用来填雷。
4、布雷
创建一个函数void setlei(char buzhi[HANGS][LIES], int hang, int lie);
用来布置雷,同样也需要在saolei.h头文件里面申明函数。在布雷这个阶段,我们就需要使用到随机数了。
void setlei(char mine[HANGS][LIES], int hang, int lie)
{
int geshu = M;//将雷的个数赋值给geshu
while (geshu)//当geshu为0时结束循环
{
int x = rand() % hang + 1;//随机生成1到9的数作为布雷位置的行
int y = rand() % lie + 1;//随机生成1到9的数作为布雷位置的列
if (mine[x][y] == '0')//这里可以避免重复布雷,只有为‘0’时才会布
{
mine[x][y] = '1';//布雷的位置为‘1’
geshu--;//每布一个雷geshu减1,直到为零跳出循环
}
}
}
最后在saolei()游戏主体函数中填入setlei(mine, HANG, LIE);
导入数值,即可布雷成功。
这里同样也可以查看布雷效果,只需要在saolei()游戏主体函数中setlei(mine, HANG, LIE);
函数的后面再次引用chushi(mine, HANG, LIE);
即可打印出来,效果如下:
5、排雷
与上面一样,我们又需要创建一个函数void shuru(char mine[HANGS][LIES], char show[HANGS][LIES], int hang, int lie);
,同样也需要在saolei.h头文件里面申明函数。每一步的解释附在相应代码后面
void shuru(char mine[HANGS][LIES],char show[HANGS][LIES], int hang, int lie)
{
int x, y, t;
int m = 0;
int n = 0;
int b = 0;
int geshu = M;
while (n<hang*lie-geshu)//hang*lie-geshu表示无雷位置的个数,n表示已经排查了的个数
{
printf("请输入你要排雷的坐标\n");
printf("行:");
scanf("%d", &x);
printf("列:");
scanf("%d", &y);
if (x <= hang && x >= 1 && y <= lie && y >= 1)//判断输入位置的合理性,合理即进入
{
if (show[x][y] != '*')//show数组被排查后的位置会显示附近九宫格的雷的个数,该位置不会为‘*’,防止重复排查产生错误
{
printf("该位置已被排查过,请重新选择");
}
else if (mine[x][y] == '1')//排查位置在mine数组中为‘1’,即踩到了雷,游戏失败
{
printf("踩到雷了,很遗憾失败了\n");
chushi(mine, HANG, LIE);//游戏失败,显示雷的位置
caidan1();//为一个菜单函数,进行选择再来一次或者退出游戏
scanf("%d", &b);
if (b == 1)
{
break;
}
else if (b == 0)
{
a = 0;//若选择退出游戏,使a=0,跳出这个函数后紧接着跳出游戏主体函数,结束程序运行
break;
}
else
{
printf("输入错误,请重新输入\n");
}
}
else//未踩到雷时,通过两层循环算出周围九宫格雷的个数
{
m = 0;//m表示周围雷的个数,初始为0
for (int i = x - 1; i <= x + 1; i++)
{
for (int j = y - 1; j <= y + 1; j++)
{
if (mine[i][j] == '1')
{
m++;//若是雷,m加1
}
}
}
show[x][y] = m + '0';//m表示的数字加上‘0’,得到字符‘m’,m随上面算出的雷的个数变化而变化
chushi(show, HANG, LIE);//打印数组show显示周围雷的个数
n++;//每排查出一个无雷的位置,n加1,直至不符合循环条件,跳出循环
}
}
else
{
printf("输入错误,请重新输入\n");//输入不合理,进行提醒
}
}
if (n == hang * lie - geshu)//已经排查的个数与无雷的个数相同,即已经全部排查出了雷,排雷成功
{
printf("恭喜你,排雷成功\n");
chushi(mine, HANG, LIE);//进行提醒:再来一次还是退出游戏
caidan1();
scanf("%d", &b);
if (b == 1)
{
;
}
else if (b == 0)
{
a = 0;
}
else
{
printf("输入错误,请重新输入\n");
}
}
}
上面的菜单函数caidan1()为:
void caidan1()
{
printf("*********************\n");
printf("**** 1、再来一次 ****\n");
printf("**** 0、退出游戏 ****\n");
printf("*********************\n");
}
最后将shuru(mine,show, HANG, LIE);
填入游戏主体函数中,引入相应的值。效果如下:
到这里扫雷游戏的编写就结束了,最后附上完整代码。
6、完整代码
saolei.h
#pragma once//创建头文件后自带
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define HANG 9
#define LIE 9
#define HANGS HANG+2
#define LIES LIE+2
#define M 10
void chushihua(char buzhi[HANGS][LIES], int hangs, int lies, char t);
void chushi(char buzhi[HANGS][LIES], int hang, int lie);
void setlei(char buzhi[HANGS][LIES], int hang, int lie);
void shuru(char mine[HANGS][LIES], char show[HANGS][LIES], int hang, int lie);
int a;
test.c
#include"saolei.h"
void caidan()
{
printf("*********************\n");
printf("**** 1、开始游戏 ****\n");
printf("**** 0、退出游戏 ****\n");
printf("*********************\n");
}
void caidan1()
{
printf("*********************\n");
printf("**** 1、再来一次 ****\n");
printf("**** 0、退出游戏 ****\n");
printf("*********************\n");
}
void saolei()
{
char mine[HANGS][LIES];
char show[HANGS][LIES];
chushihua(mine, HANGS, LIES, '0');
chushihua(show, HANGS, LIES, '*');
chushi(show, HANG, LIE);
setlei(mine, HANG, LIE);
shuru(mine,show, HANG, LIE);
}
int main()
{
srand((unsigned int)time(NULL));
do
{
caidan();
scanf("%d", &a);
switch (a)
{
case 1:
saolei();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
}
while (a);
}
saolei.h
#include"saolei.h"
void chushihua(char buzhi[HANGS][LIES], int hangs, int lies, char t)
{
int i = 0;
for (int i = 0; i < hangs; i++)
{
for (int j = 1; j < lies; j++)
{
buzhi[i][j] = t;
}
}
}
void chushi(char buzhi[HANGS][LIES], int hang, int lie)
{
for (int i = 0; i <= hang; i++)
{
printf("%d ", i);
}
printf("\n");
for (int i = 1; i <= hang; i++)
{
printf("%d ", i);
for (int j = 1; j <= lie; j++)
{
printf("%c ", buzhi[i][j]);
}
printf("\n");
}
}
void setlei(char mine[HANGS][LIES], int hang, int lie)
{
int geshu = M;
while (geshu)
{
int x = rand() % hang + 1;
int y = rand() % lie + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
geshu--;
}
}
}
void shuru(char mine[HANGS][LIES],char show[HANGS][LIES], int hang, int lie)
{
int x, y, t;
int m = 0;
int n = 0;
int b = 0;
int geshu = M;
while (n<hang*lie-geshu)
{
printf("请输入你要排雷的坐标\n");
printf("行:");
scanf("%d", &x);
printf("列:");
scanf("%d", &y);
if (x <= hang && x >= 1 && y <= lie && y >= 1)
{
if (show[x][y] != '*')
{
printf("该位置已被排查过,请重新选择");
}
else if (mine[x][y] == '1')
{
printf("踩到雷了,很遗憾失败了\n");
chushi(mine, HANG, LIE);
caidan1();
scanf("%d", &b);
if (b == 1)
{
break;
}
else if (b == 0)
{
a = 0;
break;
}
else
{
printf("输入错误,请重新输入\n");
}
}
else
{
m = 0;
for (int i = x - 1; i <= x + 1; i++)
{
for (int j = y - 1; j <= y + 1; j++)
{
if (mine[i][j] == '1')
{
m++;
}
}
}
show[x][y] = m + '0';
chushi(show, HANG, LIE);
/*chushi(mine, HANG, LIE);*/
n++;
}
}
else
{
printf("输入错误,请重新输入\n");
}
}
if (n == hang * lie - geshu)
{
printf("恭喜你,排雷成功\n");
chushi(mine, HANG, LIE);
caidan1();
scanf("%d", &b);
if (b == 1)
{
;
}
else if (b == 0)
{
a = 0;
}
else
{
printf("输入错误,请重新输入\n");
}
}
}