扫雷功能介绍:第一次下子不被炸死;当下子之后提示周围雷的数量。
大体思想:1.设置两个二维数组(相当于棋盘),一个棋盘是展示给用户的show[][],一个是在布雷和扫雷时所要用到的数组mine[][],这个mine数组不对用户展示,方便程序员在编写时对布雷和扫雷提供方便。
2.在实现第一次下子不被炸死功能时,可以想作是在如果第一次下子在雷上,将雷重新移动到其他随机没有雷的位置。
3.在实现提示周围雷的数量时,我用了几个if语句判断下子位置周围八个地方是否有雷,最后将这八个地方的雷数相加,在下子位置显示出来。
其他的函数都比较简单,不懂的地方可以看下面代码。
头文件 game.h
在头文件中将各个函数,还有数组的行列大小进行定义,以便在后期使用需要修改矩阵大小时直接改变头文件中宏定义的行列。
#ifndef __GAME_H__
#define __GAME_H__
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#define ROW 11
#define COL 11
#define count 10
enum OPTION
{
EXIT,//0
PLAY//1
};
void init_board(char mine[ROW][COL],char show[ROW][COL],int col,int row);//初始雷盘
void display(char show[ROW][COL]);//打印雷盘
void set_mine(char mine[ROW][COL]);//布雷
int get_mine(char mine[ROW][COL],int x, int y);//计算周围雷的数量
void mine_sweep(char mine[ROW][COL],char show[ROW][COL]);//判断是否踩雷
#endif //__GAME_H__
源文件 扫雷逻辑game.c
在这个源文件中,主要实现各个函数之间的调用顺序,以便进行扫雷,也是扫雷的大体逻辑顺序。用game函数调用各个函数,主函数main中实现用户的选择,外围用do...while进行循环游戏,用switch选择实现用户的选择。
#include"game.h"
void menu()
{
printf("*******************************\n");
printf("********1.PLAY 0.EXIT ********\n");
printf("*******************************\n");
}
void game()
{
char mine[ROW][COL]={0};
char show[ROW][COL]={0};
init_board(mine,show,ROW,COL);
display(show);
set_mine(mine);
mine_sweep(mine,show);
}
int main()
{
int input = 0;
do
{
menu();
scanf("%d",&input);
switch(input)
{
case 1: game(); break;
case 0: break;
default: printf("选择错误\n");break;
}
}while(input);
return 0;
}
源文件 各个函数功能的实现test.c
#include"game.h"
void init_board(char mine[ROW][COL],char show[ROW][COL],int row, int col) //初始化棋盘,并为其开辟相应的内存空间
{
memset(mine,'0',row*col); //雷盘,不想用户展示
memset(show,'*',row*col); //向用户展示的棋盘
}
void display(char show[ROW][COL]) //打印向用户展示的棋盘
{
int i = 0;
int j = 0;
printf(" ");
for(i=1; i<COL-1; i++)
{
printf("%2d",i);
}
printf("\n");
for(i=1; i<ROW-1; i++)
{
printf("%2d",i);
for(j=1; j<COL-1; j++)
{
printf("%2c",show[i][j]);
}
printf("\n");
}
}
void set_mine(char mine[ROW][COL]) //布雷,用到rand函数做到布雷的随机性
{
int i = 0;
int j = 0;
int num = count;
srand((unsigned int)time(NULL));
while(num)
{
int i = rand()%(ROW-2)+1;
int j = rand()%(COL-2)+1;
if(mine[i][j]=='0')
{
mine[i][j] = '1';
num--;
}
}
}
int get_mine(char mine[ROW][COL],int row, int col)//计算下子位置八个周围的雷数的总量,用int接收
{
int num = 0;
if(mine[row-1][col-1]=='1')
{
num++;
}
if(mine[row-1][col]=='1')
{
num++;
}
if(mine[row-1][col+1]=='1')
{
num++;
}
if(mine[row][col-1]=='1')
{
num++;
}
if(mine[row][col+1]=='1')
{
num++;
}
if(mine[row+1][col-1]=='1')
{
num++;
}
if(mine[row+1][col]=='1')
{
num++;
}
if(mine[row+1][col+1]=='1')
{
num++;
}
return num;
}
void mine_sweep(char mine[ROW][COL],char show[ROW][COL])//第一次下子不被炸死、余下步骤中是否踩雷
{
int t =1;
int i = 0;
int j = 0;
int num = 0;
int x = 0;
int y = 0;
while(num!=(ROW-2)*(COL-2)-count) //判断雷是否已扫完
{
/* printf(" "); //打印雷盘,测试代码
for(i=1; i<COL-1; i++)
{ //在测试如第一次下子不被炸死函数是否正确时
printf("%2d",i);
} //这段代码可以打印不向用户打印的雷盘,方便测试函数功能
printf("\n");
for(i=1; i<ROW-1; i++)
{
printf("%2d",i);
for(j=1; j<COL-1; j++)
{
printf("%2c",mine[i][j]);
}
printf("\n");
}*/
printf("请输入下子位置-->:");
scanf("%d%d",&i,&j);
if((i>=1)&&(j>=1)&&(i<=ROW-2)&&(j<=COL-2)) //判断输入坐标
{
while(t==1) //判断第一次下子是否碰雷
{
if(mine[i][j]=='1') //第一次下子碰雷
{
while(t==1)
{
mine[i][j] = '0';
y = rand()%9;
x = rand()%9;
if(mine[x][y] = '0') //内层while循环保证此次布雷如重叠,继续循环布雷直至不重叠
{
mine[x][y] = '1'; //需重新定义x,y不然i,j的话会使下面判断踩雷满足条件
t = 0; //布雷成功后,赋值t为0,下次循环跳出循环
}
}
}
else //第一次下子未碰雷,赋值t为0,保证下次循环跳出语句
{
t = 0;
}
}
if(mine[i][j]=='1')
{
printf("呵呵\n");
return ;
}
else
{
int ret = get_mine(mine,i,j);
show[i][j] = ret+'0';
num++;
display(show);
}
}
else printf("不是有效坐标,请重新输入-->:\n");
}
printf("Congratulations\n");
}
下面是其中的一些运行截图
