【C语言步行梯】C语言实现扫雷游戏(含详细分析)

在这里插入图片描述

🎯每日努力一点点,技术进步看得见
🏠专栏介绍:【C语言步行梯】专栏用于介绍C语言相关内容,每篇文章将通过图片+代码片段+网络相关题目的方式编写,欢迎订阅~~

文章目录

  • 需求分析
  • 具体实现
    • 主函数体
    • 菜单实现
    • 游戏实现
      • 计算雷数量
      • 盘面设计
        • 初始化盘面
        • 显示盘面
      • 布置雷
      • 排雷函数
      • 游戏函数主体
    • 完整代码
    • 分文件编写


需求分析

以前Windows都会自带一款有趣的游戏,叫做扫雷。今天我们就一起使用C语言来实现一下这个经典的游戏。
在这里插入图片描述
下图演示的是一个9×9的盘面,其中含有10个雷。我们可以看到部分方格中含有数字,以图中红色数字2为例,它所在的9宫格已被涂成黄色。在它所在9宫格范围内有2个雷,故该位置有雷。
在这里插入图片描述
在开始的时候棋盘上已经埋藏好了雷,但玩家不知道雷的具体位置。在玩家点击不是雷的位置后,该位置将显示9宫格范围内的雷的数量。在玩家找出所有不是雷的位置后,玩家获胜。如果不慎点击到雷所在位置,则游戏结束。

举个例子吧!如下图,没有数字的位置是我们还未点击,且不知道是否有雷的区域。有数字的方格是已经点击,并且没有雷的位置。由于有数字的已经点击了,且保证其中没有雷。而1所在9宫格内必定有1个雷,故绿色箭头所指区域一定是雷。我们不能点击这个区域,否则游戏结束。

在这里插入图片描述

具体实现

主函数体

在主函数体内,我们需要调用一个menu函数,用它提醒用户:输入1开始游戏,输入0退出游戏。接收用户输入后,通过switch语句,执行game()函数或者退出游戏。menu和game函数将在下文中讲解。

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");
		}
	}while(input);
	return 0;
}

菜单实现

首先,我们需要一个菜单,提示用户:输入1可以开始游戏,输入0会退出游戏。我通过封装一个menu函数实现↓↓↓

void menu()
{
	printf("**************************************************************\n");
	printf("******************* 1.play        0.exit *********************\n");
	printf("**************************************************************\n");
}

游戏实现

计算雷数量

由上面的需求可以知道,玩家在输入某个坐标后,如果该位置没有雷,则需要在该坐标位置显示其所在9宫格内雷的数量。

如下图所示,若用户输入(3,3)坐标时,我们需要统计该坐标所在9宫格内雷的数量。即将数组中的(mine[1][1]+mine[1][2]+mine[1][3]+mine[2][1]+mine[2][3]+mine[3][1]+mine[3][2]+mine[3][3])-'0'*8的数值计算出来即可。

★ps:这里的mine数组存储的字符,所以在8个坐标相加后,需要减’0’*8。如果用户输入的坐标是雷,则游戏结束,不需要统计雷的数量,所以这里不需要统计用户输入的坐标内是否有雷。
在这里插入图片描述
但如果玩家输入的坐标是(1,1)时,此时数组将会越界。为了保证数组不越界,我们将原本为9×9的盘面,使用11×11的数组来存储。(下图中,红色字符0,表示的是多开辟的空间)。
在这里插入图片描述
经过上面的分析后,我们可以写出如下计算雷的函数↓↓↓

int getMindCount(char board[ROWS][COLS], int x, int y)
{
	return (board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + board[x][y - 1] + board[x][y + 1] + board[x + 1][y - 1] + board[x + 1][y] + board[x + 1][y + 1]) - '0' * 8;
}

盘面设计

我们需要一个mine数组记录我们买下的雷的位置(如下图左侧所示)。为了不让用户看到雷的位置,我们需要另个数组,用于显示用户已经点击的位置,并将其展示给用户。
在这里插入图片描述
关于show数组,这里需要额外说明一下。假如用户输入坐标(1,1),此时需要判断mine[1][1]处是否有雷,如果有雷,则游戏结束;如果没有雷,且用户还有将所有没有雷的区域点击完,则游戏继续。在该区域没有雷的情况下,需要调用getMineCount(mine,1,1),计算该位置的雷数量,并将show[1][1]改为雷的数量。

