扫雷游戏及代码实现(超详细)

2023-11-10

前言

想必屏幕前的你,肯定玩过windows系统自带的那个游戏。扫雷 回想当年,我根本没看懂这个游戏是怎么玩的

在这里插入图片描述

1.游戏程序主函数

在编写这类游戏代码时,我们要用到的主函数基本是一致的。扫雷游戏的主函数和猜数字游戏的主函数相差很小

void menu()//简易目录
{
  printf("***************************\n");
  printf("**** 1. play   0. exit*****\n");
  printf("***************************\n");
}int main()
{
  int input = 0;
  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;

2.游戏实现原理

想写好一串代码,首先我们要知道扫雷游戏需要通过什么方式来实现
在这里插入图片描述

我们需要一个9x9的棋盘,用于生成我们的雷以及玩家的游玩

在c语言中当然无法直接产生这样的画面

但我们可以同符号*或者#来代替网格,用1和0来表示有无雷

如果我们只生成一个棋盘,那1和0会直接显示出来,达不到隐藏的效果

所以我们需要用二维数组生成两个棋盘,一个用于存放雷,一个用于玩家的游玩

	char mine[ROWS][COLS];//雷区布置
	char show[ROWS][COLS];//玩家看到的界面

扫雷游戏我们使用头文件+源文件的形式撰写代码

这样写代码的优点在于后续我们可以直接通过更改.h文件中的数组,从而更改我们的格子大小

如: 改成12x12的游玩界面,改变雷区布雷个数等等

所以我们需要在game.h中定义这些符号

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define ROW 9
#define COL 9

#define ROWS ROW+2
#define COLS COL+2

同时我们要在主函数的最上面引用这个自己写的头文件

只要把库函数头文件放入game.h文件,在其他源文件中只需引用game.h

不需要再次引用<stdio.h>、<stdlib.h>之类

#include 'game.h'

棋盘大小为什么需要11x11?

你可能注意到了,在生成数组的时候,我使用了ROWS,其值为ROW+2

我们最终展示的只是9x9的游戏界面,但生成的棋盘其实是11x11的

这是因为我们需要在mine数组中实现扫描雷区的操作

玩过扫雷游戏的你肯定知道:在你点击一个格子的时候,如果这个格子不是雷

它会显示一个数字,告诉你它周围的8个格子中有几颗雷
在这里插入图片描述

在C语言中,我们可以用函数统计周围8个格子中雷’1’的个数

但是如果你来到边缘,那就出现问题了

在这里插入图片描述
如果我们想统计边缘的格子周边有几颗雷,就会遇到这种溢出数组的情况

此时代码会报错

为了避免这个问题,我们可以在原来9x9的基础上在周围加一圈空白的格子

也就是代码所示的ROW(行)COL(列)都要+2的情况

#define ROW 9
#define COL 9

#define ROWS ROW+2
#define COLS COL+2

游戏过程

这里简单梳理一下我们的游戏过程

(1)玩家选择开始游戏

(2)生成两个棋盘,一个放置雷\扫描雷,一个向玩家展示游戏界面

(3)玩家输入坐标,选择排雷位置

(4)有雷–>玩家被炸死,游戏结束;无雷–>显示周边有几颗雷,游戏继续

(5)所有雷被排出,游戏胜利

3.游戏代码实现

接下来就进入我们的游戏代码部分

3.1 初始化和打印

	//初始化扫雷
	InitBoard(mine, ROWS, COLS, '0');
	InitBoard(show, ROWS, COLS, '*');

	//打印扫雷
	DisplayBoard(mine, ROW, COL);
	DisplayBoard(show, ROW, COL);

我们需要初始化两个棋盘,其中雷区初始化为0(0代表无雷),展示区初始化为’*’,用✳代替界面

同时我们打印这两个棋盘,查看初始化效果

因为这是我们的自定义函数,所以需要在.h文件中定义函数,在另外一个.c文件中包含函数的实现

在这里插入图片描述

//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);
//打印
void DisplayBoard(char board[ROWS][COLS], int row, int col);

初始化函数和打印函数比较简单,使用for语句达成我们的需求

void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] = set;
		}
	}
}

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("------扫雷游戏------\n");
	//打印列号
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)//只打印中心的99方格
	{
		printf("%d ", i);//打印行号
		for (j = 1; j <= col; j++)//只打印中心的99方格
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
	printf("--------------------\n");
}

