C语言项目:数组与函数实践:扫雷游戏

news2024/11/15 19:30:17

目录

目录:

1.扫雷游戏分析与设计

    1.1扫雷游戏的功能说明:

     1.1.1使用控制台实现经典扫雷的游戏

     1.1.2游戏可以通过菜单实现继续玩或者退出游戏

     1.1.3扫雷棋盘是9*9的格子

     1.1.4默认随机布置10个雷

    1.1.5 可以排查雷

2.扫雷游戏的代码实现

 1.遇到的问题

2.如何去实现 

3.扫雷游戏的扩展

4.最终代码


1.扫雷游戏分析与设计

    1.1扫雷游戏的功能说明:

     1.1.1使用控制台实现经典扫雷的游戏
     1.1.2游戏可以通过菜单实现继续玩或者退出游戏
     1.1.3扫雷棋盘是9*9的格子
     1.1.4默认随机布置10个雷
    1.1.5 可以排查雷

           1.如果位置不是雷,就显示周围有几个雷

            2.如果位置是雷,就炸死结束游戏

            3.把除10个雷之外的所有非雷都找出来,排雷成功,游戏结束

2.扫雷游戏的代码实现

 1.遇到的问题

test.c //游戏的测试逻辑

game.c game.h //游戏逻辑的实现

扫雷过程中,布置的雷和排查出的雷的信息都需要存储,所以我们需要一定的数据结构来存储这些信息,因为我们需要在9*9的棋盘上布置雷的信息和排查雷,我们首先想到的就是创建一个9*9的数组来存放信息,

如果这个位置布置雷,我们就存放1,没有布置雷就存放0.

假如我们排查(2,5)这个坐标时,我们访问周围的一圈8个黄色位置,统计周围雷的个数是1 

遇到的问题:

第一,统计的个数是1放在哪呢?如果放在(2,5)这个位置,会产生歧义,1到底是排查出的雷,还是(2,5)自己是雷

为了解决这件事,我们我们专⻔给⼀个棋盘(对应⼀个数组mine)存放布置好的雷的信息,再 给另外⼀个棋盘(对应另外⼀个数组show)存放排查出的雷的信息。

这样就互不⼲扰了,把雷布置到 mine数组,在mine数组中排查雷,排查出的数据存放在show数组,并且打印show数组的信息给后期排查参考。 同时为了保持神秘,show数组开始时初始化为字符 '*',为了保持两个数组的类型⼀致,可以使⽤同⼀ 套函数处理,mine数组最开始也初始化为字符'0',布置雷改成'1'。

第二:假如我们排查(8,6)这个坐标,我们访问周围一圈八个位置,统计周围雷的个数时,最下面的三个坐标就会越界,为了防止越界,给数组扩大一圈,雷还是布置在9*9的坐标上,周围一圈不去布置雷就OK了,这样就解决了越界的问题。所以我们将存放数据的数组创建成11*11是比较合适。

2.如何去实现 

  •  创建文件进行分布操作 
  1. test.c: //文件中写游戏的测试逻辑
  2. game.c//文件中写游戏中函数的实现
  3. game.h//文件中写游戏需要的数据类型和函数声明

//mine数组中存放布置好的雷的信息 

//show数组中存放的是排查出的雷的信息

 

 其中为了方便后续的引用,我在game.h文件中重定义了行(ROW,ROWS)、列(COL,COLS)、和要排的雷的个数(EASY_COUNT):

  •  页面设计
void menu()
{
	printf("***************************\n");
	printf("******* 1.play  ***********\n");
	printf("******* 0.exit  ***********\n");
	printf("***************************\n");
}

void test()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);//1 0 x
		switch (input)
		{
		case 1:
			game();
			/*printf("扫雷\n");*/
			break;
		case 0:
			printf("游戏结束,退出游戏\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
}

 在test.c中写入,要用到循环,这些还是比较简单的。

  • 函数的实现

1.初始化棋盘 initboard(用于存储雷的信息‘0’与‘1’,‘0’表示无雷,‘1’表示有雷,用‘*’掩盖雷的信息)

game.c中实现下列函数

void InitBoard(char arr[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++)
		{
			arr[i][j] = set;
		}
	}
}

 test.c中写入下列函数

 2.打印棋盘给用户看