初始化盘面

show数组显示给用户看前,均初始化为’*‘(星号)。而mine数组用于存储雷,在布置雷之前,应全部初始化为’0’(字符0表示没有雷,字符1表示有雷)。因此,我们需要实现一个初始化盘面的函数↓↓↓

//初始化盘面
void initBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			board[i][j] = set;
		}
	}
}
显示盘面

在玩家输入坐标前,我们需要展示当前盘面状态(哪些已经点击过了,哪些还没有点击过),以方便用户输入坐标。下面我们实现一个展示盘面的函数↓↓↓

void displayBoard(char board[ROWS][COLS], int rows, int cols)
{
	for (int i = 1; i < rows - 1; i++)
	{
		if (i == 1)
		{
			for (int j = 0; j < cols - 1; j++)
			{
				if (j == 1)
					printf(" ");
				printf("%2d", j);
			}
			printf("\n");
		}
		printf("%2d ", i);
		for (int j = 1; j < cols - 1; j++)
		{
			printf( " %c", board[i][j]);
		}
		printf("\n");
	}
}

其展示效果如下:
在这里插入图片描述

布置雷

在游戏前,我们需要给mine数组设置雷。需要使用到随机数函数rand()。其实现代码如下↓↓↓

void setMine(char board[ROWS][COLS], int rows, int cols)
{
	int mine = MINE;
	while (mine)
	{
		int x = rand() % rows + 1;
		int y = rand() % cols + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			mine--;
		}
	}
}

排雷函数

我们需要一个函数,用于与玩家进行交互,接受玩家输入的坐标,检查该坐标是否有雷。如果该坐标没有雷,则检查所有非雷坐标是否均被点击,如果均被点击,则玩家获胜;如果未全部点击,则游戏继续。如果该坐标有雷,则玩家游戏失败。
在这里插入图片描述

void findMine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols)
{
	int min = (rows - 2) * (cols - 2) - MINE;
	int x = 0;
	int y = 0;
	do
	{
		displayBoard(show, ROWS, COLS);
		printf("请输入排雷坐标>");
		scanf("%d %d", &x, &y);
		if (x >= 0 && x <= rows && y >= 0 && y <= cols)
		{
			if (mine[x][y] == '1')
			{
				printf("挑战失败,您被炸死了!\n");
				break;
			}
			else
			{
				int count = getMindCount(mine, x, y);
				show[x][y] = '0' + count;
				min--;
			}
		}
		else
		{
			printf("输入的坐标有误,请重新输入\n");
		}
	} while (min);
	if (min == 0)
		printf("恭喜你!排雷成功!\n");
}

游戏函数主体

在实现了上述各个函数后,我们只要稍加组织,就可以实现游戏了。

void game()
{
	char mine[ROWS][COLS];//存储雷
	char show[ROWS][COLS];//显示给用户看的

	//初始化盘面
	initBoard(mine, ROWS, COLS, '0');
	initBoard(show, ROWS, COLS, '*');

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

	//开始排除雷
	findMine(mine, show, ROWS, COLS);
}

完整代码

上面代码中主函数中没有加入随机数种子,在下面代码中加入了srand((unsigned int)time(NULL)),同时对于上面出现ROW、COL的宏定义等也在下方代码整体给出。

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

#define ROW 9
#define COL 9
#define MINE 10

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

void menu()
{
	printf("**************************************************************\n");
	printf("******************* 1.play        0.exit *********************\n");
	printf("**************************************************************\n");
}

//初始化盘面
void initBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			board[i][j] = set;
		}
	}
}

//显示盘面
void displayBoard(char board[ROWS][COLS], int rows, int cols)
{
	for (int i = 1; i < rows - 1; i++)
	{
		if (i == 1)
		{
			for (int j = 0; j < cols - 1; j++)
			{
				if (j == 1)
					printf(" ");
				printf("%2d", j);
			}
			printf("\n");
		}
		printf("%2d ", i);
		for (int j = 1; j < cols - 1; j++)
		{
			printf( " %c", board[i][j]);
		}
		printf("\n");
	}
}

//埋雷
void setMine(char board[ROWS][COLS], int rows, int cols)
{
	int mine = MINE;
	while (mine)
	{
		int x = rand() % rows + 1;
		int y = rand() % cols + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			mine--;
		}
	}
}

