【c语言】扫雷

news2024/11/16 7:43:21

 前言:

扫雷是一款经典的单人益智游戏,它的目标是在一个方格矩阵中找出所有的地雷,而不触碰到任何一颗地雷。在计算机编程领域,扫雷也是一个非常受欢迎的项目,因为它涉及到许多重要的编程概念,如数组、循环、条件语句和函数等。

C语言是一种广泛使用的编程语言,它具有高效、灵活和可移植等特点,非常适合编写各种类型的应用程序。因此,使用C语言编写一个扫雷游戏是一个很好的学习编程的项目。

在这篇博客中,我们将介绍如何使用C语言编写一个简单的扫雷游戏。我们将从基本的编程概念开始讲解,逐步深入到更复杂的程序设计技术。我们还将提供完整的代码示例和详细的注释,以帮助读者更好地理解和掌握这个项目。

无论您是初学者还是有一定编程经验的开发者,相信通过阅读本篇博客,您都能够学到一些有用的知识和技巧。让我们一起来探索如何使用C语言编写一个令人兴奋的扫雷游戏吧!

前期准备:

先开一个test.c文件用来游戏的逻辑测试,在分别开一个game.c文件和game.h头文件用来实现游戏的逻辑

1. 主要步骤:

1.1 游戏规则:

输入1(0)开始(结束)游戏,输入一个坐标,如果该坐标不是雷则会显示该坐标周围有几个雷

1.2 打印菜单:

void menu()
{
	printf("----------------扫雷----------------\n");
	printf("|                                  |\n");
	printf("|              1.play              |\n");
	printf("|              0.exit              |\n");
	printf("|                                  |\n");
	printf("------------------------------------\n");
}
int main()
{
	int input = 0;
	srand((unsigned int )time(NULL));
	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.3 打印棋盘:

写两个数组一个是用来打印给玩家看的棋盘,一个是用来放置炸弹的隐藏棋盘,等到游戏结束我们才会打印这个棋盘。然后我们给数组初始化,用*来初始化我们给玩家看的棋盘,用字符‘0’初始化隐藏棋盘。

   char mine[ROWS][COLS] = { 0 };
   char show[ROWS][COLS] = { 0 };

     //初始化棋盘
	InitBoard(show, ROWS, COLS, '*');
	InitBoard(mine, ROWS, COLS, '0');
	
    //打印棋盘
	DisPalyBoard(show, ROW, COL);
    //DisPalyBoard(mine, ROW, COL);

1.4 打印行列:

因为我们是用坐标来选择排雷的,所以我们需要在棋盘的周围打印出行列才可以让玩家更好的去选择。

首先在打印棋盘for循环上方加上一个打印0~9的for循环就可以打印出棋盘的行了,然后用打印列的for循环套在打印棋盘的for循环上就可以打印出棋盘的列了。

​
void DisPalyBoard(char arr[ROWS][COLS], int row, int col)
{
	printf("------扫雷游戏------\n");
    ​
    int i = 0;
    //打印行的for循环
	for (i = 0; i <= col; i++)
	{
		printf("%d ", i);
	}
	printf("\n");

	//打印列的for循环
	for ( i = 1; i <= row; i++)  
	{
		printf("%d ", i);

        //打印棋盘的for循环
		for (int j = 1; j <= col; j++)
		{
			
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
}

​

1.5 放置炸弹:

要想棋盘上随机分布十个炸弹(炸弹我们用字符‘1’定义),我们就需要生成随机数使数组的随机十个元素等于字符‘1’,而生成随机数就需要调用到前面我写猜数字游戏时讲过的rand函数、srand函数、time函数了。

void SetMine(char arr[ROWS][COLS], int row, int col)
{
	int count = EsayCount;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (arr[x][y] == '0')//防止生成相同随机数时,使多个炸弹放置在同一位置
		{
			arr[x][y] = '1';
			count--;
		}
	}
}

1.6 排查炸弹:

当我们输入一个坐标后如果时炸弹结束游戏,如果不是炸弹则需要显示炸弹的数量。

判断是否是炸弹只需写一个if语句判断该坐标中数组所对应的元素是否等于‘1’就行了。

显示周围有几个雷,我们就需要将所选坐标的周围的数加起来就可以了,这些加起来的数的和替换所选坐标的元素就可以了。

int GetMineCount(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 + 1] + mine[x - 1][y + 1] + mine[x - 1][y + 1] + mine[x][y + 1] - 8 * '0');
}

