路|【C语言/入门游戏】扫雷完整版(包含标记,安全保护及展开)
知识提要(自主编写游戏所需要的知识):
1.函数的基本实现;
2.二维数组;
目录
扫雷
1.基本界面的实现
2.初始化棋盘(二维数组)
3.棋盘的打印
4.布置雷
5.安全保护
6.雷数显示
7.排查雷
8.标记雷
9.展开
10.难度设置
11.全局代码
扫雷 效果图:
文章图片
文章图片
从以上效果图中可见,我们需要实现的功能有:
1.随机埋雷
2.显示雷数
3.展开
4.标记
5.判定输赢
如果将雷,数字,和*同时放在一个数组里是不现实的,因为如果一个格子中已经放了雷,就不可能将其变为星号显示,所以我们得到一个大体思路,要用两个数组,一个埋雷,一个显示。
还是老规矩,创建3个文件
文章图片
game.h先引用和定义必要的数据
# define _CRT_SECURE_NO_WARNINGS
#include
#include
#include #define ROW 9
#define COL 9#define ROWS ROW+2
#define COLS COL+2#define EASY_COUNT 10
这次我们用'*'当作未知量,'#'为标记,'1'为雷,'0'为非雷(此处为一个伏笔)
1.基本界面的实现 这一部分比较简单,所以就只简单提一句
void menu()
{
printf("*********************************\n");
printf("*********1. Play*********\n");
printf("*********0. Exit*********\n");
printf("*********************************\n");
}void game()
{
char mine[ROWS][COLS] = { 0 };
//存放雷的信息
char show[ROWS][COLS] = { 0 };
//展示给玩家的棋盘
intialize(mine,ROWS ,COLS,'0');
intialize(show,ROWS ,COLS,'*');
//展示棋盘
print(show, ROW, COL);
//布置雷
setmine(mine, ROW, COL);
//排查
search(mine, show, ROW, COL,0);
}int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择>:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("game start\n");
game();
break;
case 0:
printf("已退出游戏\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
} } while (input);
return 0;
}
这里可能有人要问,为什么要创建11*11的数组呢?
如果我们要在9*9的棋盘中找寻雷的个数,那么就得找寻周围8个元素,但是如果要找边边角角的格子附件雷的个数,就涉及到数组越界的问题,不太好办。所以我们将数组做大一圈,保证数组访问不会越界
文章图片
2.初始化棋盘(二维数组) 现在我们要考虑一个问题,这次我们有两个二维数组要初始化,而且其中内容也不同,那该怎么办呢?
其实也比较简单,只需要让初始化函数多接受一个需要初始化的量就可以了
void intialize(char board[ROWS][COLS], int row, int col, char target)
{
int i = 0;
for (i = 0;
i < row;
i++)
{
int j = 0;
for (j = 0;
j < col;
j++)
{
board[i][j] = target;
}
}}
这样就可以完成不同的初始化了
3.棋盘的打印 由于扫雷需要的棋盘比较大,为了方便游玩,这次还需要打印行列号
void print(char board[ROWS][COLS], int row, int col)
{
int i = 0;
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");
}
}
效果图:
文章图片
4.布置雷 布置雷就牵扯到随机数的问题,要保证雷不会重复布置且只在9*9的棋盘中布置
void setmine(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = 0;
while (1)//未布置满就一直循环
{
x = rand() % row + 1;
//使x,y在1~9间,保证数组不越界布置
y = rand() % col + 1;
if (board[x][y] != '1')//保证布置的雷不重复
{
board[x][y] = '1';
count++;
}
if (count == EASY_COUNT)//布置满所有不重复的雷后才可跳出循环
break;
}}
5.安全保护 为了防止第一次排查就猝死,提高游戏体验所以我们需要设计一下,让玩家如果第一次就踩雷,棋盘会重置,直到此处没有雷
first_die++;
if (first_die == 1 && mine[x][y] == '1')//first_die在test中创建,默认传递0进入
{
while (mine[x][y] == '1')
{
intialize(mine, ROWS, COLS, '0');
//必须先初始化棋盘,不然会导致原本的雷依然在
setmine(mine, ROW, COL);
}}
6.雷数显示
int search_show(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');
}
'0'的ASCII值为48,我们将雷设计为'1'就是为了方便相加以后减去8个'0',直接就可以得到雷的数量
7.排查雷 下面就是本文章的重点之一,雷的排查,其实实现思路也比较简单,如果踩到雷,游戏结束;如果没有,继续游戏,同时显示附近雷的个数
int x = 0;
int y = 0;
while (1)
{
printf("请输入需要排查的坐标,如:1 1\n");
scanf("%d%d", &x, &y);
first_die++;
if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入的行列号是否在规定范围
{
if (mine[x][y] == '1')
{
printf("你死了,请再接再厉\n");
print(mine, ROW, COL);
break;
}
else
{
show[x][y] = search_show(mine, ROW, COL)+'0';
//显示周围的雷数
open(mine,show, x, y,row,col);
print(show, ROW, COL);
}
}
else
{
printf("输入错误,请重新输入\n");
}
8.标记雷 我们可以在排查以后加入一个标记功能,我们规定用'#'标记,同时只能标记未知量
//标记地雷
int input1 = 0;
int input2 = 0;
if (x >= 1 && x <= row && y >= 1 && y <= col)
{do//至少要运行一次
{
printf("请输入标记坐标,输入0 0退出标记\n");
scanf("%d%d", &input1, &input2);
if (input1 >= 1 && input1 <= row && input2 >= 1 && input2 <= col)
{
if (show[input1][input2] == '*')//只标记未知量
{
show[input1][input2] = '#';
print(show, ROW, COL);
}
else
{
printf("标记失败,请重新标记\n");
}
}
else if (input1 == 0 && input2 == 0)//输入0 0退出标记
break;
else
{
printf("标记错误,请重新标记\n");
}} while (input1&&input2);
printf("已退出标记\n");
}
9.展开 这应该是最难实现的一部分,这里我们用到递归的思想
void open(char mine[ROWS][COLS],char show[ROWS][COLS], int x, int y,int row ,int col)
{
int ret = 0;
ret =search_show(mine,x,y);
if (ret == 0)//如果周围无雷,判断展开
{
show[x][y] = ' ';
//防止死递归,如果不将show[x][y]变为' ',则下一次检测可能又会是*,再次进入递归,直至卡死。
if (x - 1 > 0 && y > 0 && show[x - 1][y] == '*'|| show[x - 1][y] == '#')
open(mine, show, x - 1, y, row, col);
if (x - 1 > 0 && y + 1 <= col && show[x - 1][y + 1] == '*'|| show[x - 1][y + 1] == '#')
open(mine, show, x - 1, y + 1, row, col);
if (x > 0 && y + 1 <= col && show[x][y + 1] == '*'|| show[x][y + 1] == '#')
open(mine, show, x, y + 1, row, col);
if (x + 1 <= row && y + 1 <= col && show[x + 1][y + 1] == '*'|| show[x + 1][y + 1] == '#')
open(mine, show, x + 1, y + 1, row, col);
if (x + 1 <= row && y > 0 && show[x + 1][y] == '*'|| show[x + 1][y] == '#')
open(mine, show, x + 1, y, row, col);
if (x + 1 <= row && y - 1 > 0 && show[x + 1][y - 1] == '*'|| show[x + 1][y - 1] == '#')
open(mine, show, x + 1, y - 1, row, col);
if (x > 0 && y - 1 > 0 && show[x][y - 1] == '*'|| show[x][y - 1] == '#')
open(mine, show, x, y - 1, row, col);
if (x - 1 > 0 && y - 1 > 0 && show[x - 1][y - 1] == '*'|| show[x - 1][y - 1] == '#')
open(mine, show, x - 1, y - 1, row, col);
}
else//有雷则返回雷数
{
return show[x][y]=search_show(mine, x, y)+'0';
}}
10.难度设置 其实实现思路比较简单,可以再设置MIDDLE_COUNT和HARD_COUNT。
传参时,将难度数字也传进去即可
这里交给大家去自行实现,不算难
11.全局代码
game.h# define _CRT_SECURE_NO_WARNINGS
#include
#include
#include #define ROW 9
#define COL 9#define ROWS ROW+2
#define COLS COL+2#define EASY_COUNT 10//初始化
void intialize(char board[ROWS][COLS], int row, int col, char target);
//打印棋盘
void print(char board[ROWS][COLS], int row, int col);
//布置雷
void setmine(char board[ROWS][COLS], int row, int col);
//排查雷
void search(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col,intgame.c# define _CRT_SECURE_NO_WARNINGS
# include "game.h"void intialize(char board[ROWS][COLS], int row, int col, char target)
{
int i = 0;
for (i = 0;
i < row;
i++)
{
int j = 0;
for (j = 0;
j < col;
j++)
{
board[i][j] = target;
}
}}void print(char board[ROWS][COLS], int row, int col)
{
int i = 0;
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 setmine(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = 0;
while (1)
{
x = rand() % row + 1;
y = rand() % col + 1;
if (board[x][y] != '1')
{
board[x][y] = '1';
count++;
}
if (count == EASY_COUNT)
break;
}}int search_show(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 open(char mine[ROWS][COLS],char show[ROWS][COLS], int x, int y,int row ,int col)
{
int ret = 0;
ret =search_show(mine,x,y);
if (ret == 0)//如果周围无雷,判断展开
{
show[x][y] = ' ';
//防止死递归,如果不将show[x][y]变为' ',则下一次检测可能又会是*,再次进入递归,直至卡死。
if (x - 1 > 0 && y > 0 && show[x - 1][y] == '*'|| show[x - 1][y] == '#')
open(mine, show, x - 1, y, row, col);
if (x - 1 > 0 && y + 1 <= col && show[x - 1][y + 1] == '*'|| show[x - 1][y + 1] == '#')
open(mine, show, x - 1, y + 1, row, col);
if (x > 0 && y + 1 <= col && show[x][y + 1] == '*'|| show[x][y + 1] == '#')
open(mine, show, x, y + 1, row, col);
if (x + 1 <= row && y + 1 <= col && show[x + 1][y + 1] == '*'|| show[x + 1][y + 1] == '#')
open(mine, show, x + 1, y + 1, row, col);
if (x + 1 <= row && y > 0 && show[x + 1][y] == '*'|| show[x + 1][y] == '#')
open(mine, show, x + 1, y, row, col);
if (x + 1 <= row && y - 1 > 0 && show[x + 1][y - 1] == '*'|| show[x + 1][y - 1] == '#')
open(mine, show, x + 1, y - 1, row, col);
if (x > 0 && y - 1 > 0 && show[x][y - 1] == '*'|| show[x][y - 1] == '#')
open(mine, show, x, y - 1, row, col);
if (x - 1 > 0 && y - 1 > 0 && show[x - 1][y - 1] == '*'|| show[x - 1][y - 1] == '#')
open(mine, show, x - 1, y - 1, row, col);
}
else
{
return show[x][y]=search_show(mine, x, y)+'0';
}}int win(char show[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
int count = 0;
for (i = 1;
i <= row;
i++)
{
for (j = 1;
j <= col;
j++)
{
if (show[i][j] == '*'||show[i][j]=='#')
count++;
} }
if (count == EASY_COUNT)
return 1;
else
return 0;
}void search(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int first_die)
{
int x = 0;
int y = 0;
while (1)
{
printf("请输入需要排查的坐标,如:1 1\n");
scanf("%d%d", &x, &y);
first_die++;
//防止第一次暴毙
if (first_die == 1 && mine[x][y] == '1')
{
while (mine[x][y] == '1')
{
intialize(mine, ROWS, COLS, '0');
setmine(mine, ROW, COL);
}}if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("你死了,请再接再厉\n");
print(mine, ROW, COL);
break;
}
else
{
show[x][y] = search_show(mine, ROW, COL)+'0';
//显示周围的雷数
open(mine,show, x, y,row,col);
print(show, ROW, COL);
}
}
else
{
printf("输入错误,请重新输入\n");
}//判断输赢
int Win = win(show, row, col);
if (Win == 1)
{
printf("恭喜您,胜利了\n");
break;
}//标记地雷
int input1 = 0;
int input2 = 0;
if (x >= 1 && x <= row && y >= 1 && y <= col)
{do
{
printf("请输入标记坐标,输入0 0退出标记\n");
scanf("%d%d", &input1, &input2);
if (input1 >= 1 && input1 <= row && input2 >= 1 && input2 <= col)
{
if (show[input1][input2] == '*')
{
show[input1][input2] = '#';
print(show, ROW, COL);
}
else
{
printf("标记失败,请重新标记\n");
}
}
else if (input1 == 0 && input2 == 0)
break;
else
{
printf("标记错误,请重新标记\n");
}} while (input1&&input2);
printf("已退出标记\n");
}
}
}test.c# define _CRT_SECURE_NO_WARNINGS
# include "game.h"void menu()
{
printf("*********************************\n");
printf("*********1. Play*********\n");
printf("*********0. Exit*********\n");
printf("*********************************\n");
}void game()
{
char mine[ROWS][COLS] = { 0 };
//存放雷的信息
char show[ROWS][COLS] = { 0 };
//存放排查出的雷的信息
intialize(mine,ROWS ,COLS,'0');
intialize(show,ROWS ,COLS,'*');
//展示棋盘
print(show, ROW, COL);
//布置雷
setmine(mine, ROW, COL);
//排查
search(mine, show, ROW, COL,0);
}int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择>:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("game start\n");
game();
break;
case 0:
printf("已退出游戏\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
} } while (input);
return 0;
}
以上就是本次的分享内容了,喜欢我的分享的话,别忘了点赞加关注哟!
如果你对我的文章有任何看法,欢迎在下方评论留言或者私信我鸭!
【路|【C语言/入门游戏】扫雷完整版(包含标记,安全保护及展开)】我是白晨,我们下次分享见!!