首先还是先来看一下效果
棋盘中的格子用“*”表示,字符1表示地雷,玩家输入坐标,如果是地雷,提示玩家失败并显示地雷在格子的分布,如果不是地雷,此格显示数字,数字表示周围的地雷的个数
同井字棋游戏一样,扫雷依旧是分三个文件game.h声明函数,game.c实现函数功能,test.c测试
目录
1.创建开始菜单
逻辑和上一篇的井字棋相同便不再过多阐述,代码如下:
//test.c代码
void menu()
{
printf("++++++++++++++++++\n");
printf("+ 1.play +\n");
printf("+ 0.exit +\n");
printf("++++++++++++++++++\n");
printf("请输入:\n");
}
void test()
{
int input = 0;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:printf("START\n"); game(); break;
case 0:printf("END\n"); break;
default:printf("输入错误\n"); break;
}
} while (input);
}
int main()
{
test();
return 0;
}
我们的重点依旧是game函数的实现
2.打印棋盘
2.1建立棋盘
棋盘依旧是用二维数组来建立,但在初始化棋盘之前我们需要思考要建立多大的棋盘
游戏中的棋盘大小为10*10的大小,那么char board[10][10]?
但这个大小在后续函数功能实现的时候会很麻烦,如图:
如果边界处的坐标元素不是地雷,那么它就要显示周围的地雷的个数,函数会访问周围8个坐标元素,但显然边界周围的元素不足8个,这就会造成越界访问,那么函数就要添加判断条件坐标是否处于边界,处于边界后又是不是处于四个角落中,这样工作量又增加了
索性在建立棋盘的时候在实际棋盘大小周围再加一圈大小,即12*12。在使用时只使用中间的棋盘,这样写函数时也就不需要写过多的判断条件了
在建立棋盘的时候创建两个数组mine和show,功能如下:
代码:
//game.h文件代码
#include<stdio.h>
#define ROW 10
#define COL 10
#define ROWS ROW+2
#define COLS COL+2
game函数代码
void game()
{
char mine[ROWS][ROWS] = { 0 };
char show[ROWS][COLS] = { 0 };
}
2.2棋盘初始化
创建函数init,棋盘mine初始化成字符“0”,show初始化成“*”,那函数返回值类型应该为char,参数有数组名、行数、列数以及想要设置的字符,实现逻辑依旧是嵌套的for循环
//game.h文件代码
void init(char board[ROWS][COLS], int rows, int cols, char set);
//game.c文件代码
void init(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0, j = 0;
for ( i = 0; i < rows; ++i)
{
for ( j = 0; j < cols; ++j)
{
board[i][j] = set;
}
}
}
//test.c代码
void game()
{
char mine[ROWS][ROWS] = { 0 };
char show[ROWS][COLS] = { 0 };
init(mine, ROWS,COLS,'0');
init(show, ROWS,COLS,'*');
}
2.3放地雷
创建函数set_mine,需要确定放置地雷的个数,且地雷都需要放置mine中心的10*10大小内,地雷的位置需随机放置
//game.h
void set_mine(char mine[ROWS][COLS], int row, int col,int number);//注意这里是row和col,和定义的ROW和COL对应,二者的值为10
因为地雷位置需随机放置,那么就又要使用rand(),在使用之前依旧是要设置srand()
//game.c
void set_mine(char mine[ROWS][COLS], int row, int col, int number)
{
int i = number;
while (i)
{
int x = rand() % row + 1;//因为是12*12大小使用中间的10*10大小作为棋盘
int y = rand() % col + 1;//所以值需要从1开始,从0开始地雷就放置在棋盘外了
if (mine[x][y] == '0')
{
mine[x][y] = '1';
i--;
}
}
}
//test函数中do...while循环外添加 srand((unsigned int)time(NULL));
//在game.h中引用头文件<stdlib.g>和<time.h>
2.4打印棋盘
需要打印的是数组show中间的10*10大小的元素,使用时注意参数
//game.h
void set_mine(char mine[ROWS][COLS], int row, int col,int number);
//game.c
void display(char board[ROWS][COLS], int row, int col)
{
for (int i = 1; i <=row; ++i)
{
for (int j = 1; j <=col; ++j)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
3.判断输赢
创建函数find_mine,玩家输入坐标,如果该坐标藏有地雷,提示玩家失败,显示地雷分布后结束游戏,否则显示该坐标周围的地雷的个数,当棋盘除地雷之外的所有位置都被玩家找出来后提示玩家获胜
建立棋盘时创建了两个数组,所以find_mine参数也需要两个数组
//game.h
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
那么在坐标元素不是地雷时如何显示周围地雷个数?
我们用“1”来表示地雷,“0”表示没有,那么周围的数字加起来就正好是地雷的个数,但“1”和“0”都是字符型数据,所以需要在后面-‘0’使其变成int型数据,之后显示时+'0'改回字符
//game.c
int mine_count(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 find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0, y = 0;
printf("输入坐标\n");
scanf("%d%d", &x, &y);
int count = 0;
while (count < row * col - NUMBER)
{
if (mine[x][y] == '1')
{
printf("you lose\n");
display(mine, ROW, COL);
break;
}
else
{
int n = mine_count(mine, x, y);
show[x][y] = n + '0';//函数返回类型为int,+'0'改为字符型
count++;
display(show, ROW, COL);
}
}
if (count == row * col - NUMBER)
{
printf("you win\n");
display(mine, ROW, COL);
}
}
到这扫雷的代码基本上完成了,感谢观看,完