我们大家一定玩过扫雷游戏,那么,我们应该怎么样用C语言来实现他呢?
首先,我们要知道扫雷的游戏规则
在9*9的棋盘中逐个翻开方块,如果翻到了雷,失败,如果没有翻到,则在此方块显示周围八个坐标雷的个数。这样一个个翻方块,直到所有非雷方块翻完,则获得胜利。
首先,我们在玩游戏前先设置一个玩游戏前的准备模块(菜单,是否玩游戏的选择模块)
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void menu()
{
printf("***************************\n");
printf("******* 1.play *********\n");
printf("******* 0.exit *********\n");
printf("***************************\n");
}
void game()
{
}
void test()
{
int input = 0;
do
{
printf("请选择:>\n");
menu();
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏:\n");
break;
default:
printf("选择错误,请重新选择:\n");
break;
}
} while (input);
}
int main()
{
test();
system("pause");
return 0;
}
之后,我们就应该想想应该如何实现游戏
1.布置9*9的棋盘
2.布置10个雷
输入坐标
是雷 --------- 被炸死,游戏结束
不是雷 -------- 显示周围八个坐标有多少雷
直到把所有的非雷的位置全部找出来,游戏结束,扫雷成功
我们用两个数组(mine,show)来存储信息,mine数组储存布置好的雷的信息,show数组储存排查出的雷的信息。
1.创建 char mine[11][11] ;char show[11][11]l两个数组并初始化。(用init_board函数实现)
1.为什么棋盘只需要9*9,但却创建了11*11的两个数组?
因为我们在扫雷时在扫到一些极端位置(左上角这个位置)时,若要统计并显示它周围八个坐标雷的数量,这时就会出现数组越界的情况,为了避免这种情况出现,我们在数组的最外围加上一圈,也就是行列各增加两个。
2.为什么数组是字符类型的呢?
show数组中存储的是排查出的雷的信息,用*表示未排查的,’*‘是字符,而为了使得两个数组完全对应,因此mine数组也用char。
注意:在初始化的时候,我们设置的初始化函数传递的参数。init_board(数组名,行,列,要初始化的字符)
2.打印棋盘
注意:函数传递的参数(数组名,行(9),列(9)),我们让游戏者看到9*9的数组即可,而11*11的数组是我们在统计周围八个坐标雷的数量时防止数组越界而设置的,没有必要让游戏者看到。
void show_board(char arr[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
printf("%c ", arr[i][j]);
}
printf("\n");
}
}
但是,这样打印出来的结果没有行号和列号,对于玩游戏的人来说是极其不方便的。
显然,我们要升级代码,给打印出来的加上行号和列号。
行标号:行号在双层循环前面用一个循环,打印到第一行。
列标号:列标号在每一行的开始打印
void show_board(char arr[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
//列标号
for (i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
//行标号
printf("%d ", arr[i][j]);
for (j = 1; j <= col; j++)
{
printf("%c ", arr[i][j]);
}
printf("\n");
}
}
3.布置雷
在棋盘上面随机的布置10个雷,这就要用到rand()函数,而要用rand函数就要用srand函数,且srand函数只能用一次。(注意:使用库函数要引头文件)
void set_mine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COINT;
int x = 0;
int y = 0;
while (count)
{
x = rand() % row + 1;
y = rand() % col + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
4.排查雷(while循环)
玩家在每输入一个坐标后,
先判断是否合法(x<=行数,y<=列数);
一: 合法
1.该坐标下是雷,提示游戏失败,用break结束循环。
2.不是雷,在mine数组中计算该坐标周围八个坐标含有雷的数目(用get_mine_count函数),并且在show数组中相同位置把计算的雷数显示出来。
二: 不合法
提示坐标不合法,请重新输入,继续循环。
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("请输入要排查的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了\n");
show_board(mine, show, ROW, COL);
break;
}
else
{
int count = get_mine_count(mine, x, y);
show[x][y] = count + '0';
show_board(show, ROW, COL);
}
}
else
{
printf("坐标非法,请重新输入坐标:");
}
}
}
5.计算雷的数目
将mine数组该坐标周围八个坐标存储的字符相加减去8*'0',即可得到雷数。(这也是刚开始我们在mine数组中用字符1表示雷,用字符0表示非雷)
int get_mine_count(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
return mine[x - 1][y + 1] +
mine[x][y + 1] +
mine[x + 1][y + 1] +
mine[x - 1][y] +
mine[x + 1][y] +
mine[x - 1][y - 1] +
mine[x][y - 1] +
mine[x + 1][y - 1] -
8 * '0';
}
6.在排查雷时,函数中的循环什么时候结束呢?游戏胜利的条件又是什么呢?
显然while循环的终止条件是什么?
(while<row*col-EASY_COUNT) row*col:棋盘总格数 EASY_COUNT:雷数 row*col-EASY_COUNT:棋盘中不是雷的格子数目
应该设置一个计数器,玩家每排查一次,如果未排到雷的话,计数器加一。
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;
while (win<row*col-EASY_COINT)
{
printf("请输入要排查的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了\n");
show_board(mine, ROW, COL);
break;
}
else
{
int count = get_mine_count(mine, x, y);
show[x][y] = count + '0';
show_board(show, ROW, COL);
win++;
}
}
else
{
printf("坐标非法,请重新输入坐标:");
}
}
if (win == row*col - EASY_COINT)
{
printf("恭喜你,排雷成功\n");
show_board(mine, ROW, COL);
}
}
7.测试
到此,我们的扫雷游戏就设计完成了。
现在,我们测试一下,看看代码是否把预期的功能全部实现了,看逻辑是否正确。
将雷数(EASY_COUNT)改为80,并且将show数组打印出来,方便测试。
测试结果
这样,我们的扫雷游戏的基本功能就实现完成了。
看完觉得有收获的话点个赞哦
需要源码的可以私信,我发你