C++ 扫雷小游戏实现(小白入门 + 详细解析)

您所在的位置:网站首页 扫雷游戏小程序 C++ 扫雷小游戏实现(小白入门 + 详细解析)

C++ 扫雷小游戏实现(小白入门 + 详细解析)

2023-08-18 03:33| 来源: 网络整理| 查看: 265

扫雷小游戏具体实现

寒假的时候作为一个接触C语言一个学期的咸鱼,笔者尝试挑战了贪吃蛇的编写 不过当时的笔者在编写过程中仍然大量借助了其他各路大佬的思路与算法

时至暑假,笔者决定编写扫雷小游戏,并且全程尝试按照自己的设计思路来编写 虽然过程经常遇阻,最终设计也存有大量优化空间 历时三天笔者终于肝出了扫雷小游戏 在独立的编程中笔者也还是有了很多收获

以下尝试从头解析自己的程序,希望也能对大家有帮助(滑稽) 先上一两张效果图吧

困难游戏难度: 在这里插入图片描述 结束界面: 在这里插入图片描述 这里的背景字体颜色可以用 system(“color XX”); 调控

程序结构

我的将自己程序整理为两个头文件: Algorithm.h Mineweeper.h 前者是扫雷随机生成类,检索雷区,光标移动等相应一系列算法; 后者则是开始,结束等界面的界面设计;

扫雷的棋盘设计

三种难度的棋盘均是正方形, 只是尺寸差异; 偷懒之下就没有考虑动态开辟空间, 以最大棋盘为准定义了数组 arr[25][25]; 具体如下:

typedef struct information { string str = "□"; //对应显示在界面上的点,初始化为棋盘的默认格子"□" string num = "null"; //对应每个点所隐含的信息,没有读取J K键的情况不会加以打印 //"■"代表该点为中心的九宫格中没有地雷,笔者成为空点 //"①"——"⑧"代表该点为中心的九宫格中有1——8个地雷,笔者成为数字点 int judge = 0; //确定区域时是否被遍历的标记 int x = 0; //是否含有地雷的标记,0对应false,1对应true }Inf; 扫雷的光标移动

在笔者的扫雷程序中 以 WASD 进行上下左右的移动 用 J 进行插旗操作 用 K 进行区域确认 在这过程中首先要用 "*" 代替原来的光标 这涉及光标消失的函数

void infogone() { HANDLE hwind; //定义窗口句柄 hwind = GetStdHandle(STD_OUTPUT_HANDLE); //获取窗口信息 CONSOLE_CURSOR_INFO info; //定义光标结构体 GetConsoleCursorInfo(hwind, &info); //获取当前窗口的光标信息 info.bVisible = 0; //将光标的是否可视修改为0 SetConsoleCursorInfo(hwind, &info); //将窗口中的光标信息按照结构体重新设置 }

同理若要调回可视即将 info.bVisible 重新修改为 1 即可; 而光标又需要通过读取WASD键在地图上自由移动;

这就需要移动光标位置的函数

void gotoxy(int x, int y) { COORD pos = { (short)x ,(short)y }; //涵盖光标位置信息的结构体(x,y) HANDLE hOutput; //获取窗口句柄 hOutput = GetStdHandle(STD_OUTPUT_HANDLE); //读取窗口信息 SetConsoleCursorPosition(hOutput, pos); //根据结构体中的参数直接移动光标 }

综合这两个函数, 以及加以判断条件的循环 (触雷时跳出) 和对: _getch(); _kbhit(); 的应用,加上边界的判断条件, 就可以实现光标在棋盘上的自由移动和切换

完整的代码可以通过文章尾的链接下载

扫雷生成地雷、检索区域的算法实现

扫雷最最核心的模块就是以上两个算法, 相比之下界面无非只是起锦上添花的作用;

生成地雷决定了在整个棋盘上能随机的生成地雷,确保了每次游戏的随机性; 而检索区域则对应每次点击之后判断是否触雷是否安全, 并生成一整块提示区域以供玩家的继续游戏;

一下将这两个算法逐一分析:

首先是随机生成地雷:

笔者的第一想法是在二维数组中随机生成地雷,并且每生成一个就以遍历的方式和之前的地雷比较,若重复则重新生成,若不重复则继续,直到生成指定数量的地雷;

这个想法是笔者常规性地思维,但随即发现棋盘一个二维数组,加上遍历的循环,总共是有四个循环的嵌套,显然这在算法时间复杂度上是和毁灭性的(即使针对10X10,10个地雷的小棋盘也是如此);

笔者最终通过尝试,发现了一种伪随机生成地雷的方法,虽然不能真正意义上做到棋盘上每个点生成地雷的概率是完全一致的,但是能基本上是地雷较为均匀较为随机地分布于整个棋盘, 而最重要的是其仅仅是线性的时间复杂度;

void creatMine(int k) //k是棋盘边长-1 { for (int i = 0; i if (arr[x][y].num != "■") //如果该点自身为数字点 { arr[x][y].str = arr[x][y].num; gotoxy(a, b); cout if (jk || ik) continue; //若超出边界则跳过此次循环 if (arr[i][j].num == "√") continue; //若该点为地雷也跳过此次循环 arr[i][j].str = arr[i][j].num; gotoxy(a + (j - y) * 2, b + i - x); cout


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3