关于扫雷游戏的实现
同样完整的代码依旧会放到最后面;
1,我一般界面的会使用英语的neum
2,游戏主体都会使用英文的game。
3,然函数的调用离不开我们的main函数。
上面的三个函数在test.h中
4,我使用的是VS2022的X86的环境
——————————————————————————————————
当我们了解了上面的那么就可以创建二维数组了(放在test.h源文件里)
提醒game.h是我们的头文件 ——> 放我们的声明
game.c和test.c是我们的源文件,game.h是放我们的函数的,tesr.h是存放我们main函数和游戏实现和界面的
——————————————————————————————————
我们刚写过关于C语言猜数字游戏的视线,虽然我感觉那边写的不是很好。所以呢,这篇呢,我们再写一篇关于扫雷游戏
一个简单的游戏的三大要素
我们要有界面 并且界面,
能够进行进入和退出
,进入游戏这个游戏能够运行。
一,界面的设计。
因为是刚接触C语言,所以我们对界面的设计只能通过简单printf的函数去实现。学到后面,我们可能会学到一些其他的函数,去帮助我们实现一个更精美的界面,但是现在我们依旧使用printf()函数去帮助我们打造一个景点。
以下就是种比较简单的
void menu()
{
printf("*******************************\n");
printf("******1,play 0,exit*******\n");
printf("*******************************");
}
二,选择和退出。
当我们打造好这个界面的时候,我们应该了解到只有游戏的界面展现出来,玩家才能够进行选择,所以这时候我们就要利用
do while循环去帮助我们实现这一功能。那么对于这个界面,我们进入这个游戏或者退出这个游戏,我们都要去输入一个值,让我们所打造的这个游戏界面具有选择意义,这时候我们就要用到switch语句去帮助我们实现这一功能。
int main()
{
int input = 0; //进行选择
srand((unsigned int)time(NULL)); //随机数的生成,后面会有
do
{
menu(); //打印菜单
printf("\n请输入选项:"); //提醒玩家输入
scanf("%d", &input);
switch (input) //如果输入1,进入游戏
{
case 1:
game();
break;
case 0: //输入0,不进入游戏
break;
default: //玩家输入其他的数,用来提醒输入错误
printf("输入错误");
}
} while (input);
}
如果输入1
上面的棋盘是后面的内容,这里主要展示输入1.进入的界面
如果输入0
如果输入其他的数,会提示错误并且让你再输入。
三,游戏的主体实现
我们这里打造的是一个9×9的扫雷小游戏。
1,棋盘设计
(1)一些设计的问题
既然我们要去实现一个9×9的扫雷小游戏,那么必然要将这个游戏放到一个棋盘上面,这个棋牌我们就可以使用数组中的二维数组解决
可是当我们创造一个9×9的扫雷小游戏,如果他的棋盘只是9成9的,搭我们去统计,我们说点的地方周边的雷。那么可能会出现下面这样的情况
我们会发现统计雷的数量时,在统计边缘坐标周边的雷时会发生越界,代码会报错,怎么解决?
我们发现,,他没有实际的存储,发生了越界行为。我们如何去解决这样一个行为呢?其实很简单将我们说的棋盘变大不使用9X9的棋盘,但是只有9×9的方格会放东西,我们可以创建两个变量ROW是9 COL也是9,因为说这次的扫雷游戏是分文件的使用ROW和COL,ROWS和COLS放在game.h里
(1)棋盘放大了之后我们会发现统计雷的数量时,在统计边缘坐标周边的雷就不会发生越界行为
ROWS是ROW+2,COLS是COL+2
(2)棋盘的大小数据存放
因为方便我将库文件也放到了game.h文件中
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
//这样设计可以在未来我们想改变棋盘大小时容易改变
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
(3)棋盘的创建
创建二位数组
char mine[ROWS][COLS];
char show[ROWS][COLS];
然后将数组放到game函数里
void game()
{
char mine[ROWS][COLS];
char show[ROWS][COLS];
}
2,雷的信息的存放思考
当我们讲棋盘设计后之后,我们就要去考虑,在这个棋盘上去放我们的雷,在这里面我们雷用“1”来表示非雷用“0”来表示。
那么这样,我们如果在一个棋盘上去实现,那这样信息不就全被看到了吗?所以在这里面我们使用两个棋盘,一个棋盘,对于玩家来看,另一个棋盘用来存放我们的信息,mine是放雷的,show是展现给玩家的
3,棋盘的初始化
首先我们创建了二维数组之后,要将数组初始化,并将棋盘打印出来,这里我使用'*'来标识玩家看到的,‘0’存放雷的棋盘
(1)函数的设计
设计应该InitBoard(使用英文,便于了解)
InitBoard(mine, ROWS, COLS, '0'); //初始化'0'
InitBoard(show, ROWS, COLS, '*'); //初始化'*'
我们设计了这个函数,这个函数的功能是初始化并打印棋盘
1.1首先,使用函数要声明在game.h里
set接收的是初始化的字符
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set);
1.2完成InitBoard函数
我们使用循环先将行打印,然后打印列 #include "game.h"是引用头文件的东西
#include "game.h"
void InitBoard(char arr[ROWS][COLS], int rows, int cols,char set)
{
int i = 0;
for (i = 0; i < rows; i++) //行
{
int j = 0;
for (j = 0; j < cols; j++) //列
{
arr[i][j] = set;
}
}
}
下面是玩家看到的
4,行列的设计。
因为我们是通过简单的库函数去实现这个小类小游戏的,所以我们要设计行列,让玩家知道他所选的点是哪一点。想要去实现这一点其实很简单,我们只需要在打印棋盘的那个函数里面打印行列的序号就行了。
我们就创建应该函数去实现这个功能DisplayBoard
//打印,虽然创建的时11X11的棋盘,但是玩家看到的9X9
DisplayBoard(show,ROW,COL); //传过去的是玩家的棋盘
我们实现行列的代码
void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{
int i = 1;
for (i = 0; i <= row; i++) //打印一行的序号
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
int j = 0;
printf("%d ", i);
for (j = 1; j <= col; j++) //打印列
{
printf("%c ", arr[i][j]);
}
printf("\n");
}
}
当我们完成了棋盘的设计后,就要实现雷的随机放置
5,雷的布置
(1)函数的创建
SetMine(mine, ROW, COL);
(2)雷随机复杂和位置重复的想考
假如我们布置10个雷,因为要使用随机数,这里给rand(),但是我们知道rand()生成的是0~32767的数,但是我们的棋盘给玩家使用去玩游戏的不过9X9的大小,使用使用rand()%9+1就可以实现1~9的·雷·的生成
这里我们使用了row和col是为了方便我们以后改下棋盘的大小,
然后雷的放置是坐标,我们将mine棋盘初始化的是字符0,如果仅仅使用
int x = rand() % row + 1;
int y = rand() % col + 1;
那么雷就可能重复在一个位置放,所以使用if语句就可以实现雷的放置,并且不在同一个坐标放
void SetMine(char arr[ROWS][COLS], int row, int col)
{
//布置10个雷
//⽣成随机的坐标,布置雷
int count = 10;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (arr[x][y] == '0')
{
arr[x][y] = '1'; //字符1代表雷
count--;
}
}
}
可以使用
//DisplayBoard(mine, ROW, COL); //打印的是布置雷1的棋盘
放置在,SetMine(mine, ROW, COL);后面看雷的分布
6,扫雷游戏的判断
(1)函数的创建
这里为了方便使用FindMine去构建我们的函数
FindMine(mine, show, ROW, COL);
(2)函数的实现
int win = 0;这里是为了,当玩家全部猜出来了实现,成功的判断
win < ROW * COL - 10 是棋盘的坐标个数(没有雷的)
当我们玩当我们去玩这个游戏的时候,玩家将所有没有雷的位置全部拆出来的时候了,就要跳出我们这个循环去显示玩家成功了,玩家没有将所有没有雷的位置全部拆出来,并且踩中雷的时候我们给一个判断条件,显示玩家猜到雷了,并且在失败之后将雷的那个棋盘给打印出来,展示给玩家看。
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0; //x,y是实现坐标输入的
int y = 0;
int win = 0;
while (win < ROW * COL - 10)
{
printf("请输入坐标");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("失利了,选到雷了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
//不是雷,统计坐标旁边有多少个雷
int n = GetMineCount(mine, x, y);
show[x][y] = n + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("选择的地方不对,重输入吧");
}
}
if (win == ROW * COL - 10)
{
printf("成功,开心");
DisplayBoard(mine, ROW, COL);
}
}
那我们如何去实现扫雷游戏中当点到空白位置会有一片空白位置出现?那我们就在这个时候再创建一个函数,当玩家猜到空白位置,并且没有猜到雷的时候。我们去统计玩家首选坐标4周有没有雷?并且将有雷的个数或者没有雷的个数打印在玩家所选的坐标呢?
7,雷数量的统计
(1)函数的创建
int n = GetMineCount(mine, x, y);
(1)数量的统计
将玩家选择的坐标周围的雷统计出来,在玩家选择的坐标通过加减将周围坐标表示出来
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
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';
}
最终我们的游戏完成
代码如下
game.h头文件里的
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
//这样设计可以在未来我们想改变棋盘大小时容易改变
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set);
void DisplayBoard (char arr[ROWS][COLS], int row, int col);
void SetMine(char arr[ROWS][COLS], int row, int col);
void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS],int row, int col);
game.c源文件(函数)里的
#include "game.h"
void InitBoard(char arr[ROWS][COLS], int rows, int cols,char set)
{
int i = 0;
for (i = 0; i < rows; i++) //行
{
int j = 0;
for (j = 0; j < cols; j++) //列
{
arr[i][j] = set;
}
}
}
void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{
int i = 1;
for (i = 0; i <= row; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
int j = 0;
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", arr[i][j]);
}
printf("\n");
}
}
void SetMine(char arr[ROWS][COLS], int row, int col)
{
//布置10个雷
//⽣成随机的坐标,布置雷
int count = 10;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (arr[x][y] == '0')
{
arr[x][y] = '1';
count--;
}
}
}
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
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';
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;
while (win < ROW * COL - 10)
{
printf("请输入坐标");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("失利了,选到雷了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
//不是雷,统计坐标旁边有多少个雷
int n = GetMineCount(mine, x, y);
show[x][y] = n + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("选择的地方不对,重输入吧");
}
}
if (win == ROW * COL - 10)
{
printf("成功,开心");
DisplayBoard(mine, ROW, COL);
}
}
test.c源文件里的
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h" //声明我们的函数
void menu()
{
printf("*******************************\n");
printf("******1,play 0,exit*******\n");
printf("*******************************");
}
void game()
{
char mine[ROWS][COLS];
char show[ROWS][COLS];
//下面去实现初始化打印
InitBoard(mine, ROWS, COLS, '0'); //初始化'0'
InitBoard(show, ROWS, COLS, '*'); //初始化'*'
//打印,虽然创建的时11X11的棋盘,但是玩家看到的9X9
DisplayBoard(show,ROW,COL);
//DisplayBoard(mine, ROW, COL);
//布置雷
SetMine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL); //打印的是布置雷1的棋盘
//排查类雷
FindMine(mine, show, ROW, COL);
}
int main()
{
int input = 0; //进行选择
srand((unsigned int)time(NULL));
do
{
menu(); //打印菜单
printf("\n请输入选项:"); //提醒玩家输入
scanf("%d", &input);
switch (input) //如果输入1,进入游戏
{
case 1:
game();
break;
case 0: //输入0,不进入游戏
break;
default: //玩家输入其他的数,用来提醒输入错误
printf("输入错误\n");
}
} while (input);
}