也可以用for循环统计

int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
	int a = 0;
	for (int i = x - 1; i <= x + 1; i++)
	{
		for (int j = y - 1; j <= y + 1; j++)
		{
			a += mine[i][j];
		}
	}
	return a - '0' * 9;
}

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0, y = 0;
	int win = 0;
	while (win < row*col - EsayCount)
	{
		printf("请输入要排查的坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,你被炸死了\n");
				DisPalyBoard(mine, ROW, COL);
				break;
			}
			else
			{
				//该坐标不是雷,就得统计该坐标的周围有几个雷
				int count = GetMineCount(mine, x, y);
				show[x][y] = count + '0';
				DisPalyBoard(show, ROW, COL);
				win++;
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
	if (win == row * col - EsayCount)
	{
		printf("恭喜你,排雷成功\n");
		DisPalyBoard(mine, ROW, COL);
	}
}

1.7 周围没有雷就展开一片

首先需要判断所选坐标的周围是否有雷,即判断count是否等于0,如果所选坐标周围没有雷的话,就将此坐标的周围的坐标都调用显示雷的数量的函数。当然还需要判断一下坐标是否为‘*’,如果没有这个判断它就会重复的调用函数,从而进入了死循环。

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

	if (show[x][y] == '*')
	{
		int count = GetMineCount(mine, x, y);
		show[x][y] = count + '0';
		if (x >= 1 && x <= ROW && y >= 1 && y <= ROW)
		{
			if (count == 0)
			{
				arr(mine, show, x - 1, y);
				arr(mine, show, x - 1, y - 1);
				arr(mine, show, x - 1, y + 1);
				arr(mine, show, x, y - 1);
				arr(mine, show, x, y + 1);
				arr(mine, show, x + 1, y - 1);
				arr(mine, show, x + 1, y + 1);
				arr(mine, show, x + 1, y);
			}
		}
	}
}

1.8 计算游戏时间

time函数可以返回一个时间戳,我们可以利用这个函数计算游戏的时间。

int y = time(NULL);
while (1)
{
	system("cls");
	int x = time(NULL) - y;
	printf("%d", x);
	Sleep(1000);
}

1.9 游戏可改性

因为在写这个程序时需要输入很多的数字,如果我们想修改这些数时就要一个一个改,这样非常的麻烦。为了避免这些麻烦我们只需要在头文件定义某字符等于某个数字就可以了,这样我们想改游戏参数的时候在头文件game.h改就行了。

#define ROW 9
#define COL 9

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

比如当我们想改行和列改为16炸弹数量改为40的时候,我们只需要在头文件将ROW 与 COL定义为16就可以了。

#define ROW 16
#define COL 16

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

 

 1.10 控制台颜色的修改

使用system("color attr");函数可以修改控制台颜色,这个函数需要使用#include<windonws.h>调用。颜色可以参考下面这张图:

  例:
 

2. 完整代码

2.1 game.h头文件

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<windows.h>
#define ROW 9
#define COL 9

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

//声明函数
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char test);
//
void DisPalyBoard(char arr[ROW][COL], int row, int col, int o);
//布置雷的信息
void SetMine(char arr[ROWS][COLS], int row, int col, int o);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int o);

 2.2 game.c文件

