C语言经典小游戏之扫雷(超详解释+源码)

news2024/11/25 14:38:44

“少年气,是历尽千帆举重若轻的沉淀,也是乐观淡然笑对生活的豁达!” 今天我们学习一下扫雷游戏怎么用C语言来实现!

扫雷小游戏

  • 1.游戏介绍
  • 2.游戏准备
  • 3.游戏实现
    • 3.1生成菜单
    • 3.2游戏的具体实现
      • 3.2.1初始化棋盘
      • 3.2打印棋盘
      • 3.3布置雷
      • 3.4排查雷
    • 4.扫雷游戏的详细代码

1.游戏介绍

一个扫雷盘面由许多方格(cell)组成,方格中随机分布着一定数量的雷(mine),一个格子中至多只有1雷。胜利条件是打开所有安全格(非雷格,safe cell),失败条件是打开了一个雷格(踩雷)。下面图片中是一个9*9的示例:
在这里插入图片描述

2.游戏准备

和前面的三子棋一样,这里,我们也需要三个源文件来共同实现这个程序。
在这里插入图片描述

(1)头文件game.h,头文件里是用来存放函数的声明,#define常量的定义,库函数的引用的。
(2)源文件test.c,这个文件里面放的是游戏的测试逻辑。
(3)源文件game.c,这个文件里面放的是游戏的实现逻辑(函数实现)。

3.游戏实现

3.1生成菜单

这里呢,我们和三子棋一样,还是通过switch语句给用户选择,当用户输入不同的数字,我们的程序就会给出不同的功能。

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
#include <stdio.h>
void menu()
{
	printf("******************************\n");
	printf("*********   1.play   *********\n");
	printf("*********   0.exit   *********\n");
	printf("******************************\n");
}
void 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");
			break;
		}
	} while (input);
	return 0;
}

大致的框架就出来了,现在我们就需要看扫雷游戏的具体实现了。
在这里插入图片描述

3.2游戏的具体实现

这里我们简化游戏,设置一个9*9的棋盘,安置10个雷
排查过程如下:
1.如果这个位置是雷,那么游戏结束。
2.如果把不是雷的位置都找出来了,那么游戏结束。
3.如果这个位置不是雷,就计算这个位置的周围的8个格子有几个雷,并显示出雷的个数。

3.2.1初始化棋盘

我们这里的棋盘是9*9的,可以和三子棋一样,先将每个棋盘都初始化为0,如下图所示,然后有雷的地方填上1,如下图所示:
在这里插入图片描述
但是,我们从游戏规则中知道,当我们点到一个不是雷的格子的时候,要返回它周围八个格子中雷的个数。如下图中,如果我们点到了绿色1的那个格子,那么该位置将返回1这个值,此时,这里的1就会和表示雷的1就混起来了。
在这里插入图片描述
同时,当我们点到一个处于四边的格子的时候,还会出现越界的问题:
在这里插入图片描述
这个时候,我们就可以考虑在排查雷的时候,将棋盘扩展成11*11的棋盘。
在这里插入图片描述

同时,我们可以将排查雷的9*9的格子里都初始化为*,避免出现两个1意义不同混淆的情况。这样的话,我们就得到两个11*11的棋盘。
在这里插入图片描述

//game.h
#pragma once
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
//初始化棋盘函数的声明
void Init_Board(char board[ROWS][COLS], int rows, int cols, char set);

//game.h*
//初始化棋盘的定义
#define _CRT_SECURE_NO_WARNINGS 1
#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;
		}
	}
}

//test.c
void game()
{
	char assign[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };
	Init_Board(assign,ROWS,COLS,'0');
	Init_Board(show, ROWS, COLS, '*');
}

初始化完成之后,我们想要验证一下对不对呢?这个时候,我们就需要将棋盘打印出来。

3.2打印棋盘

虽然我们这里初始化的是11*11的棋盘,但是用户需要的是中间区域的9*9,因此,我们只需要打印中间的9*9就可以了。

//game.h
//打印棋盘函数的声明
void Display_Board(char board[ROWS][COLS], int row, int col);

