扫雷
一、扫雷是什么?
**扫雷在科技历史上也扮演了相似的角色。这个基于数字的逻辑谜题最早来自20世纪六七十年代,当时Jerimac Ratliff推出的名为“Cube”的游戏已经非常受人欢迎。几十年后的1992年,扫雷游戏被加入了Windows3.1,这并不是为了展示Windows是游戏操作系统专家,而是为了训练用户的鼠标左右键操作能力,让这些动作变得非常自然,并培养鼠标移动的速度和准确性。而随着科技的发展,越来越多的网络游戏,3A大作取代了曾经的风靡一时的扫雷,蜘蛛纸牌嫩等游戏,但这些游戏却永远留在了我们的青春里。
二、实现思路
代码的实现思路
在写任何一个代码时,我们都需要考虑好在进行具体实现,这样可以更好的帮助我们来理清思路,那么扫雷的思路是什么呢,我们来分析一下,
1.游戏菜单
2.游戏的具体实现
3.判断输赢
从以上分析中,我们不难发现,想实现一个扫雷游戏,必须有着上题的4大项,才能实现一个游戏的大致流程,而在我们确定了大致流程后,我们就可以开始上手实现他了。
1.游戏菜单
因为我们实现的是简单的扫雷游戏,只需要能够让游玩者分辨清楚即可。
void menu()//游戏菜单
{
printf("**************************\n");
printf("**************************\n");
printf("*******1.paay 0.exit*****\n");
printf("**************************\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循环,使得玩家在打开程序时可以立马打印菜单。
输出结果
此时我们完成了最基本的游戏界面编写。下面进入具体实施
2.游戏的具体实现
2.1
我们在游戏界面时,就已经编写了游戏游玩与退出的逻辑,所以,我们现在只需要进行游戏的具体游玩编写,而游戏内容编写有需要非常详细的设计,下面我们来看都需要什么设计:
2.2游戏内容的具体设计与实现
1.扫雷游戏的具体内容
2.扫雷游戏的逻辑循环
下面我们来看1.扫雷游戏的具体内容该如何实现
//主程序
void Game()
{ //存放地雷
char mine[ROWS][COLS] = { 0 };
//排查出地雷
char show[ROWS][COLS] = { 0 };
//初始化棋盘
IsitBoard(mine, ROWS, COLS,'0');
IsitBoard(show, ROWS, COLS,'*');
//打印棋盘
DisplayBoard(show, ROW, COL);
// 布置地雷
SetMine(mine, ROW, COL);
//排查雷
FindMine(mine, show, ROW, COL);
}
我们需要以上7条函数语句来填充我们扫雷游戏的具体内容,我们来逐一分析一下
所以我们需要搭配game.h文件学习了解
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#define EASY_COUNT 10//定义地雷数
#define ROW 9//定义打印的行数
#define COL 9//定义打印的列数
#define COLS COL+2//实际行数
#define ROWS ROW+2//实际列数
void InitBoard (char board[ROWS][COLS],int row,int col);//初始化棋盘数组
void DisplayBoard(char board[ROWS][COLS],int row,int col);//打印棋盘数组
void SetMine(char board[ROWS][COLS],int row,int col);//布置地雷
void FindMine(char board[ROWS][COLS],int r
函数
IsitBoard(mine, ROWS, COLS,'0');
IsitBoard(show, ROWS, COLS,'*');
在扫雷有游戏中,最重要的就是棋盘,上方两条函数语句对应的是初始化函数,下方是具体实现代码
//初始化函数
void IsitBoard(char board[ROWS][COLS], int rows, int cols,char set)
{
memset(&board[0][0], set, rows * cols * sizeof(board[0][0]));
}
而光初始化还不够,我们需要打印他,所以
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("-------扫雷--------\n");
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");
}
}
我们通过memset函数对棋盘的行数,列数 ,和棋盘内容进行了设置,
此为运行结果
通过for循环的嵌套循环,我们打印出了代表行列的数字。此时,我们完成了棋盘的设置。
2.扫雷游戏的逻辑循环
在我们的编写下,我们完成了棋盘的设置,但这还远远不够,下面我们进行具体的逻辑循环编写
2.1埋入地雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;//获取头文件中地雷的数量
while (count)//以地雷数量为实际循环
{
int x = rand() % row + 1;
int y = rand() % col + 1;//设置随机数安放在棋盘中
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;//成功安放一次减少一次循环次数,直至退出循环
}
}
}
2.2排查地雷
熟悉地雷小游戏的都知道,我们在游戏界面中,每当选择一次坐标,就会显示该坐标周围8个坐标是否有地雷,有责计数在旁边的坐标里,没有就打开其他坐标,直至该坐标周围有地雷,下面我们来具体实施:
int GetMineCount(char board[ROWS][COLS], int x, int y)//地雷计数
{
int i = 0;
int j = 0;
int count = 0;
for (i = x - 1;i <= x + 1;i++)//通过循环计数输入坐标周围是否有地雷
{
for (j = y - 1; j <= y + 1; j++)
{
if (board[i][j] == '1')
{
count++;//计数
}
}
}
return count;
}
此处,我们实现了地雷计数,下面我们实现打开其他坐标
void ExplosionSpread(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y, int* pw)
{
if (x >= 1 && x <= row&&y >= 1 && y <= col)//判断输入是否合法
{
int num = GetMineCount(mine, x, y);//判断是否循环的变量
if (num == 0)
{
(*pw)++;//胜利条件
show[x][y] = ' ';//如果没有地雷则赋值空格
int i = 0;
int j = 0;
for (i = x - 1; i <= x + 1; i++)//进入二次循环
{
for (j = y - 1; j <= y + 1; j++)
{
if (show[i][j] == '*')//递归的限制条件,当周围有地雷时,停止跳出
ExplosionSpread(mine, show, row, col, i, j, pw);//通过递归函数本身不服按判定周围情况
}
}
}
else
{
(*pw)++;
show[x][y] = num + '0';//地雷数
}
}
}
当我们完成以上函数编写后,就进入了尾声
3.判断输赢
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS] ,int row, int col)
{
int x = 0;//玩家输入的行数
int y = 0;//玩家输入的列数
int win = 0;
int* pw = &win;//设置胜利条件,且把创建存放在指针内
while (win < row * col - EASY_COUNT)//胜利条件为行数*列数-10(地雷数)
{
printf("请输入要排查的坐标>");
scanf("%d %d", &x, &y);//输入
if (x >= 1 && x <= row || y >= 1 && y <= col)//判断输入是否合法
{
if (mine[x][y] == '1')//当输入坐标有地雷
{
system("cls");//清空屏幕
printf("很遗憾,你被炸死了!\n");
DisplayBoard(mine, ROW, COL); //打印地雷棋盘
break;
}
else
{
if (mine[x][y] == ' ')
{
printf("此坐标已被排查,请重新输入\n");//重复输入
continue;
}
else//输入正确,且周围还有格子
{
ExplosionSpread(mine,show, row, col, x, y, pw);
DisplayBoard(show, ROW, COL);
}
}
}
else
{
printf("输入错误,请重新输入!\n");
}
}
if (win == row * col - EASY_COUNT)//胜利条件
{
system("cls");
printf("恭喜你,排雷成功!\n");
DisplayBoard(show, ROW, COL);
return;
}
}
我们需要一个判断函数来实现我们编写的所有函数,上方函数即调用了所有函数的具体实现
此时,我们完成了扫雷游戏的所有编写
为了方便他人学习,下方是游戏所有代码,且按顺序排放
game.h
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#define EASY_COUNT 10//定义地雷数
#define ROW 9//定义打印的行数
#define COL 9//定义打印的列数
#define COLS COL+2//实际行数
#define ROWS ROW+2//实际列数
void InitBoard (char board[ROWS][COLS],int row,int col);//初始化棋盘数组
void DisplayBoard(char board[ROWS][COLS],int row,int col);//打印棋盘数组
void SetMine(char board[ROWS][COLS],int row,int col);//布置地雷
void FindMine(c
game.c
#include"game.h"
//初始化函数
void IsitBoard(char board[ROWS][COLS], int rows, int cols,char set)
{
memset(&board[0][0], set, rows * cols * sizeof(board[0][0]));
}
//打印数组
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("-------扫雷--------\n");
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");
}
}
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;//获取头文件中地雷的数量
while (count)//以地雷数量为实际循环
{
int x = rand() % row + 1;
int y = rand() % col + 1;//设置随机数安放在棋盘中
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;//成功安放一次减少一次循环次数,直至退出循环
}
}
}
int GetMineCount(char board[ROWS][COLS], int x, int y)//地雷计数
{
int i = 0;
int j = 0;
int count = 0;
for (i = x - 1;i <= x + 1;i++)//通过循环计数输入坐标周围是否有地雷
{
for (j = y - 1; j <= y + 1; j++)
{
if (board[i][j] == '1')
{
count++;//计数
}
}
}
return count;
}
void ExplosionSpread(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y, int* pw)
{
if (x >= 1 && x <= row&&y >= 1 && y <= col)//判断输入是否合法
{
int num = GetMineCount(mine, x, y);//判断是否循环的变量
if (num == 0)
{
(*pw)++;//胜利条件
show[x][y] = ' ';//如果没有地雷则赋值空格
int i = 0;
int j = 0;
for (i = x - 1; i <= x + 1; i++)//进入二次循环
{
for (j = y - 1; j <= y + 1; j++)
{
if (show[i][j] == '*')//递归的限制条件,当周围有地雷时,停止跳出
ExplosionSpread(mine, show, row, col, i, j, pw);//通过递归函数本身不服按判定周围情况
}
}
}
else
{
(*pw)++;
show[x][y] = num + '0';//地雷数
}
}
}
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS] ,int row, int col)
{
int x = 0;//玩家输入的行数
int y = 0;//玩家输入的列数
int win = 0;
int* pw = &win;//设置胜利条件,且把创建存放在指针内
while (win < row * col - EASY_COUNT)//胜利条件为行数*列数-10(地雷数)
{
printf("请输入要排查的坐标>");
scanf("%d %d", &x, &y);//输入
if (x >= 1 && x <= row || y >= 1 && y <= col)//判断输入是否合法
{
if (mine[x][y] == '1')//当输入坐标有地雷
{
system("cls");//清空屏幕
printf("很遗憾,你被炸死了!\n");
DisplayBoard(mine, ROW, COL); //打印地雷棋盘
break;
}
else
{
if (mine[x][y] == ' ')
{
printf("此坐标已被排查,请重新输入\n");//重复输入
continue;
}
else//输入正确,且周围还有格子
{
ExplosionSpread(mine,show, row, col, x, y, pw);
DisplayBoard(show, ROW, COL);
}
}
}
else
{
printf("输入错误,请重新输入!\n");
}
}
if (win == row * col - EASY_COUNT)//胜利条件
{
system("cls");
printf("恭喜你,排雷成功!\n");
DisplayBoard(show, ROW, COL);
return;
}
}
tese.c
#include"game.h"
//主程序
void Game()
{ //存放地雷
char mine[ROWS][COLS] = { 0 };
//排查出地雷
char show[ROWS][COLS] = { 0 };
//初始化棋盘
IsitBoard(mine, ROWS, COLS,'0');
IsitBoard(show, ROWS, COLS,'*');
//打印棋盘
DisplayBoard(show, ROW, COL);
// 布置地雷
SetMine(mine, ROW, COL);
//排查雷
FindMine(mine, show, ROW, COL);
}
void menu()//游戏菜单
{
printf("**************************\n");
printf("**************************\n");
printf("*******1.paay 0.exit*****\n");
printf("**************************\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;
}
总结
以上就是我对扫雷的初步了解,如有不足,还请各位大佬批评指正,作为一个初学c语言的学徒,我会秉持着谦虚好学的态度,谢谢所有为我批评指正的大佬,并一一感谢!