需要注意的是我们的最后打印棋盘的时候是从i=1开始的,这样就能避开添加的空白边缘区域,只打印中心的99方格

同时我们添加了列号和行号,这样能让玩家清除的知道自己应该输入什么坐标

在这里插入图片描述

3.2 布置雷区

	//布置雷
	SetMine(mine, ROW, COL); 

同样的,我们需要在Game.h中定义这个函数

//布置地雷
void SetMine(char mine[ROWS][COLS], int row, int col);

在Game.c中写入自定义函数的实现

//放置雷
void SetMine(char  mine[ROWS][COLS], int row, int col)
{
  int count = EASY_COUNT;
  while (count)
  {
    int x = rand() % row + 1;
    int y = rand() % col + 1;
    if (mine[x][y] =='0')
    {
      mine[x][y] = '1';
      count--;
    }
  }
}

这里面出现了一个前面没有提到的变量,EASY_COUNT

本来这个位置只是个10

但如果我们想更改布雷个数,那每次都需要更改这里的10,后面的代码中也需要更改,非常麻烦

所以我们改为使用一个自定义变量,在Game.h中定义这个变量的值

#define EASY_COUNT 10

这个值就代表我们布置雷的个数了

3.3 玩家排查雷

//在主函数中引用这个函数
	FindMine(mine,show, ROW, COL);//需要把mine数组中排查的雷放入show

//在game.h中定义这个函数
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],int row, int col);

因为我们需要把mine数组中排查出的雷的个数放入show数组中打印出来

所以这里我们需要把两个数组都传送过去

1.输入排查的坐标

2.检查坐标处是不是雷

是雷 -boom!炸死 -游戏结束

不是雷 -统计坐标周围有几个雷-存储排雷的信息到show数组,游戏继续

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
  int x = 0;
  int y = 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 = get_mine_count(mine, x, y);
        show[x][y] = count + '0';
      }
    }
    else
    {
      printf("坐标错误,请重新输入 \n");
    }
  }
}

注意,这里面我们需要添加一个代码来判断坐标合法性

我们的棋盘是9x9,玩家要是输入一个(99,99)的坐标,那肯定不在数组中的,是无效的

我们需要提醒玩家他输错了

‘0’的作用

show[x][y] = count + '0';

你可能会对这行代码感到疑惑

为什么要在count后面+上一个‘0’?

这里就和我们ascii码表有关了
在这里插入图片描述
因为我们初始化数组和布置雷的时候,我们给数组传入的都是1和0这两个符号,并不是数字!

但是在show数组中我们需要给玩家显示一个数字的字符

在这里插入图片描述
这里面我们提供的是1的字符,并不是1它本身

而我们在计算周边雷的个数的时候,传回来的是一个具体的数字

观察表格,你会发现数字和对应的字符中间,都差了48

而48恰好是字符’0’对应的ASCII码值

所以我们需要用count加上字符’0’,以此在界面中向玩家展示周边8格有几颗雷

3.4 系统扫描雷

如何把玩家选择的格子周边的雷扫描出来呢?

设玩家的选择的坐标为x和y
在这里插入图片描述
我们只需要把这些坐标全部在二维数组中键入,就能逐个扫描出雷的个数