//game.c
//打印棋盘函数的定义
//我们只需要打印出中间的9*9的格子
void Display_Board(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

//test.c
void game()
{
	Display_Board(assign, ROW, COL);
}

在这里插入图片描述
这里我们需要把行号和列号也打印出来,能够看的更清晰。代码进行这样的修改就好啦!
在这里插入图片描述
再优化一下,就如下图所示:
在这里插入图片描述

3.3布置雷

我们希望的是在这个9*9的棋盘里随机生成10个雷,这里我们就想到了能够产生随机数的函数rand()和srand(),使用这两个函数,需要添加头文件#include <time.h>和#include <stdlib.h>,同时,在主函数内还需要添加语句srand((unsigned int)time(NULL));来产生随机数的种子。

//game.h
#define Easy_Thunder 10
#include <stdlib.h>
#include <time.h>
//布置雷函数的声明
void Set_thunder(char board[ROWS][COLS], int row, int col);

//game.c
//布置雷函数的定义
void Set_thunder(char board[ROWS][COLS], int row, int col)
{
	int count = Easy_Thunder;
	while (count)
	{
		int x = rand() % row + 1;//生成横坐标
		int y = rand() % col + 1;//生成纵坐标
		if (board[x][y] == '0')//防止在同一个地方重复布雷
		{
			board[x][y] = '1';
			count--;
		}
	}
}

//test.c
void game()
{
	char assign[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };
	Init_Board(assign,ROWS,COLS,'0');
	Init_Board(show, ROWS, COLS, '*');
	Display_Board(assign, ROW, COL);
	Set_thunder(assign, ROW, COL);
}
int main()
{
	srand((unsigned int)time(NULL));
	return 0;
}

那么,代码写好了,我们来验证一下,这样是不是能够布置出十个雷呢?
在这里插入图片描述

3.4排查雷

我们开始随机点一个格子,当这个格子不是雷的时候,可以计算它周围八个格子字符的ASCII码值,减去8个'0'的ASCII码值,就可以知道,这个格子周围有多少个雷了,然后我们加上'0'的ASCII码值就能在该处的格子上返回相应的字符。当我们把所有不是雷的格子找出来的时候,给用户提示排雷成功。当我们踩到雷的时候,也给出相应的提示给用户,游戏结束。这里和三子棋一样,我们可以添加清屏的操作system("cls");,让我们的游戏面板不是那么的冗长。

在这里插入图片描述

//game.h
//排查雷函数的声明
void Find_thunder(char assign[ROWS][COLS], char show[ROWS][COLS], int row, int col);

//game.c
int Getassign(char assign[ROWS][COLS], int row, int col)//查找不是雷的格子周围有几个雷
{
	return (assign[row - 1][col - 1]//字符'0'的ASCII值为48,字符'1'的ASCII值为49
		+ assign[row - 1][col]
		+ assign[row - 1][col + 1]
		+ assign[row][col - 1]
		+ assign[row][col + 1]
		+ assign[row + 1][col - 1]
		+ assign[row + 1][col]
		+ assign[row + 1][col + 1] - 8 * '0');
}
//排查雷函数的定义
void Find_thunder(char assign[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;//计算没有踩到雷的次数
	while (win<col*row-Easy_Thunder)
	{
		printf("请输入坐标:>");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (assign[x][y] == '1')
			{
				printf("很遗憾,你被炸死了!\n");
				Display_Board(assign, ROW, COL);
				break;
			}
			else
			{
				//如果这个位置不是雷就统计周围八个格子雷的个数
				int c = Getassign(assign, x, y);
				show[x][y] = c + '0';
				Display_Board(show, ROW, COL);
				system("cls");
				Display_Board(show, ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标非法,请重新输入!\n");
		}
	}
	if (win == row * col - Easy_Thunder)
	{
		printf("恭喜你排雷成功!\n");
		Display_Board(assign, ROW, COL);
	}	
}

//test.c
void game()
{
	Find_thunder(assign, show, ROW, COL);//排雷函数的引用
}

这里,我们随机输入,不用思考,试一下踩到雷的结果:
在这里插入图片描述
那么,如果我们仔细思考,看看当我们把所有不是雷的格子找出来的时候,能不能成功:
在这里插入图片描述

4.扫雷游戏的详细代码

//game.h
#pragma once
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define Easy_Thunder 10
#include <stdlib.h>
#include <time.h>
//初始化棋盘函数的声明
void Init_Board(char board[ROWS][COLS], int rows, int cols, char set);
//打印棋盘函数的声明
void Display_Board(char board[ROWS][COLS], int row, int col);
//布置雷函数的声明
void Set_thunder(char board[ROWS][COLS], int row, int col);
//排查雷函数的声明
void Find_thunder(char assign[ROWS][COLS], char show[ROWS][COLS], int row, int col);

//game.c
#define _CRT_SECURE_NO_WARNINGS 1
#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;
		}
	}
}
//打印棋盘函数的定义
//我们只需要打印出中间的9*9的格子
void Display_Board(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("--------扫雷--------\n");
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}
//布置雷函数的定义
void Set_thunder(char board[ROWS][COLS], int row, int col)
{
	int count = Easy_Thunder;//布置10个雷
	while (count)
	{
		int x = rand() % row + 1;//生成横坐标
		int y = rand() % col + 1;//生成纵坐标
		if (board[x][y] == '0')//防止在同一个地方重复布雷
		{
			board[x][y] = '1';
			count--;
		}
	}
}
int Getassign(char assign[ROWS][COLS], int row, int col)//查找不是雷的格子周围有几个雷
{
	return (assign[row - 1][col - 1]//字符'0'的ASCII值为48,字符'1'的ASCII值为49
		+ assign[row - 1][col]
		+ assign[row - 1][col + 1]
		+ assign[row][col - 1]
		+ assign[row][col + 1]
		+ assign[row + 1][col - 1]
		+ assign[row + 1][col]
		+ assign[row + 1][col + 1] - 8 * '0');
}
//排查雷函数的定义
void Find_thunder(char assign[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;//计算没有踩到雷的次数
	while (win<col*row-Easy_Thunder)
	{
		printf("请输入坐标:>");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (assign[x][y] == '1')
			{
				printf("很遗憾,你被炸死了!\n");
				Display_Board(assign, ROW, COL);
				break;
			}
			else
			{
				//如果这个位置不是雷就统计周围八个格子雷的个数
				int c = Getassign(assign, x, y);
				show[x][y] = c + '0';
				Display_Board(show, ROW, COL);
				system("cls");//清屏操作
				Display_Board(show, ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标非法,请重新输入!\n");
		}
	}
	if (win == row * col - Easy_Thunder)
	{
		printf("恭喜你排雷成功!\n");
		Display_Board(assign, ROW, COL);
	}	
}

//test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
#include <stdio.h>
void menu()
{
	printf("******************************\n");
	printf("*********   1.play   *********\n");
	printf("*********   0.exit   *********\n");
	printf("******************************\n");
}
void game()
{
	char assign[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };
	Init_Board(assign,ROWS,COLS,'0');
	Init_Board(show, ROWS, COLS, '*');
	Display_Board(assign, ROW, COL);
	Set_thunder(assign, ROW, COL);
	Find_thunder(assign, show, ROW, COL);
}
int main()
{
	srand((unsigned int)time(NULL));
	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;
}

以上就是关于扫雷游戏的全部代码啦!当然这个程序还是存在可优化的空间(比如我们的游戏只能一个一个点,但是不能像网页版的那样能展示一片,这还有待思考),欢迎大家在评论区交流,优化代码。

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

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

相关文章

Linux root用户执行修改密码命令,提示 Permission denied

问题 linux系统中&#xff08;ubuntu20&#xff09;&#xff0c;root用户下执行passwd命令&#xff0c;提示 passwd: Permission denied &#xff0c;如下图&#xff1a; 排查 1.执行 ll /usr/bin/passwd &#xff0c;查看文件权限是否正确&#xff0c;正常情况是 -rwsr-xr…

VAE、 EM、KL散度

文章目录 VAEVAE额外的损失函数 EMKL散度 VAE 左图相当于变量x&#xff0c;右图相当于z 假如在AE中&#xff0c;一张满月的图片作为输入&#xff0c;模型得到的输出是一张满月的图片&#xff1b;一张弦月的图片作为输入&#xff0c;模型得到的是一张弦月的图片。当从满月的code…

SpringBoot复习:(22)ConfigurationProperties和@PropertySource配合使用及JSR303校验

一、配置类 package cn.edu.tju.config;import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component;Component ConfigurationPropertie…

C++初阶——函数重载

前言&#xff1a;C中除了可以在不同的命名空间中使用同名函数&#xff0c;还有一种支持在同一个作用域中同名函数的方式——函数重载。 函数重载 一.什么是函数重载&#xff1f;二.函数重载的3种规则三.特殊情况 一.什么是函数重载&#xff1f; C允许同样同一作用域中声明几个功…

IPWorks OFX Delphi Edition Crack

IPWorks OFX Delphi Edition Crack IPWorks OFX由可以访问电子交易信息的组件组成&#xff0c;并包括银行转账和付款提交等功能。这些组件使应用程序开发人员能够构建包含更快、更准确的交易对账、发送即时交易通知以及完全关闭支付和会计之间循环的解决方案。 IPWorks OFX功能…

请求接口时报异常:org.springframework.web.multipart.MultipartException

请求接口时报异常&#xff1a;org.springframework.web.multipart.MultipartException: Current request is not a multipart request 检查后发现自己忘记传文件参数 添加参数后请求正常。

软件测试的生命周期

目录 软件测试&软件开发生命周期 如何描述一个bug? 如何定义bug的级别 bug的生命周期 测试的执行和BUG管理 产生争执怎么办&#xff08;处理人际关系&#xff09; 软件测试&软件开发生命周期 需求阶段 --测试人员需要了解需求, 对需求进行分解得出测试需求 计…

python的virtualenv虚拟环境无法激活activate

目录 问题描述&#xff1a; 解决办法&#xff1a; 解决结果&#xff1a; 问题描述&#xff1a; PS D:\pythonProject\pythonProject\DisplayToolLibs\venv\Scripts> .\activate .\activate : 无法加载文件 D:\pythonProject\pythonProject\DisplayToolLibs\venv\Scripts\…

全网最牛,在Linux系统上安装Git详细步骤,看这一篇就够了...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 yum安装 1、在Li…

学习笔记-JVM-对象结构及生命周期

申明&#xff1a;文章内容是本人学习极客时间课程所写&#xff0c;文字和图片基本来源于课程资料&#xff0c;在某些地方会插入一点自己的理解&#xff0c;未用于商业用途&#xff0c;侵删。 原资料地址&#xff1a;课程资料 对象的创建流程 常量池检查:检查new指令是否能在常…

代码随想录—力扣算法题:209长度最小的子数组.Java版(示例代码与导图详解)

版本说明 当前版本号[20230808]。 版本修改说明20230808初版 目录 文章目录 版本说明目录209.长度最小的子数组思路暴力解法滑动窗口 两种方法的区别总结 209.长度最小的子数组 力扣题目链接 更多内容可点击此处跳转到代码随想录&#xff0c;看原版文件 给定一个含有 n 个…

k8sday01

第一章 kubernetes介绍 本章节主要介绍应用程序在服务器上部署方式演变以及kubernetes的概念、组件和工作原理。 应用部署方式演变 在部署应用程序的方式上&#xff0c;主要经历了三个时代&#xff1a; 传统部署&#xff1a;互联网早期&#xff0c;会直接将应用程序部署在物…

FreeRTOS(系统配置)

一、FreeRTOSConfig.h文件 FreeRTOS的系统配置文件为FreeRTOSConfig.h&#xff0c;在此配置文件中可完成FreeRTOS的裁剪与配置。 FreeRTOSConfig.h 根据正在构建的应用程序定制 FreeRTOS 内核。因此&#xff0c;它特定于应用程序&#xff0c;而不是 FreeRTOS&#xff0c;并且应…

The Sandbox 与 D.OASIS 联手打造 D.OASIS 城市

我们非常高兴地宣布与 D.OASIS 建立合作伙伴关系&#xff0c;共同打造无与伦比的娱乐体验&#xff1a;The Sandbox 中的 D.OASIS 城市&#xff01; 作为合作的一部分&#xff0c;The Sandbox 和D.OASIS将共同打造 D.OASIS 城市&#xff0c;一座充满无限可能的大都市&#xff0…

如何不安装vnc viewer等软件,在Windows上向linux传文件

举个例子&#xff0c;举一反三 1. 在linux上安装 wget sudo apt-get install wget2. 把要下载的文件链接复制&#xff0c;下载按钮上右键 3. 输入 wget #下载地址#然后就下载好了 每天进步一点点 笔记仅供自学&#xff0c;用来回看复习&#xff0c;不一定适合你&#xff0c…

华为OD机试(含B卷)真题2023 算法分类版,58道20个算法分类,如果距离机考时间不多了,就看这个吧,稳稳的

目录 一、数据结构1、线性表2、优先队列3、滑动窗口4、二叉树5、并查集6、栈 二、算法1、基础算法2、字符串3、图4、动态规划5、数学 三、漫画算法2&#xff1a;小灰的算法进阶参与方式 很多小伙伴问我&#xff0c;华为OD机试算法题太多了&#xff0c;知识点繁杂&#xff0c;如…

MyCat分片规则——应用指定分片规则、日期分片、固定分片hash算法

1.应用指定分片规则 2.固定分片hash算法 3.字符串hash解析 4.按天&#xff08;日期&#xff09;分片 5.按自然月进行分片

hcip的重发布实验(1)

题目 拓扑图 IP地址配置 R1 < Huawei>sy Enter system view, return user view with CtrlZ. [Huawei]sysname r1 [r1]int l0 [r1-LoopBack0]ip add 1.1.1.1 24 [r1-LoopBack0]int g0/0/0 [r1-GigabitEthernet0/0/0]ip add 12.1.1.1 24 Aug 8 2023 21:28:29-08:00 r1 %%0…

4.1 Windows终端安全

数据参考&#xff1a;CISP官方 目录 安全安装保护账户安全本地安全策略安全中心系统服务安全其他安全设置软件安全获取 一、安全安装&#xff08;以安装windows系统为例&#xff09; 选择合适的版本 商业版本&#xff1a;家庭版、专业版、专业工作站版、企业版特殊版本&…

模拟实现消息队列项目(系列2) -- 项目前期的准备

目录 前言 1. 需求分析 1.1 核心概念 1.2 核心API 1.3 交换机类型 1.4 持久化 1.5 网络通信 1.6 消息应答 2. 模块划分 结语 前言 我们在上一个系列对于消息队列有了初步的认识,那我们明白了消息队列的用途之后,我们就开始进行我们的项目了,首先我们的项目是仿照Rabb…