Hello,大家好,我是余同学。这两个月真是太忙了,无暇给大家更新文章…

暑假不是写了个扫雷小游戏吗(Link)?考虑到很多同学对代码没有透彻的理解,那么,这篇文章,我们来详细分析一下代码.

我们分为三个部分来讲:生成雷区,生成雷区数字刷新与判断


Part.1 生成雷区

随机数

首先,我们的雷区不能是定义好的矩阵,肯定得用随机数生成。
用随机数的话,就出现了一个问题:

  • C++有一个生成随机数的奇妙特性(也就是在不写srand(time(NULL));的情况下)

这个特性是什么样的呢?
我们来看下示例:

#include <bits/stdc++.h>
using namespace std;int main ()
{//srand(time(NULL));int random=rand()%10;cout<<random;return 0;
}

运行结果:
第一次:

第二次:

可以看到, 虽然是"随机数",但是,程序每次输出的数却是一样的,这是怎么回事?

程序每次生成的数来源于一个随机数种子,如果我们不改变它的话,那么程序就会一直使用这个种子,从而导致每次生成的随机数都一样

因此,我们要使用随机数种子
其具体原理即是利用每次运行的时间互不相同,生成的随机数也不同
srand(time(NULL));

可以使用rand()%x生成随机数,也可以使用宏定义,即使用define

#define random(x) rand()%(x)

那么,我们看看效果吧
第一次输出:

第二次输出:

也就是说,如果我们要生成一个从ab区间的随机数,可以用以下指令:

int number=a+rand()%b; //随机数生成区间为:a ~ a+b-1
int number=rand()%b;   //随机数生成区间为:1 ~ b-1

随机数搞定了,接下来,就是考虑生成扫雷矩阵的事情了

生成雷区

现在,我们面临的最大问题就是:在不使用字符串的情况下,如何用0~9这十个数字实现数字与雷的分别

其实,实现很简单,我使用的方法是:1~8作为数字,0作为附近9格无雷标志(其实还是数字),9作为雷

那么,我们的矩阵是 10×10 的,只要通过循环生成 100 个随机数就行了

看代码吧:

#include<bits/stdc++.h>
/*
#include <iostream>
#include <cstdlib>
#include <windows.h>
#include <ctime>
#include <iomanip>
*/
#define random(x) 1+rand()%(x)
using namespace std;
int ui[12][12],b[12][12]; //多开一些没有坏处,原因后面会讲int main(){srand(time(NULL)); //random seed, srand(time(0));//system("color 1B");system("title MineSweeper");int cnt=10; //地雷个数while(cnt){int x=random(10);//a+rand()%b = [a, a+b-1]int y=random(10);if(!ui[x][y]){//if(ui[x][y]==0){ui[x][y]=9;cnt--;}}return 0;
}

