当前位置: 首页 > news >正文

用C语言实现扫雷

本篇适用于C语言初学者,主要涉及对于函数,数组,分支循环的运用。

目录

设计思想:

总代码(改进后):

运行结果展示:

分布介绍:

声明:

代码主体部分:

功能模块实现:

初始化模块:

打印模块:

埋雷模块:

判断模块:

总结:


设计思想:

首先要有一个游戏菜单,输入1表示开始,0表示结束,其它数字则提示输入错误,请重新输入;其次要有雷盘,雷盘用二维数组表示,开始时要有初始化模块对二维数组初始化,要有埋雷模块放置雷,要有判断输赢及返回结果模块,要有打印模块向玩家展示雷盘,为了更容易实现这些模块,我们选择两个二维数组表示雷盘,其中一个埋雷,其中一个向玩家展示。为了方便计算周围雷的个数,空用 '0' 表示,;雷用 '1'表示。

总代码(改进后):

#include <stdio.h>
#include <stdlib.h>
#include <time.h>#define ROW 9
#define COL 9#define ROWS ROW + 2
#define COLS COL + 2#define Easy_Mine 10void InitBorad(char borad[ROWS][COLS], int rows, int cols, char ch);
void DisplayBorad(char borad[ROWS][COLS], int row, int col);
void SetMine(char borad[ROWS][COLS], int row, int col);
void FindMine(char mine_borad[ROWS][COLS], char show_board[ROWS][COLS], int row, int col);//初始化
void InitBorad(char borad[ROWS][COLS], int rows, int cols, char ch)
{int i = 0;for (i = 0; i < rows; i++){int j = 0;for (j = 0; j < cols; j++){borad[i][j] = ch;}}
}//打印拓展
void DisplayBorad(char borad[ROWS][COLS], int row, int col)
{int i = 0;//列标for (i = 0; i <= col; i++){printf(" %d |", i);}printf("\n");for (i = 0; i <= col; i++){printf("---|", i);}printf("\n");for (i = 1; i <= row; i++){//行标printf(" %d |", i);int j = 0;for (j = 1; j <= col; j++){printf(" %c |",borad[i][j]);}printf("\n");for (j = 0; j <= col; j++){printf("---|", i);}printf("\n");}printf("\n");
}//放置雷
void SetMine(char borad[ROWS][COLS], int row, int col)
{int count = Easy_Mine;while (count){int x = rand() % row + 1;int y = rand() % col + 1;if (borad[x][y] == '0'){borad[x][y] = '1';count--;}}}//改进判断法//递归实现扫雷的展开一片
void GetMineCount(char mine_borad[ROWS][COLS], char show_borad[ROWS][COLS], int x, int y, int* count)
{if (x >= 1 && x <= ROW && y >= 1 && y <= COL && show_borad[x][y] == '*'){int i = x - 1;int j = y - 1;int sum = 0;//计算周围有几个雷for (i = x - 1; i <= x + 1; i++){for (j = y - 1; j <= y + 1; j++){sum = sum +(mine_borad[i][j] - '0');}}//如果周围没有雷,将此坐标置为空格,递归查找周围的周围是否有雷...if (sum == 0){show_borad[x][y] = ' ';for (i = x - 1; i <= x + 1; i++){for (j = y - 1; j <= y + 1; j++){//更正循环次数(*count)--;GetMineCount(mine_borad, show_borad, i, j, count);}}}//如果周围有雷,将此坐标字符该为对应雷的个数的字符else{//更正循环次数(*count)--;show_borad[x][y] = sum + '0';}}
}void FindMine(char mine_borad[ROWS][COLS], char show_board[ROWS][COLS], int row, int col)
{int x = 0;int y = 0;int count = row * col - Easy_Mine;//实现主体while (count){printf("请输入坐标:>");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (mine_borad[x][y] == '1'){printf("嘭!你被炸死了!\n");DisplayBorad(mine_borad, ROW, COL);break;}else if (mine_borad[x][y] == '0' && show_board[x][y] == '*');{GetMineCount(mine_borad, show_board, x, y, &count);//count = count_number(show_board, row, col);//DisplayBorad(mine_borad, ROW, COL);DisplayBorad(show_board, ROW, COL);}}else{printf("输入坐标非法,请重新输入!\n");}}if (count == 0){printf("恭喜你,你赢了!\n");DisplayBorad(mine_borad, row, col);}
}void menu()
{printf("******************************\n");printf("********   1.paly   **********\n");printf("********   0.exit   **********\n");printf("******************************\n");
}void game()
{//此二维数组用来放置雷char mine[ROWS][COLS] = { 0 };//此二维数组用于像玩家展示char show[ROWS][COLS] = { 0 };//初始化两个二维数组InitBorad(mine, ROWS, COLS, '0');//DisplayBorad(mine, ROW, COL);InitBorad(show, ROWS, COLS, '*');//放置雷SetMine(mine, ROW, COL);//打印棋盘DisplayBorad(show, ROW, COL);//DisplayBorad(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;
}

运行结果展示:

 

 

 

分布介绍:

声明:

如果想要更改雷盘大小,放置雷个数,只需对ROW , COL , Easy_Mine作相应的修改即可。 

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//标识符定义行与列
#define ROW 9
#define COL 9
//雷盘实际大小
#define ROWS ROW + 2
#define COLS COL + 2
//雷的个数
#define Easy_Mine 10
//主要函数声明
void InitBorad(char borad[ROWS][COLS], int rows, int cols, char ch);
void DisplayBorad(char borad[ROWS][COLS], int row, int col);
void SetMine(char borad[ROWS][COLS], int row, int col);
void FindMine(char mine_borad[ROWS][COLS], char show_board[ROWS][COLS], int row, int col);

代码主体部分:

关于作为9 * 9的雷盘为什么要选择11 * 11的二维数组表示,是为了防止越界访问,以及更容易地实现扫雷后的判断和返回结果。用字符0将要放置雷的二维数组初始化,用字符*将向玩家展示的二维数组初始化,用字符1表示雷。

//游戏菜单
void menu()
{printf("******************************\n");printf("********   1.paly   **********\n");printf("********   0.exit   **********\n");printf("******************************\n");
}
//实现主体
void game()
{//此二维数组用来放置雷char mine[ROWS][COLS] = { 0 };//此二维数组用于像玩家展示char show[ROWS][COLS] = { 0 };//初始化两个二维数组InitBorad(mine, ROWS, COLS, '0');//DisplayBorad(mine, ROW, COL);InitBorad(show, ROWS, COLS, '*');//放置雷SetMine(mine, ROW, COL);//打印棋盘DisplayBorad(show, ROW, COL);//DisplayBorad(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;
}

功能模块实现:

初始化模块:

通过嵌套for循环用传过来的字符将传过来的数组初始化。

//初始化
void InitBorad(char borad[ROWS][COLS], int rows, int cols, char ch)
{int i = 0;for (i = 0; i < rows; i++){int j = 0;for (j = 0; j < cols; j++){borad[i][j] = ch;}}
}

打印模块:

原始打印模块:

先利用for循环打印列标,再利用嵌套for循环打印行标及二维数组。代码及雷盘展示如下:

//打印
void DisplayBorad(char borad[ROWS][COLS], int row, int col)
{int i = 0;//列标for (i = 0; i <= col; i++){printf("%d ", i);}printf("\n");for (i = 1; i <= row; i++){//行标printf("%d ", i);//遍历二维数组int j = 0;for (j = 1; j <= col; j++){printf("%c ", borad[i][j]);}printf("\n");}printf("\n");
}

雷盘:

改进打印模块:

原理如上,加以修饰,代码及雷盘展示如下:

//打印拓展
void DisplayBorad(char borad[ROWS][COLS], int row, int col)
{int i = 0;//列标for (i = 0; i <= col; i++){printf(" %d |", i);}printf("\n");for (i = 0; i <= col; i++){printf("---|", i);}printf("\n");for (i = 1; i <= row; i++){//行标printf(" %d |", i);int j = 0;for (j = 1; j <= col; j++){printf(" %c |",borad[i][j]);}printf("\n");for (j = 0; j <= col; j++){printf("---|", i);}printf("\n");}printf("\n");
}

 雷盘:

埋雷模块:

要实现在雷盘上随机放置雷,需要srand()和time()库函数来确定随机数生成期起点,rand()库函数来生成随机数,将获得的随机数大小控制在1~9之间(雷盘逻辑大小),获得要放置雷的坐标后,找到与之对应的二维数组元素,将其置为字符1。(字符0表示不是雷,字符1表示雷)模块代码及放置雷的二维数组展示:

//放置雷
void SetMine(char borad[ROWS][COLS], int row, int col)
{//要放置的雷的个数int count = Easy_Mine;while (count){//获得要放置雷的坐标int x = rand() % row + 1;int y = rand() % col + 1;//如果此坐标未放置雷,则放置雷,否则重新获得坐标if (borad[x][y] == '0'){borad[x][y] = '1';count--;}}
}

放置雷的二维数组:

判断模块:

原始判断模块;

此模块需要将真雷盘和假雷盘二维数组都传过去。玩家输入要扫雷的坐标,如果坐标不合法,提示输入错误,重新输入。如果坐标合法,与放置雷的二维数组的相应坐标对照,如果此坐标是雷,则输出玩家扫雷失败,并将埋雷的二维数组向玩家展示,游戏结束,如果此坐标不是雷,则判断此坐标周围一圈有无雷,如果无雷,返回0,有雷的话,返回雷的个数,并将向玩家展示的二维数组的对应的坐标更改为雷的个数,更正循环控制条件,继续游戏。当循环控制条件不再满足(及已将所有不是雷的坐标扫出)则获得游戏胜利,游戏结束。

//原始判断法//返回此坐标周围雷的个数
int GetMineCount(char borad[ROWS][COLS], int x, int y)
{//字符1~9减去一个字符0就可以得到整型数1~9,这也是选择用字符0和1表示是否有雷的原因return (borad[x - 1][y] + borad[x - 1][y - 1] + borad[x][y - 1] + borad[x + 1][y - 1]+ borad[x + 1][y] + borad[x + 1][y + 1] + borad[x][y + 1] + borad[x - 1][y + 1] - 8 * '0');
}//判断输赢
void FindMine(char mine_borad[ROWS][COLS], char show_board[ROWS][COLS], int row, int col)
{int x = 0;int y = 0;//循环控制条件int count = row * col - Easy_Mine;while (count){printf("请输入坐标:>");scanf("%d %d", &x, &y);//判断输入坐标是否合法if (x >= 1 && x <= row && y >= 1 && y <= col){//此坐标是雷if (mine_borad[x][y] == '1'){printf("嘭!你被炸死了!\n");//打印放置雷的二维数组DisplayBorad(mine_borad, ROW, COL);break;}//此坐标不是雷else if (mine_borad[x][y] == '0' && show_board[x][y] != ' ');{//函数调用返回雷的个数int ret = GetMineCount(mine_borad, x, y);//将向玩家展示的二维数组的对应坐标更改为雷的个数(将整型数1~9加一个字符0就可转换成字符1~9)show_board[x][y] = ret + '0';//打印DisplayBorad(show_board, ROW, COL);//更正循环控制条件count--;}}else{printf("输入坐标非法,请重新输入!\n");}}//游戏胜利判定if (count == 0){printf("恭喜你,你赢了!\n");DisplayBorad(mine_borad, row, col);}
}

运行展示:

改进判断模块: 

上述判断模块跟扫雷游戏还是有些实质差异,在扫雷游戏中,当一个坐标周围一圈都没有雷时,就会为空,再对他周围的坐标的周围进行判断......因此需要对其进行改进,总体思想不变,仅需对判断坐标周围一圈雷数的子模块以及循环控制条件进行修改即可。当输入坐标周围一圈都没有雷时,将向玩家展示的二维数组的对应坐标置为空格,更改循环控制条件,并判断它周围坐标的周围是否有雷.....依此类推。这里通过循环和递归思想实现此功能。

//改进判断法//递归实现扫雷的展开一片
void GetMineCount(char mine_borad[ROWS][COLS], char show_borad[ROWS][COLS], int x, int y, int* count)
{//递归限制条件 if (x >= 1 && x <= ROW && y >= 1 && y <= COL && show_borad[x][y] == '*'){int i = x - 1;int j = y - 1;//此变量表示雷的个数 int sum = 0;//计算周围有几个雷for (i = x - 1; i <= x + 1; i++){for (j = y - 1; j <= y + 1; j++){sum = sum +(mine_borad[i][j] - '0');}}//如果周围没有雷,将此坐标置为空格,递归查找周围的周围是否有雷...if (sum == 0){show_borad[x][y] = ' ';for (i = x - 1; i <= x + 1; i++){for (j = y - 1; j <= y + 1; j++){//更正循环次数(*count)--;//递归 GetMineCount(mine_borad, show_borad, i, j, count);}}}//如果周围有雷,将此坐标字符改为对应雷的个数的字符else{//更正循环次数(*count)--;show_borad[x][y] = sum + '0';}}
}void FindMine(char mine_borad[ROWS][COLS], char show_board[ROWS][COLS], int row, int col)
{int x = 0;int y = 0;int count = row * col - Easy_Mine;//实现主体while (count){printf("请输入坐标:>");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (mine_borad[x][y] == '1'){printf("嘭!你被炸死了!\n");DisplayBorad(mine_borad, ROW, COL);break;}else if (mine_borad[x][y] == '0' && show_board[x][y] == '*');{GetMineCount(mine_borad, show_board, x, y, &count);//count = count_number(show_board, row, col);//DisplayBorad(mine_borad, ROW, COL);DisplayBorad(show_board, ROW, COL);}}else{printf("输入坐标非法,请重新输入!\n");}}if (count == 0){printf("恭喜你,你赢了!\n");DisplayBorad(mine_borad, row, col);}
}

运行展示:

 

 

总结:

关于扫雷游戏的基本模块已经实现,可以开始游戏啦!当然,这个简易扫雷游戏还是可以继续优化的,比如增加标记功能等,这些模块的实现就需要大家自行去探索了,我就不过多阐述了。本期内容就到这里,如果帮到你的话,还请给个一键三连吧。

相关文章:

  • 基于python实现视频和音频长度对齐合成并添加字幕
  • ubuntu gitlab 部署 私有git库
  • 银河麒麟系统安装
  • 为什么javascript中数组可以存储不同类型的元素,而大多编程语言数组必须存储相同的元素?
  • LeetCode-day11-2813. 子序列最大优雅度
  • 每日一题——Python实现PAT乙级1012 数字分类(举一反三+思想解读+逐步优化)五千字好文
  • 基于YOLO检测算法(单检测器网络+多视频输入)设计与实现
  • pdf格式转成jpg图片,pdf格式如何转jpg
  • 网络安全等级保护基本要求解读- 安全计算环境-应用系统和数据安全
  • 19.2 HTTP客户端-定制HTTP请求、调试HTTP、响应超时
  • 国产芯片狂飙,连遥遥领先都给他们写感谢信
  • 2024蓝桥杯初赛决赛pwn题全解
  • java如何预防sql注入
  • 46-4 等级保护 - 网络安全等级保护概述
  • 构建 deno/fresh 的 docker 镜像
  • cookie和session
  • E-HPC支持多队列管理和自动伸缩
  • LeetCode算法系列_0891_子序列宽度之和
  • Node项目之评分系统(二)- 数据库设计
  • php面试题 汇集2
  • QQ浏览器x5内核的兼容性问题
  • Redis 懒删除(lazy free)简史
  • spring cloud gateway 源码解析(4)跨域问题处理
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • 关于extract.autodesk.io的一些说明
  • 基于Javascript, Springboot的管理系统报表查询页面代码设计
  • 记一次删除Git记录中的大文件的过程
  • 两列自适应布局方案整理
  • 聊聊hikari连接池的leakDetectionThreshold
  • 微服务核心架构梳理
  • 走向全栈之MongoDB的使用
  • mysql面试题分组并合并列
  • 宾利慕尚创始人典藏版国内首秀,2025年前实现全系车型电动化 | 2019上海车展 ...
  • 浅谈sql中的in与not in,exists与not exists的区别
  • $.proxy和$.extend
  • (1)(1.11) SiK Radio v2(一)
  • (10)ATF MMU转换表
  • (23)Linux的软硬连接
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (JSP)EL——优化登录界面,获取对象,获取数据
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (附源码)springboot 智能停车场系统 毕业设计065415
  • (三十五)大数据实战——Superset可视化平台搭建
  • (译)计算距离、方位和更多经纬度之间的点
  • (原創) X61用戶,小心你的上蓋!! (NB) (ThinkPad) (X61)
  • (最完美)小米手机6X的Usb调试模式在哪里打开的流程
  • ****三次握手和四次挥手
  • ***检测工具之RKHunter AIDE
  • .bat批处理出现中文乱码的情况
  • .net core使用EPPlus设置Excel的页眉和页脚
  • .NET关于 跳过SSL中遇到的问题
  • [ 手记 ] 关于tomcat开机启动设置问题
  • [Android]使用Git将项目提交到GitHub
  • [AutoSar]BSW_Memory_Stack_003 NVM与APP的显式和隐式同步
  • [BUUCTF NewStarCTF 2023 公开赛道] week3 crypto/pwn