扫雷游戏优化详解——c语言实现

news2024/11/24 1:53:34

文章目录

一、扫雷游戏的简单认识与解释 

二、扫雷游戏的代码及思路实现

一、扫雷游戏的思路

1、菜单打印 

2、创建扫雷区

3、初始化雷区

4、打印雷区

5、布置雷区

6、排雷

 三、扫雷游戏代码的整合

 game.h

 game.c

 test.c 


标题:猜数字小游戏 

作者:@Ggggggtm

寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景

 

一、扫雷游戏的简单认识与解释 

  相信大家都玩过扫雷游戏吧。但是你真的会玩扫雷游戏吗?那就让我来给你具体讲一下扫雷游戏的玩法。规则如下:

  1. 首先是已经布置好雷区,第一次排雷全靠运气;
  2. 当未踩中雷,会显示出以你排的位置为中心,9x9的范围内有多少颗雷;
  3. 当未踩中雷,且9x9的范围内没有雷时,会直接拓展区域,直到周围有雷停止拓展;
  4. 当你踩中雷时,游戏直接结束;
  5. 直到你排完雷,才算游戏取得胜利。

  既然我们熟悉了规则,那我们来看一下具体的代码及思路的实现吧。

二、扫雷游戏的代码及思路实现

一、扫雷游戏的思路

   我们先来大概想一下整体的思路。简单的可分为以下步骤:

  1. 菜单打印
  2. 创建扫雷区域
  3. 初始化扫雷区域
  4. 打印雷区
  5. 布置雷区
  6. 排雷

  有了上面的整体的扫雷实现思路,我们就来一一展开实现。当然在不同板块实现中还有很多的小细节,具体的细节我们再实现中一一引出来分析。

1、菜单打印 

  菜单的打印需要简单明了即可。且实现比较简单。注意要单独放在一个自定义函数中,让主函数中的代码尽量减少,方便观察。

void meau()
{
	printf("************************\n");
	printf("*****   1、play    *****\n");
	printf("*****   0、exit    *****\n");
	printf("************************\n");
}

  通过上面的菜单,我们可以很容易的看出选择 ‘ 1 ’ 开始游戏,选择 ‘ 0 ’ 退出游戏。

2、创建扫雷区

  创建雷区需要注意的是,我们后期可能要改变雷区的大小。为了方便后期更改雷区大小,所以我们这里选择define定义常量。

  我们在这里创建雷区时选择创建两个二位数组。一个数组放雷,另一个数组输出提示。这样会更加方便实现。假如我们这里只创建一个二维数组的话,在扫雷的同时还需要输出提示会很麻烦。

  当我们选择9x9的雷区时,我们定义的雷区需要在上下左右各加一行,以便后面我们排雷时不会越界访问数组。代码如下:

#define ROW 9
#define COL 9

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

char mine[ROWS][COLS] = { 0 };  //放雷数组
char show[ROWS][COLS] = { 0 };  //输出数组

3、初始化雷区

  我们先把两个数组初始化。在mine[ROWS][COLS]中,我们将整个数组初始化成 ’ 0 ’;将show[ROWS][COLS] 全部初始化成 ‘*’。把mine数组初始化成’ 0 ’,是因为我们要把雷设置成 ‘ 1 ’,以便我们后期统计雷的数量。把show数全部初始化成 ‘ * ’,是因为输出的时候可看性比较高。接下来我们看一下代码的实现:

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


init_board(mine, ROWS, COLS, '0');
init_board(show, ROWS, COLS, '*');

4、打印雷区

  打印雷区时,我们可以自己适当添加一些格式,以便后期玩家更加方便的玩游戏。这里我们添加了行和列标示,还有扫雷区的提示。代码的实现如下: 

void print_board(char board[ROWS][COLS], int row, int col)
{
	int j = 0;
	int i = 0;
	printf("-------G扫雷-------\n");
	printf("\n");
	for (j = 0; j <= col; j++)
	{
		printf("%d ", j);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
	printf("\n");
	printf("-------G扫雷-------\n");
}


print_board(mine, ROW, COL);
print_board(show, ROW, COL);

 

5、布置雷区

  布置雷区当然是要随机布置的。 提到随机,我们就因该联想到rand()函数srand()函数,在这里我就不详细介绍这两个函数的使用方法了,在之前的猜数字小游戏中有详细的解释,可以去了解一下。需要注意的是,我们要把布置的雷区放在9x9的范围内,且已经布置过的地方不能重新布置。我们看一下代码的实现:

void set_mine(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--;
		}
	}
}


set_mine(mine, ROW, COL);

