IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【扫雷游戏】简单模拟实现讲解 -> 正文阅读

[数据结构与算法]【扫雷游戏】简单模拟实现讲解

前言


  • 🚄 输入是学习的本质,输出是学习的手段。
  • 🔖 分享每一次的学习,期待你我都有收获。
  • 🎇 欢迎🔎关注👍点赞??收藏?评论,共同进步!
  • 🌊 “要足够优秀,才能接住上天给的惊喜和机会”
  • 💬 博主水平有限,如若有误,请多指正,万分感谢!

主要讲一下思想和一些注意点。
扫雷是什么,相信大家没玩过也听过,我就不过多赘述了。
这是一个扫雷界面。
![在这里插入图片描述](https://img-blog.csdnimg.cn/7f7344259c7940fb91aebb0b272ddc12.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Luj5bKaXw==,size_13,color_FFFFFF,t_70,g_se,x_要写一个扫雷游戏需要分为以下步骤

要实现扫雷,需要分为以下步骤:

  • 创造一个这样的棋盘
  • 布置雷
  • 扫雷

??1. 创造棋盘,假设我们需要的是9*9的棋盘。

当我们选中一个位置时,如果这个位置不是雷,那么游戏就应该给我们一个反馈,告诉我们周围一圈8个位置有几个雷。
就像这样:在这里插入图片描述

这就表明周围这一圈里有3个雷。如果恰好我们选的位置就是雷,那么我们就被炸死了,游戏就直接结束。


这里就面临一个问题了,如果我选的是中间的位置,那周围有8个位置可以反馈,如果我选的是边缘呢?
在这里插入图片描述
显然这已经超出数组范围,越界了。因此,我们不妨再创造这样一个棋盘时,就将范围扩大些。

比如我们要的是一个9*9的棋盘,那么我们就将范围扩大到11 * 11(上下、左右各增加一行一列。绿色为扩大后的范围),只要不在扩大的那部分中埋雷,那么显示出来的数字也只会是9 * 9 这个区间中雷的个数,如图所示:
(假设 * 表示雷)
在这里插入图片描述

  • 创建数组——大小确定
//用define更方便调整游戏棋盘大小

//实际游戏范围
#define ROW 9  
#define COL 9  


//扩大的范围
#define ROWS 11
#define COLS 11

??2.如何设置雷,如何设置反馈?

有些老铁觉得可以在一个棋盘里
用1和0分别表示雷和非雷
就像这样:(1表示雷 ,0表示非雷)
在这里插入图片描述
但是这样做会和反馈周围雷数的1产生二义性,因此不合适。


又有些老铁认为可以用*表示雷,#表示非雷,但是这样不够方便,没有用0和1表示来得方便。为什么不够方便一会儿就知道了,当然如果非要这样实现也是可以的。只是判断的时候会比较复杂一点。

在这里插入图片描述


既然我们既要用1和0表示雷和非雷,又不能与反馈的数字产生二义性,那么我们不妨再开一个等大的棋盘,这样,一个棋盘用来布置雷,但是不展示给玩家,另一个棋盘则作为反馈信息的棋盘,展示给玩家。


一开始我们先把布置雷的棋盘初始化,全置为0(非雷),以后再随机埋雷。
将反馈展示给玩家的棋盘全置为 * ,就是一个没有动过的棋盘

//初始化棋盘
void InitBoard(char board[ROWS][COLS], int row, int col, char set)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			board[i][j] = set;
		}
	}
}
	char mine[ROWS][COLS]; //雷盘
	char show[ROWS][COLS];//反馈盘

	//初始化棋盘
	InitBoard(mine, ROWS, COLS, '0');  //0非雷 
	InitBoard(show, ROWS, COLS, '*');  //全置 *

效果如下(对比):

在这里插入图片描述

在这里插入图片描述
然后是布置雷:

#define Count 10   //布置10个雷

//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
	int count = Count;
	while (count)
	{
		int x = rand() % 9 + 1;
		int y = rand() % 9 + 1;
		if (mine[x][y] == '0') //如果这个位置不是雷
		{
			mine[x][y] = '1';
			count--;
		}
		//如果这个位置已经是雷,就不会再重复布置。
	}

}

布置完雷后,我们可以看一下效果:
在这里插入图片描述

  • 布置雷盘和反馈盘

??3. 扫雷,何时结束,如何反馈。

int Show(char mine[ROW][COL], int x, int y)
{
	return mine[x - 1][y - 1] +
		   mine[x - 1][y] +
		   mine[x - 1][y + 1] +
		   mine[x + 1][y - 1] +
		   mine[x + 1][y] +
		   mine[x + 1][y + 1] +
		   mine[x][y - 1] +
		   mine[x][y + 1];
}

