目录
get_mine_count(mine, x, y)是用来计算已排除的方格周围的埋雷数
一、前言
扫雷游戏几乎能称得上是家喻户晓了,小的时候也有那么一段时间对此无比着迷。学了C语言后,慢慢的就想着能不能用编程语言来实现这样的游戏。今天呢,就让我们亲手实现扫雷游戏,再次体验下儿时那简单纯粹的快乐!!
二、游戏原理
想要实现扫雷游戏,第一步就是要清楚扫雷游戏的原理
这里我就简单的阐述一下扫雷游戏的原理
1.游戏在一个棋盘中进行,比如9*9棋盘

2.棋盘中存在着若干个地雷,玩家需要在系统的提示下避开这些地雷,排除所有埋雷的方格(即不能踩到雷!!),才算通关!!
3.玩家每排一个没有雷的方格,方格就会显示周围所有方格中藏有地雷的数目,如果踩到有雷的方格,就被炸死,游戏结束。

三、游戏实现思路
扫雷的过程中,布置的雷和排查出的雷的信息都需要存储,所以我们需要⼀定的数据结构来存储这些 信息。 因为我们需要在9*9的棋盘上布置雷的信息和排查雷,我们⾸先想到的就是创建⼀个9*9的数组来存放 信息
那如果这个位置布置雷,我们就存放1,没有布置雷就存放0.

我们也需要注意到这样的问题,每排一个雷,我们就要周围方格雷的数目,这里我们可以将需统计的区域涂为黄色,当我们排到周边的方格时,就可能出现越界的问题。

为了解决这样的问题,我们可以将棋盘扩大一圈,如将原本的9*9棋盘扩大为11*11棋盘(以此类推)

只要在扩大的区域不布雷就好了!! (绿色区域不放雷)
再继续分析,我们在棋盘上布置了雷,棋盘上雷的信息(1)和⾮雷的信息(0),假设我们排查了某 ⼀个位置后,这个坐标处不是雷,这个坐标的周围有1个雷,那我们需要将排查出的雷的数量信息记录 存储,并打印出来,作为排雷的重要参考信息的。那这个雷的个数信息存放在哪⾥呢?如果存放在布 置雷的数组中,这样雷的信息和雷的个数信息就可能或产⽣混淆和打印上的困难。
这⾥我们肯定有办法解决,⽐如:雷和⾮雷的信息不要使⽤数字,使⽤某些字符就⾏,这样就避免冲 突了,但是这样做棋盘上有雷和⾮雷的信息,还有排查出的雷的个数信息,就⽐较混杂,不够⽅便。 这⾥我们采⽤另外⼀种⽅案,我们专⻔给⼀个棋盘(对应⼀个数组mine)存放布置好的雷的信息,再 给另外⼀个棋盘(对应另外⼀个数组show)存放排查出的雷的信息。这样就互不⼲扰了,把雷布置到 mine数组,在mine数组中排查雷,排查出的数据存放在show数组,并且打印show数组的信息给后期 排查参考。
同时为了保持神秘,show数组开始时初始化为字符 '*',为了保持两个数组的类型⼀致,可以使⽤同⼀ 套函数处理,mine数组最开始也初始化为字符'0',布置雷改成'1'。如下如:

四、游戏代码的实现
这里我们可以使用创建多个文件的方法来实现这样的代码
这里我们就创建三个文件,两个.c文件,一个.h文件:
game.c :文件中写游戏的测试逻辑
test.c :文件中写游戏中函数的实现
game.h:文件中写游戏需要的数据类型和函数声明
1.test.c
首先还是先写我们的主函数
int main()
{
test();
return 0;
}
在这里我们直接将定义的test 函数放入使用,游戏的所有逻辑实现均汇集在其中。
void test()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请输入您想进入的模式\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("扫雷游戏开始!!\n");
game();
break;
case 0:
printf("您已退出游戏!!\n");
break;
default:
printf("输入错误请重新输入!!!\n");
break;
}
} while (input);
}
如果说游戏是一棵枝繁叶茂的打树那么,这里的test函数就是树的主干了
menu函数是菜单界面的显示
void menu()
{
printf("****************************\n");
printf("******0.exit ********\n");
printf("******1.play ********\n");
printf("****************************\n");
printf("****************************\n");
}
game函数就是游戏逻辑实现的全部,这里我们就主要介绍game函数的实现逻辑
void game()
{
char mine[rows][cols];//存放类的信息
char show[rows][cols];//存放排查出雷的信息
//初始化棋盘
InitBoard(mine, rows, cols, '0');
InitBoard(show, rows, cols, '*');
//打印棋盘
DisplayBoard(show, row, col);
//DisplayBoard(mine, row, col);
//布置雷
Setmine(mine, row, col);
//排雷环节
Findmine(mine,show, row, col);
}
前面提到mine和show是我们专⻔给⼀个棋盘(对应⼀个数组mine)存放布置好的雷的信息,再 给另外⼀个棋盘(对应另外⼀个数组show)存放排查出的雷的信息。
棋盘的初始化、棋盘的打印及其他更多的功能有不同的函数实现,在使用时,我们也需要将这些函数放在.h文件中进行声明,再到game,c文件中实现相应的功能
game.h:
这些是.h文件中声明的函数和变量
后面我会一一介绍其功能
#pragma once
# include<stdio.h>
# include<stdlib.h>
# include<time.h>
#define row 9
#define col 9
#define rows row+2
#define cols col+2
#define Easy_count 10
//初始化棋盘
void InitBoard(char board[rows][cols],
int Rows, int Cols,char set);
//打印棋盘
void DisplayBoard(char board[rows][cols], int Row, int Col);
//布置雷
void Setmine(char mine[rows][cols], int Row,int Col);
//排雷环节
void Findmine(char mine[row][col], char show[row][col], int Row, int Col);
1.row和col就表示行和列为了能使整个程序的关联性更强(即在修改棋盘的参数的时候更加的方便),在表示棋盘的参数时尽量不要直接使用数字,再有前面考虑到的越界问题,棋盘的大小应为理想行列数+2!!(rows cols)
InitBoard:初始化棋盘
前面说过,排雷我们在mine数组中进行,排雷信息在show数组中展示,为了表现神秘感,
show数组用“*”初始化,mine 数组用‘0’初始化,后面我们就用‘1‘表示雷
这样我们就能将mine和show分别初始化(初始化时需要以rows和cols的标准初始化才能有效地解决越界问题)
初始化函数的声明:
//初始化棋盘
void InitBoard(char board[rows][cols],
int Rows, int Cols,char set);
实现:
void InitBoard(char board[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++)
{
board[i][j] = set;
}
}
}


DisplayBoard:打印棋盘
在打印棋盘时我们只要看可以布雷的区域就行了,这里我们就只显示9*9的范围。
(打印时的范围为board[1-9][1-9],初始化的范围是board[0-10][0-10])
打印函数的声明:
void DisplayBoard(char board[rows][cols], int Row, int Col);
实现:

打印效果:

Setmine:布置雷
接下来我们要在mine数组中布置雷 ,即在mine数组中随机选几个格子将’0‘-->’1‘
布雷函数传参:
Setmine(mine, row, col);
布雷函数的声明:
//布置雷
void Setmine(char mine[rows][cols], int Row,int Col);
布雷函数的实现:
////布置雷(随即布置雷)
void Setmine(char mine[rows][cols],
int Row, int Col)
{
int count = Easy_count;
int x = 0;
int y = 0;
while (count)
{
x = rand() % Row + 1;
y = rand() % Col + 1;
if (mine[x][y]!='1')
{
mine[x][y] = '1';
count--;
}
}
}
在实现布雷的过程中,我们可以考虑到
1.要布雷的数量:这里我们可以自己定义变量,来实现游戏难度的控制,这里的Easy_count
就是我定义的布雷数量,对应头文件中的
2.随机坐标的布置
这里就会涉及到
srand、time函数的知识想要深入了解的uu们可一点开看看
很明显这里我们要在9*9键盘中随机布雷所以
x的范围 1--9
y的范围1--9
布好雷后让我们来看看效果
这里我们看到在9*9键盘中刚好就生成了10个雷
Foundmine:排雷
排雷函数的传参:
//排雷环节
Findmine(mine,show, row, col);
排雷函数的声明:
//排雷环节
void Findmine(char mine[row][col], char show[row][col], int Row, int Col);
排雷函数的实现:
//输入坐标
//判断是否越界
//如果这个位置是雷就被炸死
//否则统计周边雷的个数,显示
//排除所有的雷后,游戏结束玩家胜利!
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 -Easy_count)
{
printf("请输入要排查的坐标\n");
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 count = get_mine_count(mine, x, y);
show[x][y] = count + '0';
//将数字转化为字符时+‘0’;
DisplayBoard(show, row, col);
win++;
}
}
else
{
printf("输入错误应该输入的范围为x(1-%d),y(1-%d)请重新输入!!!\n",Row,Col);
}
}
if (win == row * col - Easy_count)
{
printf("恭喜您排雷成功!!!\n");
DisplayBoard(mine, row, col);
}
}
get_mine_count(mine, x, y)是用来计算已排除的方格周围的埋雷数
int get_mine_count(char mine[rows][cols],int x,int y)
{
//想要将字符转化为数字可以用原来的字符减去’0‘
//如’2‘-’0‘=2
//’1‘-’0‘=1诸如此类!!!
int i = 0;
int j= 0;
int count = 0;
for (i = -1; i <= 1; i++)
{
for (j = -1; j <= 1;j++)
{
count += (mine[x+i][y+j] - '0');
}
}
return count;
}
注://想要将字符转化为数字可以用原来的字符减去’0‘
//如’2‘-’0‘=2
//’1‘-’0‘=1诸如此类!!!
//将数字转化为字符时+‘0’;
在计算周边的埋雷数时,我们可以将周围方格的字符转为数字,再相加,即可得到埋雷数。
五、参考代码
然后扫雷游戏就算是基本完成了
这里我就在展示一下参考代码:
game.h
#pragma once
# include<stdio.h>
# include<stdlib.h>
# include<time.h>
#define row 9
#define col 9
#define rows row+2
#define cols col+2
#define Easy_count 10
//初始化棋盘
void InitBoard(char board[rows][cols],
int Rows, int Cols,char set);
//打印棋盘
void DisplayBoard(char board[rows][cols], int Row, int Col);
//布置雷
void Setmine(char mine[rows][cols], int Row,int Col);
//排雷环节
void Findmine(char mine[row][col], char show[row][col], int Row, int Col);
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
printf("****************************\n");
printf("******0.exit ********\n");
printf("******1.play ********\n");
printf("****************************\n");
printf("****************************\n");
}
void game()
{
char mine[rows][cols];//存放类的信息
char show[rows][cols];//存放排查出雷的信息
//初始化棋盘
InitBoard(mine, rows, cols, '0');
InitBoard(show, rows, cols, '*');
//打印棋盘
DisplayBoard(show, row, col);
//DisplayBoard(mine, row, col);
//布置雷
Setmine(mine, row, col);
// DisplayBoard(mine, row, col);
//排雷环节
Findmine(mine,show, row, col);
}
void test()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请输入您想进入的模式\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("扫雷游戏开始!!\n");
game();
break;
case 0:
printf("您已退出游戏!!\n");
break;
default:
printf("输入错误请重新输入!!!\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void InitBoard(char board[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++)
{
board[i][j] = set;
}
}
}
void DisplayBoard(char board[rows][cols],
int Row, int Col)
{
int i = 0;
int j = 0;
printf("-------扫雷------\n");
for (i = 0; i <= Row; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= Col; i++)
{
printf("%d ", i);
for (j = 1; j <=Col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
////布置雷(随即布置雷)
void Setmine(char mine[rows][cols],
int Row, int Col)
{
int count = Easy_count;
int x = 0;
int y = 0;
while (count)
{
x = rand() % Row + 1;
y = rand() % Col + 1;
if (mine[x][y]!='1')
{
mine[x][y] = '1';
count--;
}
}
}
int get_mine_count(char mine[rows][cols],int x,int y)
{
//想要将字符转化为数字可以用原来的字符减去’0‘
//如’2‘-’0‘=2
//’1‘-’0‘=1诸如此类!!!
int i = 0;
int j= 0;
int count = 0;
for (i = -1; i <= 1; i++)
{
for (j = -1; j <= 1;j++)
{
count += (mine[x+i][y+j] - '0');
}
}
return count;
}
//排查雷
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 -Easy_count)
{
printf("请输入要排查的坐标\n");
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 count = get_mine_count(mine, x, y);
show[x][y] = count + '0';
//将数字转化为字符时+‘0’;
DisplayBoard(show, row, col);
win++;
}
}
else
{
printf("输入错误应该输入的范围为x(1-%d),y(1-%d)请重新输入!!!\n",Row,Col);
}
}
if (win == row * col - Easy_count)
{
printf("恭喜您排雷成功!!!\n");
DisplayBoard(mine, row, col);
}
}
好,今天的的扫雷游戏就讲到这里,感谢大家的支持,拜拜!!
本文介绍了用C语言实现扫雷游戏的方法。先阐述游戏原理,玩家需在棋盘避开地雷通关。接着说明实现思路,用两个数组分别存放雷和排查信息,扩大棋盘解决越界问题。最后给出代码实现,创建三个文件,介绍各函数功能,完成扫雷游戏基本开发。
8404