6、排雷

  排雷的时候需要我们注意以下几种情况:

  1. 输入所要排雷的坐标需要合法,不合法时要给出相应的提示;
  2. 排查过的坐标不需要重复排查;
  3. 排查的坐标3x3的周围没有雷时要进行相应的展开;
  4. 踩中雷时,要给出相应的提示,并且同时打印书雷区数组。

  上面的雷区展开,我们进行展开时需要用到递归。我们结合着代码综合理解一下,代码如下:

int sum_mine(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');
}

void spread_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{

	int n = sum_mine(mine, x, y);
	if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
	{
		if (show[x][y] == '*')
		{
			if (n == 0)
			{
				show[x][y] = '0';
				spread_mine(mine, show, x - 1, y);
				spread_mine(mine, show, x - 1, y - 1);
				spread_mine(mine, show, x, y - 1);
				spread_mine(mine, show, x + 1, y - 1);
				spread_mine(mine, show, x + 1, y);
				spread_mine(mine, show, x + 1, y + 1);
				spread_mine(mine, show, x, y + 1);
				spread_mine(mine, show, x - 1, y + 1);
			}
			else
			{
				show[x][y] = n + '0';
			}
		}
	}

}

void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win<(row*col- EASY_COUNT))
	{
		printf("请输入你要排查的坐标:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (show[x][y] != '*')
			{
				printf("该坐标已经被排查过了哦。\n");
				continue;
			}
			if (mine[x][y] == '0')
			{
				spread_mine(mine, show, x, y);
				int n = sum_mine(mine, x, y);
				show[x][y] = n + '0';
				print_board(show, ROW, COL);
				win++;
			}
			else
			{
				printf("不好意思,你踩中雷了。雷区如下:\n");
				print_board(mine, ROW, COL);
				break;
			}
		}
		else
		{
			printf("你输入的坐标非法哦,请重新输入合法坐标。\n");
		}
	}
	if (win == (row * col - EASY_COUNT))
	{
		printf("恭喜你,排雷成功了ovo!\n");
	}
}


find_mine(mine,show, ROW, COL);

 三、扫雷游戏代码的整合

  由于代码量相对来说有一点多,所以我们就将函数的声明的定义分开,这样有利于提高代码的可读性,同时会保持一个良好的思路,且方便编写代码。

  我们将函数的声明放在单独的一个game.h的头文件,函数的实现放在一个单独的game.c源文件,函数的主方法及调用放在另一个单独的test.c源文件。

 game.h

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>


#define ROW 9
#define COL 9

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

#define EASY_COUNT 80 //雷的个数

//初始化扫雷界面
void init_board(char board[ROWS][COLS], int rows, int cols, char set);

//打印扫雷界面
void print_board(char board[ROWS][COLS], int row, int col);

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

//排雷
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

 game.c



#include "game.h"

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

void print_board(char board[ROWS][COLS], int row, int col)
{
	int j = 0;
	int i = 0;
	printf("-------G扫雷-------\n");
	printf("\n");
	for (j = 0; j <= col; j++)
	{
		printf("%d ", j);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
	printf("\n");
	printf("-------G扫雷-------\n");
}

void set_mine(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--;
		}
	}
}
int sum_mine(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');
}

void spread_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{

	int n = sum_mine(mine, x, y);
	if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
	{
		if (show[x][y] == '*')
		{
			if (n == 0)
			{
				show[x][y] = '0';
				spread_mine(mine, show, x - 1, y);
				spread_mine(mine, show, x - 1, y - 1);
				spread_mine(mine, show, x, y - 1);
				spread_mine(mine, show, x + 1, y - 1);
				spread_mine(mine, show, x + 1, y);
				spread_mine(mine, show, x + 1, y + 1);
				spread_mine(mine, show, x, y + 1);
				spread_mine(mine, show, x - 1, y + 1);
			}
			else
			{
				show[x][y] = n + '0';
			}
		}
	}

}

//void spread_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
//{
//	判断坐标是否越界
//	if (x == 0 || y == 0 || x == ROWS - 1 || y == COLS - 1)
//		return;
//	判断是否已经被排除
//	if (show[x][y] != '*')
//	{
//		return;
//	}
//	int count = sum_mine(mine, x, y);
//	if (count > 0)
//	{
//		show[x][y] = count + '0';
//		return;
//	}
//	递归拓展地图
//	else if (count == 0)
//	{
//		show[x][y] = '0';
//		spread_mine(mine, show, x - 1, y);
//		spread_mine(mine, show, x - 1, y - 1);
//		spread_mine(mine, show, x, y - 1);
//		spread_mine(mine, show, x + 1, y - 1);
//		spread_mine(mine, show, x + 1, y);
//		spread_mine(mine, show, x + 1, y + 1);
//		spread_mine(mine, show, x, y + 1);
//		spread_mine(mine, show, x - 1, y + 1);
//	}
//}
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	while (win<(row*col- EASY_COUNT))
	{
		printf("请输入你要排查的坐标:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (show[x][y] != '*')
			{
				printf("该坐标已经被排查过了哦。\n");
				continue;
			}
			if (mine[x][y] == '0')
			{
				spread_mine(mine, show, x, y);
				int n = sum_mine(mine, x, y);
				show[x][y] = n + '0';
				print_board(show, ROW, COL);
				win++;
			}
			else
			{
				printf("不好意思,你踩中雷了。雷区如下:\n");
				print_board(mine, ROW, COL);
				break;
			}
		}
		else
		{
			printf("你输入的坐标非法哦,请重新输入合法坐标。\n");
		}
	}
	if (win == (row * col - EASY_COUNT))
	{
		printf("恭喜你,排雷成功了ovo!\n");
	}
}