//计算雷的数量
int getMindCount(char board[ROWS][COLS], int x, int y)
{
	return (board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + board[x][y - 1] + board[x][y + 1] + board[x + 1][y - 1] + board[x + 1][y] + board[x + 1][y + 1]) - '0' * 8;
}

//找雷
void findMine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols)
{
	int min = (rows - 2) * (cols - 2) - MINE;
	int x = 0;
	int y = 0;
	do
	{
		displayBoard(show, ROWS, COLS);
		printf("请输入排雷坐标>");
		scanf("%d %d", &x, &y);
		if (x >= 0 && x <= rows && y >= 0 && y <= cols)
		{
			if (mine[x][y] == '1')
			{
				printf("挑战失败,您被炸死了!\n");
				break;
			}
			else
			{
				int count = getMindCount(mine, x, y);
				show[x][y] = '0' + count;
				min--;
			}
		}
		else
		{
			printf("输入的坐标有误,请重新输入\n");
		}
	} while (min);
	if (min == 0)
		printf("恭喜你!排雷成功!\n");
}

//游戏
void game()
{
	char mine[ROWS][COLS];//存储雷
	char show[ROWS][COLS];//显示给用户看的

	//初始化盘面
	initBoard(mine, ROWS, COLS, '0');
	initBoard(show, ROWS, COLS, '*');

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

	//开始排除雷
	findMine(mine, show, ROWS, COLS);
}

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");
		}
	} while (input);
	return 0;
}

分文件编写

可以创建game.h保存头文件,及各函数的函数声明;game.c保存各个函数的具体实现;main.c中保存主函数。

game.h ↓↓↓

#pragma once

#define _CRT_SECURE_NO_WARNINGS 1

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

#define ROW 9
#define COL 9
#define MINE 10

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

//菜单
void menu();

//初始化盘面
void initBoard(char board[ROWS][COLS], int rows, int cols, char set);

//显示盘面
void displayBoard(char board[ROWS][COLS], int rows, int cols);

//埋雷
void setMine(char board[ROWS][COLS], int rows, int cols);

//计算雷的数量
int getMindCount(char board[ROWS][COLS], int x, int y);

//找雷
void findMine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols);

//游戏
void game();

game.c ↓↓↓

#include "game.h"

void menu()
{
	printf("**************************************************************\n");
	printf("******************* 1.play        0.exit *********************\n");
	printf("**************************************************************\n");
}

//初始化盘面
void initBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			board[i][j] = set;
		}
	}
}

//显示盘面
void displayBoard(char board[ROWS][COLS], int rows, int cols)
{
	for (int i = 1; i < rows - 1; i++)
	{
		if (i == 1)
		{
			for (int j = 0; j < cols - 1; j++)
			{
				if (j == 1)
					printf(" ");
				printf("%2d", j);
			}
			printf("\n");
		}
		printf("%2d ", i);
		for (int j = 1; j < cols - 1; j++)
		{
			printf( " %c", board[i][j]);
		}
		printf("\n");
	}
}

//埋雷
void setMine(char board[ROWS][COLS], int rows, int cols)
{
	int mine = MINE;
	while (mine)
	{
		int x = rand() % rows + 1;
		int y = rand() % cols + 1;
		if (board[x][y] == '0')
		{
			board[x][y] = '1';
			mine--;
		}
	}
}

//计算雷的数量
int getMindCount(char board[ROWS][COLS], int x, int y)
{
	return (board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + board[x][y - 1] + board[x][y + 1] + board[x + 1][y - 1] + board[x + 1][y] + board[x + 1][y + 1]) - '0' * 8;
}

//找雷
void findMine(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols)
{
	int min = (rows - 2) * (cols - 2) - MINE;
	int x = 0;
	int y = 0;
	do
	{
		displayBoard(show, ROWS, COLS);
		printf("请输入排雷坐标>");
		scanf("%d %d", &x, &y);
		if (x >= 0 && x <= rows && y >= 0 && y <= cols)
		{
			if (mine[x][y] == '1')
			{
				printf("挑战失败,您被炸死了!\n");
				break;
			}
			else
			{
				int count = getMindCount(mine, x, y);
				show[x][y] = '0' + count;
				min--;
			}
		}
		else
		{
			printf("输入的坐标有误,请重新输入\n");
		}
	} while (min);
	if (min == 0)
		printf("恭喜你!排雷成功!\n");
}