#include"game.h"
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			arr[i][j] = set;
		}
	}
}
void DisPalyBoard(char arr[ROWS][COLS], int row, int col,int o)
{
	//清屏
	system("cls");
	printf("-----------扫雷游戏----------\n");
	//计算时间
	printf("已用时间:%ds\n", time(NULL) - o);
	int i = 0;
	for (i = 0; i <= col; i++)
	{
		printf("%2d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%2d ", i);
		for (int j = 1; j <= col; j++)
		{
			printf("%2c ", arr[i][j]);
		}
		printf("\n");
	}
}

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

int GetMineCount(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 + 1] + mine[x - 1][y + 1] + mine[x + 1][y] + mine[x][y + 1] - 8 * '0');
	int a = 0;
	for (int i = x - 1; i <= x + 1; i++)
	{
		for (int j = y - 1; j <= y + 1; j++)
		{
			a += mine[i][j];
		}
	}
	return a - '0' * 9;
}

int win = 0;
void arr(char mine[ROWS][COLS], char show[ROWS][COLS], int x,int y)
{

	if (show[x][y] == '*'&& x >= 1 && x <= ROW && y >= 1 && y <= ROW)
	{
		int count = GetMineCount(mine, x, y);
		show[x][y] = count + '0';
		win++;
		if (count == 0)
		{
			arr(mine, show, x - 1, y);
			arr(mine, show, x - 1, y - 1);
			arr(mine, show, x - 1, y + 1);
			arr(mine, show, x, y - 1);
			arr(mine, show, x, y + 1);
			arr(mine, show, x + 1, y - 1);
			arr(mine, show, x + 1, y + 1);
			arr(mine, show, x + 1, y);
		}
	}
}

void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int o)
{
	int x = 0, y = 0;
	while (win < row * col - EsayCount)
	{
		
		printf("请输入要排查的坐标(0 0重开):>");
		scanf("%d %d", &y, &x);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				DisPalyBoard(mine, ROW, COL, o);
                printf("你被炸死了!!!\n");
				break;
			}
			else
			{
				//该坐标不是雷,就得统计该坐标的周围有几个雷
				arr(mine, show, x, y);
				DisPalyBoard(show, ROW, COL, o);
			}
		}
		else if (x == 0 && y == 0)
		{
			printf("重新开始游戏。\n");
			break;
		}
		else
		{
			printf("坐标非法,请重新输入\a\n");
		}
	}
	if (win == row * col - EsayCount)
	{
		DisPalyBoard(mine, ROW, COL, o);
        printf("恭喜你,排雷成功\n");
	}
}

2.3 test.c文件

#include"game.h"

void menu()
{
	printf("----------------扫雷----------------\n");
	printf("|                                  |\n");
	printf("|              1.play              |\n");
	printf("|              0.exit              |\n");
	printf("|                                  |\n");
	printf("------------------------------------\n");
}

void game()
{
	int o = time(NULL);
	//存放布置好雷的信息
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };

	InitBoard(show, ROWS, COLS, '*');
	InitBoard(mine, ROWS, COLS, '0');
	//随机布置10个雷
	SetMine(mine, ROW, COL, o);
	//打印棋盘
	/*DisPalyBoard(mine, ROW, COL,o);*/
	DisPalyBoard(show, ROW, COL, o);

	//排查雷
	FindMine(mine, show, ROW, COL, o);
}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("游戏结束,退出游戏\n");
			break;
		default:
			printf("输入错误请重新输入\a\n");
		}
	} while (input);
	return 0;
}

2.4 效果图:

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

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

相关文章

HNU-编译原理-甘晴void学习感悟

前言 熬过煎熬的考试周、复习以及更加煎熬的等成绩&#xff0c;查到成绩的那一刻&#xff0c;心里还是挺开心的。 虽然我没有完全学懂这门课程&#xff0c;但我还是兢兢业业地通过了课程的考试&#xff0c;拿到了这门课程的认可。 记录一下自己对编译原理的学习感悟&#xf…

