手把手教你写个扫雷(插旗,及展开图解与实现)

学习了二维数组以后,不仅可以写个三子棋,我们也可以更近一步,来写个扫雷玩玩?

编写程序的时候,一定要先做好构思与大体思路步骤,扫雷的基本运行逻辑其实并不算非常复杂,我们只需要把每一步捋顺即可。

本人能力有限,难免有叙述错误或者不详细之处!希望读者在阅读时可以反馈一下错误以及不够好的地方!感激不尽!

目录

菜单的创建与变量的创建

雷区的打印与初始化

游戏主体逻辑

插旗效果实现

展开的实现

插旗排雷

 


1.做一个简单可互动的菜单,准备好需要用到的变量。

2.创建两个二维数组,一个用于存放真实的雷区,另一个存放显示用的雷区,其中真实的雷区用随机数随机填入地雷,真实雷区范围设置 要设置成11 11,显示雷区范围在9 9内,否则数组将会越界。
3.也是打印雷区地图,雷子用1与0,外面用于遮盖的用*。

4.编写可以随机在雷区内埋雷的函数与对雷区初始化的函数。

5.玩家行动的编写,失败的触发条件,玩家行动时的选择,是排查还是插旗子。

6.游戏主体逻辑的编写:包涵检测胜利,以及最终难点,扫雷的展开。

菜单的创建与变量的创建

 变量的创建

我们先在头文件内创建一个新文件,在其中定义我们所需要的变量以及所需库函数的调用。

我们的扫雷棋盘设置为9X9,所以我们定义两个变量:ROW,COL分别为其赋值为9,但是由于涉及到需要遍历格子旁边8格的地雷数量函数的编写,如果选择计算最左上角的格子附近8格的地雷数量,9X9的数组元素个数完全不够,会出现数组越界的情况,我们不妨为其新建另外两个真实的控制二维数组大小变量的值,让ROW与COL只显示9X9的雷区,而真实的二维数组大小应是11X11,我们创建两个变量ROWS,ROLS为其赋值为11。

一旦设置成9X9,我们编写的寻找附近地雷的函数就会越界,因为它找不着附近的元素了。

#include  <stdio.h>
#include <stdlib.h>
#include <time.h >
#define ROW 9
#define COL 9
#define ROWS 11
#define COLS 11

 接下来我们在main函数里创建二维数组,一个用于存放真实的雷区,另一个用于显示外面的覆盖雷区。

int main()
{char mine[ROWS][COLS] = { 0 };//真实雷区char showmine[ROWS][COLS] = { 0 };//显示雷区return 0;
}

   目标实现的效果如下:                        

              真雷区                          覆盖后雷区

 


menu()

这个并不算困难,首先是打印基本的UI界面,只需要创建一个函数放入几个printf即可,个人代码如下,想创建成其他样式请随意。

void menu()
{printf("\n");printf("======|      扫雷      |======\n");printf("======|     1.play     |======\n");printf("======|     0.exit     |======\n");
}

菜单的互动

我们使用case语句来编写菜单的互动,非常简单,玩家输入1进入游戏,输入0退出,输入错误重试,代码如下:

int main()
{char mine[ROWS][COLS] = { 0 };char showmine[ROWS][COLS] = { 0 };int c = 1;menu();do{scanf("%d", &c);switch (c){case 1:printf("游戏开始!祝你好运!\n");game();break;case 0:printf("退出游戏!\n");break;default:printf("输入错误,请重新选择输入!\n");}} while (c);return 0;
}

雷区的打印与初始化

雷区初始化

这一部分的代码请注意作用于真实雷区,即mine而非showmine,我们创建另一个源文件function来实现这个函数

由于我们有两个雷区都涉及到初始化以及打印的问题,那么我们不妨集成一下功能,让这个函数不仅可以打印还可以初始化雷区,设置形参的时候我们多创建一个char类型的变量n,当我们需要初始化真实雷区的时候n传参0,反之,显示雷区则传递*,若是直接打印当前雷区情况则输入其他字符都可以。

9X9的二维数组,两个for循环为其赋值字符0即可完成初始化

