目录
一:扫雷的基本规则和逻辑
1:游戏概述:
扫雷是一款经典的小游戏,想必在做的各位应该都玩过这一款游戏,玩法是让和我们在一个9×9的格子里面排查出隐藏在里面的10个地雷,如果在排查的过程中不小心踩到地雷游戏就会失败,所以要求我们精准的把所有地雷都找出来
2:游戏规则:
- 盘面上有许多方格,方格中随机分布着一些雷。
- 你的目标是避开雷,打开其他所有格子。
- 一个非雷格中的数字表示其相邻8格中的雷数,你可以利用这个信息推导出安全格和雷的位置。
- 你可以用右键在你认为是雷的地方插旗(称为标雷)。
- 你可以用左键打开安全的地方,左键打开雷将被判定为失败。
- 扫雷游戏胜利的条件是揭示所有不包含地雷的格子。
- 利用安全格子提供的信息,我们可以推断一个格子附近的格子有没有雷。
- 安全格子的类型:数字表示它周围八个格子中地雷的数量;空白表示附近都没有地雷。
- 扫雷技巧:刚开始需要碰运气,只要点开一个区域,就可以正式开始了。根据现有情况,判断出一定有雷的位置。利用右键和左键的组合可以快速揭示周围的方块。
3:实现思路
1)先创建一个游戏的开始界面
2)首先创建一个mine数组存放布置好的雷的信息,并将其中的数组全部初始化为字符' 0 ',还得创建一个show数组用来存放排查出的雷的信息,将里面初始化成 ' * '
3)然后对棋盘进行初始化和打印
4)将雷放入到创建的mine数组中去,雷为‘1’
5)最后寻找雷,知道排查出所有雷为止或被雷炸死
二:代码的实现
1:文件结构设计和头文件
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
2:菜单以及主函数
菜单:游戏菜单如下,1为开始游戏,0为退出游戏
void menu()
{
printf("********************\n");
printf("**** 1. palay ****\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;
}
3:初始化棋盘
首先我们来初始化棋盘,在初始化之前我们先来定义ROW和COL的大小
有的人会问这里的ROW+2和COL+2是什么意思呢?我们在初始化棋盘的时候虽然我们实际初始化的9*9的棋盘大小,但是我们在周围还应该布置一圈,所以大小在9*9的基础上+2,这多出来的一圈是为了防止越界访问
这里用mine数组来存放布置好的雷的信息,用show数组来存放排查出的雷的信息,并将mine初始化为'*',show初始化为'*'
char mine[ROWS][COLS] = { 0 };//存放布置好的雷的信息
char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
//初始化棋盘
InitBoard(mine, ROWS, COLS,'0');
InitBoard(show, ROWS, COLS,'*');
//game.h文件
//棋盘的初始化
void InitBoard(char board[ROWS][COLS], int rows, int cols,int set);
//game.c文件
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, int set)
{
int i = 0;
for (i = 0; i < rows;i++)
{
int j = 0;
for (j = 0; j < cols;j++)
{
board[i][j] = set;
}
}
}
3:打印棋盘
以上是初始化棋盘的代码,在初始化好棋盘后我们可以给初始化的棋盘加上行号和列号,也就是打印棋盘
//打印棋盘
DisplayBoard(mine, ROW, COL);
//game.h文件
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);
//game.c文件
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
printf("------ 扫雷 ------\n");
//打印列号
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 ", board[i][j]);
}
printf("\n");
}
}
弹出游戏菜单后,我们选择1.play开始游戏,然后打印出隐藏好雷的棋盘,用户通过输入坐标来排查棋盘中布置好的雷
4:布置雷
我们完成了棋盘的初始化和打印,接下来我们将10个雷随机的布置到棋盘当中去,在布置的时候我们需要在game.h文件中定义一个变量EASY_COUNT,这里的变量同前面的的ROWS和COLS是一样的道理,如果需要增加布置的雷只需修改声明的变量10即可
接下来我们可以正式开始布置雷了
//布置雷
void SetMaine(char board[ROWS][COLS], int row, int col);
1):我们先定义一个count表示布置的雷的个数,但是为了后续的修改我们可以将int count = 10;改为int count = EASY_COUNT;
2):这里我们需要用到rand函数,rand函数会返回⼀个伪随机数,这个随机数的范围是在0~RAND_MAX之间,这个RAND_MAX的大小是依赖编译器上实现的,但是大部分编译器上是32767
其中while循环中的rand() % 9; rand() % 9;可以让我们将x和y的范围控制在0~9;我们如果在后面分别加上+1可以使x,y的范围控制在1~9,正好是我们棋盘的大小9*9的范围
3):再将9改为row和col变量,这可以方便我们后续对棋盘的修改,我们在初始化棋盘时将存放布置雷的棋盘初始化为'0';如果为'0',我们就可以将雷'1'布置到其中然后count--
//布置雷
void SetMaine(char board[ROWS][COLS], int row, int col)
{
int count = 10;
while (count)
{
int x = rand() % 9 + 1;
int y = rand() % 9 + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
以下是优化后的代码
//布置雷
void SetMaine(char board[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
5:排查雷
布置好雷以后我们开始排查雷,这一步是非常重要的一部也是较为复杂的一部
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
1):在排查雷的时候,我们先要弄清楚在排查雷的过程中,在存放排查出的雷的棋盘中,如果排查的坐标位置不是雷,我们需要以九宫格为中心雷的个数给打印到棋盘中去,其实这也是比较好实现和了解的
2):因为字符'0'的ASCLL值为--48,字符'1'的ASCLL值为--49,字符'2'的ASCLL值为--50,由此我饿们可以总结出字符'2' - '0' = 2(数字2), '1' - '0' = 1(数字1),'6' - '0' = 6(数字6),我饿们可以通过此来就算雷的个数
3):通过下面的图片中的数据来就算九宫格中四周的雷,横为y,竖为x,然后分别他们挨个加起来,最后总的减去8*'0'就可以求出雷的个数了
x-1,y-1 | x-1,y | x-1,y+1 |
x,y-1 | x,y | x,y+1 |
x-1,y-1 | x+1,y | x+1,y+1 |
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';
}
4):首先我们定义一个下x,y变量来表示数组[row][col],在创建一个变量win不是雷的个数,接下来进入循win<row*col-EASY_COUNT,我们输入需要排查的雷的坐标,用scanf函数来输入,进入第一个if语句如果x,y在1~9中执行循环反之则退出循环,进入第二个if语句,如果输入的[x][y]坐标位置有雷,则输出被炸死了,然后将存放排查出的雷的信息打印给用户,然后break退出循环
5):如果进入else语句,说明输入的坐标位置没有雷,并统计mine数组的x,y坐标周围的8个坐标中有几个雷,这里调用我们上面封装的函数GetMineCount,计算出周围的雷的数量,然后打印棋盘用DisplayBoard函数,win++,进入下一个else语句时,如果输入的坐标超出棋盘则打印输入的是无效坐标,请重新输入,最后如果将所有的雷都找了出来,游戏也就结束了
//排查雷
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("请输入要排查的坐标");
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
{
//统计mine数组的x,y坐标周围的8个坐标中有几个雷
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("输入的是无效坐标,请重新输入\n");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你排雷成功\n");
DisplayBoard(mine, ROW, COL);
}
}
三:扫雷总代码
1:test.c
#include "game.h"
void menu()
{
printf("********************\n");
printf("**** 1. palay ****\n");
printf("**** 0. exit ****\n");
printf("********************\n");
}
//完成扫雷的全部过程
void game()
{
char mine[ROWS][COLS] = { 0 };//存放布置好的雷的信息
char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
//初始化棋盘
InitBoard(mine, ROWS, COLS,'0');
InitBoard(show, ROWS, COLS,'*');
//打印棋盘
//DisplayBoard(mine, ROW, COL);
//布置雷
SetMaine(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
//DisplayBoard(mine, ROW, COL);
//排查雷
FindMine(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;
}
2.game.h
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define EASY_COUNT 10
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//棋盘的初始化
void InitBoard(char board[ROWS][COLS], int rows, int cols,int set);
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);
//布置雷
void SetMaine(char board[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
3:game.c
#include "game.h"
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, int 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;
printf("------ 扫雷 ------\n");
//打印列号
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 ", board[i][j]);
}
printf("\n");
}
}
//布置雷
void SetMaine(char board[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
int y = rand() % col + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
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-EASY_COUNT)
{
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
{
//统计mine数组的x,y坐标周围的8个坐标中有几个雷
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("输入的是无效坐标,请重新输入\n");
}
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你排雷成功\n");
DisplayBoard(mine, ROW, COL);
}
}
以上就是扫雷的全部代码了,创作不易,求求大家点个小赞赞,感谢各位老们的赏脸观看,随手点个赞,养成好习惯,如有问题,感谢反馈!