//游戏
void game()
{
	char mine[ROWS][COLS];//存储雷
	char show[ROWS][COLS];//显示给用户看的

	//初始化盘面
	initBoard(mine, ROWS, COLS, '0');
	initBoard(show, ROWS, COLS, '*');

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

	//开始排除雷
	findMine(mine, show, ROWS, COLS);
}

main.c ↓↓↓

#include "game.h"

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;
}

🚩这篇文章结束了~~
如果文章中出现了错误,欢迎私信或留言。(๑•̀ㅂ•́)و✧
有任何疑问请评论或私信哦~~o( ̄▽ ̄)ブ

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AI预测福彩3D第14弹【2024年3月20日预测--新算法重新开始计算第11次测试】

今天继续对第一套算法进行测试。废话不多说了&#xff0c;直接上分析出的图表&#xff0c;再上结果。 最终&#xff0c;经过研判分析&#xff0c;2024年3月20日福彩3D的七码预测结果如下&#xff1a; 百位&#xff1a;7 8 4 3 5 6 9(1换9) 十位&#xff1a;5 4 3 6 1 2 0(07分一…

day14-SpringBoot 原理篇

一、配置优先级 SpringBoot 中支持三种格式的配置文件&#xff1a; 注意事项 虽然 springboot 支持多种格式配置文件&#xff0c;但是在项目开发时&#xff0c;推荐统一使用一种格式的配置 &#xff08;yml 是主流&#xff09;。 配置文件优先级排名&#xff08;从高到低&…

事务同步管理器TransactionSynchronizationManager

事务同步管理器的使用场景&#xff1a; 同步涉及的资源包括&#xff1a;SqlSession & Connection。同步资源核心目的是线程共享&#xff0c;意味着必须跟线程绑定。同步资源伴随着线程生存或者消亡&#xff0c;意味着线程结束之前必须手动清除其绑定的资源。事务同步管理器…

基于SpringBoot+Redis实现接口限流

前言 业务中需要对一些接口进行限流处理&#xff0c;防止机器人调用或者保证服务质量&#xff1b; 实现方式 基于redis的lua脚本 引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis&…

Linux Deepin系统安装x11vnc+cpolar实现Windows系统电脑远程其桌面

文章目录 1. 安装x11vnc2. 本地远程连接测试3. Deepin安装Cpolar4. 配置公网远程地址5. 公网远程连接Deepin桌面6. 固定连接公网地址7. 固定公网地址连接测试 x11vnc是一种在Linux系统中实现远程桌面控制的工具&#xff0c;它的原理是通过X Window系统的协议来实现远程桌面的展…

linux用git拉取我云端以及git处理冲突

拉取后切换一个跟云端分支(dev)一样的 git branch --set-upstream-toorigin/dev dev 之后就同步了 A在dev分支写了iii,提交 B在dev分支写了hhh,提交,冲突 怎么修改,B把云端的拉下来,随便改改就行

YOLOv7 | 添加GSConv,VoVGSCSP等多种卷积,有效提升目标检测效果,代码改进(超详细)

⭐欢迎大家订阅我的专栏一起学习⭐ &#x1f680;&#x1f680;&#x1f680;订阅专栏&#xff0c;更新及时查看不迷路&#x1f680;&#x1f680;&#x1f680; YOLOv5涨点专栏&#xff1a;http://t.csdnimg.cn/QdCj6 YOLOv7专栏&#xff1a; http://t.csdnimg.cn/dy…

Qt 多元素控件

Qt开发 多元素控件 Qt 中提供的多元素控件有: QListWidgetQListViewQTableWidgetQTableViewQTreeWidgetQTreeView xxWidget 和 xxView 之间的区别 以 QTableWidget 和 QTableView 为例. QTableView 是基于 MVC 设计的控件. QTableView 自身不持有数据. 使用QTableView 的 …

latex如何让标题section取消数字标号

解决方法——加一个*号 在LaTeX中&#xff0c;如果你想让section标题取消数字标号&#xff0c;可以使用section*代替section。section*将生成一个不带数字标号的节标题。 例如&#xff0c;你可以这样写&#xff1a; \section*{这是不带数字标号的节标题}这将生成一个标题&am…

