C经典小游戏之扫雷

news2024/11/25 6:45:33

编译环境:VS022

目录

1.算法思路

2.代码模块

   2.1 game.h

   2.2 game.cpp

   2.3 test.cpp

3.重点分析

4.金句省身


1.算法思路

         主要采用二维数组进行实现,设置两个二维数组,一个打印结果,即为游戏界面显示的效果,一个用来存放雷的位置信息,在判断玩家想要查看的坐标时,通过对比雷的位置信息数组来在显示的数组里来输出信息,在输出信息时,如果该坐标的八个方向上都没有雷,就会以该坐标为中心,展开附近的所有的安全区(类似于bfs),此处呢,我也是用了普通递归和bfs两种方法来展开安全区,详细思路请见代码。

2.代码模块

   2.1 game.h

//game.h
#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include <bits/stdc++.h>
#include <Windows.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2//空出来两行是为了防止数组越界访问
#define COLS COL+2

//初始化棋盘
void init(char board[ROWS][COLS], int rows, int cols,char ch);

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

//布置雷
void setmine(char board[ROWS][COLS], int row, int col, int difficulty_selection);

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

//递归遍历展开安全区方法1
void dfs(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y);

//递归遍历展开安全区方法2
void bfs(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y);

2.2 game.cpp

//game.cpp
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
using namespace std;
//初始化棋盘
void init(char board[ROWS][COLS], int rows, int cols,char ch)
{
	memset(board,ch, rows * cols * sizeof(char));
}

//打印棋盘
void display(char board[ROWS][COLS], int row, int col)
{
	//可以先打印行列号便于区分
	printf("******  扫雷  ******\n");
	for (int i = 0; i <= col; 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 board[ROWS][COLS], int row, int col,int  difficulty_selection)
{
	int count = difficulty_selection ? 10 : 25;
	while (count)
	{
		
			int x = rand() % row + 1;
			int y = rand() % col + 1;
			if (board[x][y] == '0')
			{
				board[x][y] = '1';
				count--;
			}
	}
}


//(x,y)坐标上雷的数量
int countmine(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');

}

//对于周围不存在雷的坐标加以递归遍历到边界处(存在雷的地方),也就是展开安全区

void bfs(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	int dx[8] = {-1,0,1,1,1,0,-1,-1};//分别表示八个方向的方向数组
	int dy[8] = {1,1,1,0,-1,-1,-1,0};
	//标记数组,用于判断是否已经被访问
	queue<pair<int, int>> m;
	m.push({ x,y });
	while (!m.empty())
	{
		int tempx = m.front().first;
		int tempy = m.front().second;
		m.pop();
		for (int i = 0; i < 8; i++)
		{
			int xx = tempx + dx[i];
			int yy = tempy + dy[i];
			if (xx >= 1 && xx <= ROW && yy >= 1 && yy <= COL && show[xx][yy] == '*')
			{
				int k = countmine(mine, xx, yy);
				if (!k)
				{
					show[xx][yy] = '0';
					m.push({ xx,yy });
				}
				else
					show[xx][yy] = k + '0';
			}
		}
	}
}
/*
void dfs(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	 int count= countmine(mine, x, y);
	 if (!count)//展开安全区
	 {
		 show[x][y] = '0';
		 for (int i = x - 1; i <= x + 1; i++)
			 for (int j = y - 1; j <= y + 1; j++)
			 {
				 if (i >= 1 && i <= ROW && j >= 1 && j <= COL && show[i][j] == '*' && mine[i][j] != 1)
					 dfs(mine, show, i, j);

			 }
	 }
	 else
		 show[x][y] = '0' + count;
}
*/
//排查雷
void findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x, y;
	while (1)
	{
		printf("请输入要排查的目标坐标:->\n");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				
				printf("很遗憾,你被炸死了\n");
				printf("\n说明:其中数字\"1\"表示雷,数字\"0\"表示非雷\n");
				display(mine,ROW,COL);
				Sleep(5000);
				break;
			}
			else
			{
				//该坐标不是雷
				int count = countmine(mine, x, y);
				show[x][y] = count + '0';
				if(count==0)
				{ 
					//运用两种方法遍历到边界处,前一种试过的已经加了注释
 					//dfs(mine, show, x, y);
					bfs(mine, show, x, y);
				}
				display(show, ROW, COL);
			}
			
		}
		else
		printf("坐标输入有误,请重新输入\n");
	}
}

2.3 test.cpp

//test.cpp
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"