//统计雷的个数
static int get_mine_count(char mine[ROWS][COLS], int x, int y)
{
  return mine[x - 1][y - 1] +
    mine[x - 1][y] +
    mine[x - 1][y + 1] +
    mine[x][y - 1] +
    mine[x][y + 1] +
    mine[x + 1][y - 1] +
    mine[x + 1][y] +
    mine[x + 1][y + 1] - 8 * '0';

这里因为我们扫描出来的也是‘1’的字符,系统中是字符1的ascii码值49

所以我们需要减去8个字符‘0’,这样就能得到雷的个数的数字

(然后在之前的那个函数中接受,count+‘0’,在show数组中显示)

这个函数是在玩家排查雷的函数之前的

因为在主函数中我们不需要使用这个自定义函数,所以不需要在game.h中定义

我们想让它只在game.c中生效,所以用static修饰它

static的作用

1.修饰局部变量

2.修饰全局变量

3.修饰函数

上面的代码其实还少了一个东西

我们需要判断玩家什么时候胜利——雷区的0(无雷方块)全部被玩家找出,玩家就胜利了

	int win = 0;
	while (win< row * col - EASY_COUNT)

这里我们需要更改的是whlie函数

其中 row * col - EASY_COUNT 指方格总数减去雷的个数,得到的是无雷方块的个数

玩家每成功排除一个无雷方块,win就会加一个数字

	else
	{
		//不是雷的情况下,统计坐标周围有几个雷
		int count = get_mine_count(mine, x, y);
		show[x][y] = count + '0';
		//显示排查出来的信息
		DisplayBoard(show, ROW, COL);
        win++;
	}

当win达到无雷方块个数的时候,whlie循环就会停止

随后我们判断玩家是否胜利,如果胜利,就打印棋盘,让玩家知道雷的位置

	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,游戏胜利!\n");
		DisplayBoard(mine, ROW, COL);
	} 

这里必须要判断,因为你失败了也是会跳出循环的!

到此,我们的扫雷代码就是完成了

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

扫雷游戏及代码实现(超详细) 的相关文章