//扫雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS])
{
	int x, y;
	int endcount = ROW * COL - Count; //非雷的个数,用于标记
	int count = Count;//雷的个数

	//程序结束有两种情况:
	//1.被炸死
	//2.非雷点全走过了,只剩下雷点,排雷成功
	do
	{
		if (endcount == 0) //非雷点为0
		{
			printf("已无雷区\n");
			break;
		}
		printf("请输入坐标:\n");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
		{
			{
				if (mine[x][y] == '1')
				{
					printf("你被炸死了\n");
					//展开整个图
					PrintBoard(mine, ROW, COL);
					break;
				}
				//否则提示该坐标周围有多少雷
				else
				{
					int showcount = Show(mine, x, y);

					show[x][y] = showcount + '0';//数字转字符
					PrintBoard(show, ROW, COL);
				}
			}
		}

		else
		{
			printf("坐标错误,请重新输入");
			continue;
		}
	} while (1);
}

解释一下Show函数:
在ASCII表中,我们可以观察到,
‘0’-‘0’=0 ( 字符0-字符0等于 数字0 )
而其他任意数字字符减去字符0可以得到该数,比如
‘5’-‘0’= 5
在这里插入图片描述
因此 Show函数将周围八个字符(不是0就是1)
全加起来,再减去8个‘0’。就能得到一个数字,
该数字就表明周围有几个1。


这也就解释了为什么说用1和0表示雷和非雷方便。


最后再解释一下这行代码:

show[x][y] = showcount + '0';//数字转字符

因为show数组保存的是字符,无法完全接收这个返回来的整型数字。

字符数 - ‘0’ = 数字 ——> 字符数 = 数字 + ‘0’


完整代码:

game.h

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>

//实际游戏范围
#define ROW 9  
#define COL 9  


//扩大的范围
#define ROWS 11
#define COLS 11

#define Count 10; //雷的个数


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

//打印棋盘
void PrintBoard(char board[ROWS][COLS], int row, int col);

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

//扫雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS]);

game.c

#define _CRT_SECURE_NO_WARNINGS
#include"game.h"


//初始化棋盘
void InitBoard(char board[ROWS][COLS], int row, int col, char set)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			board[i][j] = set;
		}
	}
}



//打印棋盘
void PrintBoard(char board[ROWS][COLS], int row, int col)
{
	for (int i = 0; i <= row; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (int i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (int j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

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

}

int Show(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 + 1][y - 1] +
			mine[x + 1][y] +
			mine[x + 1][y + 1] +
			mine[x][y - 1] +
			mine[x][y + 1] - 8 * '0';
		
}



//扫雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS])
{
	int x, y;
	int endcount = ROW * COL - Count; //非雷的个数,用于标记
	int count = Count;//雷的个数

	//程序结束有两种情况:
	//1.被炸死
	//2.非雷点全走过了,只剩下雷点,排雷成功
	do
	{
		if (endcount == 0) //非雷点为0
		{
			printf("已无雷区\n");
			break;
		}
		printf("请输入坐标:\n");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
		{
			{
				if (mine[x][y] == '1')
				{
					printf("你被炸死了\n");
					//展开整个图
					PrintBoard(mine, ROW, COL);
					break;
				}
				//否则提示该坐标周围有多少雷
				else
				{
					endcount--; //没找到一个非雷点,非雷数减一,当非雷数为0 ,说明排雷成功,游戏结束
					int showcount = Show(mine, x, y);

					show[x][y] = showcount + '0';
					PrintBoard(show, ROW, COL);
				}
			}
		}

		else
		{
			printf("坐标错误,请重新输入");
			continue;
		}
	} while (1);
}



test.c

#define _CRT_SECURE_NO_WARNINGS

#include"game.h"
#include<time.h>


void game()
{
	srand((unsigned int)time(NULL));

	char mine[ROWS][COLS]; //雷盘
	char show[ROWS][COLS];//反馈盘

	//初始化棋盘
	InitBoard(mine, ROWS, COLS, '0');  //0非雷 
	InitBoard(show, ROWS, COLS, '*');
	//布置雷
	SetMine(mine, ROW, COL);
	PrintBoard(show, ROW, COL);
	//扫雷
	int x, y;
	FindMine(mine, show);


}




int main()
{
	game();
}

在这里插入图片描述

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-01-24 11:09:15  更:2022-01-24 11:10:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 18:26:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码