1.需要存储雷的信息,创建二维数组来存储数据信息,把为雷设置为1,不是雷设置为0。
2.在某个位置存储其所围成的正方形区域中雷的个数,若个数为1,则在查看棋盘的时候,会与雷的位置1产生歧义,所以创建两个二维数组,棋盘1(show二维数组)用来排查雷(玩家可以看到的棋盘RowCol)、棋盘2(meni二维数组 )用来设置雷的位置((Row+2)乘以(Col+2))。
3.在玩家可以看到的棋盘中,把全部数据初始化为 ‘’,为了方便进行二个棋盘的相互利用,从而无需调用两个函数分别对两棋盘单独处理,把设置雷的二维数组存储的数据类型改成字符型。
思路:
遍历棋盘1(show二维数组),并与棋盘2(meni二维数组 )搭配使用判断是否已经在该位置设置了雷
1.让电脑在合法的区域内(Row*Col)产生随机坐标;
2.设置雷的限制条件:如果该坐标在棋盘1内数据为 ’0‘时,才可以在此位置设置一个雷(原因:若放置前一个雷的坐标与本次放置雷的坐标相同,如果无限制条件,则在此位置处本次设置雷就覆盖了前一次设置的雷,因为设置雷的个数是确定的,会造成在棋盘中设置雷的个数不满足规定雷的个数)。
void SetMeni(char board[Rows][Cols], int row, int col) //设置棋盘中雷的位置,雷设置的范围在Row*Col棋盘内
{
int x = 0; //将是雷的地方设置成1,不是雷的地方设置为0作用:在获得一个位置周边(所围成的正方形区域)雷的个数,可以直接进行计算,直接返回结果,不需要每次判断某个位置是否雷
int y = 0;
int count = Count; //已经定义规定好要设置的雷的个数
while (count)
{ //产生随机数的所有库函数:rand函数--调用-->srand函数--调用-->time函数
x = rand() % row + 1;//电脑随机产生要设置雷的坐标
y = rand() % col + 1;
if (board[x][y] == '0') //防止下一次设置雷的坐标与上次设置雷的坐标相同,重复设置,从而达不到规定的要设置的雷的个数
{
board[x][y] = '1';
--count; //每设置完一个雷,规定数目的雷减一
}
}
}
将是雷的地方设置成1,不是雷的地方设置为0作用:在获得一个位置周边(所围成的正方形区域)雷的个数,可以直接进行计算,直接返回结果,不需要每次判断某个位置是否雷,效率提高。
产生随机数的所有库函数:rand函数–调用–>srand函数–调用–>time函数,rand函数、srand函数均需要调用头文件#include
,time函数需要调用头文件#include 。
思路:
排查的条件:循环变量小于(RowCol-Count)棋盘1中数据减去规定雷的个数,排查的坐标需要是合法的坐标范围内(在RowCol);
若该坐标在棋盘2(meni数组)对应的位置为雷,则跳出循环,反之,则进行扩展区域函数。
void FindMeni(char meni[Rows][Cols], char show[Rows][Cols], int row, int col) //排查雷
{
int x = 0;
int y = 0;
while (i<row*col-Count)
{
printf("请输入要排查的坐标,中间以空格隔开>:");
scanf("%d %d", &x, &y);
if (x >= 1 && y >= 1 && x <= row && y <= col)
{
if (meni[x][y] == '1')
{
printf("你被炸死了\n");
printboard(meni, Row, Col);
break;
}
else
{
Extendboard(meni, show, row, col,x,y); //扩展区域
printboard(show, Row, Col); //打印扩展后Row*Col棋盘,用于检查是否扩展成功
int input = 0;
printf("请选择是否要标记雷,若要标记雷,请输入1>:");
scanf("%d", &input);
switch (input)
{
case 1:
MarkMeni(show, row, col);
break;
default:
break;
}
}
}
else
{
printf("需要排查的坐标不合法,请重新输入\n");
}
}
if (i == row * col - Count) //当所有不是雷的元素都排查完,才是排雷成功
{
printf("恭喜你,排雷成功\n");
printboard(meni, Row, Col);
}
}
思路:
前提条件:标记雷的坐标要在合法的范围内(Row*Col),在棋盘1(show数组)进行标记,且要标记的位置原来存储的数据为 ’ * ',才可以进行标记(在棋盘上存储了空格和数字的位置已经被判断出不是雷)。
void MarkMeni(char show[Rows][Cols], int row, int col) //标记雷可能存在的地方
{
printf("标记雷\n");
int x = 0; //存储我们输入的雷可能存在的坐标
int y = 0;
while (1)
{
printf("请输入要标记雷的坐标,中间以空格隔开");
scanf("%d %d", &x, &y);
if (x >= 1 && y >= 1 && x <= row && y <= col) //标记雷的位置要在Row*Col棋盘上
{
if (show[x][y] == '*') //某位置可标记的条件
{
show[x][y] ='?';
break;
}
else
{
printf("该位置不能被标记,请重新输入\n");
}
}
else
{
printf("需要标记雷的坐标不合法,请重新输入\n");
}
}
printboard(show, Row, Col); //打印执行标记后Row*Col棋盘,可以检查该位置是否被标记
}
思路:遍历棋盘1(Row*Col)
打印坐标的行、列数:对于棋盘2(meni二维数组),棋盘1(show二维数组)在棋盘2的位置行、列均是从1开始;
打印存放在棋盘1中的数据,供玩家观看。
void printboard(char board[Rows][Cols], int row, int col) //打印棋盘
{
printf("------扫雷游戏------\n");
int i = 0;
for(i = 0 ; i <= row ; i++) //设置列号,并打印
printf("%d ", i);
printf("\n");
i = 0;
for (i = 1; i <= row; i++) //打印的是Row*Col棋盘
{
printf("%d ", i); //设置行号,并打印
int j = 0;
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]); //打印棋盘上的数据
}
printf("\n"); //每一行打印完都需要换行,不然下一行的数据会衔接
}
}
思路:
遍历棋盘2(meni二维数组),赋初始值,打印Row*Col区域。
数字字符减去0字符等于其对应的数字
思路:
方法1:采用双层for循环来遍历棋盘2(meni二维数组)
从以某位置为中心围成的正方形区域(3*3)第一行开始遍历,直到遍历完第三行,依次将存放在棋盘2中对应位置的数字字符数据转化为对应的数字,在分别相加。
int GetMenicount(char meni[Rows][Cols], int x, int y) //获得雷的个数,前提条件,该位置已经证明了不是雷,存放的是‘0’
{
int sum = 0; //存放获得一个位置周边(所围成的正方形区域)雷的个数
int i = 0;
for (i = x - 1; i <= x + 1; i++) //遍历该位置所围成的正方形区域
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
sum += meni[i][j]-'0'; //数字字符减去字符0得到的是数字
}
}
return sum;
}
方法2:
return mine[x - 1][y] +mine[x - 1][y - 1] +mine[x][y - 1] +mine[x + 1][y - 1] +mine[x + 1][y] +
mine[x + 1][y + 1] +mine[x][y + 1] +mine[x - 1][y + 1]-8*'0';
思路:
采用递归实现,该位置处不是雷、该位置周边(所围成的正方形区域)不是雷 ,且不能在扩展已经设为空格的位置,
否则会造成死递归,从而造成栈溢出采用递归实现,
扩展的坐标应在合法的区域(Row*Col),不然会造成数组越界;
采用双层for循环来遍历棋盘2(meni二维数组),从以某位置为中心围成的正方形区域(33)第一行开始遍历,
判断该坐标所在棋盘1(show数组)所对应的数值是否为 '’ 或者为 ‘?’(‘?’只是我们手动标记雷可能存在的地方,可能也满足该函数的前提条件,若满足,则需要扩展),直到遍历完第三行,
void Extendboard(char meni[Rows][Cols], char show[Rows][Cols], int row, int col,int x,int y) //扩展区域,进入到该函数就说明该位置处不是雷,从此位置向外扩展
{ //采用递归实现,该位置处不是雷、该位置周边(所围成的正方形区域)不是雷 ,且不能在扩展已经设为空格的位置,否则会造成死递归,从而造成栈溢出采用递归实现
int count = 0; //存放获得一个位置周边(所围成的正方形区域)雷的个数
if (x >= 1 && y >= 1 && x <= row && y <= col) //扩展的坐标应在Row*Col棋盘
{
count=GetMenicount(meni, x, y);
if (count==0) //该位置可以扩展
{
show[x][y] = ' ';
i++; //记录不是雷的元素个数
int i = 0;
for (i = x - 1; i <= x + 1; i++)
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
if (show[i][j] == '*'||show[i][j]=='?') //注意‘?’只是我们手动标记雷可能存在的地方,可能也满足该函数的前提条件,若满足,则需要扩展
{
Extendboard(meni, show, row, col, i,j);
}![在这里插入图片描述](https://img-blog.csdnimg.cn/c1cfaa1860174181a0827d6e9e62f3bc.png#pic_center)
}
}
}
else //该位置周边(所围成的正方形区域)有雷,就把该位置周边(所围成的正方形区域)雷的个数转化为字符存储在该位
{
show[x][y] = count + '0'; // 数字+字符0等于数字字符
i++; //记录不是雷的元素个数
}
}
}
#define _CRT_SECURE_NO_WARNINGS 1
#include"meni.h"
void meue()//菜单栏
{
printf("****************\n");
printf("**** 1.play ****\n");
printf("**** 0.exit ****\n");
printf("****************\n");
}
void game()
{
char meni[Rows][Cols] = { 0 }; //设置雷数组
char show[Rows][Cols] = { 0 }; //排查雷数组
Initboard(meni, Rows,Cols,'0'); //初始化设置雷的棋盘全为‘0’
//printboard(meni, Row, Col);
SetMeni(meni, Row, Col); //设置棋盘中雷的位置
//(meni, Row, Col); //打印设置雷的棋盘
Initboard(show, Rows, Cols, '*'); //初始化排查雷的棋盘为‘*’
printboard(show, Row, Col); //打印排查雷的棋盘
FindMeni(meni, show, Row, Col); //排查雷
}
int main()
{
srand((unsigned int)time(NULL)); //生成随机数要调用的函数,srand的头文件为#include、time的头文件为#include
int input = 0;
do
{
meue();
printf("请选择>:");
scanf("%d", &input);
switch (input)
{
case 0:
printf("退出游戏\n");
break;
case 1:
game();
break;
default:
printf("选择错误,请重新选择\n");
break;
}
}while (input);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include"meni.h"
int i = 0;
void Initboard(char board[Rows][Cols], int rows, int cols, char set)//初始化棋盘,形参的名字和实参的名字可以相同也可不同
{
int i = 0; //初始化棋盘
for (i = 0; i < rows; i++) //遍历Rows*Cols棋盘
{
int j = 0;
for (j = 0; j < cols; j++)
{
board[i][j] = set; //将棋盘初始化为自己规定的格式
}
}
}
void printboard(char board[Rows][Cols], int row, int col) //打印棋盘
{
printf("------扫雷游戏------\n");
int i = 0;
for(i = 0 ; i <= row ; i++) //设置列号,并打印
printf("%d ", i);
printf("\n");
i = 0;
for (i = 1; i <= row; i++) //打印的是Row*Col棋盘
{
printf("%d ", i); //设置行号,并打印
int j = 0;
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]); //打印棋盘上的数据
}
printf("\n"); //每一行打印完都需要换行,不然下一行的数据会衔接
}
}
void SetMeni(char board[Rows][Cols], int row, int col) //设置棋盘中雷的位置,雷设置的范围在Row*Col棋盘内
{
int x = 0; //将是雷的地方设置成1,不是雷的地方设置为0作用:在获得一个位置周边(所围成的正方形区域)雷的个数,可以直接进行计算,直接返回结果,不需要每次判断某个位置是否雷
int y = 0;
int count = Count; //已经定义规定好要设置的雷的个数
while (count)
{ //产生随机数的所有库函数:rand函数--调用-->srand函数--调用-->time函数
x = rand() % row + 1;//电脑随机产生要设置雷的坐标
y = rand() % col + 1;
if (board[x][y] == '0') //防止下一次设置雷的坐标与上次设置雷的坐标相同,重复设置,从而达不到规定的要设置的雷的个数
{
board[x][y] = '1';
--count; //每设置完一个雷,规定数目的雷减一
}
}
}
int GetMenicount(char meni[Rows][Cols], int x, int y) //获得雷的个数,前提条件,该位置已经证明了不是雷,存放的是‘0’
{
int sum = 0; //存放获得一个位置周边(所围成的正方形区域)雷的个数
int i = 0;
for (i = x - 1; i <= x + 1; i++) //遍历该位置所围成的正方形区域
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
sum += meni[i][j]-'0'; //数字字符减去字符0得到的是数字
}
}
return sum;
}
void Extendboard(char meni[Rows][Cols], char show[Rows][Cols], int row, int col,int x,int y) //扩展区域,进入到该函数就说明该位置处不是雷,从此位置向外扩展
{ //采用递归实现,该位置处不是雷、该位置周边(所围成的正方形区域)不是雷 ,且不能在扩展已经设为空格的位置,否则会造成死递归,从而造成栈溢出采用递归实现
int count = 0; //存放获得一个位置周边(所围成的正方形区域)雷的个数
if (x >= 1 && y >= 1 && x <= row && y <= col) //扩展的坐标应在Row*Col棋盘
{
count=GetMenicount(meni, x, y);
if (count==0) //该位置可以扩展
{
show[x][y] = ' ';
i++; //记录不是雷的元素个数
int i = 0;
for (i = x - 1; i <= x + 1; i++)
{
int j = 0;
for (j = y - 1; j <= y + 1; j++)
{
if (show[i][j] == '*'||show[i][j]=='?') //注意‘?’只是我们手动标记雷可能存在的地方,可能也满足该函数的前提条件,若满足,则需要扩展
{
Extendboard(meni, show, row, col, i,j);
}
}
}
}
else //该位置周边(所围成的正方形区域)有雷,就把该位置周边(所围成的正方形区域)雷的个数转化为字符存储在该位
{
show[x][y] = count + '0'; // 数字+字符0等于数字字符
i++; //记录不是雷的元素个数
}
}
}
void MarkMeni(char show[Rows][Cols], int row, int col) //标记雷可能存在的地方
{
printf("标记雷\n");
int x = 0; //存储我们输入的雷可能存在的坐标
int y = 0;
while (1)
{
printf("请输入要标记雷的坐标,中间以空格隔开");
scanf("%d %d", &x, &y);
if (x >= 1 && y >= 1 && x <= row && y <= col) //标记雷的位置要在Row*Col棋盘上
{
if (show[x][y] == '*') //某位置可标记的条件
{
show[x][y] ='?';
break;
}
else
{
printf("该位置不能被标记,请重新输入\n");
}
}
else
{
printf("需要标记雷的坐标不合法,请重新输入\n");
}
}
printboard(show, Row, Col); //打印执行标记后Row*Col棋盘,可以检查该位置是否被标记
}
void FindMeni(char meni[Rows][Cols], char show[Rows][Cols], int row, int col) //排查雷
{
int x = 0;
int y = 0;
while (i<row*col-Count)
{
printf("请输入要排查的坐标,中间以空格隔开>:");
scanf("%d %d", &x, &y);
if (x >= 1 && y >= 1 && x <= row && y <= col)
{
if (meni[x][y] == '1')
{
printf("你被炸死了\n");
printboard(meni, Row, Col);
break;
}
else
{
Extendboard(meni, show, row, col,x,y); //扩展区域
printboard(show, Row, Col); //打印扩展后Row*Col棋盘,用于检查是否扩展成功
int input = 0;
printf("请选择是否要标记雷,若要标记雷,请输入1>:");
scanf("%d", &input);
switch (input)
{
case 1:
MarkMeni(show, row, col);
break;
default:
break;
}
}
}
else
{
printf("需要排查的坐标不合法,请重新输入\n");
}
}
if (i == row * col - Count) //当所有不是雷的元素都排查完,才是排雷成功
{
printf("恭喜你,排雷成功\n");
printboard(meni, Row, Col);
}
}
#define _CRT_SECURE_NO_WARNINGS 1
#define Row 9 //控制排查雷的棋盘,用户可以直接看到的棋盘
#define Col 9 //#define 行、列的值,有利于实现多列、多行的棋盘
#define Rows Row+2 //为了记录该位置周边(所围成的正方形区域)雷的个数时,防止造成越界
#define Cols Col+2
#define Count 10 //规定雷的个数,常量不能被修改,不可直接++、--
#include
#include
#include
void Initboard(char board[Rows][Cols], int rows, int cols, char set); //初始化棋盘
void printboard(char board[Rows][Cols], int rows, int cols); //打印棋盘
void SetMeni(char board[Rows][Cols], int rows, int cols); //设置雷
void FindMeni(char meni[Rows][Cols],char show[Rows][Cols], int rows, int cols); //排查雷
int GetMenicount(char meni[Rows][Cols], int rows, int cols); //获得该位置周边(所围成的正方形区域)雷的个数
void Extendboard(char meni[Rows][Cols], char show[Rows][Cols], int rows, int cols,int x,int y); //扩展区域
void MarkMeni( char show[Rows][Cols], int rows, int cols); //标记雷
运行结果
铁铁们,扫雷游戏的实现就到此结束啦,请动动你们的手给作者点个鼓励吧,你们的鼓励就是我的动力✨