今天我们用C语言实现一个扫雷游戏,升级版哦
可以展开,标记,取消标记,记录已排查坐标数。
直接来看看效果吧
除了没用鼠标点以外,是很接近原版的。
目录
扫雷主体思路
扫雷游戏主体的实现
1.游戏菜单的实现
2.初始化棋盘/雷盘
3.打印棋盘/雷盘
4.布置雷
5.排查雷/标记雷的实现
5.1 排查雷
5.2 标记雷/取消标记
5.3 判断输赢和显示当前已排查的坐标
6.展开雷
生成Release版
全部代码
game.c
game.h
tese.c
扫雷主体思路
需要实现扫雷游戏,我们可以先看看别人的扫雷是如何实现的,
可以看出,棋盘是具有两层的,第一层是我们想让玩家直接可以看到的,第二层则是隐藏起来的,存放的是雷。
所以我们需要生成两个二维数组,一个二维数组,用来存放棋盘,另一个二维数组用来存放雷(可以称为雷盘)。
棋盘初始化为*
雷盘初始化为0 然后随机放入雷(随机就可以想到用rand函数)
然后再进行排查雷,展开雷区等功能的实现。
可能有点抽象,我们来实现看看吧。等实现完就会觉得其实并不难啦,很好理解的。
扫雷游戏主体的实现
我们先创建三个文件
1.游戏菜单的实现
我们需要打印一个简单的游戏菜单,就像我们平时玩游戏也是有菜单的,让玩家选择。
使用do while循环语句与switch 选择语句 实现
代码实现如下:
void menu()
{
// 33[34m 33[0m 是实现字体颜色 34代表蓝色 31代表红色
printf("*********************n");
printf("****** 33[34m 1.play 33[0m *******n");
printf("****** 33[31m 0.exit 33[0m *******n");
printf("*********************n");
}
void test()
{
int input = 0;
do
{
//菜单
menu();
printf("请选择:>");
scanf("%d", &input);
system("cls");//输入后清理屏幕
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏n");
break;
default:
printf("选择错误!n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
这里的菜单 1.play 0.exit 字体颜色 进行了设置,我觉得这样看起来有趣一些,不那么的枯燥。
2.初始化棋盘/雷盘
我们需要创建两个char类型二维数组
一个用于存放展示给玩家看的棋盘,另一个用于存放雷。
为了方便后期的更改,我们可以用#define 定义常量 作为数组大小。
我们创建个9*9的棋盘吧
但是这里有一个问题,如果我们创建 9*9的,想要展示给玩家看的就是9*9的棋盘,如果玩家要查找棋盘边缘的坐标,周围的雷的数量,
像上面图中那样,就会出现数组越界访问的问题,所以我们最好把数组创建大一点,打印的时候仍然打印9*9的,但是创建数组,可以创建11*11的这样就避免了数组越界的情况。
所以可以这样定义
现在来看看代码实现:
test.c里
//扫雷游戏的实现
void game()
{
//创建棋盘
//mine数组是用来存放布置好的雷的信息
char mine[ROWS][COLS] = { 0 };//'0'
//show数组是存放排查出的雷的信息
char show[ROWS][COLS] = { 0 };// '*'
//创建棋盘初始化
InisBoard(mine, ROWS, COLS,'0');//传个字符'0'过去,代表把雷盘初始化为全'0'
InisBoard(show, ROWS, COLS, '*'); //传个字符'*'过去,代表把雷盘初始化为全'0'
}
game.c里
//初始化mine雷盘/show棋盘 都可以调用这个函数实现
void InisBoard(char board[ROWS][COLS],int rows,int cols,char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
gama.h里
#define ROW 9 // 展示给玩家看的行
#define COL 9 //
#define ROWS ROW+2 //实际创建的行
#define COLS COL+2
//初始化雷盘的声明
void InisBoard(char arr[ROWS][COLS], int rows, int cols,char set);
头文件别忘了引用哦,我代码块里没有加进去,但是文章末尾的完整代码里都会有的。
3.打印棋盘/雷盘
实际游戏中雷盘不会打印给玩家看的。
为了方便玩家识别行列位置,我们可以加上打印行号 和列号
为了更加接近平时玩的扫雷,我设置了不同数字以不同颜色显示,1 蓝色 2白色 3黄色 标记(!)雷红色显示
来看看代码吧:
game.c中
//打印mine雷盘/show 棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
printf("--------扫雷-------n");
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 ", i);//打印行号
for (j = 1; j <= col; j++)
{
if (board[i][j] == '!')//!代表标记了的雷 红色显示 游戏结束后雷蓝色显示
{
printf(" 33[31m%c 33[0m", board[i][j]);
continue;
}
else if (board[i][j] == '1')
{
printf(" 33[34m%c 33[0m", board[i][j]);//蓝色显示
continue;
}
else if (board[i][j] == '3')
{
printf(" 33[32m%c 33[0m", board[i][j]);//黄色显示
continue;
}
printf("%c ", board[i][j]);
}
printf("n");
}
printf("--------扫雷-------n");
}
game.h中
//打印函数的声明
void DisplayBoard(char show[ROWS][COLS], int row, int col);
我们来看看棋盘效果
4.布置雷
我们雷盘也初始化为全'0'了,我们现在需要布置雷了,可以把'1'作为雷
随机把'1'赋值到雷盘上9*9的格子里,我们要布置10个雷 就随机赋值10个1在雷盘上。
雷的数量也可以用#define 定义,方便后面更改。
game.c中
//布置雷
void Set_Mine(char mine[ROWS][COLS], int rows, int cols)
{
int x = 0;
int y = 0;
int count1 = count;//count是define定义的常量 需要先赋值给一个变量 才能改
while (count1)
{
x = rand() % rows+1;
y = rand() % cols+1; //1-9 取值范围之间
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count1--;
}
}
}
game.h中
#define count 10 //代表10个雷
//布置雷函数的声明
void Set_Mine(char mine[ROWS][COLS], int rows, int cols)
我们调用打印函数 打印雷盘看看效果
5.排查雷/标记雷的实现
5.1 排查雷
雷已经布置了,现在就可以来进行游戏,排查雷
思路是这样的
我们输入一个坐标(x,y),如果这个坐标是雷则提示被炸死了,就返回到菜单,
如果不是雷,就统计周围8个坐标内雷的个数,相加,然后赋值给该坐标,如果周围坐标都不是雷,就把' '空白 赋值给该坐标。
如果周围8个坐标有雷,那我们把8个坐标相加然后再减8*字符'0' 得到周围雷的个数
我们可以写一个get_mine函数实现这个功能。
5.2 标记雷/取消标记
我们需要标记雷,可以创建一个char类型的的临时变量 a,然后输入坐标后再输入
当 a=='f' 表示排查该坐标 a=='s'时 表示标记该坐标 a=='c'时 表示该坐标取消标记
5.3 判断输赢和显示当前已排查的坐标
我这里是在game.c里定义了一个全局变量sum 用于统计每次排查坐标后sum++,最后总坐标(ROW*COL)-count==sum 代表雷排完了,也就是获胜了。
每次在输入要排查的坐标之前都判断一次,并且实时打印当前排查了的坐标数量。
当然这里判断输赢可以再写一个判断输赢函数去遍历整个棋盘,但是我们这里就用个全局变量统计,就没有再去写判断输赢函数。
整体代码如下:
game.c中
void find_mine(char show[ROWS][COLS],char mine[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
char a = 0;//标记雷:s 取消标记:c 排查雷:f
while(1)
{
printf("已排查坐标数量: 33[36m%d 33[0mn", sum);//事实显示已经排查了的坐标数量
if (sum==ROW*COL-count)//判断输赢 已排查的坐标数-雷
{
DisplayBoard(mine, ROW, COL);//打印雷的位置
printf(" 33[31m 恭喜您扫雷成功!n 33[0mn");//游戏结束红色显示
return;
}
printf("请输入要排查坐标以f结束/要标记的雷以s结束:>");
scanf("%d %d %c", &x, &y,&a);
if (x >= 1 && x <= row && y >= 1 && y <= col && a=='f')
{
int i = 0;
int j = 0;
if (mine[x][y] == '0'&&show[x][y]=='*')// 即不是雷 又没被排查过
{
expand_mine(show,mine, x, y);//展开雷
system("cls");//每次打印棋盘之前清理屏幕
DisplayBoard(show, ROW, COL);
}
else if (show[x][y] != '*')
{
printf("该坐标已经排查过了,请重新输入n");
}
else//只能是mine[x][y]=='1'的时候(即是雷)
{
printf("你被炸死了n");
DisplayBoard(mine, ROW, COL);//并且给玩家展示一下雷盘 让他知道是怎么输的
break;
}
}
else if (x >= 1 && x <= row && y >= 1 && y <= col && show[x][y] == '*' && a == 's') //把雷标记为!
{
show[x][y] = '!';
system("cls");
DisplayBoard(show, ROW, COL);
printf("坐标已经标记,输入坐标以c结尾可取消标记n");
}
else if (x >= 1 && x <= row && y >= 1 && y <= col && show[x][y] == '!' && a == 'c')// 取消标记
{
show[x][y] = '*';
system("cls");
DisplayBoard(show, ROW, COL);
}
else if(x >= 1 && x <= row && y >= 1 && y <= col)
{
printf("坐标已排查或标记请重新输入n");
}
else
{
printf("坐标非法,请重输入");
}
}
}
上面代码里expand_mine 是展开雷的函数,马上就会讲到,get_mine 获取周围雷的个数的函数 也是在expand_mine函数里调用。
还运用到了sysem("cls")每次打印棋盘之前先清理屏幕。
6.展开雷
我们如果只运用get_mine函数每次只能排查一个坐标,效率很慢,无法像平时我们玩的扫雷那样
一点展开一大片
那我们现在就来实现他,我们仔细观察这个图,可以发现只要周围没有雷就继续展开,遇到周围8个坐标内有雷才停止展开。那我们就可以运用递归,来实现这个函数。
当排查的坐标x,y周围没有雷时,我们就排查他周围的8个坐标是否有雷,这样递归下去,直到周围坐标有雷就停止递归返回回去。这里的排查周围8个坐标我写了个循环实现,就显得代码量少点。
但是要注意的点是,1.排查过的坐标不再排查。 2.如果是标记了的坐标也是要排查的。3.x,y的取值范围最好是在1-9之间,这样方便后面我们统计排查的次数。
现在来看看代码吧
game.c中
void expand_mine(char show[ROWS][COLS],char mine[ROWS][COLS],int x,int y)
{
if (x == 0 || y == 0 || y == COLS - 1 || x == ROWS - 1)//如果不用这个边界判断条件 排查的次数就会是ROWS*COLS 并且会导致随着雷的位置如果在边缘 排查次数就会相对来说少点,排查次数会不固定
{
return;
}
if (get_mine(show,mine,x,y)!=0 && (show[x][y] == '*' || show[x][y] == '!') && mine[x][y] != '1') //!=0是指周围8个坐标没有雷 show[x][y]=='*'是指没有被排查过 并且被标记了也会排查
{
show[x][y] = get_mine(show,mine,x,y) + '0';
sum++; //统计排查次数 每次排查过后sum++
return ;
}
else if((show[x][y] == '*'||show[x][y]=='!')&&mine[x][y]!='1') // //解决c6385 读取数据无效 就加个对x y的限制语句 !='*'是表示已经被排查过的 就直接return 不排查了
{
show[x][y] = ' ';
sum++;//每次排查过后sum++
int i = 0;
int j = 0;
for (i = -1; i <= 1; i++)
{
for (j = -1; j <= 1; j++)
{
if (j == 0 && i == 0)
{
continue;// 当 i=0 j=0 会再次重复执行expand_mine 所以直接跳到下一个
}
expand_mine(show, mine, x + i, y + j);
}
}
}
}
来看看实现效果
生成Release版
现在我们已经实现了全部功能,可以发给好友玩玩试玩试玩。
如果用VS的小伙伴,可以生成Release版 然后就会在本地生成一个Release文件,然后去找到里面的.exe文件,就可以直接发给朋友玩了。
好啦,今天就分享到这里,文中可能有些地方表达不够清楚,请见谅。谢谢大家的支持
全部完整代码会贴在文章末尾,有兴趣的小伙伴可以看看。
全部代码
game.c
#include"game.h"
int sum = 0;//统计被排查了的坐标数量
//
//初始化mine雷局/show棋盘 都可以调用这个函数实现
void InisBoard(char board[ROWS][COLS],int rows,int cols,char set)
{
sum = 0;//每局游戏把sum重置成0
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
//计时器//功能待完善
//打印mine雷盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
printf("--------扫雷-------n");
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 ", i);//打印行号
for (j = 1; j <= col; j++)
{
if (board[i][j] == '!')//标记了的雷红色显示 游戏结束后雷红色显示
{
printf(" 33[31m%c 33[0m", board[i][j]);
continue;
}
else if (board[i][j] == '1')
{
printf(" 33[34m%c 33[0m", board[i][j]);//蓝色显示
continue;
}
else if (board[i][j] == '3')
{
printf(" 33[32m%c 33[0m", board[i][j]);//黄色显示
continue;
}
printf("%c ", board[i][j]);
}
printf("n");
}
printf("--------扫雷-------n");
}
//布置雷
void Set_Mine(char mine[ROWS][COLS], int rows, int cols)
{
int x = 0;
int y = 0;
int count1 = count;
while (count1)
{
x = rand() % rows+1;
y = rand() % cols+1; //
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count1--;
}
}
}
//递归展开雷
int get_mine(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)
{
return (mine[x][y + 1] +
mine[x][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x + 1][y - 1] +
mine[x - 1][y] +
mine[x - 1][y + 1] +
mine[x - 1][y - 1] - 8 * '0');
}
//递归实现展开雷
void expand_mine(char show[ROWS][COLS],char mine[ROWS][COLS],int x,int y)//字符0减去字符0 ==数字1 字符1减去字符1==数字1...
{
if (x == 0 || y == 0 || y == COLS - 1 || x == ROWS - 1)//如果不用这个边界判断条件 排查的次数就会是ROWS*COLS 并且会导致随着雷的位置如果在边缘 排查次数就会相对来说少点,排查次数会不固定
{
return;
}
if (get_mine(show,mine,x,y)!=0 && (show[x][y] == '*' || show[x][y] == '!') && mine[x][y] != '1') //!=0是指周围8个坐标没有雷 show[x][y]=='*'是指没有被排查过 并且被标记了也会排查
{
show[x][y] = get_mine(show,mine,x,y) + '0';
sum++; //每次排查过后sum++
return ;
}
else if((show[x][y] == '*'||show[x][y]=='!')&&mine[x][y]!='1') // //解决c6385 读取数据无效 就加个对x y的限制语句 !='*'是表示已经被排查过的 就直接return 不排查了
{
show[x][y] = ' ';
sum++;//每次排查过后sum++
int i = 0;
int j = 0;
for (i = -1; i <= 1; i++)
{
for (j = -1; j <= 1; j++)
{
if (j == 0 && i == 0)
{
continue;//i=0 j=0 会再次执行expand_mine 所以直接跳到下一个
}
expand_mine(show, mine, x + i, y + j);
}
}
}
}
//排查雷
void find_mine(char show[ROWS][COLS],char mine[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
char a = 0;//标记雷:s 取消标记:c 排查雷:f
while(1)
{
printf("已排查坐标数量: 33[36m%d 33[0mn", sum);//事实显示已经排查了的坐标数量
if (sum==ROW*COL-count)//判断输赢 已排查的坐标数-雷
{
//system("cls");//
DisplayBoard(mine, ROW, COL);//打印雷的位置
printf(" 33[31m 恭喜您扫雷成功!n 33[0mn");//游戏结束红色显示
return;
}
printf("请输入要排查坐标以f结束/要标记的雷以s结束:>");
scanf("%d %d %c", &x, &y,&a);
if (x >= 1 && x <= row && y >= 1 && y <= col && a=='f')
{
int i = 0;
int j = 0;
if (mine[x][y] == '0'&&show[x][y]=='*')// 即不是雷 又没被排查过
{
expand_mine(show,mine, x, y);//sum这里需要传址 因为要改变它的值
system("cls");//每次打印下次屏幕之前清理屏幕
DisplayBoard(show, ROW, COL);
}
else if (show[x][y] != '*')
{
printf("该坐标已经排查过了,请重新输入n");
}
else//只能是mine[x][y]=='1'的时候(即是雷)
{
printf("你被炸死了n");
DisplayBoard(mine, ROW, COL);//并且给玩家展示一下雷盘 让他知道是怎么输的
break;
}
}
else if (x >= 1 && x <= row && y >= 1 && y <= col && show[x][y] == '*' && a == 's') //把雷标记为!
{
show[x][y] = '!';
system("cls");
DisplayBoard(show, ROW, COL);
printf("坐标已经标记,输入坐标以c结尾可取消标记n");
}
else if (x >= 1 && x <= row && y >= 1 && y <= col && show[x][y] == '!' && a == 'c')// 取消标记
{
show[x][y] = '*';
system("cls");
DisplayBoard(show, ROW, COL);
}
else if(x >= 1 && x <= row && y >= 1 && y <= col)
{
printf("坐标已排查或标记请重新输入n");
}
else
{
printf("坐标非法,请重输入");
}
}
}
game.h
#pragma once
#include
#include
#include
#include
#define ROW 9 // 展示给玩家看的行
#define COL 9 //
#define ROWS ROW+2 //实际创建的行
#define COLS COL+2
#define count 10 //雷的数量
//初始化雷盘/棋盘
void InisBoard(char board[ROWS][COLS], int rows, int cols,char set);
//打印
void DisplayBoard(char show[ROWS][COLS], int row, int col);
//布置雷
void Set_Mine(char mine[ROWS][COLS], int row, int col);
//排查雷
void find_mine(char show[ROWS][COLS],char mine[ROWS][COLS], int row, int col);
//展开雷(递归实现)
void expand_mine(char show[ROWS][COLS], char mine[ROWS][COLS],int x,int y);
tese.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//菜单
void menu()
{
printf("*********************n");
printf("****** 33[34m 1.play 33[0m *******n");// 33[34m 33[0m 是实现字体颜色 34代表蓝色 31代表红色
printf("****** 33[31m 0.exit 33[0m *******n");
printf("*********************n");
}
//扫雷游戏的实现
void game()
{
//创建棋盘
//mine数组是用来存放布置好的雷的信息
char mine[ROWS][COLS] = { 0 };//'0'
//show数组是存放排查出的雷的信息
char show[ROWS][COLS] = { 0 };// '*'
//创建棋盘初始化
InisBoard(mine, ROWS, COLS,'0');
InisBoard(show, ROWS, COLS, '*');
//布雷
Set_Mine(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
//排查雷
find_mine(show,mine,ROW,COL);
}
void test()
{
int input = 0;
do
{
//菜单
menu();
printf("请选择:>");
scanf("%d", &input);
system("cls");//输入后清理屏幕
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏n");
break;
default:
printf("选择错误!n");
break;
}
} while (input);
}
int main()
{
srand((unsigned)time(NULL));//不能写在布置雷的循环里,写进去就很慢每次都要生成时间戳
system("mode con cols=25 lines=25");//设置窗口宽度高度
test();//函数的实现
return 0;
}
game.c
#include"game.h"
int sum = 0;//统计被排查了的坐标数量
//
//初始化mine雷局/show棋盘 都可以调用这个函数实现
void InisBoard(char board[ROWS][COLS],int rows,int cols,char set)
{
sum = 0;//每局游戏把sum重置成0
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
//计时器//功能待完善
//打印mine雷盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
printf("--------扫雷-------n");
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 ", i);//打印行号
for (j = 1; j <= col; j++)
{
if (board[i][j] == '!')//标记了的雷红色显示 游戏结束后雷红色显示
{
printf(" 33[31m%c 33[0m", board[i][j]);
continue;
}
else if (board[i][j] == '1')
{
printf(" 33[34m%c 33[0m", board[i][j]);//蓝色显示
continue;
}
else if (board[i][j] == '3')
{
printf(" 33[32m%c 33[0m", board[i][j]);//黄色显示
continue;
}
printf("%c ", board[i][j]);
}
printf("n");
}
printf("--------扫雷-------n");
}
//布置雷
void Set_Mine(char mine[ROWS][COLS], int rows, int cols)
{
int x = 0;
int y = 0;
int count1 = count;
while (count1)
{
x = rand() % rows+1;
y = rand() % cols+1; //
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count1--;
}
}
}
//递归展开雷
int get_mine(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)
{
return (mine[x][y + 1] +
mine[x][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x + 1][y - 1] +
mine[x - 1][y] +
mine[x - 1][y + 1] +
mine[x - 1][y - 1] - 8 * '0');
}
//递归实现展开雷
void expand_mine(char show[ROWS][COLS],char mine[ROWS][COLS],int x,int y)//字符0减去字符0 ==数字1 字符1减去字符1==数字1...
{
if (x == 0 || y == 0 || y == COLS - 1 || x == ROWS - 1)//如果不用这个边界判断条件 排查的次数就会是ROWS*COLS 并且会导致随着雷的位置如果在边缘 排查次数就会相对来说少点,排查次数会不固定
{
return;
}
if (get_mine(show,mine,x,y)!=0 && (show[x][y] == '*' || show[x][y] == '!') && mine[x][y] != '1') //!=0是指周围8个坐标没有雷 show[x][y]=='*'是指没有被排查过 并且被标记了也会排查
{
show[x][y] = get_mine(show,mine,x,y) + '0';
sum++; //每次排查过后sum++
return ;
}
else if((show[x][y] == '*'||show[x][y]=='!')&&mine[x][y]!='1') // //解决c6385 读取数据无效 就加个对x y的限制语句 !='*'是表示已经被排查过的 就直接return 不排查了
{
show[x][y] = ' ';
sum++;//每次排查过后sum++
int i = 0;
int j = 0;
for (i = -1; i <= 1; i++)
{
for (j = -1; j <= 1; j++)
{
if (j == 0 && i == 0)
{
continue;//i=0 j=0 会再次执行expand_mine 所以直接跳到下一个
}
expand_mine(show, mine, x + i, y + j);
}
}
}
}
//排查雷
void find_mine(char show[ROWS][COLS],char mine[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
char a = 0;//标记雷:s 取消标记:c 排查雷:f
while(1)
{
printf("已排查坐标数量: 33[36m%d 33[0mn", sum);//事实显示已经排查了的坐标数量
if (sum==ROW*COL-count)//判断输赢 已排查的坐标数-雷
{
//system("cls");//
DisplayBoard(mine, ROW, COL);//打印雷的位置
printf(" 33[31m 恭喜您扫雷成功!n 33[0mn");//游戏结束红色显示
return;
}
printf("请输入要排查坐标以f结束/要标记的雷以s结束:>");
scanf("%d %d %c", &x, &y,&a);
if (x >= 1 && x <= row && y >= 1 && y <= col && a=='f')
{
int i = 0;
int j = 0;
if (mine[x][y] == '0'&&show[x][y]=='*')// 即不是雷 又没被排查过
{
expand_mine(show,mine, x, y);//sum这里需要传址 因为要改变它的值
system("cls");//每次打印下次屏幕之前清理屏幕
DisplayBoard(show, ROW, COL);
}
else if (show[x][y] != '*')
{
printf("该坐标已经排查过了,请重新输入n");
}
else//只能是mine[x][y]=='1'的时候(即是雷)
{
printf("你被炸死了n");
DisplayBoard(mine, ROW, COL);//并且给玩家展示一下雷盘 让他知道是怎么输的
break;
}
}
else if (x >= 1 && x <= row && y >= 1 && y <= col && show[x][y] == '*' && a == 's') //把雷标记为!
{
show[x][y] = '!';
system("cls");
DisplayBoard(show, ROW, COL);
printf("坐标已经标记,输入坐标以c结尾可取消标记n");
}
else if (x >= 1 && x <= row && y >= 1 && y <= col && show[x][y] == '!' && a == 'c')// 取消标记
{
show[x][y] = '*';
system("cls");
DisplayBoard(show, ROW, COL);
}
else if(x >= 1 && x <= row && y >= 1 && y <= col)
{
printf("坐标已排查或标记请重新输入n");
}
else
{
printf("坐标非法,请重输入");
}
}
}
game.h
#pragma once
#include
#include
#include
#include
#define ROW 9 // 展示给玩家看的行
#define COL 9 //
#define ROWS ROW+2 //实际创建的行
#define COLS COL+2
#define count 10 //雷的数量
//初始化雷盘/棋盘
void InisBoard(char board[ROWS][COLS], int rows, int cols,char set);
//打印
void DisplayBoard(char show[ROWS][COLS], int row, int col);
//布置雷
void Set_Mine(char mine[ROWS][COLS], int row, int col);
//排查雷
void find_mine(char show[ROWS][COLS],char mine[ROWS][COLS], int row, int col);
//展开雷(递归实现)
void expand_mine(char show[ROWS][COLS], char mine[ROWS][COLS],int x,int y);
tese.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//菜单
void menu()
{
printf("*********************n");
printf("****** 33[34m 1.play 33[0m *******n");// 33[34m 33[0m 是实现字体颜色 34代表蓝色 31代表红色
printf("****** 33[31m 0.exit 33[0m *******n");
printf("*********************n");
}
//扫雷游戏的实现
void game()
{
//创建棋盘
//mine数组是用来存放布置好的雷的信息
char mine[ROWS][COLS] = { 0 };//'0'
//show数组是存放排查出的雷的信息
char show[ROWS][COLS] = { 0 };// '*'
//创建棋盘初始化
InisBoard(mine, ROWS, COLS,'0');
InisBoard(show, ROWS, COLS, '*');
//布雷
Set_Mine(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
//排查雷
find_mine(show,mine,ROW,COL);
}
void test()
{
int input = 0;
do
{
//菜单
menu();
printf("请选择:>");
scanf("%d", &input);
system("cls");//输入后清理屏幕
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏n");
break;
default:
printf("选择错误!n");
break;
}
} while (input);
}
int main()
{
srand((unsigned)time(NULL));//不能写在布置雷的循环里,写进去就很慢每次都要生成时间戳
system("mode con cols=25 lines=25");//设置窗口宽度高度
test();//函数的实现
return 0;
}
#pragma once #include#include #include #include #define ROW 9 // 展示给玩家看的行 #define COL 9 // #define ROWS ROW+2 //实际创建的行 #define COLS COL+2 #define count 10 //雷的数量 //初始化雷盘/棋盘 void InisBoard(char board[ROWS][COLS], int rows, int cols,char set); //打印 void DisplayBoard(char show[ROWS][COLS], int row, int col); //布置雷 void Set_Mine(char mine[ROWS][COLS], int row, int col); //排查雷 void find_mine(char show[ROWS][COLS],char mine[ROWS][COLS], int row, int col); //展开雷(递归实现) void expand_mine(char show[ROWS][COLS], char mine[ROWS][COLS],int x,int y);