给老婆整了个短剧搜索机器人APP

最近短剧挺火&#xff0c;很多群友们都在做一些资源分享&#xff0c;老胡于是基于这些资源做了个短剧搜索引擎&#xff0c;挺多朋友喜欢看的&#xff0c;我老婆也在看哈哈&#xff0c;真上头&#xff0c;废话不多说&#xff0c;上短剧机器人。 短剧机器人 直接在微信群输入&…

解决由于历史原因解析tflite失败的问题

文章目录 0. 背景1. tflite 历史遗留问题2. schema3. flatbuffers 编译器3.1 安装 FlatBuffers 编译器3.2. 编译 FlatBuffers schema 文件3.3 使用生成的 Python 文件 4 问题未解决终极解决方案 写在最前面&#xff1a;解决方法是升级tensorflow版本&#xff0c;重新生成tflite…

【go从入门到精通】if else 条件控制

Go 语言条件语句&#xff1a; 在 Go 语言中&#xff0c;条件语句用于根据不同的条件执行不同的代码。Go 语言提供了两种条件语句&#xff1a;if 语句和switch 语句。 if语句 if由一个布尔表达式后紧跟一个或多个语句组成。 语法 Go 编程语言中 if 语句的语法如下&#xff…

反向海淘系统中的数据安全挑战与解决方案探讨

**反向海淘系统中的数据安全挑战与解决方案探讨** **一、背景** 随着反向海淘市场的不断扩大&#xff0c;涉及的数据安全挑战也日益增多。本文旨在探讨反向海淘系统中面临的数据安全挑战&#xff0c;以及相应的解决方案。 **二、数据安全挑战** 1. **数据传输安全**&#x…

微信支付宝--充ChatGPTPLUS/openAI key

ChatGPT是人工智能技术驱动的自然语言处理工具&#xff0c;它能够基于在预训练阶段所见的模式和统计规律&#xff0c;来生成回答&#xff0c;还能根据聊天的上下文进行互动&#xff0c;真正像人类一样来聊天交流&#xff0c;甚至能完成撰写论文、邮件、脚本、文案、翻译、代码等…

【Python】反编译PyInstaller打包的exe

查看exe基本信息 需要反编译的exe 查看exe文件的打包工具&#xff0c;查看exe信息的软件叫Detect It Easy(查壳工具) 由图我们可以看出当前选中的exe文件是由名叫PyInstaller的打包工具打包好的exe 反编译 exe反编译工具&#xff1a;pyinstxtractor.py 使用方法 python py…

面试算法-65-二叉树的层平均值

题目 给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[3.00000,14.50000,11.00000] 解释&#xff1a;第 0 层的…

【Spring高级】AOP和动态代理

目录 AspectJ实现AOPJava Agent实现AOPProxy&#xff08;代理&#xff09;模式实现AOPJDK代理CGLIB代理 AOP的底层实现切点Aspect与Advisor切面AOP底层的实现演示 Spring中的代理选择 在Java中&#xff0c;AOP&#xff08;面向切面编程&#xff09;的实现可以通过以下几种方法&…

MySQL的日志:undo log、redo log、binlog有什么作用

目录 从一个update语句说起 undo log 为什么需要undo log undo log 版本链 undo log 是如何持久化到磁盘? redo log 为什么需要redo log redo的组成 redo Log的刷盘策略 redo Log循环写 crash-safe能力 binlog 为什么需要 binlog &#xff1f; binlog与redo lo…

淘宝API接口开发系列——淘宝详情数据采集

淘宝详情数据采集涉及多种技术和方法&#xff0c;下面列举几种常见的方式&#xff1a; 请求示例&#xff0c;API接口接入Anzexi58 爬虫技术&#xff1a;使用编程语言&#xff08;如Python&#xff09;编写网络爬虫程序&#xff0c;通过模拟浏览器行为访问淘宝网站&#xff0c;…

XMind:让思维可视化,提升工作效率的利器

XMind是一款全球领先的开源思维导图和头脑风暴软件&#xff0c;它应用全球最先进的Eclipse RCP软件架构&#xff0c;拥有优秀的用户体验&#xff0c;凭借简单易用、功能强大的特点&#xff0c;在2013年被著名互联网媒体Lifehacker评选为全球最受欢迎的思维导图软件。目前&#…