目录
一,基本思路
1.使用两个棋盘(也就是要求创建两个二维数组),一个用以存放雷的位置,一个用以展示给玩家看
2.明确要实现的几个主要功能:1)把棋盘打印到屏幕,展示给玩家
2)玩家进行排雷,给出玩家所排点周围雷的个数
3)设置失败的触发条件:玩家踩雷
4)设置成功的触发条件:玩家排雷次数已达到上限值
(上限值=棋盘总格数 - 玩家设置的雷的个数)
二,排雷整体实现(含空白展开功能)
本人小白哈哈,刚玩扫雷的时候并没有注意这个空白展开的功能,后来补加上去的,比较赶,并未做太多的算法优化,请见谅哈哈🤣🤣🤣
下面是总代码,接着会有细节的讲述
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void chushihua(char a[11][11],char p);
void print_board(char b[11][11]);
int pailei(char a[11][11],char b[11][11]);
void setbomb(char a[11][11],int n);
void kaipi(char a[11][11],char b[11][11],int x,int y);
int countlei(char a[11][11],int x,int y);
int pan(char b[11][11],int x,int y);
int pan2(char b[11][11]);
int x1=0,y1=0;
int main()
{
again:
printf("请输入1或2\n1为开始游戏 2为退出游戏");
int u,n;
scanf("%d",&u);
switch (u)
{
case 1:
printf("游戏开始\n设置雷的数量\n");
scanf("%d",&n);
char a[11][11];//用以存放雷的位置,其中'0'为无雷区,其中'1'为雷区
char b[11][11];//用以展示给玩家,其中'*'表示未被探索区域
chushihua(a,'0');
chushihua(b,'*');
setbomb(a,n);
while(1)//利用循环实现多次下棋
{
int k=1;
print_board(b);
k=pailei(a,b);
if(k==2)
{
kaipi(a,b,x1,y1);
}
if(k==0)
{
print_board(a);
printf("You Lost!你被炸死了");
break;
}
if(pan2(b)==n)
{
printf("You Win!");
break;
}
}
break;
case 2:
printf("游戏已退出");
break;
default:
printf("输入错误,请重新输入\n");
goto again;
}
return 0;
}
//函数定义
void chushihua(char a[11][11],char p)
{
for(int i=0;i<=10;i++)
{
for(int j=0;j<=10;j++)
{
a[i][j]=p;
}
}
}
void print_board(char b[11][11])
{
for(int i=0;i<=9;i++)
{
printf("%d ",i);
}
printf("\n");
for(int i=1;i<=9;i++)
{
printf("%d ",i);
for(int j=1;j<=9;j++)
{
printf("%c ",b[i][j]);
}
printf("\n");
}
}
void setbomb(char a[11][11],int n)
{
int x,y,z,r,count=0;
srand((unsigned)time(NULL));
while(1)
{
z = rand();
r = rand();
x=z%9+1;
y=r%9+1;
if(a[x][y]=='0')
{
a[x][y]='1';
count++;
}
if(count==n)
{
break;
}
}
}
int countlei(char a[11][11],int x,int y)
{
int count=a[x-1][y-1]+a[x-1][y]+a[x-1][y+1]+a[x][y-1]+a[x][y+1]+a[x+1][y-1]+a[x+1][y]+a[x+1][y+1]-8*'0';
return count;
}
int pailei(char a[11][11],char b[11][11])//返回值为0时,被炸死
{
int x,y,count=0;
while(1)
{
printf("输入需要排查的坐标\n");
scanf("%d %d",&x,&y);
if(x<1||x>9||y<1||y>9||b[x][y]!='*')
{
continue;
}
if(a[x][y]=='1')
{
return 0;
}
count=a[x-1][y-1]+a[x-1][y]+a[x-1][y+1]+a[x][y-1]+a[x][y+1]+a[x+1][y-1]+a[x+1][y]+a[x+1][y+1]-8*'0';
b[x][y]='0'+count;
if(count==0)
{
x1=x;
y1=y;
return 2;
}
return 1;
}
}
void kaipi(char a[11][11],char b[11][11],int x,int y)
{
for(int i=-1;i<=1;i++)
{
for(int j=-1;j<=1;j++)
{
if(i!=0||j!=0)
{
b[x+i][y+j]=countlei(a, x+i, y+j)+'0';
}
}
}
for(int i=-1;i<=1;i++)
{
for(int j=-1;j<=1;j++)
{
if(b[x+i][y+j]=='0'&& pan(b,x+i,y+j)==1)
{
kaipi(a,b,x+i,y+j);
}
}
}
}
int pan(char b[11][11],int x,int y)//有*号返回1
{
for(int i=-1;i<=1;i++)
{
for(int j=-1;j<=1;j++)
{
if(i!=0||j!=0)
{
if(b[x+i][y+j]=='*')
{
return 1;
}
}
}
}
return 0;
}
int pan2(char b[11][11])//计算b数组中的*数
{
int count=0;
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
{
if(b[i][j]=='*')
{
count++;
}
}
}
return count;
}
三,排雷的细节讲解
1.首先,我们先看代码的函数声明部分(解释见图)
2.接着,看代码躯干(main函数部分)
3.最后,我们看各个函数的定义
1)初始化
2)打印棋盘
3)电脑随机在a盘中布置雷,雷记为'*'
4)数坐标为(x,y)的位置周围的雷的数量,返回值即雷的数量
5)玩家排雷(返回值为0时,被炸死;返回值为2时,说明周围无雷,可以进行空白的开辟)
6)周围无雷,进行空白的开辟(利用函数递归),其中if(b[x+i][y+j]=='0'&& pan(b,x+i,y+j)==1)的递归的边界条件极为重要i
条件1:该位置周围无雷;
条件2:该位置周围的区域并未被翻开
7)看坐标为(x,y)处周围是否有*,为kaipi函数的函数递归做边界条件
8)计算b中’*‘的数量,即未排查区的数量,当未排除区为0,玩家即可获得胜利
以上就是我关于扫雷的一些实现,小白新人,如有错误,感谢各位大佬的指正啦~~😁😁😘😝