虹科分享丨汽车技术的未来:Netropy如何测试和确保汽车以太网的性能

来源&#xff1a;艾特保IT 虹科分享丨汽车技术的未来&#xff1a;Netropy如何测试和确保汽车以太网的性能 原文链接&#xff1a;https://mp.weixin.qq.com/s/G8wihrzqpJJOx5i0o63fkA 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; #汽车以太网 #车载网络 #Netropy …

【格密码基础】基于LWE问题的密码系统

目录 一. 介绍 二. LWE密码方案简单介绍 三. LWE经典归约 四. LWE性质 五. LWE的鲁棒性 一. 介绍 在2005年&#xff0c;Regev基于LWE问题提出了一个新的公钥密码方案。该方案可实现语义安全&#xff08;semantic security&#xff09;&#xff0c;其中误差率&#xff08;…

2023年我国民用无人机产业规模超过1200亿元,低空经济时代来临

2023年我国民用无人机产业规模超过1200亿元&#xff0c;低空经济时代来临 根据最新数据显示&#xff0c;2023年中国的民用无人机产业规模已经超过了1200亿元&#xff0c;稳居全球榜首。预计到2025年&#xff0c;这个数字将突破2000亿元&#xff0c;届时低空经济对国民经济的综…

SpringBoot 自定义Filter 提前返回 CORS 错误 处理前后端分离跨域配置无效问题解析

前言 浏览器有跨域限制&#xff0c;非同源策略 (协议、主机名或端口不同) 被视为跨域请求&#xff0c;解决跨域有跨域资源共享(CORS)、反向代理和 JSONP的方式。本篇通过 SpringBoot 的资源共享配置 (CORS) 来解决前后端分离项目的跨域&#xff0c;以及从原理上去解决跨域配置…

docker指令存档

目录 Docker 1、概念 2、架构图 3、安装 4、Docker怎么工作的&#xff1f; 5、Docker常用命令 帮助命令 镜像命令 1、查看镜像 2、帮助命令 3、搜索镜像 4、拉取镜像 5、删除镜像 容器命令 1、启动 2、查看运行的容器 3、删除容器 4、启动&停止 其他命令…

开始学习Vue2(axios和Vuex)

一、Axios 1、Axios 简介 Axios 是一个基于 promise 网络请求库 &#xff0c;作用于node.j s 和浏 览器中。它是 isomorphic 的(即同一套代码可以运行在浏览器 和 node.js 中)。在服务端它使用原生 node.js http 模块, 而在 客户端 (浏览端) 则使用 XMLHttpRequests。 …

滴滴开源小程序框架 Mpx 新特性:局部运行时能力增强

Mpx 是滴滴开源的一款增强型跨端小程序框架&#xff0c;自 2018 年立项开源以来如今已经进入第六个年头&#xff0c;在这六年间&#xff0c;Mpx 根植于业务&#xff0c;与业务共同成长&#xff0c;针对小程序业务开发中遇到的各类痛点问题提出了解决方案&#xff0c;并在滴滴内…

C语言实现插入排序算法(附带源代码)

插入排序 插入排序&#xff08;英语&#xff1a;Insertion Sort&#xff09;是一种简单直观的排序算法。它的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相应位置并插入。插入排序在实现上&#xff0c;通常…

【Vue3】计算属性computed和监听属性watch

目录 &#x1f449; computed &#x1f448; &#x1f40c;只读取不修改 ☃️既读取又修改 &#x1f449; watch &#x1f448; 1、监听 ref 基本类型 数据 2、监听 ref 对象类型 数据 3、监听 reactive 对象类型 数据 4、监听对象类型的某个属性 5、监视以上多个数据…

小程序 样式 WXSS

文章目录 样式 WXSS尺⼨单位样式导⼊选择器⼩程序中使⽤less 样式 WXSS WXSS( WeiXin Style Sheets )是⼀套样式语⾔&#xff0c;⽤于描述 WXML 的组件样式。 与 CSS 相⽐&#xff0c;WXSS 扩展的特性有&#xff1a; 响应式⻓度单位 rpx样式导⼊ 尺⼨单位 rpx &#xff08;…

