目录
思路
1.设置一个游戏菜单,让玩家可以自主选择开始游戏或者退出游戏。
2. 定义并初始化两个二维数组,一个用于存放雷阵,一个用于打印出游戏界面(玩家看的)。
3. 游戏主界面的打印。
4. 在雷阵中布置雷(随机生成)。
5. 排查雷(游戏主体)。
6. 结合以上所有步骤,完成扫雷游戏
实现
首先我们打开我们的Visual Studio,创建一个项目
为了代码的简洁性和方便我们调试代码,我们在这里创建了一个头文件,两个源文件
接下来我们开始编写程序一步步实现我们的扫雷游戏。
1.游戏菜单
1.1 打印游戏菜单
首先我们可以使用printf函数打印出一个相对精美的游戏菜单
代码如下:
//test.c
void menu()
{
printf("********************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("********************\n");
}
void test()
{
menu();//打印游戏菜单
}
int main()
{
test();
return 0;
}
1.2 玩家自主选择
我们要实现玩家自主选择玩还是不玩的功能,可以引入一个input变量来接受玩家键入的数据,然后通过switch语句来根据玩家键入的数据作出对应的操作。
同时,如果玩家玩一次不过瘾想继续玩,我们就需要利用循环结构来完成这一操作,我们可以发现,菜单一开始肯定是要打印出来的,所以是先做一次再判断,我们用do...while语句来实现这个功能。
代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
void menu()
{
printf("********************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("********************\n");
}
void game()
{
printf("扫雷\n");
}
void test()
{
int input = 0;
do
{
menu();//打印游戏菜单
printf("请做出你的选择:>");//提示玩家输入
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);//如果玩家键入0,游戏结束,跳出循环
}
int main()
{
test();
return 0;
}
2.定义并且初始化二维数组
我们要实现扫雷游戏的功能,首先需要一个二维数组来存放地雷,其次,玩家肯定不能直接看到地雷的位置,这时候我们就需要另一个二维数组用于给玩家看。
2.1 定义两个二维数组
为了后续我们能够升级扫雷难度(扩张行和列),我们可以在game.h文件中利用#define定义的常量标识符来充当行和列,届时我们只需要修改ROW和COL的值就可以更改扫雷的行列数。注:
假设我们要实现9*9的扫雷,如果我们定义的是9*9的二维数组,我们在扫最边上的位置时,就会造成数组越界,所以为了避免这种情况的发生,我们需要定义一个11*11(ROW+2*COL+2)的二维数组。
代码如下:
//test.c
#include "game.h" //包含头文件
void menu()
{
printf("********************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("********************\n");
}
void game()
{
char mine[ROWS][COLS] = { 0 };//定义地雷数组
char show[ROWS][COLS] = { 0 };//定义展示数组
}
void test()
{
int input = 0;
do
{
menu();//打印游戏菜单
printf("请做出你的选择:>");//提示玩家输入
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);//如果玩家键入0,游戏结束,跳出循环
}
int main()
{
test();
return 0;
}
//game.h
#define _CRT_SECURE_NO_WARNINGS 1
//因为test.c文件中包含了game.h,所以可以直接在game.h文件中包含头文件
#include <stdio.h>
//定义行列数
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
//game.c
#include "game.h"//包含头文件
void init_board(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
board[i][j] = set;//给数组中每个元素赋值
}
}
}
2.2 初始化二维数组
初始化二维数组之前,我们先得知道我们需要把它们初始化成什么,为了后续方便,我们把地雷数组的雷赋值为'1',其他位置赋值为'0'。(这个后文会讲到),而展示数组,我们可以把他全部赋值为 '*',因为'*'代表未知,当然你要想设置成其他字符也可以,这里我们还是把它初始化为'*'。
接下来我们设置一个函数来初始化两个二维数组
代码如下:
//test.c
void game()
{
//定义地雷数组
char mine[ROWS][COLS] = { 0 };
//定义展示数组
char show[ROWS][COLS] = { 0 };
//初始化地雷数组
init_board(mine, ROWS, COLS, '0');
//初始化展示数组
init_board(show, ROWS, COLS, '*');
}
//game.h
//因为test.c文件中包含了game.h,所以可以直接在game.h文件中包含头文件
#include <stdio.h>
//定义行列数
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
//初始化二维数组
void init_board(char board[ROWS][COLS], int rows, int cols, char set);
//game.c
#include "game.h"//包含头文件
void init_board(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
board[i][j] = set;//给数组中每个元素赋值
}
}
}
3.打印游戏主界面
我们先看看游戏界面
当然这是博主自己的游戏界面,如果觉得不好看你也可以自己设计一个,不过打印数组一定不能省略。
我们需要在游戏开始后打印一个展示界面,以便后续玩家来选取坐标。
代码如下:
//test.c
void game()
{
//定义地雷数组
char mine[ROWS][COLS] = { 0 };
//定义展示数组
char show[ROWS][COLS] = { 0 };
//初始化地雷数组
init_board(mine, ROWS, COLS, '*');
//初始化展示数组
init_board(show, ROWS, COLS, '*');
//打印展示界面
print_board(show, ROW, COL);
}
//game.h
//打印游戏主界面
void print_board(char show[ROWS][COLS], int rows, int cols);
//game.c
void print_board(char board[ROWS][COLS], int row, int col)
{
int i = 0,j = 0;
printf("0|");//美观
for (j = 1; j <= row; j++)
{
printf("%d ", j);//打印列提示数字
}
printf("|\n");//换行
printf("-|");//美观
for (j = 0; j < col; j++)
{
printf("--");//美观
}
printf("|\n");
for (i = 1; i <= row; i++)//由于二维数组行列数为11,所以行下标从1开始打印
{
//打印行
printf("%d|", i);//打印行提示数字
for (j = 1; j <= row; j++)//由于二维数组行列数为11,所以行下标从1开始打印
{
printf("%c ", board[i][j]);
}
printf("|\n");//打印完一行后换行
}
printf("-|");//美观
for (j = 0; j < col; j++)
{
printf("--");//美观
}
printf("|\n");
}
4. 在雷阵中布置雷(随机生成)
既然是扫雷游戏,我们肯定就要布置地雷,上文中已经讲过,我们将地雷数组的雷赋值为'1',其他位置赋值为'0',现在已经把地雷数组全部初始化为'0',那么接下来我们就需要安放地雷,也就是布置'1'进地雷数组。
当然,如果我们需要随机生成雷,我们就要用到rand()函数、srand()函数和time()函数,而这三个库函数分别要引入<stdlib.h>头文件和<time.h>头文件,这里就不做过多讲解,可以自行查找。
代码如下:
//test.c
void game()
{
//随机数起点
srand((unsigned int)time(NULL));
//定义地雷数组
char mine[ROWS][COLS] = { 0 };
//定义展示数组
char show[ROWS][COLS] = { 0 };
//初始化地雷数组
init_board(mine, ROWS, COLS, '0');
//初始化展示数组
init_board(show, ROWS, COLS, '*');
//打印展示界面
print_board(show, ROW, COL);
//布置雷
set_mine(mine, ROW, COL);
print_board(mine, ROW, COL);//调试时检测雷是否被正确安置
}
//game.h
//定义雷数
#define NUMMINE 10
//布置雷
void set_mine(char mine[ROWS][COLS], int row, int col);
//game.c
void set_mine(char mine[ROWS][COLS], int row, int col)
{
int count = 0;//循环变量
while(count<NUMMINE)
{
int x = rand() % row + 1;//每次生成随机行下标
int y = rand() % col + 1;//每次生成随机列下标
//判断随机坐标是否已经有雷
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count++;//不可放在if语句外
}
}
}
5.排查雷
前期工作已经准备完毕,接下来就轮到排查雷了,我们知道扫雷游戏是检测玩家选中的坐标,如果该坐标有雷,游戏结束;如果该坐标没雷,检查周围八个坐标探测雷的个数并在该坐标显示出来。
那么我们怎么通过代码来实现这一操作呢?
代码如下:
//test.c
void game()
{
//随机数起点
srand((unsigned int)time(NULL));
//定义地雷数组
char mine[ROWS][COLS] = { 0 };
//定义展示数组
char show[ROWS][COLS] = { 0 };
//初始化地雷数组
init_board(mine, ROWS, COLS, '0');
//初始化展示数组
init_board(show, ROWS, COLS, '*');
//打印展示界面
print_board(show, ROW, COL);
//布置雷
set_mine(mine, ROW, COL);
//print_board(mine, ROW, COL);//调试时检测雷是否被正确安置
//排查雷
search_mine(mine, show, ROW, COL);
}
//game.h
//排查雷
void search_mine(char mine[ROWS][COLS ],char show[ROWS][COLS], int row, int col);
//game.c
//探查周围雷的个数
int get_mine_num(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y - 1] + 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 search(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y, int* pcount)
{
int ret = get_mine_num(mine, x, y) + '0';//获取周围雷的个数
if (ret == '0')
{
show[x][y] = ' ';
}
else
{
show[x][y] = ret;
}
*pcount = *pcount + 1;//每成功探查一个坐标,count+1
}
void search_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0, y = 0;
int count = 0;//判断是否胜利
while (1)
{
printf("请输入你要排查的坐标:>");
scanf("%d %d", &x, &y);
printf("\n");
//判断坐标是否合法
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//判断该坐标是否被排查过
if (show[x][y] == '*')
{
//判断该坐标是否是雷
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了\n");
print_board(mine, ROW, COL);//打印雷阵,显示雷的位置
break;
}
else if (mine[x][y] == '0')
{
search(mine, show, row, col, x, y, &count);//查找该位置
print_board(show, ROW, COL);//每探查过一次打印一次展示界面
//判断是否已经探查出所有的雷
if (count == (row * col - NUMMINE))
{
printf("恭喜你成功探查出所有的雷!!!\n");
printf("\n");
print_board(mine, ROW, COL);//打印雷阵,显示雷的位置
break;
}
}
}
else
{
printf("该坐标已经被排查过,请重新输入\n");
printf("\n");
}
}
else
{
printf("输入错误,请重新输入\n");
printf("\n");
}
}
}
6. 结合以上所有步骤,完成扫雷游戏
我们把扫雷的实现细化为5个步骤,现在让我们把他们整合起来
最终我们得到了扫雷的全部代码:
分文件展示
game.h:
//因为test.c文件中包含了game.h,所以可以直接在game.h文件中包含头文件
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//定义行列数
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
//初始化二维数组
void init_board(char board[ROWS][COLS], int rows, int cols, char set);
//打印游戏主界面
void print_board(char show[ROWS][COLS], int rows, int cols);
//定义雷数
#define NUMMINE 10
//布置雷
void set_mine(char mine[ROWS][COLS], int row, int col);
//排查雷
void search_mine(char mine[ROWS][COLS ],char show[ROWS][COLS], int row, int col);
test.c:
#include "game.h" //包含头文件
void menu()
{
printf("********************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("********************\n");
}
void game()
{
//随机数起点
srand((unsigned int)time(NULL));
//定义地雷数组
char mine[ROWS][COLS] = { 0 };
//定义展示数组
char show[ROWS][COLS] = { 0 };
//初始化地雷数组
init_board(mine, ROWS, COLS, '0');
//初始化展示数组
init_board(show, ROWS, COLS, '*');
//打印展示界面
print_board(show, ROW, COL);
//布置雷
set_mine(mine, ROW, COL);
//print_board(mine, ROW, COL);//调试时检测雷是否被正确安置
//排查雷
search_mine(mine, show, ROW, COL);
}
void test()
{
int input = 0;
do
{
menu();//打印游戏菜单
printf("请做出你的选择:>");//提示玩家输入
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);//如果玩家键入0,游戏结束,跳出循环
}
int main()
{
test();
return 0;
}
game.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"//包含头文件
void init_board(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
board[i][j] = set;//给数组中每个元素赋值
}
}
}
void print_board(char board[ROWS][COLS], int row, int col)
{
printf("-------------扫雷-------------\n");
int i = 0,j = 0;
printf("0|");//美观
for (j = 1; j <= row; j++)
{
printf("%d ", j);//打印列提示数字
}
printf("|\n");//换行
printf("-|");//美观
for (j = 0; j < col; j++)
{
printf("--");//美观
}
printf("|\n");
for (i = 1; i <= row; i++)//由于二维数组行列数为11,所以行下标从1开始打印
{
//打印行
printf("%d|", i);//打印行提示数字
for (j = 1; j <= row; j++)//由于二维数组行列数为11,所以行下标从1开始打印
{
printf("%c ", board[i][j]);
}
printf("|\n");//打印完一行后换行
}
printf("-|");//美观
for (j = 0; j < col; j++)
{
printf("--");//美观
}
printf("|\n");
printf("-------------扫雷-------------\n\n");
}
void set_mine(char mine[ROWS][COLS], int row, int col)
{
int count = 0;//循环变量
while(count<NUMMINE)
{
int x = rand() % row + 1;//每次生成随机行下标
int y = rand() % col + 1;//每次生成随机列下标
//判断随机坐标是否已经有雷
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count++;//不可放在if语句外
}
}
}
//探查周围雷的个数
int get_mine_num(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y - 1] + 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 search(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y, int* pcount)
{
int ret = get_mine_num(mine, x, y) + '0';//获取周围雷的个数
if (ret == '0')
{
show[x][y] = ' ';
}
else
{
show[x][y] = ret;
}
*pcount = *pcount + 1;//每成功探查一个坐标,count+1
}
void search_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0, y = 0;
int count = 0;//判断是否胜利
while (1)
{
printf("请输入你要排查的坐标:>");
scanf("%d %d", &x, &y);
printf("\n");
//判断坐标是否合法
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//判断该坐标是否被排查过
if (show[x][y] == '*')
{
//判断该坐标是否是雷
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了\n");
print_board(mine, ROW, COL);//打印雷阵,显示雷的位置
break;
}
else if (mine[x][y] == '0')
{
search(mine, show, row, col, x, y, &count);//查找该位置
print_board(show, ROW, COL);//每探查过一次打印一次展示界面
//判断是否已经探查出所有的雷
if (count == (row * col - NUMMINE))
{
printf("恭喜你成功探查出所有的雷!!!\n");
printf("\n");
print_board(mine, ROW, COL);//打印雷阵,显示雷的位置
break;
}
}
}
else
{
printf("该坐标已经被排查过,请重新输入\n");
printf("\n");
}
}
else
{
printf("输入错误,请重新输入\n");
printf("\n");
}
}
}
进阶
以上的扫雷游戏只是基础版本,我们还需要不断的完善,进阶。
那么我们需要添加一些什么功能呢?
让我们打开网上的扫雷游戏
1.发散式
思路
我们可以看到,在我们排查了一个坐标以后,如果这个坐标周围都没有雷,那么他的周围呈发散式散开,直到遇到周围有雷的坐标,如果我们需要实现这个功能,需要怎么做呢?
让我们想一想,如果我们排查了一个周围都没有雷的坐标,是不是就要排查这个坐标周围的八个坐标,然后这八个坐标如果其中还有周围都没有雷的坐标,我们还需要再排查这些坐标周围的没有被排查过的坐标,这很明显可以通过递归来实现,通过之前的学习我们知道,递归要有两个必要条件:
- 存在限制条件,当满足这个限制条件的时候,递归便不再继续。
- 每次递归调用之后越来越接近这个限制条件。
那我们来想一想这个递归函数的限制条件
限制条件
1. 该坐标在游戏界面之中
2. 该坐标不是雷
3. 该坐标周围没有雷
4. 该坐标没有被排查过
以上的2和3可以合并为1个,1和4可以合并成一个所以我们只需要用两个判断语句就可以完成
代码
代码如下:
//查找该位置
void search(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y, int* pcount)
{
//递归限制条件1 4
if (x >= 1 && x <= row && y >= 1 && y <= col && show[x][y] == '*')
{
int ret = get_mine_num(mine, x, y) + '0';//获取周围雷的个数
if (ret == '0')
{
show[x][y] = ' ';
}
else
{
show[x][y] = ret;
}
*pcount = *pcount + 1;//每成功探查一个坐标,count+1
//递归限制条件2 3
if (show[x][y] == ' ')
{
search(mine, show, row, col, x - 1, y - 1, pcount);
search(mine, show, row, col, x - 1, y, pcount);
search(mine, show, row, col, x - 1, y + 1, pcount);
search(mine, show, row, col, x, y - 1, pcount);
search(mine, show, row, col, x, y + 1, pcount);
search(mine, show, row, col, x + 1, y - 1, pcount);
search(mine, show, row, col, x + 1, y, pcount);
search(mine, show, row, col, x + 1, y + 1, pcount);
}
}
}
通过以上的代码我们就成功完成了发散式的操作。
2.标记地雷与取消标记
如图所示,圈中的坐标很明显一定是雷,但我们如果下次不小心查到这个坐标,游戏就会失败,所以我们需要把这种一定是雷的坐标标记起来,让我们在下次不小心查到这个坐标的时候提示一下重新查,而且当我们标记错坐标时,我们还得取消标记,所以我们需要添加标记地雷和取消地雷这一操作,同时提醒剩余的雷数。
这里就不作过多介绍。直接看更改过的代码
全面改进后
game.h:
#define _CRT_SECURE_NO_WARNINGS 1
//因为test.c文件中包含了game.h,所以可以直接在game.h文件中包含头文件
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//定义行列数
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
//初始化二维数组
void init_board(char board[ROWS][COLS], int rows, int cols, char set);
//打印游戏主界面
void print_board(char show[ROWS][COLS], int rows, int cols);
//定义雷数
#define NUMMINE 10
//布置雷
void set_mine(char mine[ROWS][COLS], int row, int col);
//排查雷
void search_mine(char mine[ROWS][COLS ],char show[ROWS][COLS], int row, int col);
test.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 game()
{
//随机数起点
srand((unsigned int)time(NULL));
//定义地雷数组
char mine[ROWS][COLS] = { 0 };
//定义展示数组
char show[ROWS][COLS] = { 0 };
//初始化地雷数组
init_board(mine, ROWS, COLS, '0');
//初始化展示数组
init_board(show, ROWS, COLS, '*');
//打印展示界面
print_board(show, ROW, COL);
//布置雷
set_mine(mine, ROW, COL);
print_board(mine, ROW, COL);//调试时检测雷是否被正确安置
//排查雷
search_mine(mine, show, ROW, COL);
}
void test()
{
int input = 0;
do
{
menu();//打印主菜单
printf("请做出你的选择:>");//提示玩家输入
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);//如果玩家键入0,游戏结束,跳出循环
}
int main()
{
test();
return 0;
}
game.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"//包含头文件
void init_board(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
board[i][j] = set;//给数组中每个元素赋值
}
}
}
void print_board(char board[ROWS][COLS], int row, int col)
{
printf("-------------扫雷-------------\n");
int i = 0,j = 0;
printf("0|");//美观
for (j = 1; j <= row; j++)
{
printf("%d ", j);//打印列提示数字
}
printf("|\n");//换行
printf("-|");//美观
for (j = 0; j < col; j++)
{
printf("--");//美观
}
printf("|\n");
for (i = 1; i <= row; i++)//由于二维数组行列数为11,所以行下标从1开始打印
{
//打印行
printf("%d|", i);//打印行提示数字
for (j = 1; j <= row; j++)//由于二维数组行列数为11,所以行下标从1开始打印
{
printf("%c ", board[i][j]);
}
printf("|\n");//打印完一行后换行
}
printf("-|");//美观
for (j = 0; j < col; j++)
{
printf("--");//美观
}
printf("|\n");
printf("-------------扫雷-------------\n\n");
}
void set_mine(char mine[ROWS][COLS], int row, int col)
{
int count = 0;//循环变量
while(count<NUMMINE)
{
int x = rand() % row + 1;//每次生成随机行下标
int y = rand() % col + 1;//每次生成随机列下标
//判断随机坐标是否已经有雷
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count++;//不可放在if语句外
}
}
}
//探查周围雷的个数
int get_mine_num(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y - 1] + 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 search(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y, int* pcount)
{
//递归限制条件1 4
if (x >= 1 && x <= row && y >= 1 && y <= col && show[x][y] == '*')
{
int ret = get_mine_num(mine, x, y) + '0';//获取周围雷的个数
if (ret == '0')
{
show[x][y] = ' ';
}
else
{
show[x][y] = ret;
}
*pcount = *pcount + 1;//每成功探查一个坐标,count+1
//递归限制条件2 3
if (show[x][y] == ' ')
{
search(mine, show, row, col, x - 1, y - 1, pcount);
search(mine, show, row, col, x - 1, y, pcount);
search(mine, show, row, col, x - 1, y + 1, pcount);
search(mine, show, row, col, x, y - 1, pcount);
search(mine, show, row, col, x, y + 1, pcount);
search(mine, show, row, col, x + 1, y - 1, pcount);
search(mine, show, row, col, x + 1, y, pcount);
search(mine, show, row, col, x + 1, y + 1, pcount);
}
}
}
//打印游戏菜单
void game_menu()
{
printf("|---------------------------|\n");
printf("|--------1.继续扫雷---------|\n");
printf("|--------2.标记地雷---------|\n");
printf("|--------3.取消标记---------|\n");
printf("|-------0.返回主菜单--------|\n");
printf("|---------------------------|\n");
}
//标记地雷
void mark_mine(char show[ROWS][COLS], int row, int col, int* pleave_mine_num)
{
int x = 0, y = 0;
//判断是否还有标记位置
if (*pleave_mine_num > 0)
{
while (1)
{
printf("请输入你要标记的坐标:>");
scanf("%d %d", &x, &y);
//判断坐标合法性
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//判断坐标是否已被排查
if (show[x][y] == '*')
{
show[x][y] = '#';
print_board(show, ROW, COL);
*pleave_mine_num = *pleave_mine_num - 1;
printf("剩余雷的个数:%d\n", *pleave_mine_num);
break;
}
else
printf("该坐标已被排查,请重新输入\n");
}
else
{
printf("坐标输入有误,请重新输入\n");
}
}
}
else
{
printf("标记地雷数已达上限,请取消标记或继续扫雷!\n");
}
}
//取消标记
void quit_mark(char show[ROWS][COLS], int row, int col, int *pleave_mine_num)
{
//判断是否存在标记
if (*pleave_mine_num == NUMMINE)
{
printf("你并没有任何标记,请标记地雷或继续扫雷\n");
}
else
{
int x = 0, y = 0;
while (1)
{
printf("请输入你想要取消标记的雷的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//判断该坐标是否已被标记
if (show[x][y] == '#')
{
show[x][y] = '*';
print_board(show, ROW, COL);
*pleave_mine_num = *pleave_mine_num + 1;
printf("剩余雷的个数:%d\n", *pleave_mine_num);
break;
}
}
else
{
printf("坐标输入有误,请重新输入\n");
}
}
}
}
//选择
void choice(char show[ROWS][COLS], int row, int col, int* pleave_mine_num, int *pflag)
{
int input = 0;
do
{
game_menu();//打印选择菜单
printf("请输入你的选择:>");
scanf("%d", &input);
printf("\n");
print_board(show, row, col);
*pflag = input;
switch (input)
{
case 1:
break;
case 2:
mark_mine(show, row, col, pleave_mine_num);//标记地雷
break;
case 3:
quit_mark(show, row, col, pleave_mine_num);//取消标记
break;
case 0:
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input == 2 || input == 3);
}
void search_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0, y = 0;
int count = 0;//判断是否胜利的变量
int leave_mine_num = NUMMINE;//表示剩余雷数的变量
int flag = 0;//判断是否退出游戏的变量
while (1)
{
printf("请输入你要排查的坐标:>");
scanf("%d %d", &x, &y);
printf("\n");
//判断坐标是否合法
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//判断该坐标是否被标记
if (show[x][y] == '#')
{
printf("该坐标已被标记,不能被排查\n");
}
//判断该坐标是否被排查过
else if (show[x][y] == '*')
{
//判断该坐标是否是雷
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了\n");
print_board(mine, ROW, COL);//打印雷阵,显示雷的位置
break;
}
else if (mine[x][y] == '0')
{
search(mine, show, row, col, x, y, &count);//查找该位置
print_board(show, ROW, COL);//每探查过一次打印一次展示界面
printf("剩余雷的个数:%d\n\n", leave_mine_num);//提醒剩余雷的个数
//判断游戏是否结束
if (count != (row * col - NUMMINE))
{
choice(show, ROW, COL, &leave_mine_num, &flag);
}
//判断玩家是否选择退出游戏
if (flag == 0)
{
printf("返回主菜单\n\n");
break;
}
//判断是否已经探查出所有的雷
if (count == (row * col - NUMMINE))
{
printf("恭喜你成功探查出所有的雷!!!\n");
printf("\n");
print_board(mine, ROW, COL);//打印雷阵,显示雷的位置
break;
}
}
}
else
{
printf("该坐标已经被排查过,请重新输入\n");
printf("\n");
}
}
else
{
printf("输入错误,请重新输入\n");
printf("\n");
}
}
}
好了,以上就是扫雷游戏的C语言实现,让我们下篇文章再见!