test.c 

#include "game.h"
void game()
{
	srand((unsigned int)time(NULL));
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };
	//初始化扫雷界面
	init_board(mine, ROWS, COLS, '0');
	init_board(show, ROWS, COLS, '*');
	//打印扫雷界面
	//print_board(mine, ROW, COL);
	print_board(show, ROW, COL);
	//布置雷区
	set_mine(mine, ROW, COL);
	print_board(mine, ROW, COL);
	//排雷
	find_mine(mine,show, ROW, COL);
}
void meau()
{
	printf("************************\n");
	printf("*****   1、play    *****\n");
	printf("*****   0、exit    *****\n");
	printf("************************\n");
}
void test()
{
	int input = 0;
	do
	{
		meau();
		printf("请选择是否要开始游戏:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏。\n");
			break;
		default:
			printf("选择错误,请重新选择哦\n");
			break;
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}

  这里相对较难理解的是排雷时的展开,也是需要重点理解的地方。

  希望这篇文章能给你带来一个很好的理解,对你有所帮助,感谢阅读。

  后续会一直更新的哦ovo!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

你适合考PMP还是软考?两者的区别是否清楚,分别能给你带来什么价值

PMP与软考之间有什么区别&#xff0c;应该考哪个更适合自己&#xff1f; 下面从9个方面给大家简单的介绍做一个对比&#xff0c;希望能帮上忙~ 软考和PMP哪个更适合自己&#xff1f; 01 考试介绍 PMP&#xff1a;PMP是项目管理专业人士资格认证&#xff0c;由美国项目管理协…

腾讯云相同配置8核16G的云服务器和轻量服务器该如何选择?

很多个人或者中小企业用户在选择云服务器的时候&#xff0c;已经确认配置的情况下&#xff0c;去选购的时候发现有出现了轻量应用服务器&#xff0c;那么轻量应用服务器和云服务器又有哪些区别&#xff0c;价格为啥又有那么大的差别&#xff0c;该如何选择呢&#xff1f; 从上边…

SSM框架整合详细教程

目录 1. 什么是SSM&#xff1f; 2. SSM整合的时候容器之间如何访问 3. SSM下面的开发步骤 4. SSM整合时候时容易混乱的知识点 1. 什么是SSM&#xff1f; SSM是对三个框架名字的简写&#xff0c;其中第一个S指的是SpringMVC,第二个S指的是Spring&#xff0c;第三个M指的是M…

项目搭建(七)爱心代码❤网站部署(静态网站)

爱心代码❤网站部署&#xff08;静态网站&#xff09;一、环境基础二、修改Tomcat启动配置三、放置静态网站四、启动Tomcat一、环境基础 如果你已经部署了Apache-Tomcat&#xff0c;恭喜你&#xff0c;你已经完成90%的部署工作 如果没有tomcat&#xff0c;那你先部署tomcat吧 …

4_单机优化(确定性算法,优化框架)

优化框架机器学习的优化框架正则化经验风险最小化优化算法的收敛速率假设条件凸函数定义强凸函数定义光滑函数定义优化算法的分类机器学习的优化框架 正则化经验风险最小化 有监督的机器学习问题&#xff1a; 假设输入输出数据 Sn{(xi,yi);i1,...,n}S_n \left\{(x_i, y_i);…

C++与C语言中的字符串

目录 1、关于c语言中的字符串 &#xff08;1&#xff09;c语言中字符串与字符指针 &#xff08;2&#xff09;字符串结尾 2、关于c中的字符串string &#xff08;1&#xff09;从本质上了解string &#xff08;2&#xff09;c中的字符串转换与关联 &#xff08;3&#x…

【MySQL入门指北】MySQL备份及恢复

MySQL备份及恢复 文章目录MySQL备份及恢复1.Percona 介绍2.安装Percona 需要的 MySQL 包3.安装percona-xtrabackup4.完全备份流程5.完全恢复流程6.增量备份流程7.差异备份8.差异恢复流程9.记录的导入和导出10.mysqldumpbinlog11.MySQL恢复数据12.二进制日志恢复13.误删除库的问…

基于51单片机的室内温度可燃气体检测报警系统Proteus仿真

资料编号&#xff1a;133 下面是相关功能视频演示&#xff1a; 133-基于51单片机的室内温度可燃气体检测报警系统Proteus仿真&#xff08;源码仿真全套资料&#xff09;功能介绍&#xff1a; 采用51单片机作为主控&#xff0c;LCD1602显示当前温度和可燃气体浓度&#xff0c;…

Netty源码阅读(1)之——客户端源码梗概

目录 准备 开始 NioSocketChannel 的初始化过程 指定 初始化 关于unsafe属性&#xff1a; 关于pipeline的初始化 小结 EventLoopGroup初始化 小结 channel的注册过程 handler的注册过程 客户端连接 总结 准备 源码阅读基于4.1.84.Final版本。从github下载netty项目…

WordPress设置浏览器切换标签网站动态标题

我们在逛别人网站的时候&#xff0c;经常看到&#xff0c;有些网站当我们离开该页面浏览其他页面的时候&#xff0c;离开的页面标题上会显示比如&#xff1a;“你别走吖 Σ(っ Д ;)っ”这样的字样&#xff0c;当我们点回来的时候页面上面的标题又变成了“你又回来啦&#xff0…

[附源码]计算机毕业设计JAVAjsp学生档案管理系统

[附源码]计算机毕业设计JAVAjsp学生档案管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM myb…

前端基础向--从项目入手封装公共组件

本文就从 “详情卡片” 业务组件的封装的几个阶段来说明我在编写公共组件的设计思路。 1. 阶段一&#xff1a;基础需求 假设我们现在有这样一个需求&#xff1a;需要满足显示产品的详细信息&#xff1b;需要可以根据不同分辨率适配不同的显示方式&#xff08;2列&#xff0c;…

【Linux】进程通信 | 管道

今天让我们来认识如何使用管道来进行进程间通信 文章目录1.何为管道&#xff1f;1.1 管道是进程间通信的一种方式1.2 进程通信1.3 管道分类2.匿名管道2.0 康康源码2.1 创建2.2 父子通信完整代码2.3 等待写入等待读取等待源码中的体现2.4 控制多个子进程2.5 命令行 |3.命名管道3…

linux无界面手敲命令笔记

0 Ubuntu相关命令简介 1. 文件及目录操作命令 pwd&#xff1a;显示用户当前所处的目录 ls&#xff1a;列出目录下的文件清单 cd&#xff1a;改变当前目录cd … 返回上一级目cd / 进入根目录不加参数或参数为“~”&#xff0c;默认切换到用户主目录 mkdir&#xff1a;建立目录 …

Ant Design表单之labelCol 和wrapperCol的实际开发笔记

目录 前言 一、labelCol和wrapperCol是什么 二、布局的栅格化 1.布局的栅格化系统的工作原理 三、栅格常用的属性 1.左右偏移 2.区块间隔 3.栅格排序 四、labelCol和wrapperCol的实际使用 总结 前言 主要是记录一下栅格布局的一些属性和labelCol、wrapperCol等。 一…

[附源码]java毕业设计毕业设计管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

国产AI绘画软件“数画”刷爆朋友圈,网友到底在画什么

人们常说&#xff0c;眼见为实&#xff0c;只有自己亲眼见到的才会相信。但是我们都知道眼睛会产生错觉&#xff0c;而且人们在生活中被错觉误导的情况屡见不鲜。例如图中&#xff0c;你以为她们肯定是真人的照片。世界上有些事情&#xff0c;即使是自己亲眼所见到的也未必一定…

c/c++内存管理

前言&#xff1a; 开篇前就聊聊篮球&#xff0c;在众多球星中&#xff0c;我觉得杜兰特&#xff08;KD&#xff09;非常专注于篮球&#xff0c;他一直坚持他所热爱的事业。尽管有很多缺点&#xff0c;但是他对于篮球的态度是坚定不移&#xff0c;这是我非常钦佩的。当然库里&am…

大数据环境搭建 —— VMware Workstation 安装详细教程

大数据系列文章&#xff1a;&#x1f449; 目录 &#x1f448; 文章目录一、下载安装包1. 下载 VMware Workstation2. 小技巧二、安装软件1. 软件安装2. 虚拟环境搭建一、下载安装包 1. 下载 VMware Workstation ① 打开 VMware Workstation 官方下载网站 VMware Workstati…

【Linux】管理文件和目录的命令大全

目录 Linux 管理文件和目录的命令 1.命令表 2.细分 1.pwd命令 2.cd 命令 3.ls 命令 4.cat 命令 5.grep 命令 6.touch 命令 7.cp 命令 8.mv 命令 9.rm 命令 10.mkdir 命令 11.rmdir 命令 赠语&#xff1a;Even in darkness, it is possible to create light.即使在…