如何用C语言快速实现初级版扫雷(步骤详细)
Posted Gyun.君
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何用C语言快速实现初级版扫雷(步骤详细)相关的知识,希望对你有一定的参考价值。
目录
前言
附上扫雷小游戏链接,先来体味感受下真正的扫雷是怎样的
本文章为手把手讲解实现C语言扫雷(好好看,相信不会太难的说)
当你自己完成后一定成就感幸福感满满的!!
问题描述
用C语言实现小游戏扫雷初级版(9x9棋盘/10个地雷)
工具
vs2019
基本思路和流程
扫雷的规则
尽快找出雷区中的所有不是地雷的方块
根据点击格子出现的数字找出所有非雷格子
同时避免踩雷,踩到一个雷即全盘皆输
代码实现思路
1.菜单选择开始或者退出游戏
2.初始化并打印雷区
3.第一次免雷和周边雷排查
4.雷区展开
5.判断胜利6.游戏结束后展示玩家用时
实现步骤
模块化
1.test.c :写整个游戏实现思路流程
2.game.c: 写游戏实现思路中的各个函数的定义,完成函数内容实现函数功用
3.game.h :引用需要用到的头文件,以及对各个自定义函数的声明
(其他模板上方只需要加上 #include “game.h”,避免重复引用相同头文件)
注:模块化便于管理和修改
菜单界面
比较简单直接上代码
代码
//菜单界面
void menu()
{
printf("************************\\n");
printf("******* 1.play *******\\n");
printf("******* 0.exit *******\\n");
printf("************************\\n");
}
选择的实现
玩家通过输入1/0 来选择是开始游戏还是退出游戏
用do while语句实现比较适合
do
{
menu();
printf("请输入选择:>");
scanf("%d", &input);
switch (input)
{
case 0:
printf("成功退出游戏!\\n");
break;
case 1:
printf("欢迎进入游戏!\\n");
game();
break;
default:
printf("输入出错,请重新输入\\n");
break;
}
} while (input);
初始化和打印雷区
考虑问题
因为我们在设计算法时需要统计坐标周围8个方位雷的个数
假如要统计边界坐标周围雷的个数,那么就会有数组越界的问题
那我们就要在9X9的边界多上一圈元素,也就要定义11X11的数组元素
这些元素我们显示给玩家看就可以了
雷区
使用9行9列的二维数组来表示,元素类型是char
char mine[ROWS][COLS] = { 0 };//存放雷的信息
char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
使用宏定义
1.推高代码可读性,后续代码中遇到,方便理解含义
2.提高扩展性,如果将来要修改棋盘尺寸,代码修改会很方便
#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)
{
int i = 0;
for (i = 0; i < rows; i++)//行
{
int j = 0;
for (j = 0; j < cols; j++)//列
{
board[i][j] = '0';
}
}
}
设置雷
//布置雷
void SetMine(char board[ROWS][COLS], int row, int col)
{
int count = COUNT;
while (count)
{
//生成随机下标
int x = rand() % row + 1;//取余后的范围是0-8
int y = rand() % col + 1;//加一后符合游戏范围
if (board[x][y] != '1')
{
board[x][y] = '1';
count--;//设置10个后 count为0 不再循环
}
}
}
打印
考虑如何实现图表
什么时候该打印
什么时候不该打印
打印的间距
换行的考虑
打印布局的美观性
参考代码
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;//在外围打印标数以便于玩家定位坐标
printf("-----------------------------------------\\n");
for (i = 0; i <= 9; i++)//0-9打印最上排数字
{
printf("| %d ", i);
}
printf("|\\n");
printf("-----------------------------------------\\n");
for (i = 1; i <= row; i++)
{
int j = 0;
printf("| %d |", i);//1-9打印最左排数字
for (j = 1; j <= col; j++)
{
printf(" %c |", board[i][j]);
}
printf("\\n");//一定注意要换行
printf("-----------------------------------------\\n");//每打印一排内容,再打印一排横线,形成表格,提升美观
}
效果图
玩家排雷
考虑问题
1.因为实际雷区是11x11的,也就是说显示雷区的下标是从1开始的,符合玩家思维
2.排雷范围
3.第一次免雷
4.显示周围雷数
免雷
//第一次免雷
void FirstSafe(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y)
{
int count = 0;
if (mine[x][y] == '1')
{
mine[x][y] = '0';//替换
while (1)
{
int rx = rand() % row + 1;
int ry = rand() % col + 1;
if (mine[rx][ry] == '0' && (rx != x) && (ry != y))
{
mine[rx][ry] = '1';//再次布雷
break;
}
}
count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
ExtendNotMine(mine, show, x, y, '0', '*');
DisplayShow(show, row, 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 (1)
{
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
{
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';//替换成字符数,显示雷数
DisplayBoard(show, ROW, COL);
}
}
else
{
printf("坐标非法,重新输入\\n");
}
}
周围雷数
int GetMineCount(char mine[ROWS][COLS], int x, int y)//获取周边一圈雷个数的信息
{
int ret = 0;
for (int i = x - 1; i <= x + 1; i++)
{
for (int j = y - 1; j <= y + 1; y++)//3X3范围
{
ret += mine[i][j];
}
}
return ret - mine[x][y] - 8 * '0';//注:'1'-'0'=1(ASCII码值)
}//返回值代表雷的个数
雷区展开
考虑用递归实现
//扩展排雷,展开周围非雷区
void ExtendNotMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
int n = 0;
n = GetMineCount(mine, x, y);
if (n == 0)
{
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 (mine[i][j] =='0'&& show[i][j]=='*')//周围坐标满足自身不是雷且还是初始化字符,进入递归再次扩展排雷
{
{
ExtendNotMine(mine, show, i, j, '0', '*');//递归排雷
}
}
}
}
else
show[x][y] = n + '0';//如果附近有雷,展示雷的个数
}
胜利判断
遍历雷区剩余的初始值个数进行判断
//求展示扫雷棋盘上含有初始化字符的个数,用来判断游戏何时终止
int AroundInitCount(char board[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 (board[i][j] == '0')
count++;
}
}
return count;
}
if (count == EASY_COUNT)
{
printf("恭喜你!扫雷成功!\\n");
DisplayShow(mine, ROW, COL);
break;
}
显示用时
void SpendTime(clock_t start)
{
clock_t end = clock();
clock_t total = end - start;
printf("游戏所用时间为:%.1lf秒!\\n", 1.0 * total / CLOCKS_PER_SEC);
}
以上是关于如何用C语言快速实现初级版扫雷(步骤详细)的主要内容,如果未能解决你的问题,请参考以下文章
扫雷游戏(C语言实现)初级版和优化版(增加了自动展开标记地雷功能,同时排除了第一次排到地雷的情况)