忘记说了,我设了两个二维数组,其中,ui数组的功能是:存储整个雷区;数组b的功能则是:存储每个方格的状态(详见Part.3

至此,我们的第一部分结束。

如果有的同学疑惑上面的代码没有输出时,那是因为我们只写了生成雷区的代码,并没有写生成雷区旁数字的代码,详细请看Part.2 生成雷区数字


Part.2 生成雷区数字

要完成这一部分,我们首先得了解地雷旁数字的生成规律:

每个数字代表周围8格内的地雷数量

还是上图片:

这样,我们的逻辑就清晰了,只要用双重循环遍历二维数组b的每一项,判断这个点是否为地雷,如果是,就跳过这个点,继续向下遍历;否之,计算出该点周围8个方格的总雷数(我们暂且定义为sum),sum就是这个点的数值

来把这一部分的代码实现吧

for(int i=1;i<=10;i++){for(int j=1;j<=10;j++){int sum=0; //统计周围地雷数量if(ui[i][j]!=9){ //该点不为雷/*下面的这些坐标具体位置详见上图*/if(ui[i-1][j-1]==9) sum++;//sum=!(a[i-1][j-1]-9)+!(a[i-1][j]-9)...if(ui[i-1][j]==9) sum++;if(ui[i-1][j+1]==9) sum++;if(ui[i][j-1]==9) sum++;if(ui[i][j+1]==9) sum++;if(ui[i+1][j-1]==9) sum++;if(ui[i+1][j]==9) sum++;if(ui[i+1][j+1]==9) sum++;ui[i][j]=sum;}}
}

现在,我们就知道了为什么前面的两个二维数组都要开大一点了:

因为二维数组的索引是从0开始的,而我们使用1作为起始索引(具体见上方代码两个for循环中),就是为了避免在边缘上的方块无法获取到周围地雷数,从而导致程序出bug的原因

然后,代码中的8个 if 语句都是统计周围地雷数的,如果你想简单亿点的话,把if语句替换成这一行:

sum=!(ui[i-1][j-1]-9)+!(ui[i-1][j]-9)+!(ui[i-1][j+1]-9)+
!(ui[i][j-1]-9)+!(ui[i][j+1]-9)+!(ui[i+1][j-1]-9)+!(ui[i+1][j]-9)+!(ui[i+1][j+1]-9);

这里我分做两行写,是怕有的同学看不清,大家在实际替换中删掉换行符就可以了

这一部分完整代码:

#include<bits/stdc++.h>
#include "windows.h"
/*
#include <iostream>
#include <cstdlib>
#include <windows.h>
#include <ctime>
#include <iomanip>
*/
#define random(x) 1+rand()%(x)
using namespace std;int ui[12][12],b[12][12];
int main(){srand(time(NULL)); //random seed//system("color 1B");system("title MineSweeper");int cnt=10;//cout<<"Booms:";cin>>cnt;while(cnt){int x=random(10);//a+rand()%b = [a, a+b-1]int y=random(10);if(!ui[x][y]){//if(ui[x][y]==0){ui[x][y]=9;cnt--;}}for(int i=1;i<=10;i++){for(int j=1;j<=10;j++){int sum=0;if(ui[i][j]!=9){if(ui[i-1][j-1]==9) sum++;//sum=!(a[i-1][j-1]-9)+!(a[i-1][j]-9)...if(ui[i-1][j]==9) sum++;if(ui[i-1][j+1]==9) sum++;if(ui[i][j-1]==9) sum++;if(ui[i][j+1]==9) sum++;if(ui[i+1][j-1]==9) sum++;if(ui[i+1][j]==9) sum++;if(ui[i+1][j+1]==9) sum++;/*sum=!(ui[i-1][j-1]-9)+!(ui[i-1][j]-9)+!(ui[i-1][j+1]-9)+!(ui[i][j-1]-9)+!(ui[i][j+1]-9)+!(ui[i+1][j-1]-9)+!(ui[i+1][j]-9)+!(ui[i+1][j+1]-9);*/ui[i][j]=sum;}}}/*for(int i=1;i<=10;i++){for(int j=1;j<=10;j++){cout<<ui[i][j]<<' '; //output the numbers}cout<<endl;}*/return 0;
}

大家把最后一段的注释符删掉,就可以看到我们的矩阵了

但是,我们到现在才做完整个项目的一半,我们还没有写判断操作符的代码,这就要留到Part 3来讲了


Part 3. 状态更新与判断输入

刷新屏幕

我们先来讲刷新屏幕

为什不先写判断输入的代码呢?
因为我们得让程序先把扫雷的矩阵输出出来

我们看看这张图片

这是原版的扫雷界面,通过观察每个方格,可以发现,每个方格都会出现三种状态:已翻开(包括空格和数字,用1表示)、未翻开(包括数字和地雷)和旗子(用户标雷处)

那么,我们可以用"#"表示未翻开的区域,用"P"表示旗子(

C++ · 手把手教你写一个扫雷小游戏相关推荐

  1. ChatGPT实现用C语言写一个扫雷小游戏

    前几天我们利用 ChatGPT实现用C语言写一个学生成绩管理系统 其过程用时不到30秒,速度惊人 今天又让ChatGPT用C语言写了一个扫雷小游戏,它的回答是:抱歉,我是AI语言模型,无法编写程序. ...

  2. 手把手教你写一个微信小程序日历组件

    今天我们一起写一个微信小程序日历组件 微信小程序日历组件 github.com/749264345/w- 好,我们先看一下要实现的模样,如下图 由以上截图我们可以看到 1.日历可以通过按钮[切换展示效 ...

  3. 使用C语言写一个扫雷小游戏

    前言 相信扫雷游戏小伙伴们肯定都玩过吧,学习了C语言中的数组.函数等基础内容之后就可以自己写一个简易的扫雷小游戏了,今天就我写扫雷小游戏的过程及思路写一篇博客,希望大家看完我的博客能有所收获. 软件及 ...

  4. 【tkinter】用不到50行Python代码,写一个扫雷小游戏

    文章目录 定制按钮 生成雷区 主流程 Tkinter系列: GUI初步

  5. 手把手教你写一个生成对抗网络

    成对抗网络代码全解析, 详细代码解析(TensorFlow, numpy, matplotlib, scipy) 那么,什么是 GANs? 用 Ian Goodfellow 自己的话来说: " ...

  6. 手把手教你写个微信小程序

    手把手教你写个微信小程序 很多人看完bmob快速入门,并完成了bmob的基本配置之后依然不知道如何下手去写自己的代码,那么跟着我一起来一步一步做个小程序吧. 工具:Bmob后端云 新建小程序项目 一. ...

  7. python k线合成_手把手教你写一个Python版的K线合成函数

    手把手教你写一个Python版的K线合成函数 在编写.使用策略时,经常会使用一些不常用的K线周期数据.然而交易所.数据源又没有提供这些周期的数据.只能通过使用已有周期的数据进行合成.合成算法已经有一个 ...

  8. 手把手教你写一个spring IOC容器

    本文分享自华为云社区<手把手教你写一个spring IOC容器>,原文作者:技术火炬手. spring框架的基础核心和起点毫无疑问就是IOC,IOC作为spring容器提供的核心技术,成功 ...

  9. 手把手教你写一个Matlab App(一)

    对于传统工科的学生用的最多的编程软件应该就是matlab,其集成度高,计算能力强,容易上手,颇受大众青睐.今天挖的这个新坑,主要是分享用matlab app designer设计GUI界面的一些方法和 ...

最新文章

  1. 送你一份 Kubernetes 实用命令速查表
  2. PostgreSQL 10.1 手册_部分 III. 服务器管理_第 21 章 数据库角色_21.4. 删除角色
  3. Keil中RO-data、RW-data、ZI-data意义
  4. C语言--对数组地址的解析
  5. 0xde c语言合法常量_【期初优课堂】2020“云课堂”开讲啦!第3期(C语言)
  6. sqlmap的简单用法
  7. mysql —— 分表分区(1)
  8. Eclipse里编辑代码,进度条出现“Remote System Explorer Operation”解决方法
  9. 微信小程序列表局部(单条)刷新
  10. UML——实现图(构件图与部署图)
  11. QListView的使用方法
  12. 为什么计算机连不上无线网络,为什么电脑连不上wifi(wifi正常 电脑连不上网)
  13. Python - 面向对象编程 - 类变量、实例变量/类属性、实例属性
  14. 《古诗词里的快意人生》读后感
  15. amc 美国数学竞赛能用计算机吗,美国数学竞赛AMC的三种级别
  16. Verilog分频器的设计(6分频和1.5分频)
  17. 《模仿游戏》没有告诉你的图灵真相
  18. ArcGIS中将一个shp图层批量分割成单个的shp;shp批量转geojson
  19. 基于北方苍鹰优化算法的函数寻优算法
  20. 培训c语言程序,编程人员培训手册C语言程序设计基础.PPT

热门文章

  1. linux 命令:uptime 详解
  2. 价格真的会影响蓝牙耳机音质吗?100-1000哪款蓝牙耳机适合学生党
  3. 实用脚本分享01:opencv拍摄视频、抽帧、合帧、批量改图片尺寸、批量改图片格式
  4. 轻装版本Find7测评
  5. Android 10 来袭
  6. 比特未来,一家真正以用户价值为第一的平台
  7. 删除IE下所有临时文件
  8. 【Numpy】创建数组
  9. linux 360wifi ap热点,rk3288 ap6335 linux下的wifi 热点功能使用
  10. 开机启动雷电模拟器 全屏 启动指定app