//头文件内的设置:void IntMineField(char mine[ROWS][COLS], int row, int col);void DrawMineField(char mine[ROWS][COLS], int row, int col, char n)
{int i = 0;int j = 0;printf("________OwO________\n");for (j = 0; j < col+1; j++)//纵向打印坐标数字,方便知道坐标{printf("%d ", j);} printf("\n");for (i = 1; i <=row; i++){printf("%d ", i);   //横向打印坐标数字for (j = 1; j <= col; j++){if (n == '0' || n == '*')//如果输入字符0或者*,则初始化,不输入就纯打印{mine[i][j] = n;//之后若是需要让其发挥初始化功能从这下手}printf("%c ", mine[i][j]);}printf("\n");}printf("===================\n");}
DrawMineField(showmine, ROW, COL, '*');初始化显示雷区
DrawMineField(showmine, ROW, COL, 'k');打印雷区,打印哪一个雷区只需要换传入的参数即可
DrawMineField(mine, ROW, COL, '0');初始化并显示真实雷区

在这里我们可以发现,虽然它可以实现初始化的功能,但是会打印出来,更改其中的逻辑会使得这个函数变得过于冗长,不妨直接再编写一个初始化的函数方便我们初始化。当然想要更正实现这一功能也很简单,在这里就不做优化了。

单纯的初始化真实雷区,不打印
void IntMineField(char mine[ROWS][COLS], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){mine[i][j] = '0';}}
}

坐标数字的打印已经在代码段内用注释标出。

随机埋雷:

而为了达成随机条件,则需要生成随机数。随机数的生成我们可以借助rand函数来进行生成。


rand函数在生成随机数的时候,会随机生成一个种子值,然后rand函数会借由这个种子值生成随机数,但是每一次只产生一次种子值rand函数所产生的随机数不是完全随机的,所以我们在使用rand函数之前还需要借助srand函数来使得rand函数的种子值不断变化以达成真正的随机数生成。而一直不断变化的值,那就是系统时间了。

srand(unsigned seed)通过参数seed改变系统提供的种子值,从而可以使得每次调用rand函数生成的伪随机数序列不同,从而实现真正意义上的“随机”。通常可以利用系统时间来改变系统的种子值,即srand(time(NULL)),可以为rand函数提供不同的种子值,进而产生不同的随机数序列。


rand函数位于#include <stdlib.h>的头文件内。

为了使用time函数,也需要使用<time.h>的头文件。

我们先在main函数中先实现随机数

int main()
{srand((unsigned int)time(NULL));return 0;
}

然后编写一个函数,用于随机埋雷,代码如下:

void ReadyForMine(char  mine[ROWS][COLS], int row, int col)
{int x = 0;int y = 0;int i = 0;int count = 0;while (count < 10){x = rand() % row+1;//控制随机数的范围y = rand() % col+1;if (mine[x][y] != '1'){mine[x][y] = '1';count++;}}}

效果如下:

游戏主体逻辑

以下为逻辑概述:

首先是提醒玩家行动,分为:1.插旗排雷 2.排查地雷

进入插旗排雷行动后,每一次插旗进行一次判断,当成功插在地雷上则雷的总数-1,当雷的总数计数为0时,跳出循环胜利。

排查时,获取玩家输入的坐标,排查过的区域不能反复排查,将获得的坐标与真实雷区的坐标比对,等于字符1则游戏失败,等于字符0则继续游戏并且进行展开的判断

插旗效果实现

首先我们先创建一个用于检测是否胜利的全局变量地雷数量minenumber,当minenumber等于0的时候游戏胜利。

我们需要实时更新被排掉的雷,若是在函数内进行创建每一次函数在被调用的时候minenumber会被重新赋值一次,所以创建全局变量。

int minenumber = 10;//地雷数量int  Flag(char  mine[ROWS][COLS], char  showmine[ROWS][COLS], int x, int y)
{if (showmine[x][y] == '*'){showmine[x][y] = '@';//插上旗帜的坐标位置用@替代DrawMineField(showmine, ROW, COL, 'k');if (mine[x][y] == '1'){minenumber--;printf("%d\n", minenumber);if (minenumber == 0){return 2;}return 1;}return 1;}else{printf("坐标非法,请重新输入!");}

展开的实现

展开的实现需要先满足以下3种情况:


该坐标不是雷,且没有被排查过

该坐标周围没有雷
该坐标的附近一旦有雷,则不要进入展开函数,遍历附近格子数得到附近8格地雷数量


首先则是实现对输入坐标附近8格进行地雷查找

思路是将当前坐标附近8格真实雷区里的元素值相加再减去字符0的值,可以得到附近8格里有几个1了。简单来说,收集附近8格的值,有雷就+1。

代码如下:

//获得坐标处旁的地雷数量
int  countmine(char  board[ROWS][COLS], int x,int y)
{int count = board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] +board[ x ]  [y - 1] + board[x][y + 1] +board[x + 1][y - 1] + board[x + 1][y] + board[x + 1][y + 1] - 8 * '0';return count;
}

 


接下来则是展开,代码如下:

void Spread(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{int offset_x = 0;int offset_y = 0;int count = 0;//坐标合法if (x >= 1 && x <= 9 && y >= 1 && y <= 9){//遍历周围坐标for (offset_x = -1; offset_x <= 1; offset_x++){for (offset_y = -1; offset_y <= 1; offset_y++){//如果这个坐标不是雷if (mine[x + offset_x][y + offset_y] == '0'){//统计周围雷的个数count = countmine(mine, x + offset_x, y + offset_y);if (count == 0){if (show[x + offset_x][y + offset_y] == '*'){show[x + offset_x][y + offset_y] = ' ';Spread(mine, show, x + offset_x, y + offset_y);}}else{show[x + offset_x][y + offset_y] = count + '0';}}}}}
}

展开的代码的逻辑是有点绕的,为了更好的方便我们去理解这一串套娃,我决定画图来分析。


 

 


效果如下:

插旗排雷

插旗排雷的代码逻辑并不困难,需要注意的是为了在函数里成功判断的地雷数量是否达成胜利条件,地雷数量的变量我在声明时使用了全局变量。

代码如下:

//插旗子:int  Flag(char  mine[ROWS][COLS], char  showmine[ROWS][COLS], int x, int y)
{if (showmine[x][y] == '*'){showmine[x][y] = '@';//为插上棋子的地方放上一个@当旗子DrawMineField(showmine, ROW, COL, 'k');//插完旗子后显示雷区,让玩家知道自己的棋子插在了哪里if (mine[x][y] == '1'){minenumber--;//如果插下的棋子底下真的是雷,地雷数量减一printf("%d\n", minenumber);//调试时用于检测函数是否生效if (minenumber == 0)//每一次插完旗子检测一次是否胜利,胜利返回2{return 2;}return 1;//还有地雷就返回1,继续}return 1;}else{printf("坐标非法,请重新输入!");}
}

 至此,我们大部分所需要的函数都写好了,把它们放到game函数里整理逻辑即可。

代码如下:

//游戏主体逻辑
void game(char  mine[ROWS][COLS], char  showmine[ROWS][COLS], int row, int col, int rows, int cols)
{int x = 0;int y = 0;int minenumber = 0;int ret = 1;int ret2 = 1;int c = 0;IntMineField(mine, ROWS, COLS);//初始化雷区DrawMineField(showmine, ROW, COL, '*');//初始化雷区后打印外面的隐藏雷区ReadyForMine(mine, ROW, COL);//埋雷//DrawMineField(mine, ROW, COL, 'k');//此处解除注释即可在初始化的时候看见雷的部署情况do{printf("请选择接下来的动作:\n1.探查地雷 2.为确认的地雷插下旗帜\n");scanf("%d", &c);if (2 == c){printf("请输入需要 插下旗帜 的坐标->.");scanf("%d %d", &x, &y);ret2 = Flag(mine, showmine, x, y);if (ret2 == 2)//当Flag函数返回2的时候跳出循环,进行胜利的判断break;}else if (1 == c){printf("请输入需要 排查 的坐标->.");scanf("%d %d", &x, &y);ret = Check(mine, x, y);//判断玩家是否踩到了雷if (showmine[x][y] != '*'){printf("该坐标被排查过了,不能重复排查\n");}else if (ret == 1){Spread(mine, showmine, x, y);//展开函数}DrawMineField(showmine, ROW, COL, 'k');//打印排查完毕后的雷区状况}else{printf("输入错误,请重新输入!\n");}} while (ret);if (ret == 0){printf("寄!你被炸死了,下辈子小心!XD\n");DrawMineField(mine, ROW, COL, 'k');//玩家失败,展示真实雷区情况}if (ret2 == 2){printf("NICE!你排完了所有的地雷,高手!");}//DrawMineField(showmine, ROW, COL, 'k');
}

当然main函数里也要加上一些其他的逻辑:

int main()
{srand((unsigned int)time(NULL));char mine[ROWS][COLS] = { 0 };char showmine[ROWS][COLS] = { 0 };int c = 1;menu();do{scanf("%d", &c);switch (c){case 1:printf("游戏开始!祝你好运!\n");game(mine, showmine, ROW, COL, ROWS, COLS);menu();IntMineField(mine, ROWS, COLS);break;case 0:printf("退出游戏!\n");break;default:printf("输入错误,请重新选择输入!\n");}} while (c);return 0;
}

完整代码地址:C语言刷题仓库: 装刷过的题目代码 - Gitee.com

 感谢阅读!希望能对你有一些帮助!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/26920.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

四步手把手教你实现扫雷游戏(c语言)

七步手把手教你实现扫雷游戏 c语言实现扫雷游戏一. 整体思路二. 设计棋盘以及初始化三. 埋雷四. 扫雷 c语言实现扫雷游戏 一. 整体思路 和上一篇文章的三子棋一样 第一步咱们创建三个工程文件 game.c 文件 用来实现游戏的函数定义 game.h 文件 用来声明函数以及需要的头文件 …

C/【扫雷】

**本文是用C语言写的扫雷小游戏———一个C语言前期寓教于乐的小游戏。 &#x1f331;博客主页&#xff1a;大寄一场. &#x1f331;系列专栏&#xff1a;C语言学习笔记 &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 目录 一.游戏菜单的创建 二.游戏实现…

扫雷游戏-C实现

扫雷游戏 纯C&#xff0c;运用数组&#xff0c;循环实现&#xff0c;基础巩固 注&#xff1a;本篇将重心放在思路以及核心步骤讲解&#xff0c;重要的不是将每一部分代码记下了&#xff0c;而是将核心思路和代码实现理解透彻。如果你对本篇一些内容跳转&#xff0c;细节表示茫然…

ChatGPT 速通手册——ChatGPT 的自我介绍

从 ChatGPT 的名字就可以看出&#xff0c;它的最核心功能就是 Chat(聊天)。那么&#xff0c;我们就以聊天的形式&#xff0c;开始本书的内容。 先让 ChatGPT 自己做一次自我介绍。既可以展现 ChatGPT 的产品使用形式&#xff0c;也可以快速了解 ChatGPT 的技术概念&#xff1a;…

VUE svg图标 报错

&#xff1a;咱前端用到svg的地方多了去了 这可得会 目录 下载安装 svg 配置config文件 在vue.config.js 创建icon文件夹&#xff0c;存放svg格式图片 icon/index.js 创建组件components ---> SvgIcon src/utils/validate.js 在main.js引入 下载安装 svg npm ins…

可以微调类ChatGPT模型啦!开源Alpaca-LoRA+RTX 4090就能搞定

源 | 机器之心 Alpaca-LoRA 将微调类 ChatGPT 模型的算力需求降到了消费级&#xff0c;训练个自己的中文对话模型真就没那么难了。 2023 年&#xff0c;聊天机器人领域似乎只剩下两个阵营&#xff1a;「OpenAI 的 ChatGPT」和「其他」。 ChatGPT 功能强大&#xff0c;但 OpenAI…

如何使用OpenAI fine-tuning(微调)训练属于自己专有的ChatGPT模型?

要使用OpenAI的微调技术来训练自己的专有模型,您需要遵循以下步骤: 获取和准备数据集:首先,您需要准备自己的数据集。可以使用公共数据集,也可以使用自己的数据集。数据集需要以特定格式(如JSONL)进行存储,并且需要经过清洗和预处理。 选择合适的模型和超参数:根据您…

一觉睡醒,ChatGPT 竟然被淘汰了?

转自机器之心 编辑&#xff1a;杜伟、陈萍 OpenAI 的 Andrej Karpathy 都大力宣传&#xff0c;认为 AutoGPT 是 prompt 工程的下一个前沿。 近日&#xff0c;AI 界貌似出现了一种新的趋势&#xff1a;自主人工智能。 这不是空穴来风&#xff0c;最近一个名为 AutoGPT 的研究开始…

ChatGPT实现stackoverflow 解释

stackoverflow 解释 ChatGPT 公开服务以来&#xff0c;程序员们无疑是最早深入体验和"测试"的一批人。出色的效果也引发了一系列知识产权上的争议。著名的 stackoverflow 网站&#xff0c;就宣布禁止用户使用 ChatGPT 生成的内容来回答问题&#xff0c;一经发现&…

ChatGPT疯狂生成「辣鸡」内容,Stack Overflow气急,连夜封杀!

时下爆火的ChatGPT&#xff0c;被网友们用来生成海量答案。而Stack Overflow已经不堪其扰&#xff0c;发起「追杀」&#xff1a;应封尽封&#xff01; OpenAI的新模型ChatGPT才诞生没几天&#xff0c;已经成为广大网友的「装逼利器」。 它的回答不说正确不正确&#xff0c;乍一…

轻松掌握RecyclerView缓存机制

在 Android 应用程序中&#xff0c;RecyclerView 是一个非常重要的控件。它被广泛使用&#xff0c;因为它可以帮助我们展示大量的数据&#xff0c;同时也能够提供流畅的滑动体验。然而&#xff0c;如果我们不小心处理好 RecyclerView 的缓存机制&#xff0c;就可能会导致性能下…

chatgpt赋能python:Python内存管理:如何清理内存

Python内存管理&#xff1a;如何清理内存 Python作为一种高级编程语言&#xff0c;在各种应用领域都得到了广泛的应用。作为一种解释型语言&#xff0c;Python有着自动垃圾回收器的优点&#xff0c;但在长时间运行的应用程序中&#xff0c;Python可能会占用大量内存&#xff0…

[chat-GPT]解决OpenAI‘s services are not available in your country问题

OpenAI‘s services are not available in your country 按照网上的教程一步步配置chat-GPT&#xff0c;一直换不同国家的梯子也无济于事&#xff0c;各种搜索尝试&#xff0c;终于解决 解决方法 1.换浏览器 我换了firefox 一开始用的谷歌浏览器 2.清楚当前使用的浏览器所有…

最新版ui成语填空答题,成语接龙小程序源码,修复登录接口问题

这类的成语接龙填词游戏&#xff0c;之前我就见过朋友在玩&#xff0c;自带裂变属性&#xff0c;引流、广告效果都是一绝。强制分享广告&#xff0c;可拆随机金额红包&#xff0c;广告配置、激励配置等都在后台即可配置管理&#xff0c;无需翻改代码。朋友运营过的东西&#xf…

小程序“成语猜题”部分答案

哀哀父母可哀呀可哀&#xff0c;我的父母啊&#xff01;原指古时在暴政下人民终年在外服劳役&#xff0c;对父母病痛、老死不能照料而悲哀。哀哀欲绝绝&#xff1a;断气&#xff0c;死。形容极其悲痛。哀兵必胜原意是力量相当的两军对阵&#xff0c;悲愤的一方获得胜利。后指受…

chatgpt赋能python:Python怎样模拟成语填空游戏

Python怎样模拟成语填空游戏 成语填空游戏是一种非常受欢迎的智力游戏。在这个游戏中&#xff0c;玩家需要根据提示&#xff0c;在给出的空格中填入对应的成语。而Python是一个功能强大的编程语言&#xff0c;用起来十分简单。在本文中&#xff0c;我们将介绍如何使用Python来…

看图猜成语小程序设计与实现(小程序+PHP)

目 录 摘 要 I Abstract II 1 绪论 1 1.1 研究背景 1 1.2 国内外研究现状 1 1.2.1 国内研究现状 1 1.2.2 国外研究现状 2 1.3 论文组织结构 3 2 相关技术 4 2.1微信小程序介绍 4 2.1.1微信介绍 4 2.1.2微信小程序简介 4 2.1.3微信小程序基本功能 5 2.2开发技术的介绍 6 2.2.1 P…

12月编程语言排行榜:前三终于变了,Java跌出前三?它居然首次进前三!

因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享 点击关注#互联网架构师公众号&#xff0c;领取架构师全套资料 都在这里 0、2T架构师学习资料干货分 上一篇&#xff1a;爆火的ChatGPT太强了&#xff01;写代码、改bug&#xff0c;网友&…

C++ 涨幅依旧亮眼,Visual Basic 一降再降!TIOBE 5 月榜单发布

整理 | 郑丽媛 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; 作为编程语言排行榜领域最权威的组织之一&#xff0c;今天 TIOBE 最新发布了 5 月榜单&#xff0c;快让我们看看这个月编程语言的流行趋势有何变化吧&#xff01; C 涨幅依旧亮眼&#xff0c;Visual …

忆享聚焦|ChatGPT、AI、网络数字、游戏……近期热点资讯一览

“忆享聚焦”栏目第十四期来啦&#xff01;本栏目汇集近期互联网最新资讯&#xff0c;聚焦前沿科技&#xff0c;关注行业发展动态&#xff0c;筛选高质量讯息&#xff0c;拓宽用户视野&#xff0c;让您以最低的时间成本获取最有价值的行业资讯。 目录 行业资讯 1.科技部部长王志…