随机推荐

  • 贪婪的非分层灰狼优化算法(G-NHGWO)(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 Matlab代码实现 4 参考文献 1 概述 狼优化 GWO 算法是基于灰狼社会等级及其
  • 织梦网站后台基本设置

    栏目概述 最主要还是说熟悉下网站后台基本设置 然后及我安装文件的常规操作 登陆网站后台 点击系统 基本参数 输入站点根网址 删除文档HTML默认保存路径a 填写下网站版权信息点击确定 小皮面板点击网站管理点开网站根目录删除install文件
  • java 输入_详解Java输入输出数据流模型和Web应用程序开发

    前言 Web应用开发架构技术不断的演化 从基于通用网关接口CGI开发的能够在操作系统上运行的独立组件 到专门的隔离运行的Servlet 一直到到现在我们对复杂应用开发使用Java EE技术或者Spring框架系列 其实其底层的核心逻辑基本上
  • Hystrix使用说明,配置参数说明

    四 配置信息 default或HystrixCommandKey 最常用的几项 超时时间 默认1000ms 单位 ms 1 hystrix command default execution isolation thread timeout
  • 1141:删除单词后缀(C C++)

    题目描述 给定一个单词 如果该单词以er ly或者ing后缀结尾 则删除该后缀 题目保证删除后缀后的单词长度不为0 否则不进行任何操作 输入 输入一行 包含一个单词 单词中间没有空格 每个单词最大长度为32 输出 输出按照题目要求处理后的单
  • BigQuery 如何帮助大规模交付业务型企业提供物联网解决方案

    介绍 Leverege是一家软件公司 它使全球市场领导者能够快速且经济高效地构建企业物联网应用程序 以提供以数据为中心的决策能力 优化运营 改善客户体验 交付客户价值并增加收入 Leverege 的主要 SaaS 产品 Leverege I
  • 不用虚拟机也能在Windows下使用Linux

    不用虚拟机也能在Windows下使用Linux 想学习热门的Linux系统 可是一开始就需要安装虚拟机软件 这样很容易消耗Linux初学者的热情 比如常用的VMWare虚拟机 虽然步骤并不复杂 但是一开始的搭建和配置过程 容易劝退一部分新手
  • 开源CA搭建-基于openssl实现数字证书的生成与分发

    目录 一 前言 二 openssl介绍 三 openssl的常用用法 一 单向加密 二 生成随机数 三 生成公钥 私钥 1 生成私钥 2 提取公钥 四 搭建CA 一 创建根CA私钥 二 生成自签名证书 三 创建数据库以及新颁发证书数字 四
  • Gitee Go代码格式审查、程序编译和冒烟测试

    本文分享自中移OneOS微信公众号 CI CD搭建流程 Gitee篇 作者 Kisann Gitee CI CD能力 Gitee 即码云 是OSCHINA NET推出的代码托管平台 已有超过600 万的开发者选择Gitee Gitee Go
  • ESP8266实现网页交互

    前言 物联网LOT intermet of things 时代 万物互联 wifi芯片是非常重要的 乐鑫的高性价比的ESP8266芯片凭借低功耗低成本高集成度等优势在市场上占有较高的份额 为什么选用这款芯片可以参考之前的调研报告 在之前的资
  • RBF神经网络参数的参数优化(进化算法)+Matlab源码

    RBF神经网络参数的参数优化 进化算法 1 RBF神经网络引入 1985年 Powell提出了多变量插值的径向基函数 RBF 方法 径向基函数是一个取值仅仅依赖于离原点距离的实值函数 也就是 x x 或者还可以是到任意一点c的距离 c点称为
  • aix系统常用的命令

    1 系统性能 1 看 CPU个数 lsdev C grep proc 几条记录就是几个CPU 注意考虑 AIX 5 3的 SMP 2 看每个CPU的大小 lsattr El proc0 3 看 内存条数 lsdev C grep mem 4
  • 借助LVS+Keepalived实现负载均衡

    借助LVS Keepalived实现负载均衡 一 负载均衡 必不可少的基础手段 1 1 找更多的牛来拉车吧 当前大多数的互联网系统都使用了服务器集群技术 集群即将相同服务部署在多台服务器上构成一个集群整体对外提供服务 这些集群可以是Web应
  • ElasticSearch 学习笔记(一):倒排索引(Inverted index)

    分析一个术语 要先从名称入手倒排索引 英文原名Inverted index 大概因为 Invert 有颠倒的意思 就被翻译成了倒排 但是倒排这个名称很容易让人理解为从A Z颠倒成Z A 个人觉得翻译成反向索引更好 倒排索引是区别于正排索引
  • Java中Path环境变量的设置

    第一步 打开文件管理器选择 此电脑 右键 此电脑 选择属性 第二步 再此电脑属性页面找到 高级系统设置 第三步 选择 环境变量 选择最下面的新建 则弹出新建系统变量 变量名为JAVA HOME 一定要大写 变量值为jdk的存储路劲 变量名
  • 小程序首页轮播图设计

    效果图 微信小程序的数据详解 indicator dots 是否显示面板指示点 默认false indicator color 指示点颜色 默认rgba 0 0 0 3 indicator active color 当前选中的指示点颜色 默
  • java如何使用cdn_网站部署使用CDN网络缓存(示例代码)

    CDN原理及为自己的网站部署 CDN是什么 CDN Content Delivery Network or Content Ddistribute Network 内容分发网络 其目的是使用户可就近取得所需内容 解决 Internet网络拥
  • 【超分辨率实验】使用MMEditing进行图像超分辨率

    使用MMEditing进行图像超分辨率 使用MMEditing进行图像超分辨率 安装MMEditing 使用预训练模型完成推理 查找并下载预训练模型 调用API构建模型 调用API进行推理 分析图像恢复效果 使用自定义的数据集微调模型 准备
  • shell命令更新mysql数据库

    bin sh mysql h10 10 10 10 uroot p123456 e use centain database use finereport close sage model for update SET SQL SAFE U
  • 扫雷游戏及代码实现(超详细)

    扫雷游戏及代码实现 前言 1 游戏程序主函数 2 游戏实现原理 游戏过程 3 游戏代码实现 3 1 初始化和打印 3 2 布置雷区 3 3 玩家排查雷 3 4 系统扫描雷 前言 想必屏幕前的你 肯定玩过windows系统自带的那个游戏 扫雷