基本构思
1.菜单:创建一个简单的菜单来可供选择进行游戏或退出
2.扫雷游戏的创建:
a.布局的构成
b.布置地雷
c.获取玩家的坐标,并扫出周围一圈的地雷个数
d.判断游戏的成败
(完整代码在底下)
1.菜单的创建
void menu()
{
printf("*************************\n");
printf("***** 1.PLAY *****\n");
printf("***** 0.EXIT *****\n");
printf("*************************\n");
}
2.扫雷游戏
a.布局的构建:
首先我们要知道扫雷游戏需要有地雷的块和空白块区分,在选择了空白块后还需要展示附近3*3内地雷的数目。既要有地雷的放置还需要统计,仅通过一个数组是比较难以实现的。所以我们可以创建两个二位数组,分别进行地雷、空白块的放置和展示、统计的作用。
相应的我们就要创建两个二维数组,那他们的大小应该是多少呢?我们的目标是创建一个9*9的布局,那我们数组的应该是[9][9]大小吗?
答案应该是创建两个个[11][11]大小的的二维数组,为了防止地雷安置在边界的时候扫描周围3*3区域时会发生越界现象,我们应该目标大小上对上下纵向和左右横向分别+1。
char game1[R][C] = { 0 };//用于储存
char show[R][C] = { 0 };//检测及展示
我们该怎么将数组变成地雷和无雷区呢?那就是先要将数组分别初始化
对于game1数组,即储存数组,我们可以先将他全部赋予字符‘0’来代表无雷区,后续再安置‘1’代表地雷(注意:‘0’和‘1’是字符噢
对于show数组,即展示和统计的数组我们可以赋予一种喜欢的字符号来表示空白块,给玩家进行选择,如果选到了地雷将结束游戏,是无雷区则会展示附近3*3区域内的地雷个数
//数组初始化
init(game1, R, C,'0');
init(show, R, C,'*');//我选择用‘*’来表示空白块
void init(char ch[R][C],int a,int b,char set)//数组初始化
{
int i = 0;
int j = 0;
for (i = 0; i < a; i++)
{
for (j = 0; j < b; j++)
{
ch[i][j] = set;// 如果我们将set改为‘0’或‘*’,就只能给一组数组赋值
//这样的话则会要创建多一个函数来赋值其他的数组
} //会比较复杂,所以我们就可以在定义函数的时候多加一个字符变量
} //来自行选择填充数组的字符,实现一种函数多种用途
}
看到代码可能有人要问了,为什么不可以直接在函数里赋值呢,而是要通过以函数调用的形式将要赋值的字符带过去。
因为我们想的是以一个函数来实现多种选择,如果在函数体内直接赋值的化就不能对多种函数赋值为不同的字符。
我们已经实现了数组的初始化,下一步则是将其打印出来。
(我们可以先把两种数组都打印出来方便观察,到后面正式进行游戏的时候记得取消打印噢
void Printf(char ch[R][C],int a,int b)//打印游戏界面
{
printf("-----------------------\n");//分割线
int i = 0;
int j = 0;
for (i = 0; i <= a; i++)
{
printf("%d ",i);//打印横向坐标
}
printf("\n");
for (i = 1; i <= a; i++)//别忘了我们的数组是11*11.从i=1开始,下标1则是数组的第二位。
{
printf("%d ", i);//打印纵向坐标
for (j = 1; j <= b; j++)
{
printf("%c ", ch[i][j]);
}
printf("\n");
}
}
效果图
b.地雷的布置
对于地雷的布置需要满足三个条件:
1.在9*9范围内
2.地雷个数可控(我们也可以调节地雷个数的多少来构成游戏难度的难易
3.具有随机性和不重复性
srand((unsigned int)time(NULL));
//随机生成地雷
boom(game1, R2, C2);
void boom(char ch[R][C], int a, int b)//放置地雷
{
int i = 0;
int j = 0;
int h = 0;
int count = level;//level=10,地雷的个数
while (count)//不能用for循环的原因:for只能指定循环10次,如果赋值不成功
//还是继续进行下一步,地雷就有可能不能铺够十个
{
i = rand() % a + 1;//表示生成1到a的随机数
j = rand() % b + 1;//取余a后得到0~a-1的范围
if (ch[i][j] == '0')//+1后得到1~a的范围
{
ch[i][j] = '1';//字符1为地雷
count--;
}
}
}
效果图
c.获取玩家的坐标,并扫出周围一圈的地雷个数
d.判断游戏的成败
后面两个我们就一起来讲吧,因为每当玩家进行一次操作我们都需要对目前的局面进行判断是否碰到了地雷导致结束或继续下一步
目标实现:
1.我们要求玩家输入的坐标不能超出范围
2.不能重复选择已经选择过的坐标
3.判断是否踩到地雷,是则结束游戏,否则检测周围3*3区域获取地雷个数并赋值给show数组所选坐标
//玩家选取坐标进行扫雷
play(show,game1,R2,C2);
void play(char show[R][C],char ch[R][C],int a,int b)//输入坐标扫雷
{
int x = 0;
int y = 0;
int win = 0; //level我定义为了10表示为一共有10个地雷
while (win<a*b-level)//获胜的条件:选出了全部的无雷区
{
printf("请输入坐标进行扫雷\n");
scanf("%d %d", &x, &y);
if ((x >= 1 && x <= a) && (y >= 1 && y <= b))//防止选到范围外
{
if (show[x][y] != '*')
{
printf("坐标已被选择,请重新选择\n");
continue;//回到开始的while循环
}
if (ch[x][y] == '1')//选中地雷 失败
{
printf("BOOM!!! 很遗憾,失败:<\n");
printf("-----地雷分布-----\n");
Printf(ch, a, b);//打印game数组展示地雷分布
break;
}
else
{
int det = detection(ch, x, y);//这里我们下一段讲噢,不要着急
show[x][y] = det+'0';
Printf(show,a,b);//返回周围地雷个数的数值
win++;
}
}
else
{
printf("所选坐标无效,请重新选择\n");
}
}
if (win == (a * b) - level)//注意除了满足胜利条件跳出while循环,还有其他条件
{ //也会break跳出循环,所以我们要判断是否满足胜利条件
printf("恭喜你,成为一名合格的排雷兵\n");
}
}
检测周围3*3地雷个数的实现函数
记得结合上面的代码一起看噢
我们以选取的坐标为(x,y),则其周围的坐标为:(我以x为行,y为列,从左往右,从上往下逐渐增大)
首先先将周围一圈除自身外8个坐标所相加,不要忘记我们之前存放的都是字符噢,查看ASCII表可以知道'0'字符的对应值为48,‘1’字符为49。
从此我们是不是可以拿各个坐标分别减去‘0’就可以得到地雷的个数呢
如果周围有一个地雷(地雷为字符‘1’,值为49),则相加分别为49+48*7,我们再减去48*8可得到1,即地雷的个数.
int detection(char ch[R][C], int x, int y)//检测所选择坐标周围的地雷个数
{ //注意不要把x,y也加进来
return (ch[x - 1][y - 1] + ch[x - 1][y] + ch[x - 1][y + 1]
+ ch[x][y - 1]+ ch[x][y + 1]
+ ch[x + 1][y - 1] + ch[x + 1][y] + ch[x + 1][y + 1] - 8 * '0');
}
目前我们就已经分别实现了扫雷游戏的各个基础功能,已经可以开心游玩了。对于更高级的功能和优化,请等待我的后续更新叭
完整代码:
game.h头文件
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define R2 9
#define C2 9
#define R 11
#define C 11
#define level 10//地雷个数
void menu();
void init(char ch[R][C], int a, int b, char set);//数组初始化
void boom(char ch[R][C], int a, int b);//放置地雷
void Printf(char ch[R][C], int a, int b);//打印游戏界面
int detection(char ch[R][C], int x, int y);//检测所选择坐标周围的地雷个数
void play(char show[R][C], char ch[R][C], int a, int b);
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void game()
{
char game1[R][C] = { 0 };//用于储存
char show[R][C] = { 0 };//检测及展示
//数组初始化
init(game1, R, C,'0');
init(show, R, C,'*');
//随机生成地雷
boom(game1, R2, C2);
Printf(game1, R2, C2);//游玩时,记得备注取消掉
//打印界面及添加坐标
Printf(show,R2,C2);
//玩家选取坐标进行扫雷
play(show,game1,R2,C2);
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
int a = 1;
menu();
printf("输入对应数字开始或退出游戏\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始游戏\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default :
printf("选择无效,请重新输出对应数字\n");
break;
}
} while (input);
}
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("*************************\n");
printf("***** 1.PLAY *****\n");
printf("***** 0.EXIT *****\n");
printf("*************************\n");
}
void init(char ch[R][C],int a,int b,char set)//数组初始化
{
int i = 0;
int j = 0;
for (i = 0; i < a; i++)
{
for (j = 0; j < b; j++)
{
ch[i][j] = set;
}
}
}
void boom(char ch[R][C], int a, int b)//放置地雷
{
int i = 0;
int j = 0;
int h = 0;
int count = level;//level=10
while (count)//不能用for循环的原因:for只能指定循环10次,如果赋值不成功
//还是继续进行下一步,地雷就有可能不能铺够十个
{
i = rand() % a + 1;//表示生成1到a的随机数
j = rand() % b + 1;//取余a后得到0~a-1的范围
if (ch[i][j] == '0')//+1后得到1~a的范围
{
ch[i][j] = '1';//字符1为地雷
count--;
}
}
}
void Printf(char ch[R][C],int a,int b)//打印游戏界面
{
printf("-----------------------\n");
int i = 0;
int j = 0;
for (i = 0; i <= a; i++)
{
printf("%d ",i);
}
printf("\n");
for (i = 1; i <= a; i++)
{
printf("%d ", i);
for (j = 1; j <= b; j++)//横向打印记得要从1开始,不如坐标就会有两个0
{
printf("%c ", ch[i][j]);
}
printf("\n");
}
}
int detection(char ch[R][C], int x, int y)//检测所选择坐标周围的地雷个数
{
return (ch[x - 1][y - 1] + ch[x - 1][y] + ch[x - 1][y + 1]
+ ch[x][y - 1]+ ch[x][y + 1]
+ ch[x + 1][y - 1] + ch[x + 1][y] + ch[x + 1][y + 1] - 8 * '0');
}
void play(char show[R][C],char ch[R][C],int a,int b)//输入坐标扫雷
{
int x = 0;
int y = 0;
int win = 0;
while (win<a*b-level)
{
printf("请输入坐标进行扫雷\n");
scanf("%d %d", &x, &y);
if ((x >= 1 && x <= a) && (y >= 1 && y <= b))//防止选到范围外
{
if (show[x][y] != '*')
{
printf("坐标已被选择,请重新选择\n");
continue;
}
if (ch[x][y] == '1')//选中地雷 失败
{
printf("BOOM!!! 很遗憾,失败:<\n");
printf("-----地雷分布-----\n");
Printf(ch, a, b);
break;
}
else
{
int det = detection(ch, x, y);
show[x][y] = det+'0';//这里看看回放
Printf(show,a,b);
win++;
}
}
else
{
printf("所选坐标无效,请重新选择\n");
}
}
if (win == (a * b) - level)
{
printf("恭喜你,成为一名合格的排雷兵\n");
}
}