game.c写入

void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{
	int i = 0;
	//打印列好
	printf("------扫雷游戏-----\n");
	for (i = 0; i <= col; i++)
	{
		printf("%2d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		printf("%2d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%2c ", arr[i][j]);
		}
		printf("\n");
	}
}

 test.c写入(前面谈到了,我们是要用两个棋盘,打印只需要一个给用户,另外一个是调试用的,验证是否我们的代码是否正确)

3.布置雷的函数(用随机数生成,将是‘0’的数组中的元素布置为‘1’,用count计数,count=EASY_COUNT 也就是10,每布置完一个雷就让count减一)

game.c写入

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

test.c 写入

4.排查雷的函数(设置变量x,y,用于表示要输入的坐标,win表示排雷的过程,如果xin=row*col-EASY_COUNT,说明除了雷的位置都已经排除,剩下的都是雷,也就是排雷成功,如果输入的坐标刚好是‘1’的位置,那么就说明排雷失败,打印输出“你被炸死了”,如果排雷的坐标不存在,就显示输入错误,并重新输入)

game.c写入

第一个函数主要为Findmind函数作用,所以不需要写入到game.h,我们可以加入static进行限制。

static int Get_mine_count(char mine[ROWS][COLS], int x, int y)
{
	int i = 0;
	int count = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
		int j = 0;
		for (j = y - 1; j <= y + 1; j++)
		{
			count += (mine[i][y] - '0');
		}
	}
	return count;
}
void FindMind(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] == '*')
			{
				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';
					DisplayBoard(show, ROW, COL);
					win++;
				}
			}
			else
			{
				printf("该坐标已经被排查了,重新输入坐标\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功\n");
		DisplayBoard(mine, ROW, COL);
	}
}

test.c写入 

 

  • 主函数声明函数 
  • game.h声明函数

3.扫雷游戏的扩展

可以自己去尝试实现如下扩展的内容。

4.最终代码

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

#define EASY_COUNT 10

//声明函数

//棋盘初始化的函数
void InitBoard(char arr[ROWS][COLS], int rows, int cols,char set);

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

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

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

game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"

void InitBoard(char arr[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++)
		{
			arr[i][j] = set;
		}
	}
}

void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{
	int i = 0;
	//打印列好
	printf("------扫雷游戏-----\n");
	for (i = 0; i <= col; i++)
	{
		printf("%2d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		printf("%2d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%2c ", arr[i][j]);
		}
		printf("\n");
	}
}

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

//static int Get_mine_count(char mine[ROWS][COLS],int x,int y)
//{
//	return mine[x - 1][y] +
//		   mine[x - 1][y - 1] +
//		   mine[x][y - 1] +
//		   mine[x + 1][y - 1] +
//		   mine[x + 1][y] +
//		   mine[x + 1][y + 1] +
//		   mine[x][y + 1] + 
//		   mine[x - 1][y + 1]-8*'0';
//}

static int Get_mine_count(char mine[ROWS][COLS], int x, int y)
{
	int i = 0;
	int count = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
		int j = 0;
		for (j = y - 1; j <= y + 1; j++)
		{
			count += (mine[i][y] - '0');
		}
	}
	return count;
}

void FindMind(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] == '*')
			{
				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';
					DisplayBoard(show, ROW, COL);
					win++;
				}
			}
			else
			{
				printf("该坐标已经被排查了,重新输入坐标\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功\n");
		DisplayBoard(mine, ROW, COL);
	}
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"
void menu()
{
	printf("***************************\n");
	printf("******* 1.play  ***********\n");
	printf("******* 0.exit  ***********\n");
	printf("***************************\n");
}

