目录
♍️一、扫雷的简介
游戏的目标是在一个矩阵布局的区域内找到所有的地雷(也称为“雷区”),而不触发任何一颗地雷。玩家会在一个数值矩阵中选择一个方块,然后从该方块开始探索,直到确定周围没有地雷为止。如果一个方块周围的八个方向都没有地雷,那么它会显示一个数字,该数字表示周围格子中有多少个地雷。玩家需要根据数字和已经探索的区域来确定地雷的位置。 如果玩家不小心选择了一个地雷,就会导致游戏失败。扫雷随着难度的增加而变得更加困难,玩家需要更加小心谨慎地选择每个方块,以避免不必要的错误。
♎️二、C语言实现思路
大体框架的构建
1.创建一个游戏界面,并在界面上创建一个棋盘,用于显示游戏地图。
2.将雷随机分布在棋盘中,同时在每个非雷方块上计算周围雷的数量。
3.为每个方块创建一个按钮,并在按钮上显示周围雷的数量或者一个雷的图标。
4.添加点击按钮的事件处理程序,如果点击到一个未翻开的方块,则显示该方块上的内容,并根据该方块的类型进行相应的操作。
5.如果点击到雷,则游戏结束,显示游戏失败的信息,并重置游戏。
6.如果所有非雷方块都被翻开,则游戏结束,显示游戏胜利的信息,并重置游戏。
接口的定义
用ROW和COL定义棋盘的大小,MINE来确定要随机种下的雷的数量,ROWS和COLS是实际上的棋盘大小(看不到,为了方便判断周围雷),其他接口分别为初始化棋盘、显示棋盘、获得地雷,以及判赢操作。
#define ROW 9
#define COL 9
#define MINE 10
#define ROWS ROW+2
#define COLS COL+2
void Initboard(char board[ROWS][COLS], int rows, int cols, char a);//初始化
void Showboard(char board[ROW][COL], int row, int col);//打印
void Getmine(char board[ROWS][COLS],int mine);//种地雷
void win(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);//判赢
♏️三、根据所写接口实现函数主体
菜单的构建
void menu()//菜单
{
printf("--------------------\n");
printf("|******************|\n");
printf("|***** 1.play *****|\n");
printf("|***** 0.exit *****|\n");
printf("|******************|\n");
printf("--------------------\n");
}
大道至简,无需多言 !
game()主体的构建
游戏大体框架构建->游戏主体->游戏主体用什么实现?->两个数组->一个显示(玩家所见)另外一个用来储存数据(存雷以及数据处理)->看玩家的选择错误与否->提示->主体需要一个循环来实现菜单以及游戏主体的显示->大体框架确认完毕。
实现如下:
void game()//游戏本体
{
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
Initboard(mine, ROWS, COLS,'0');
Initboard(show, ROWS, COLS, '*');
Getmine(mine, MINE);
//Showboard(mine, ROW, COL);
printf("--------------------\n");
Showboard(show, ROW, COL);
win(mine, show, ROW, COL);
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
printf(" -扫雷游戏-\n");
game();
break;
case 0:
printf("退出成功!\n");
break;
default:
printf("输入错误,请重新输入!\n");
break;
}
} while (input);
return 0;
}
各部分功能的实现
需要什么功能?->初始化->种地雷->查地雷->得到地雷数量的数据->判输赢条件。每次操作都需要判断是否踩到地雷->因此不如初始化存地雷数据的数组为‘1’和‘0’,‘1’代表雷‘0’代表没雷。
实现如下:
void Initboard(char board[ROWS][COLS],int rows,int cols,char a)//初始化数组为a
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
board[i][j] = a;
}
}
}
void Showboard(char board[ROWS][COLS], int row, int col)//打印扫雷的游戏棋盘
{
for (int i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n ———————————————————\n");
for (int i = 1; i <= row; i++)
{
printf("%d|", i);
for (int j = 1; j <= col; j++)
{
if(j!=col)
printf("%c ", board[i][j]);
else
printf("%c|", board[i][j]);
}
printf("\n");
}
printf(" ———————————————————\n");
}
void Getmine(char board[ROWS][COLS], int mine)//种地雷,种的数量为mine
{
int count = 0;
while (count < mine)
{
int x = rand() % 9 + 1;
int y = rand() % 9 + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count++;
}
}
}
int Countmine(char board[ROWS][COLS], int row, int col)//数周围的地雷数量
{
return (board[row - 1][col] + board[row-1][col-1] + board[row][col-1] + board[row+1][col-1] + board[row+1][col] +
board[row+1][col+1] + board[row][col+1] + board[row-1][col+1] - '0'*8 );
}
void flower(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int* count)//递归查询周围地雷实现地雷游戏的遍地开花
{
if (row > 0 && row < ROWS && col>0 && col < COLS)//使数组不越距
{
if (show[row][col] == '*')//递归结束条件
{
if (Countmine(mine, row, col) == 0)//周围都空遍地开花
{
show[row][col] = ' ';//使其显示为空格
(*count)--;
flower(mine, show, row - 1, col, count);
flower(mine, show, row - 1, col - 1, count);
flower(mine, show, row, col - 1, count);
flower(mine, show, row + 1, col - 1, count);
flower(mine, show, row + 1, col, count);
flower(mine, show, row + 1, col + 1, count);
flower(mine, show, row, col + 1, count);
flower(mine, show, row - 1, col + 1, count);
}
else//周围不是全空则标出周围地雷数量
{
show[row][col] = Countmine(mine, row, col) + '0';
(*count)--;
}
}
}
}
void change(char mine[ROWS][COLS], int row, int col)//就是为了好看点^_^用来游戏结尾显示地雷
{
for (int i = 1; i <= row; i++)
{
for (int j = 1; j <= col; j++)
{
if (mine[i][j] == '1')
mine[i][j] = '$';
}
}
}
void win(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//判断输赢
{
int a = 0, b = 0;
int move = 81 - MINE;
while (move != 0)
{
printf("输入扫雷位置(空格隔开):");
scanf("%d %d", &a, &b);
if (a >= 1 && a <= row && b >= 1 && b <= col&&show[a][b]=='*')//使数组不越距并且防止选同样的位置
{
if (mine[a][b] == '1')
{
system("cls");//清屏为了好看
change(mine, ROW, COL);
printf("你被炸4了!\n");
Showboard(mine, row, col);
break;
}
else
{
flower(mine, show, a, b, &move);
system("cls");
Showboard(show, row, col);
}
}
else
{
printf("输入错误!请重新输入! ");
}
}
if (move == 0)
{
system("cls");
printf("恭喜你!扫完了全部雷!\n");
change(mine, ROW, COL);
Showboard(mine, row, col);
}
}
🛑精华点—重点在判输赢!
怎么算赢?主要在于玩家扫完所有雷,因此需要定义一个变量move来实现计数,move一开始的数量为9X9-地雷数量,玩家每动一步便-1直到为0跳出循环。重点在于遍地开花(选中的坐标包括周围共8个空位没有地雷)每找到一个就让他为空格,这也算是玩家动作也需让move-1;每多出来一个空以及标明附近地雷数量都要让move-1。
遍历递归函数
void flower(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int* count)//递归查询周围地雷实现地雷游戏的遍地开花
{
if (row > 0 && row < ROWS && col>0 && col < COLS)//使数组不越距
{
if (show[row][col] == '*')//递归结束条件
{
if (Countmine(mine, row, col) == 0)//周围都空遍地开花
{
show[row][col] = ' ';//使其显示为空格
(*count)--;
flower(mine, show, row - 1, col, count);
flower(mine, show, row - 1, col - 1, count);
flower(mine, show, row, col - 1, count);
flower(mine, show, row + 1, col - 1, count);
flower(mine, show, row + 1, col, count);
flower(mine, show, row + 1, col + 1, count);
flower(mine, show, row, col + 1, count);
flower(mine, show, row - 1, col + 1, count);
}
else//周围不是全空则标出周围地雷数量
{
show[row][col] = Countmine(mine, row, col) + '0';
(*count)--;
}
}
}
}
判赢函数
void win(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//判断输赢
{
int a = 0, b = 0;
int move = 81 - MINE;
while (move != 0)
{
printf("输入扫雷位置(空格隔开):");
scanf("%d %d", &a, &b);
if (a >= 1 && a <= row && b >= 1 && b <= col&&show[a][b]=='*')//使数组不越距并且防止选同样的位置
{
if (mine[a][b] == '1')
{
system("cls");//清屏为了好看
change(mine, ROW, COL);
printf("你被炸4了!\n");
Showboard(mine, row, col);
break;
}
else
{
flower(mine, show, a, b, &move);
system("cls");
Showboard(show, row, col);
}
}
else
{
printf("输入错误!请重新输入! ");
}
}
if (move == 0)
{
system("cls");
printf("恭喜你!扫完了全部雷!\n");
change(mine, ROW, COL);
Showboard(mine, row, col);
}
}
♐️四、总体代码
game.h
#pragma once
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 9
#define COL 9
#define MINE 10
#define ROWS ROW+2
#define COLS COL+2
void Initboard(char board[ROWS][COLS], int rows, int cols, char a);//初始化
void Showboard(char board[ROW][COL], int row, int col);//打印
void Getmine(char board[ROWS][COLS],int mine);//种地雷
void win(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);//判赢
game.c
#define _CRT_SECURE_NO_WARNINGS 01
#include"game.h"
void Initboard(char board[ROWS][COLS],int rows,int cols,char a)//初始化数组为a
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
board[i][j] = a;
}
}
}
void Showboard(char board[ROWS][COLS], int row, int col)//打印扫雷的游戏棋盘
{
for (int i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n ———————————————————\n");
for (int i = 1; i <= row; i++)
{
printf("%d|", i);
for (int j = 1; j <= col; j++)
{
if(j!=col)
printf("%c ", board[i][j]);
else
printf("%c|", board[i][j]);
}
printf("\n");
}
printf(" ———————————————————\n");
}
void Getmine(char board[ROWS][COLS], int mine)//种地雷,种的数量为mine
{
int count = 0;
while (count < mine)
{
int x = rand() % 9 + 1;
int y = rand() % 9 + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count++;
}
}
}
int Countmine(char board[ROWS][COLS], int row, int col)//数周围的地雷数量
{
return (board[row - 1][col] + board[row-1][col-1] + board[row][col-1] + board[row+1][col-1] + board[row+1][col] +
board[row+1][col+1] + board[row][col+1] + board[row-1][col+1] - '0'*8 );
}
void flower(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int* count)//递归查询周围地雷实现地雷游戏的遍地开花
{
if (row > 0 && row < ROWS && col>0 && col < COLS)//使数组不越距
{
if (show[row][col] == '*')//递归结束条件
{
if (Countmine(mine, row, col) == 0)//周围都空遍地开花
{
show[row][col] = ' ';//使其显示为空格
(*count)--;
flower(mine, show, row - 1, col, count);
flower(mine, show, row - 1, col - 1, count);
flower(mine, show, row, col - 1, count);
flower(mine, show, row + 1, col - 1, count);
flower(mine, show, row + 1, col, count);
flower(mine, show, row + 1, col + 1, count);
flower(mine, show, row, col + 1, count);
flower(mine, show, row - 1, col + 1, count);
}
else//周围不是全空则标出周围地雷数量
{
show[row][col] = Countmine(mine, row, col) + '0';
(*count)--;
}
}
}
}
void change(char mine[ROWS][COLS], int row, int col)//就是为了好看点^_^用来游戏结尾显示地雷
{
for (int i = 1; i <= row; i++)
{
for (int j = 1; j <= col; j++)
{
if (mine[i][j] == '1')
mine[i][j] = '$';
}
}
}
void win(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//判断输赢
{
int a = 0, b = 0;
int move = 81 - MINE;
while (move != 0)
{
printf("输入扫雷位置(空格隔开):");
scanf("%d %d", &a, &b);
if (a >= 1 && a <= row && b >= 1 && b <= col&&show[a][b]=='*')//使数组不越距并且防止选同样的位置
{
if (mine[a][b] == '1')
{
system("cls");//清屏为了好看
change(mine, ROW, COL);
printf("你被炸4了!\n");
Showboard(mine, row, col);
break;
}
else
{
flower(mine, show, a, b, &move);
system("cls");
Showboard(show, row, col);
}
}
else
{
printf("输入错误!请重新输入! ");
}
}
if (move == 0)
{
system("cls");
printf("恭喜你!扫完了全部雷!\n");
change(mine, ROW, COL);
Showboard(mine, row, col);
}
}
text.c
#define _CRT_SECURE_NO_WARNINGS 01
#include"game.h"
void menu()//菜单
{
printf("--------------------\n");
printf("|******************|\n");
printf("|***** 1.play *****|\n");
printf("|***** 0.exit *****|\n");
printf("|******************|\n");
printf("--------------------\n");
}
void game()//游戏本体
{
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
Initboard(mine, ROWS, COLS,'0');
Initboard(show, ROWS, COLS, '*');
Getmine(mine, MINE);
//Showboard(mine, ROW, COL);
printf("--------------------\n");
Showboard(show, ROW, COL);
win(mine, show, ROW, COL);
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
printf(" -扫雷游戏-\n");
game();
break;
case 0:
printf("退出成功!\n");
break;
default:
printf("输入错误,请重新输入!\n");
break;
}
} while (input);
return 0;
}