嗨,小伙伴们,大家好!还记得电脑桌面里面的扫雷游戏吗?
今天我们就来动手实践一下这款休闲小游戏---扫雷,准备好了吗? 我们开始咯!
1.扫雷游戏分析和设计
1.1扫雷游戏的功能说明
-
使用控制台实现经典的扫雷游戏
-
游戏可以通过菜单实现继续玩或者退出游戏
-
扫雷的棋盘是 9*9的格子
-
默认随机布置10个雷
-
可以排查雷
- 如果位置不是雷,就显示周围有几个雷
- 如果位置是雷,就被炸死 ,游戏结束
把除10个雷以外的所有非雷都找出来,排雷成功,游戏结束
游戏的界面:
开始界面 排雷界面 排雷失败界面
1.2 游戏的分析和设计
为了实现扫雷游戏,我们需要在 9*9 的棋盘上布置雷的信息和排查雷,我们首先想到的就是创建一个 9*9 的数组来存放信息
但是边界的位置,我们需要额外设置一个棋盘,在原来棋盘的基础上进行延伸并将其赋予0的数值
我们把棋盘设定好后,就可以开始啦
首先,为扫雷游戏创建一个主菜单 menu() 函数,1表示真,进入游戏; 0表示假,退出游戏
void menu() {
printf("******************************\n");
printf("****** 1. play ************\n");
printf("****** 0. exit ************\n");
printf("******************************\n");
}
接下来,我们到 main 函数中调用 menu() 函数
int main() {
srand((unsigned int)time(NULL));
int input = 0;
do {
menu();
printf("请选择:(1/0)>");
scanf("%d", &input);
switch (input) {
case 1:
game();
break;
case 0:
printf("退出游戏!\n");
break;
default:
printf("输入错误,请重新选择!\n");
break;
}
} while (input);
return 0;
}
整体思路清晰后,我们就可以设置棋盘了,我们将棋盘放在game()函数中
第一步,我们要用两个数组,分别存放雷的信息('1'表示这个位置是地雷,'0'表示这个位置无地雷)和存放排查出的雷的信息
char mine[ROWS][COLS]; //存放布置好的雷
char show[ROWS][COLS]; //存放排查出雷的信息
第二步,我们需要对两个数组初始化
mine数组(布置好雷的数组初始化全为'0',表示这个数组暂时还没有设置地雷)
show数组(初始化全为'*')
//初始化棋盘
// mine数组最开始全是'0'
// show数组最开始全是'*'
initBoard(mine, ROWS, COLS, '0');
initBoard(show, ROWS, COLS, '*');
我们新建一个 game.h 的头文件包含所有棋盘与雷的函数声明,并新建一个 game.c 来完成函数的实现,并在测试文件 test.c 文件中完成对扫雷游戏的测试(注意: test.c 文件中包含 game.h)
game.h
我们要先规划好在 game.h 头文件中所包含的内容,首先定义棋盘 的 行列大小 和 隐藏棋盘的大小
首先,在 game.h 的头文件中建一个 初始化函数 ,用来 初始化 我们的两个棋盘
注意啦,这里有四个参数, 我们的棋盘 , 行 , 列 还有 字符 ,然后完成对两个棋盘的 初始化
实际参数的两个函数如下:
完成之后,我们定义一个 DisplayBoard() 函数 来打印我们的棋盘, 并展示"show"这个棋盘,这里要规划好我们的形式参数(只能打印 9*9 的玩家可排查雷的区域)
实际参数的函数:
接下来我们看一下打印效果:
我们知道数组第一位下标为0,那我们可以在第一位打上数字方便后续的排查
设置完棋盘之后,我们就可以布置雷了
定义 SetBoard() 函数,利用 rand() 函数随机埋雷,将 '1' 当做是 雷 , '0' 代表 非雷
当然咯,这里虽然是随机埋雷,但是其"种子"相同,即我们每次打开雷的地方相同,这时候,我们在主函数中引入 srand()函数 , 来改变其种子
埋雷后,就该找雷了,我们此时设置 CheckBoard()函数 ,同时传递我们开始所建立的两个棋盘,如果踩到雷即展示所有的雷并退出
我们首先定义一个 EASY_COUNT 表示雷的数量,这里我来赋值为 10
while语句 条件表示为 排查的次数 , row*col 表示 所有的格数,减去雷的值 即为我们 要排查的空白值,将这个值设置为 win。如果 win 与 后面的值相等,说明我们已经找到了所有的空位,剩下的全都是雷,意味着我们扫雷成功,结束游戏
//排查棋盘
void CheckBoard(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_COUNT) {
printf("请输入要排查雷的坐标:\n");
scanf("%d", &x);
scanf("%d", &y);
if (x >= 1 && x <= row && y >= 1 && y <= col) {
//键盘录入的 x,y 坐标在合法的范围内
if (mine[x][y] == '1') {
//该坐标为雷
printf("很遗憾,你被炸死了!\n");
DisplayBoard(mine, ROW, COL);
//打印 mine数组 存放雷的信息
break;
//退出循环
}
else {
//该坐标不是雷
//统计这个坐标周围雷的个数
int count = CountBoard(mine, x, y);
show[x][y] = count + '0';
//在 show数组 中在该坐标处填入数字字符
DisplayBoard(show, ROW, COL);
win++;
//每排查完一次,找到的空位数自加一次
}
}
else {
//x或y或者x和y的坐标都不合法,重新输入
printf("输入的坐标有误,请重新输入!\n");
}
}
if (win == row * col - EASY_COUNT) {
//如果 win 与 后面的值相等,说明我们已经找到了所有的空位,剩下的全都是雷
//意味着我们扫雷成功,结束游戏
printf("恭喜你,排查成功!\n");
DisplayBoard(mine, ROW, COL);//打印 mine数组存放雷的信息
}
}
上述中,我们需要新建一个函数来表示周围雷的个数
(Tips: 字符'0'的ASCII码值为48,字符'1'的ASCII码值为49, 字符'2'的ASCII码值为50,'0' - '0' = 0, '1' - '0' = 1, '2' - '0' = 2 ,'4' - '0' = 4, 不难发现,任意一个数字字符和字符'0' 相减,可以得到相应的数字)
那么统计这个坐标周围雷的个数,我们只需要把这个坐标周围的八个坐标字符都相加,再和字符'0'相减,就可以得到这个坐标周围雷的个数,把这个数值存放在 count 里面。此时我们需要打印 show 数组, 展示给玩家这个坐标周围雷的个数(字符型),因此,我们需要 count + '0',存入到相应的 show 数组 该点的坐标中
这个时候,简易版的扫雷游戏就完成啦,我们来看看它的实际效果
这里是完整代码:
game.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9 //玩家可以排查雷的行数
#define COL 9 //玩家可以排查雷的列数
#define ROWS ROW+2 //为了防止最底下一层的坐标越界,
//我们在设计的时候,将数组扩大一圈
#define COLS COL+2 //雷还是布置在中间的 9*9 的坐标上,
//周围一圈不去布置雷,解决了越界问题
#define EASY_COUNT 10
//初始化棋盘
void initBoard(char arr[ROWS][COLS], int rows, int cols, char set);
//打印棋盘
void DisplayBoard(char arr[ROWS][COLS], int row, int col);
//布置雷
void SetBoard(char arr[ROWS][COLS], int row, int col);
//排查雷
void CheckBoard(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int row, int col);
game.c
#include"game.h"
//初始化棋盘
void initBoard(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 DisplayBoard(char arr[ROWS][COLS], int row, int col) {
printf("--------------扫雷游戏---------------\n");
for (int i = 0; i <= row; i++) {
printf("%d ", i); //打印一行的 0 1 2 3 4 5 6 7 8 9
}
printf("\n"); //打印完之后换行
for (int i = 1; i <= row; i++) {
printf("%d ", i); //打印一列的 1 2 3 4 5 6 7 8 9
for (int j = 1; j <= col; j++) {
printf("%c ", arr[i][j]);
}
printf("\n");
}
}
//布置棋盘
void SetBoard(char arr[ROWS][COLS], int row, int col) {
int count = EASY_COUNT; //布置10个雷
while (count != 0) {
int x = rand() % row + 1; //生成随机坐标
int y = rand() % col + 1;
if (arr[x][y] == '0') { //该坐标为非雷区域
arr[x][y] = '1'; //将雷布置在此坐标
count--; //每布置完一个雷,雷的总数减1
}
}
}
//统计这个坐标雷的个数
int CountBoard(char arr[ROWS][COLS], int x, int y) {
return arr[x - 1][y - 1] + arr[x - 1][y] +
arr[x - 1][y + 1] + arr[x][y - 1] +
arr[x][y + 1] + arr[x + 1][y - 1] +
arr[x + 1][y] + arr[x + 1][y + 1] - 8 * '0';
}
//排查棋盘
void CheckBoard(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_COUNT) {
printf("请输入要排查雷的坐标:\n");
scanf("%d", &x);
scanf("%d", &y);
if (x >= 1 && x <= row && y >= 1 && y <= col) {
//键盘录入的 x,y 坐标在合法的范围内
if (mine[x][y] == '1') {
//该坐标为雷
printf("很遗憾,你被炸死了!\n");
DisplayBoard(mine, ROW, COL);
//打印 mine数组 存放雷的信息
break;
//退出循环
}
else {
//该坐标不是雷
//统计这个坐标周围雷的个数
int count = CountBoard(mine, x, y);
show[x][y] = count + '0';
//在 show数组 中在该坐标处填入数字字符
DisplayBoard(show, ROW, COL);
win++;
//每排查完一次,找到的空位数自加一次
}
}
else {
//x或y或者x和y的坐标都不合法,重新输入
printf("输入的坐标有误,请重新输入!\n");
}
}
if (win == row * col - EASY_COUNT) {
//如果 win 与 后面的值相等,说明我们已经找到了所有的空位,剩下的全都是雷
//意味着我们扫雷成功,结束游戏
printf("恭喜你,排查成功!\n");
DisplayBoard(mine, ROW, COL);//打印 mine数组存放雷的信息
}
}
test.c
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include"game.h"
void menu() {
printf("******************************\n");
printf("****** 1. play ************\n");
printf("****** 0. exit ************\n");
printf("******************************\n");
}
void game() {
char mine[ROWS][COLS]; //存放布置好的雷
char show[ROWS][COLS]; //存放排查出雷的信息
//初始化棋盘
// mine数组最开始全是'0'
// show数组最开始全是'*'
initBoard(mine, ROWS, COLS, '0');
initBoard(show, ROWS, COLS, '*');
//打印棋盘
DisplayBoard(show, ROW, COL);
//DisplayBoard(mine, ROW, COL);
//布置雷
SetBoard(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL);
//排查雷
CheckBoard(mine, show, ROW, COL);
}
int main() {
srand((unsigned int)time(NULL));
int input = 0;
do {
menu();
printf("请选择:(1/0)>");
scanf("%d", &input);
switch (input) {
case 1:
game();
break;
case 0:
printf("退出游戏!\n");
break;
default:
printf("输入错误,请重新选择!\n");
break;
}
} while (input);
return 0;
}
好啦,今天就到这里啦,我们下次再见!