void game()
{
	//完成扫雷游戏
	//mine数组中存放布置好的雷的信息
	char mine[ROWS][COLS] = { 0 };//数组全部初始化为‘0’,写‘0’不能全部初始化,只能初始化一部分

	//show数组中存放的是排查出的雷的信息
	char show[ROWS][COLS] = { 0 };//数组全部初始化为‘*’
	//初始化棋盘
	InitBoard(mine,ROWS,COLS,'0');//二维数组传参
	InitBoard(show, ROWS, COLS, '*');
	
	//布置雷
	//就是在9*9的棋盘上随机布置10个雷
	SetMine(mine,ROW,COL);
	/*DisplayBoard(mine, ROW, COL);*/

	//打印棋盘(考虑用户体验)
	/*DisplayBoard(mine, ROW, COL);*/
	DisplayBoard(show, ROW, COL);

	//排查雷
	FindMind(mine, show, ROW, COL);
}

void test()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);//1 0 x
		switch (input)
		{
		case 1:
			game();
			/*printf("扫雷\n");*/
			break;
		case 0:
			printf("游戏结束,退出游戏\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}

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

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

相关文章

Latex插入pdf图片,去除空白部分

目录 参考链接&#xff1a; 流程&#xff1a; 参考链接&#xff1a; ​科研锦囊之Latex-如何插入图片、表格、参考文献 http://t.csdnimg.cn/vpSJ3 流程&#xff1a; Latex的图片插入支持PDF文件&#xff0c;这里笔者建议都使用PDF文件进行图片的插入&#xff0c;因为PDF作…

SinoDB数据库运行分析

SinoDB数据库运行主要从数据库互斥资源等待、数据库写类型、备份文件有效性、Chunk状态等15个方向进行分析&#xff0c;具体说明如下&#xff1a; 一、数据库互斥资源等待 检查项目 数据库互斥资源等待 检查命令 onstat -g con |head -20 说明 onstat -g con 查看目前数据处…

【C++练级之路】【Lv.14】二叉搜索树(进化的二叉树——BST)

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《C语言》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、二叉搜索树介绍二、二叉搜索树的模拟实现2.1 结点2.2 成员变量2.3 默认成员函数2.3.1 constructor2.3.2…

汽车功能安全整体方法

摘 要 ISO26262道路车辆功能安全标准已经制定实践了多年&#xff0c;主要目标是应对车辆的电子和电气&#xff08;E/E&#xff09;系统失效。该方法践行至今&#xff0c;有些系统功能安全方法已经成熟&#xff0c;例如电池管理系统&#xff08;BMS&#xff09;&#xff0c;并且…

MindGraph:文字生成知识图

欢迎来到MindGraph&#xff0c;这是一个概念验证、开源的、以API为先的基于图形的项目&#xff0c;旨在通过自然语言的交互&#xff08;输入和输出&#xff09;来构建和定制CRM解决方案。该原型旨在便于集成和扩展。以下是关于X的公告&#xff0c;提供更多背景信息。开始之前&a…

每日OJ题_牛客HJ75 公共子串计算(IO型OJ)

目录 牛客HJ75 公共子串计算 解析代码 牛客HJ75 公共子串计算 公共子串计算_牛客题霸_牛客网 解析代码 #include <iostream> using namespace std; int main() {string str1 "", str2 "";cin >> str1 >> str2;int n1 str1.size()…

【Selenium(一)】

简介 Selenium是一个开源的自动化测试工具&#xff0c;主要用于Web应用程序的自动化测试。它支持多种浏览器&#xff0c;包括Chrome、Firefox、Internet Explorer等&#xff0c;以及多种编程语言&#xff0c;如Java、Python、C#、Ruby等&#xff0c;使得它成为Web自动化测试中…

一个用稳压二极与MOS管构成的过压保护电路

一个用稳压二极与MOS管构成的过压保护电路 如图&#xff0c;利用稳压管和PMOS管组成一个保护电路&#xff0c;起过压保护和防反接的的作用。 分析&#xff1a; 1.当输入端是5V左右的电压的时候&#xff08;VDD-IN5V&#xff09;&#xff0c;稳压二极管D1没有被反向击穿&#…

【异常处理】SpringMVC无法跳转视图问题

浏览器发送请求给控制器&#xff0c;但是结果是404报错&#xff0c;又试了一下返回json字符串&#xff0c;json可以获取到&#xff0c;所以应该springmvc出了问题。 查看controller&#xff0c;发现无法加载视图

RealBasicVSR使用记录

对各种场景图片、视频超分结果都很不错的模型。 paper&#xff1a;https://arxiv.org/pdf/2111.12704.pdf code&#xff1a;https://github.com/ckkelvinchan/RealBasicVSR 一、使用步骤 1. git clone https://github.com/ckkelvinchan/RealBasicVSR.git 2. 我的环境已安装…

问界汽车提车全流程及注意点【伸手党福利】

问界汽车提车全流程及注意点 目录 说明为没买车和没提车的小伙伴提供参考全程必须车主办理&#xff08;人必须在场&#xff09;&#xff0c;如果不是车主授权书很难办。时间&#xff1a;提车用时4小时&#xff0c;2个人 提车提前联系-交付专员做好需求调研当天-到店验车-千万不…

并发编程Semaphore(信号量)浅析

目录 一、简介二、API三、使用3.1 demo13.1 demo2 四、适用场景 一、简介 Semaphore&#xff08;信号量&#xff09;是 Java 中用于控制同时访问特定资源的线程数量的工具类。Semaphore 维护了一组许可证&#xff0c;线程在访问资源之前必须先获取许可证&#xff0c;访问完毕后…

前端 -- 基础 表单标签 -- 表单域

表单域 # 表单域是一个包含 表单元素 的区域 在 HTML 标签中&#xff0c; <form> 标签 用于定义表单域&#xff0c; 以实现用户信息的收集和传递 简单通俗讲&#xff0c; 就是 <form> 会把它范围内的表单元素信息提交给后台&#xff08;服务器) 对于上面讲…

1058:求一元二次方程

【题目描述】 利用公式 求一元二次方程axbxc0的根&#xff0c;其中a不等于0。结果要求精确到小数点后5位。 【输入】 输入一行&#xff0c;包含三个浮点数a,b,c&#xff08;它们之间以一个空格分开&#xff09;&#xff0c;分别表示方程axbxc0的系数。 【输出】 输出一行&…

蓝桥杯 2023 省B 接龙数列

思路分析&#xff1a; 创建一个大小为10的向量 hash&#xff0c;用于记录以每个数字结尾的字符串数量。输入字符串数量 n。循环读取每个字符串&#xff0c;并更新 hash 中以当前字符串结尾的字符串数量。同时更新最大字符串数量 count。输出不可达的字符串数量&#xff0c;即 …

掘根宝典之C++正向迭代器和反向迭代器详解

简介 迭代器是一种用于遍历容器元素的对象。它提供了一种统一的访问方式&#xff0c;使程序员可以对容器中的元素进行逐个访问和操作&#xff0c;而不需要了解容器的内部实现细节。 C标准库里每个容器都定义了迭代器&#xff0c;这迭代器的名字就叫容器迭代器 迭代器的作用类…

鸿蒙-自定义组件-语法

目录 语法组成 在学习自定义组件前&#xff0c;先看一下ArkTS的组成 装饰器 用于装饰类、结构、方法以及变量&#xff0c;并赋予其特殊的含义。如上述示例中Entry、Component和State都是装饰器 Entry 表示该自定义组件为入口组件 Component 表示自定义组件 State 表示组…

Html+threejs数字孪生三维场景实现

程序示例精选 Htmlthreejs数字孪生三维场景实现 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《Htmlthreejs数字孪生三维场景实现》编写代码&#xff0c;代码整洁&#xff0c;规则&#xf…

【机器学习】基于机器学习的分类算法对比实验

摘要 基于机器学习的分类算法对比实验 本论文旨在对常见的分类算法进行综合比较和评估&#xff0c;并探索它们在机器学习分类领域的应用。实验结果显示&#xff0c;随机森林模型在CIFAR-10数据集上的精确度为0.4654&#xff0c;CatBoost模型为0.4916&#xff0c;XGBoost模型为…

高端竞赛活动中的软硬件供应商要如何选择

知识竞赛活动属于“直播”类活动&#xff0c;一旦开始无法重来&#xff0c;所以软硬件稳定可靠至关重要&#xff0c;要历经多次活动的磨炼&#xff0c;性能稳定可靠&#xff0c;要有多重防灾难设计和备用方案。所以一定要选择历经磨炼的高端竞赛软件和执行团队。 可以从以下几个…