void menu()
{
	printf("********************************\n");
	printf("******     1.   play      ******\n");
	printf("******     0.   exit      ******\n");
	printf("********************************\n");
}
void game()
{
	char mine[ROWS][COLS]={0};//表示实际上的布雷情况
	char show[ROWS][COLS]={0};//表示显示在控制台上的界面
	int difficulty_selection = 0;
again:
		printf("请选择游戏难度->\n");
		printf("********************\n");
		printf("*****EASY---PLAY INPUT THR NUMBER \"1\"\n");
		printf("*****DIFFICULTY ---PLAY INPUT THE NUMBER \"0\"\n");
		printf("********************\n");
		scanf("%d", &difficulty_selection);
		if (difficulty_selection != 0 && difficulty_selection != 1)
		{
			printf("\n选择错误,请重新选择->\n\n");
			goto again;
		}
	//初始化棋盘
	init(mine, ROWS, COLS,'0');
	init(show, ROWS, COLS,'*');
	//打印棋盘
	//display(mine, ROW, COL);
	display(show, ROW, COL);

	//布置雷的信息
	setmine(mine,ROW,COL, difficulty_selection);
	//display(mine, ROW, COL);

	//排查雷
	findmine(mine,show,ROW,COL);
}
int main()
{
	int input;
	srand((unsigned int)time(NULL));
	do {
		system("cls");
		menu();
		printf("请选择:->");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}


	} while (input);


	return 0;
}

3.重点分析

        bfs和dfs的两种递归,对于学过数据结构或者之前有了解的人比较友好,其实这两者本质上是递归的应用,dfs基本和递归没什么区别,简单说一下bfs,大多数情境下,bfs在配合C++的STL中的栈或者队列来使用(当然dfs是可以直接用c来实现的,在代码中也有体现),通过将初始元素压入队,对队中的元素依次进行判断,再将判断后符合入队条件的元素再次入队,当然,也要将该层的元素出队并做好不再参与入队的标记,当队列为空时,即是递归到达了截止条件,向外层的扩展得以结束。

4.金句省身

        有志少年,先谋生而后谋爱,唯有父母和前程不可辜负,想想你往那些虚拟的世界里扔出的金钱,再想想父母的努力,醒醒吧,如果一单648能让你觉醒的看清资本家的嘴脸,那么这单是值得的,如果你的父母依旧辛苦,那么我们长大的意义又在哪里?变好的过程都不太舒服,试试再努力点。加油,为你也为我...

         

 

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

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

相关文章

值类型和引用类型

一、值类型和引用类型示例&#xff1a; 值类型&#xff1a;基本数据类型系列&#xff0c;如&#xff1a;int&#xff0c;float&#xff0c;bool&#xff0c;string&#xff0c;数组和结构体等。 引用类型&#xff1a;如&#xff1a;指针&#xff0c;slice切片&#xff0c;map&a…

windows wireshark抓到未加入组的组播消息

现象 在Windows上开启wireshark&#xff0c;抓到了大量地址为239.255.255.251的组播包。 同时&#xff0c;根据组播相关命令&#xff0c;调用netsh interface ipv4 show joins&#xff0c;显示当前并没加入 239.255.255.251 组播组。 解决 根据IGMP Snooping&#xff0c;I…

《机器学习》学习笔记

第 2 章 模型评估与选择 2.1 经验误差与过拟合 精度&#xff1a;精度1-错误率。如果在 mmm 个样本中有 aaa 个样本分类错误&#xff0c;则错误率 Ea/mEa/mEa/m&#xff0c;精度 1−a/m1-a/m1−a/m。误差&#xff1a;一般我们把学习器的实际预测输出与样本的真实输出之间的差…

MySQL---单表查询、多表查询

一、单表查询 素材&#xff1a; 表名&#xff1a;worker-- 表中字段均为中文&#xff0c;比如 部门号 工资 职工号 参加工作 等 CREATE TABLE worker ( 部门号 int(11) NOT NULL, 职工号 int(11) NOT NULL, 工作时间 date NOT NULL, 工资 float(8,2) NOT NULL, 政治面貌 v…

STM32驱动RC522

STM32驱动RC522开发环境&#xff1a;STM32CUBEMXKeil5使用平台&#xff1a;STM32F401CCU6该内容由网上内容改编,若不合适&#xff0c;请联系删除。一、使用STM32CUBEMX配置SPI二、驱动部分三、主函数调用四、移值攻略开发环境&#xff1a;STM32CUBEMXKeil5 使用平台&#xff1…

力扣:珠玑妙算(详解)

前言&#xff1a;内容包括四大模块&#xff1a;题目&#xff0c;代码实现&#xff0c;大致思路&#xff0c;代码解读 题目&#xff1a; 珠玑妙算游戏&#xff08;the game of master mind&#xff09;的玩法如下。 计算机有4个槽&#xff0c;每个槽放一个球&#xff0c;颜色可…

电力系统网架规划MATLAB程序分享

网架数据展示&#xff1a;完整程序&#xff1a;close all;clear all;clc;warning off; % 去除警告 tic; % tic用来保存当前时间&#xff0c;而后使用toc来记录程序完成时间%% 基本参数T12; % 典型日 8-19h % 8-19h 负荷各时段负荷总量total_P_LOAD[828,1001,1105,1105,994,1105…

STM32CubeMX+SPI+FATFS读写SD卡

一、软件硬件说明软件&#xff1a;STM32CubeMX V6.6.1 /KEIL5 V5.29硬件&#xff1a;正点原子mini开发板&#xff0c;SD卡,通过SPI方式驱动SD卡&#xff0c;用的是SPI1接口以上内容来源于正点原子mini开发板手册&#xff0c;SD卡的详细介绍也可以去查阅这个手册。二、STM32Cube…

