整个游戏的实现分为五个部分:
在文章的最后会有完整的代码呈现
首先是游戏选择部分,你可以在此选择是否开始游戏
且每当结束一把对局,也会回到该界面,再次进行选择
void menu()
{
printf(" \n");
printf(" 1.paly \n");
printf(" 0.exit \n");
printf(" \n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请输入:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
这里我们用do…while语句配合switch…case语句,实现游戏选择的基本功能
如果对方输入“1”,那么我们将开始游戏,但在此之前会初始化棋盘、并将其打印的
我们以一个9×9的棋盘为例,这对应的就是一个9行9列的二维数组
我们都知道扫雷游戏的玩法:点开一个格子,会显示其周围一圈八个格子存在雷的数量。
但倘若我们点的格子恰好在边缘上,这时候再判断周围八个格子是否是雷时会有几个坐标在棋盘外部,这时再通过遍历这八个坐标判断时,会发生数组越界
为了避免这种麻烦,我们再定义一个11×11的二维数组,专门用于判断,并且在超过9×9的地方都赋值0,这样在判断时也不会将其判定为雷
综上:
我们需要设计两个二维数组,一个数组(show)9×9(尽管初始化时我将show初始化成11×11的数组,但实际上只用到了中间的9×9),专门用于存放被排查出的雷的信息,并呈现给玩家;另一个数组(mine)11×11,专门用于判断周围是否有雷,并将排查出来的信息传递给show数组
对于初始化:
mine数组初始化为全’0’,被埋雷的地方则改为’1’;show数组初始化为’*‘,被排查的地方则显示器周围相应的雷的数量,如’2’
代码实现:
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
void init_board(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;
}
}
}
void game()
{
//定义两个数组
char mine[ROWS][COLS];
char show[ROWS][COLS];
//初始化数组
init_board(mine, ROWS, COLS, '0');
init_board(show, ROWS, COLS, '*');
}
尽管我们设计了两个数组,但在打印时只会打印show数组,mine数组是不打印的,其存在目的只是为了使show数组能够显示每个格子周围雷的信息
打印结果展示:
看到上面的打印结果或许有人要问:这个行和列旁边的0~9是什么意思啊?
不急,这就涉及到后面内容-棋盘打印了,在文章后续会讲
下面我们先看雷的布置
在初始化棋盘完成后,就需要布置雷了
雷的布置要满足随机的要求,所以就要用到随机数rand和srand(注意头文件的引用)
我们提前在main函数中初始化一个随机数发生器srand((unsigned int)time(NULL));
,便于生成随机数
因为雷的布置玩家是不知道的,所以只需要在mine数组中布置即可,即将mine数组中的’0’变成’1’
代码实现:
//设置雷的个数
#define easy_count 10
void set_mine(char board[ROWS][COLS], int row, int col)
{
int count = easy_count;
//布置easy_count个雷,每布置一个就减少1
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
//该坐标要确定没被布置过雷
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
这里的int x = rand() % row + 1和int y = rand() % col + 1
是保证布置的雷不会超出9×9的范围
在布置完雷后,就可以进行打印棋盘供玩家开始排查雷了
所打印的棋盘是不能让玩家知道雷是怎么布置的所以,mine数组不能打印,只需打印show数组即可
代码实现:
void dispaly_board(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
for (j = 0; j <= col; j++)
{
printf("%d ", j);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
为了使玩家在排查雷时方便输入坐标,我们在棋盘的上侧和左侧标上列号和行号,即在初始化棋盘时见到的那样
棋盘被成功打印后就要开始真正的“扫雷”了
玩家在输入一个坐标后,我们需要在mine数组上的该坐标周围8个坐标判断有没有雷,有几颗雷,并将这个数据传给show数组进行显示
同时我们也要给出游戏结束的条件:踩雷了或者非雷的坐标都排查完毕
代码实现:
int get_mine_count(char board[ROWS][COLS],int x,int y)
{
return (board[x - 1][y - 1] +
board[x - 1][y] +
board[x - 1][y + 1] +
board[x][y - 1] +
board[x][y + 1] +
board[x + 1][y - 1] +
board[x + 1][y] +
board[x + 1][y + 1] - 8 * '0');
}
void find_mine(char board1[ROWS][COLS], char board2[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;
while (win< row * col - easy_count)
{
printf("请输入坐标:");
scanf("%d%d", &x, &y);
//首先判断输入的坐标是否符合棋盘大小规定
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//再判断这个坐标是否已经排查过了
if (board2[x][y] == '*')
{
if (board1[x][y] == '1')
{
printf("很遗憾,你被炸死了!\n");
dispaly_board(board1, ROW, COL);
break;
}
else
{
//用来接收该坐标周围的雷数
int count = get_mine_count(board1, x, y);
//因为我们在show数组中都是字符数字,所以也要让count变成字符数字,所以这里+上了'0'
board2[x][y] = count + '0';
//进行屏幕清空
system("cls");
dispaly_board(board2, ROW, COL);
//每成功扫一个雷就win++
win++;
}
}
else
{
printf("坐标已被排查,请重新输入:");
}
}
else
{
printf("坐标非法,请重新输入:");
}
}
if (win == row * col - easy_count)
{
printf("恭喜你,扫雷成功\n");
dispaly_board(board1, ROW, COL);
}
}
具体排查过程各位可以看代码,是比较好理解的
值得一提的是,在提取坐标周围雷的信息时,我们是将这八个坐标遍历,将这8个字符加起来-8*‘0’,这样就可以得到雷的个数
因为’0’对应的ASCII码值为48,'1’对应49,倘若周围没有雷,则8个48相加减去8乘48等于0,即没有雷,符合要求
我写这个游戏时是多文件工程,所以我也就分文件给大家呈现了
main.c
#include"game.h"
void menu()
{
printf(" \n");
printf(" 1.paly \n");
printf(" 0.exit \n");
printf(" \n");
}
void game()
{
//定义两个数组
char mine[ROWS][COLS];
char show[ROWS][COLS];
//初始化数组
init_board(mine, ROWS, COLS, '0');
init_board(show, ROWS, COLS, '*');
//布置雷
set_mine(mine, ROW, COL);
//打印最初的棋盘
dispaly_board(show, ROW, COL);
//排查雷
find_mine(mine, show, ROW, COL);
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请输入:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
game.h
#pragma once
#include
#include
#include
#include
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//设置雷的个数
#define easy_count 10
//初始化数组
void init_board(char board[ROWS][COLS], int rows, int cols, char set);
//打印棋盘
void dispaly_board(char board[ROWS][COLS], int row, int col);
//布置雷
void set_mine(char board[ROWS][COLS], int row, int col);
//排查雷
void find_mine(char board[ROWS][COLS], int rows, int cols);
game.c
#include"game.h"
//初始化数组
void init_board(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;
}
}
}
//打印棋盘
//这里只需要打印中间9*9的棋盘就可以了
void dispaly_board(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
for (j = 0; j <= col; j++)
{
printf("%d ", j);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
//布置雷
//这里只需要在中间9*9的棋盘布置即可,将mine数组中'0'变成'1'
//因为要在棋盘中随机布置雷,所以要用到随机数
void set_mine(char board[ROWS][COLS], int row, int col)
{
int count = easy_count;
//布置easy_count个雷,每布置一个就减少1
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
//该坐标要确定没被布置过雷
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
int get_mine_count(char board[ROWS][COLS],int x,int y)
{
return (board[x - 1][y - 1] +
board[x - 1][y] +
board[x - 1][y + 1] +
board[x][y - 1] +
board[x][y + 1] +
board[x + 1][y - 1] +
board[x + 1][y] +
board[x + 1][y + 1] - 8 * '0');
}
//排查雷
//玩家在选定一个坐标后,我们需要在mine数组上的该坐标周围8个坐标判断有没有雷,有几颗雷,并将这个数据传给show数组进行显示
void find_mine(char board1[ROWS][COLS], char board2[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;
while (win< row * col - easy_count)
{
printf("请输入坐标:");
scanf("%d%d", &x, &y);
//首先判断输入的坐标是否符合棋盘大小规定
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//再判断这个坐标是否已经排查过了
if (board2[x][y] == '*')
{
if (board1[x][y] == '1')
{
printf("很遗憾,你被炸死了!\n");
dispaly_board(board1, ROW, COL);
break;
}
else
{
//用来接收该坐标周围的雷数
int count = get_mine_count(board1, x, y);
//因为我们在show数组中都是字符数字,所以也要让count变成字符数字,所以这里+上了'0'
board2[x][y] = count + '0';
//进行屏幕清空
system("cls");
dispaly_board(board2, ROW, COL);
//每成功扫一个雷就win++
win++;
}
}
else
{
printf("坐标已被排查,请重新输入:");
}
}
else
{
printf("坐标非法,请重新输入:");
}
}
if (win == row * col - easy_count)
{
printf("恭喜你,扫雷成功\n");
dispaly_board(board1, ROW, COL);
}
}
到这里,扫雷游戏就算是实现了,不过这里的游戏也存在缺陷
我写的代码在排查雷时只能一次排查一个,无法做到像网上游戏一样,有时候可以一次排查一片
其他若有写的不对、不好、不严谨的地方欢迎各位指正
感谢各位的阅读观看,谢谢大家!