目录
1、成品展示
2、扫雷的实现讲解
2.1游戏制作三部曲
2.2从打印菜单选择是否开始或者结束的整体逻辑
2.3、扫雷游戏整体的逻辑实现
2.3.1、棋盘设计(初始化棋盘和打印棋盘)
2.3.2、布置雷
2.3.3、排查雷
3、完结撒花
1、成品展示
扫雷成品
全部代码分享
game.h:
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#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 SetMine(char arr[ROWS][COLS], int row, int col);
void FindBoard(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col);
text.c:
#include "game.h"
void meau()
{
printf("************************************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("************************************\n");
}
void game()
{
//完成扫雷游戏
char mine[ROWS][COLS] = { 0 };//数组全部初始化为字符0
char show[ROWS][COLS] = { 0 };//数组全部初始化为字符*
InitBoard(mine, ROWS, COLS, '0');//初始化棋盘
InitBoard(show, ROWS, COLS, '*');
//布置雷的个数
//就在9*9棋盘上面布置10个雷
SetMine(mine, ROW, COL);
DisplayBoard(show, ROW, COL);//打印棋盘
//DisplayBoard(mine, ROW, COL);
FindBoard(show,mine,ROW,COL);//排查雷
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
meau();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("已退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
}
} while (input);
}
int main()
{
test();
return 0;
}
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 <= col; 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");
}
void SetMine(char arr[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (arr[x][y] == '0')
{
arr[x][y] = '1';
count--;
}
}
}
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
//因为雷为字符1,可以根据ASCLL值进行计算
return mine[x - 1][y - 1] + //这里也可以使用for循环,感兴趣的可以试一下
mine[x - 1][y] +
mine[x - 1][y + 1] +
mine[x][y - 1] +
mine[x][y + 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] - 8 * '0';
}
void FindBoard(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
{
int win = ROW * COL - EASY_COUNT;
int x = 0;
int y = 0;
while (win)
{
printf("请输入要排查的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//检查坐标的有效性
{
if (show[x][y] == '*')
{
if (mine[x][y] == '1')//判断是不是雷
{
printf("很遗憾!你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else//统计坐标周围雷的个数
{
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(show, ROW, COL);
win--;
}
}
else
{
printf("该位置已被排查过了,请重新排查\n");
}
}
else
{
printf("输入坐标非法,请重新输入\n");
}
}
if (win == 0)
{
printf("恭喜你,排雷成功!\n");
DisplayBoard(mine, ROW, COL);
}
}
2、扫雷的实现讲解
2.1游戏制作三部曲
对于扫雷游戏的实现我们应在编译器中先创建三个文件(下面以VS2022为例)1.text.c,用来测试整个游戏的逻辑。2.game.h,用来存放函数的声明。3.game.c,用来存放函数的实现。game.h和game.合起来为游戏逻辑的实现。
2.2从打印菜单选择是否开始或者结束的整体逻辑
这里设计的是整个游戏测试的逻辑,除了头文件,都是在taxt.c中完成的。比较简单我们直接上代码
game.h:
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
taxt.c:
#include "game.h"
void meau()
{
printf("************************************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("************************************\n");
}
void test()
{
int input = 0;
do
{
meau();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始游戏\n");
break;
case 0:
printf("已退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
}
} while (input);
}
int main()
{
test();
return 0;
}
代码整理好后我们可以运行,查看代码逻辑是否正确,结果如下
2.3、扫雷游戏整体的逻辑实现
2.3.1、棋盘设计(初始化棋盘和打印棋盘)
我们要实现简单的扫雷游戏,游戏棋盘先设计成99的一个棋盘,成品如图所示:
我们先对扫雷进行分析,要完成扫雷游戏我们肯定要设置雷(这里说明我们用字符1来表示所设置的雷,字符0表示没有雷),而在游戏过程中要向游戏玩家展示的是如上图所示的一片未知区(如上图,展示棋盘初始化用字符来表示整个棋盘),设置雷的位置肯定不能展示出来,所以我们需要制定两个棋盘即定义两个二维数组,一个用来存放雷使用,一个用来向玩家展示使用。先假定棋盘大小为99,我们在选择坐标时需要判定其位置是不是雷,如果是雷则游戏结束,如果不是雷我们需要统计这个位置四周8个位置的雷的个数并显示出来,这其实并不难实现,但当我们统计棋盘四边的雷的个数的话,如下图:
我们如果统计下面那个黄色区域,棋盘的大小为99,下面哪一行是统计不了的,为防止这类情况发生,我们可以直接把两个二维数组定义成1111的大小,而在打印的时候只打印第1行到第9行和第1列到第9列即可。如下图:
所以对于两个二维数组,布置雷的那个棋盘初始化为全字符0,展示的棋盘初始化为全为字符。代码如下:
game.h:
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
void InitBoard(char arr[ROWS][COLS], int rows, int cols,char set);
void DisplayBoard(char arr[ROWS][COLS], int row, int col);
taxt.c:
#include "game.h"
void meau()
{
printf("************************************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("************************************\n");
}
void game()
{
//完成扫雷游戏
char mine[ROWS][COLS] = { 0 };//数组全部初始化为字符0
char show[ROWS][COLS] = { 0 };//数组全部初始化为字符*
InitBoard(mine, ROWS, COLS, '0');//初始化棋盘
InitBoard(show, ROWS, COLS, '*');
DisplayBoard(show, ROW, COL);//打印棋盘
//布置雷的个数
}
void test()
{
int input = 0;
do
{
meau();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("已退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
}
} while (input);
}
int main()
{
test();
return 0;
}
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 <= col; 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");
}
可以看到在定义时,使用宏定义定义了4个数据,ROW,COL,ROWS,COLS,这是因为以后方便我们调节游戏难度,比如:我们要增大难度打印一个20*20的棋盘,只需在ROW,COL,后该成20即可,如图:
至于对其问题,只需在打印输出的占位符前面加一个符号就行,这里就不在过多赘述。
2.3.2、布置雷
下面我们需要在二维数组mine里面布置雷,我们可以先设定好布置雷的数量,因为没把游戏雷是随机布置的,这不难想到会使用rand生成随机数的函数,生成随机数在存放雷的时候我们要在19行和19列之间进行存放,所以生成的随机数要在1~9之间,在没有存放雷的位置将’0‘改为’1‘,代码见下:
game.h:
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#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 SetMine(char arr[ROWS][COLS], int row, int col);
text.c:
#include "game.h"
void meau()
{
printf("************************************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("************************************\n");
}
void game()
{
//完成扫雷游戏
char mine[ROWS][COLS] = { 0 };//数组全部初始化为字符0
char show[ROWS][COLS] = { 0 };//数组全部初始化为字符*
InitBoard(mine, ROWS, COLS, '0');//初始化棋盘
InitBoard(show, ROWS, COLS, '*');
DisplayBoard(show, ROW, COL);//打印棋盘
//布置雷的个数
//就在9*9棋盘上面布置10个雷
SetMine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL);
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
meau();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("已退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
}
} while (input);
}
int main()
{
test();
return 0;
}
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 <= col; 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");
}
void SetMine(char arr[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (arr[x][y] == '0')
{
arr[x][y] = '1';
count--;
}
}
}
代码敲完我们可以把mine棋盘打印出来进行观察是否正确,如下图:
可以看到每次布置的雷均为10个且位置都是随机的。
2.3.3、排查雷
在分析排查雷的逻辑之前,我们先把text.c,里面的打印棋盘DisBoard函数和布置雷的SetMine函数的顺序交换一下,因为要先布置雷后才要打印棋盘嘛。代码如下:
text.c:
#include "game.h"
void meau()
{
printf("************************************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("************************************\n");
}
void game()
{
//完成扫雷游戏
char mine[ROWS][COLS] = { 0 };//数组全部初始化为字符0
char show[ROWS][COLS] = { 0 };//数组全部初始化为字符*
InitBoard(mine, ROWS, COLS, '0');//初始化棋盘
InitBoard(show, ROWS, COLS, '*');
//布置雷的个数
//就在9*9棋盘上面布置10个雷
SetMine(mine, ROW, COL);
DisplayBoard(show, ROW, COL);//打印棋盘
//DisplayBoard(mine, ROW, COL);
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
meau();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("已退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
}
} while (input);
}
int main()
{
test();
return 0;
}
下面我们实现排查雷的逻辑:
在排查雷时,要用到mine和show两个二维数组,所以定义排查雷的函数要把两个二维数组都传参传过去,之后肯定要输入要排查的坐标,因为我们只能在99的棋盘里面查找,所以要先去判断输入坐标的有效性,即排查坐标是否在99的棋盘内,如果排查坐标有效,那么我们就进一步判断该位置是不是雷,如果是则结束游戏,如果不是则需统计四周雷的个数并显示出来,到最后如果把不是雷的位置全部排查出来则游戏获胜,所以我们要创个变量记录空白位置,代码如下:
game.h:
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#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 SetMine(char arr[ROWS][COLS], int row, int col);
void FindBoard(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col);
text.c:
#include "game.h"
void meau()
{
printf("************************************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("************************************\n");
}
void game()
{
//完成扫雷游戏
char mine[ROWS][COLS] = { 0 };//数组全部初始化为字符0
char show[ROWS][COLS] = { 0 };//数组全部初始化为字符*
InitBoard(mine, ROWS, COLS, '0');//初始化棋盘
InitBoard(show, ROWS, COLS, '*');
//布置雷的个数
//就在9*9棋盘上面布置10个雷
SetMine(mine, ROW, COL);
DisplayBoard(show, ROW, COL);//打印棋盘
//DisplayBoard(mine, ROW, COL);
FindBoard(show,mine,ROW,COL);//排查雷
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
meau();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("已退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
}
} while (input);
}
int main()
{
test();
return 0;
}
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 <= col; 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");
}
void SetMine(char arr[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (arr[x][y] == '0')
{
arr[x][y] = '1';
count--;
}
}
}
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
//因为雷为字符1,可以根据ASCLL值进行计算
return mine[x - 1][y - 1] + //这里也可以使用for循环,感兴趣的可以试一下
mine[x - 1][y] +
mine[x - 1][y + 1] +
mine[x][y - 1] +
mine[x][y + 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] - 8 * '0';
}
void FindBoard(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
{
int win = ROW * COL - EASY_COUNT;
int x = 0;
int y = 0;
while (win)
{
printf("请输入要排查的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//检查坐标的有效性
{
if (show[x][y] == '*')
{
if (mine[x][y] == '1')//判断是不是雷
{
printf("很遗憾!你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else//统计坐标周围雷的个数
{
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(show, ROW, COL);
win--;
}
}
else
{
printf("该位置已被排查过了,请重新排查\n");
}
}
else
{
printf("输入坐标非法,请重新输入\n");
}
}
if (win == 0)
{
printf("恭喜你,排雷成功!\n");
DisplayBoard(mine, ROW, COL);
}
}
我们如果想检验代码是否正确,是否可以排雷成功,可以把雷的数量改成80,并且在打印的时候将mine的二维数组也打印出来,如图:
3、完结撒花
其中其实还有许多细节,比如:重复排查,计算周围雷的数量等我都在代码里面完善了。大家感兴趣的话可以自己上手试一试就知道了,这里就不再一一赘述啦。如果有什么问题或者不懂的地方欢迎下方评论留言,互相指教感谢支持!