Ethercat系列(3)TWCat3下抓包实例分析

简介研究Ethercat协议&#xff0c;必须知道数据包格式&#xff0c;以及其真实含义。以一个真实的数据包来学习是最有效的。Twcat3下用wireshark抓包&#xff0c;需要设置一下混杂模式&#xff0c;否则不能直接抓到Ethercat数据包。Twcat抓包设置在正确加载驱动器配置文件后&…

可深度二次开发的智能插座 工业化物联网多场景的高定系统服务商

物联网时代&#xff0c;各类物联网需求越来越迫切。物联网设备呈现出爆发式增长。同时近年来国家不断出台相关的法规政策&#xff0c;为物联网行业发展创造机遇&#xff0c;三大运营商积极部署NB-IOT网络建设&#xff0c;建成90万NB-IoT基站。据统计2012-2022年期间&#xff0c…

缺省参数+函数重载+构造函数

目录 一、缺省参数 &#xff08;一&#xff09;缺省参数概念 &#xff08;二&#xff09;缺省参数分类 1. 全缺省参数 2. 半缺省参数&#xff08;缺省部分参数&#xff09; 3. 注意 二、函数重载 &#xff08;一&#xff09;基本概念 &#xff08;二&#xff09;举例 …

“算丰AI视界”人工智能技术内容征集活动正式开启!

2023年2月8日&#xff0c;首届“算丰AI视界”人工智能技术内容征集活动正式拉开帷幕&#xff01;本次活动主要征集AI、CV、TPU-MLIR、RISC-V等方向的代表性视频和文章&#xff0c;面向国内外的企业、高校和科研院所的优秀开发者。 活动紧扣人工智能行业相关AI视觉技术&#xff…

申请苹果开发者账号的方法

1、打开苹果id注册地址&#xff0c;输入相关信息注册&#xff0c;如果已经有苹果账号了看第二步&#xff0c; https://appleid.apple.com/account?localangzh_CN 2、注册成功了&#xff0c;或者有苹果账号了&#xff0c;登录苹果开发者中心 https://developer.apple.com/acc…

LearnOpenGL 笔记 - 入门 04 你好,三角形

系列文章目录 LearnOpenGL 笔记 - 入门 01 OpenGLLearnOpenGL 笔记 - 入门 02 创建窗口LearnOpenGL 笔记 - 入门 03 你好&#xff0c;窗口 文章目录系列文章目录前言你好&#xff0c;三角形顶点输入顶点着色器&#xff08;Vertex Shader&#xff09;编译着色器片段着色器&…

SpringBoot集成Flink-CDC 采集PostgreSQL变更数据发布到Kafka

一、业务价值 监听数据变化&#xff0c;进行异步通知&#xff0c;做系统内异步任务。 架构方案&#xff08;懒得写了&#xff0c;看图吧&#xff09;&#xff1a; 二、修改数据库配置 2.1、更改配置文件postgresql.conf # 更改wal日志方式为logical&#xff08;必须&#xf…

PCB设计是不是该去除孤铜

你知道PCB设计是不是该去除孤铜? PCB设计的技巧需要注意很多问题&#xff0c;各个器件的兼容问题&#xff0c;以及成品问题等等都是需要考虑的重要因素。 我们今天的主题是PCB设计的时候是不是该去除孤铜的问题?有人说应该除去&#xff0c;原因大概是&#xff1a; 会造成EMI问…

学习深入理解JVM虚拟机及JavaGuide后的学习笔记

JVM虚拟机 一、JVM组成部分&#xff1a; 1.程序计数器 作用&#xff0c;是记住下一条JVM指令的内存地址&#xff1b;1.多线程情况下&#xff0c;程序计数器用于记录当前线程执行的位置&#xff0c;从而线程切换回来的时候能够知道线程上次运行到哪儿了。2.字节码解释器通过改变…

6 前缀、中缀、后缀表达式

文章目录1 前缀表达式 1. 1 缀表达式的计算机求值 2 中缀表达式3 后缀表达式 3. 1 后缀表达式的计算机求值 3. 2 中缀表达式转换为后缀表达式1 前缀表达式 前缀表达式又称波兰式&#xff0c;前缀表达式的运算符位于操作数之前 举例说明&#xff1a; (34)5-6 对应的前缀表达式就…

Orin + SC16IS752+SP3072 SPI转串口485

文章目录 1.前言2.修改过程2.1 sc16is752 芯片2.1.1引脚说明2.1.2 设备树配置2.2.1 源码分析3 调试1.前言 Orin 有四路串口,对于多数设备来说已经够用。 通过SPI 转串口再转RS485在Orin平台应该属于极个例,所以记录一下。 串口扩展芯片: SC16IS752RS485收发器: SP3072通信…

初次尝试-注册openai并使用chatGPT

1 环境 本次我打算在win11虚拟机下进行(不打算动真机的时区啦)。 2 科学上网 这里就不多介绍了&#xff0c;使用科学上网工具连接外网即可。由于软件可连接限制&#xff0c;我这里选择美国网络。 3 更改时区 这里的时区最好和上述的所连接的地区一致。 3 登录网站 1、…