08.Elasticsearch应用(八)

Elasticsearch应用&#xff08;八&#xff09; 1.为什么需要相关性算分 我们在文档搜索的时候&#xff0c;匹配程度越高的相关性算分越高&#xff0c;算分越高的越靠前&#xff0c;但是有时候我们不需要算分越高越靠前我们可能需要手动影响算分来控制顺序比如广告&#xff08…

数学建模学习笔记||一文了解美赛论文如何写作

目录 ​编辑 Title/标题 要求 形式 Summary Sheet/摘要 要求 三要素 书写特点 内容 开头段 中间段 格式 内容 结尾段 关键词 Contents/目录 Introduction/引言 Problem Background/问题背景 Restatement of the Problem/问题重述 Literature Review/文献综…

有向图的拓扑序列——拓扑排序

问题描述 什么是拓扑序列 若一个由图中所有点构成的序列 A 满足&#xff1a;对于图中的每条边 (x,y)&#xff0c;x 在 A 中都出现在 y 之前&#xff0c;则称 A 是该图的一个拓扑序列。图中不能有环图中至少存在一个点的入度为0 如何求拓扑序列&#xff1f; 计算出每个节点的…

将Python打包为exe+inno setup将exe程序封装成向导安装程序

为什么要打包&#xff1f; Python脚本不能在没有安装Python的机器上运行。如果写了一个脚本&#xff0c;想分享给其他人使用&#xff0c;可她电脑又没有装Python。如果将脚本打包成exe文件&#xff0c;即使她的电脑上没有安装Python解释器&#xff0c;这个exe程序也能在上面运行…

数据结构实验八:排序的应用

目录 一、实验目的 二、实验原理 1.直接插入排序 2.快速排序 三、实验内容 实验1 代码 截图 实验2 代码 截图 一、实验目的 1、掌握排序的基本概念&#xff1b; 2&#xff0e;掌握并实现以下排序算法&#xff1a;直接插入排序、快速排序。 二、实验原理 1.直接插…

RK3399ProD开发板的固件烧录实战

参考 Toybrick-开源社区-TB-RK3399ProD-RK3399ProD开发板的固件烧录教程 https://download.csdn.net/download/quantum7/88769396 环境 主机&#xff1a;win10 开发板&#xff1a;TB-RK3399ProD 烧录工具&#xff1a;FlashTool_CN\Windows\AndroidTool.exe 串口驱动&#xf…

14.5 Flash查询和添加数据库数据

14.5 Flash查询和添加数据库数据 在Flash与数据库通讯的实际应用中&#xff0c;如何实现用户的登录与注册是经常遇到的一个问题。登录实际上就是ASP根据Flash提供的数据查询数据库的过程&#xff0c;而注册则是ASP将Flash提供的数据写入数据库的过程。 1.启动Access2003&…

linux 查找文件或查找内容 (find grep)

一 linux 查找包含指定内容的文件&#xff1a; 在linux 有时我们只我知道内容但不知道文件在哪&#xff0c;可以使用find 与grep查找 例1 要查找指定目录&#xff08;默认包含子目录&#xff09;文件内容包含 xxx 的文件 find /etc/ -type f -exec grep -l "mysql"…

音频格式之AAC:(2)AAC封装格式ADIF,ADTS,LATM,extradata及AAC ES存储格式

系列文章目录 音频格式的介绍文章系列&#xff1a; 音频编解码格式介绍(1) ADPCM&#xff1a;adpcm编解码原理及其代码实现 音频编解码格式介绍(2) MP3 &#xff1a;音频格式之MP3&#xff1a;(1)MP3封装格式简介 音频编解码格式介绍(2) MP3 &#xff1a;音频格式之MP3&#x…