【C语言】扫雷游戏

news2024/11/15 4:56:48

这里写目录标题

  • 前言
  • 1.初始化棋盘
  • 2.展示棋盘
  • 3.布置雷
  • 4.开始扫雷
    • 4.1判断输赢
    • 4.2扫雷时连续性展开
    • 4.3展示玩法
  • 5.整体代码展示
    • 5.1 game.h头文件展示
    • 5.2 game.c源文件展示
    • 5.3 text.c源文件展示

所属专栏:C语言
博主首页:初阳785
代码托管:chuyang785
感谢大家的支持,您的点赞和关注是对我最大的支持!!!
博主也会更加的努力,创作出更优质的博文!!
关注我,关注我,关注我,重要的事情说三遍!!!!!!!!

前言

  • 我们的扫雷和三子棋也是有一点形同之处的。
  • 就比如我们写的菜单其实是形同的,这里就不多讲了。
  • 直接上菜单:
void menu()
{
	printf("***********************\n");
	printf("******** 1.play *******\n");
	printf("******** 0.exit *******\n");
	printf("***********************\n");
}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("开始游戏\n\n");
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
			printf("选择错误,请重新选择:>");
		default:
			break;
		}
	} while (input);
	return 0;
}
  • 这个可以说是一个模板了,我们之前写的猜数字游戏和三子棋游戏都是用到了这个模板的,现在我们的扫了游戏也用到了,可以说是固定搭配了,小伙伴们可以慢慢品味。

  • 再看我我们的引用的头文件:

#pragma once
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
//设置棋盘规格
#define ROW 9
#define COL 9

//扩大的棋盘
#define ROWS ROW+2
#define COLS COL+2

//雷的个数
#define MIN_NUM 10

1.初始化棋盘

  • 要先写出扫雷游戏,我们必须要先知道扫雷游戏的规则,这里相信大家都有过了解,所以这里就不做过多的解释。‘
    在这里插入图片描述
  • 如图这是一个简单的9×9的扫雷游戏,同样的要设计出一个二维数组。
  • 而以上图片的格子下面可能存放着雷,但是如果只有有一个二维数组的话,我们不但要存放我们用来遮挡雷的格子还有在各自下面存放我们的雷,似乎一个数组是不够用的。
  • 所以我们要定义两个二维数组,一个数组用来存放挡住雷的格子,另一个数组用来存放雷的个数。
  • 而我们就是通过两个数组之间的关联,通过布置雷数组来给布置格子的数组信息,从而达到我们想要的效果。
    在这里插入图片描述
  • 再看上面的图片我们看到了当我们点击不是雷的地方的时候,在有雷的地方的周围会有与之对应雷个数的数字,而这个范围是在以这个数字为中心,判读这个数周围8个格子有多少个雷。
  • 有了这个思路我们就可以一一遍历一个个格子的周围的8个格子,来判盘断雷的个数。
  • 但是是不是每个格子都可以判断上判断8次呢?

在这里插入图片描述

  • 如果是子在角上或者边边子上呢?还会判断8次吗。显然并不会,所以这里我们就想出了一个好办法,那就是在这个9×9的棋盘外边在加上一圈,让他每个格子都能遍历上8次。
    在这里插入图片描述
    于是我们就要定义两个数组:
	//存放雷的棋盘
	Initboard(min, ROWS, COLS,'0');
	//展示的棋盘
	Initboard(shar, ROWS, COLS,'*');

这里我们用字符’*'来当作我我们遮挡雷的格子,而我们布置了的棋盘用字符’0’初始化。

void Initboard(char board[ROWS][COLS], int rows, int cols, char ret)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			board[i][j] = ret;
		}
	}
}

2.展示棋盘

  • 这里要注意的就是,我们要的是9×9的棋盘,但是我们创建的时候是创建的11×11的,原因是我们在原来的期盼的周围有多加了两行两列,使其在吧遍历雷的个数的时候更方便。
  • 而我们创建出来的期盼的下标是0-10,而我们真正要的下标是1-9,所以我们在打印处期盼的时候得控制一下范围。
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	printf("--------扫雷游戏-------\n");
	int i = 0;
	for (i = 0; i <= row; i++)
	{
		printf("%d ", i);
		if (i == 0)
			printf("|");
	}
	printf("\n");
	for (i = 0; i <= row; i++)
	{
		printf("--");
		if (i == 0)
			printf("|");
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		printf("%-2d|", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}

}
  • 因为我们玩的时候是输入下标的,所以我们可以适当的给我们的棋盘添加一下行数和列数:
  • 展示效果
    在这里插入图片描述

3.布置雷

  • 我们布置雷的是放入字符’1’的,而我放置雷的坐标是随机的,这个时候又要用到我们的随机函数srand和rand()。
  • 同时对生成的随机数也是有要求的,就是不能越界。
void SetMin(char min[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int count = MIN_NUM;
	while (count)
	{
		x = rand() % row + 1;
		y = rand() % col + 1;
		//放置生成的随机数越界了。
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (min[x][y] == '0')
			{
				min[x][y] = '1';
				count--;
			}
		}
	}
	//这个是不用打印出来的,这里打印出来是观察一下我们布置雷有没有成功。
	//DisplayBoard(min, ROW, COL);
}

4.开始扫雷

4.1判断输赢

  • 我们赢的方式只有一种就是吧除雷以外的格子都排除了就赢了。
  • 也就是说我们要排除ROW*COL-MIN_NUM个格子才算赢了。
void PlayGame(char min[ROWS][COLS], char shar[ROWS][COLS], int row, int col)
{
	int win = 0;
	while (win<ROW*COL-MIN_NUM)
	{
		int x = 0;
		int y = 0;
		printf("请输入坐标,中间用空格隔开>:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
				if (min[x][y] == '1')
				{
					printf("抱歉,你被炸死了\n");
					//被炸死了,打印除布置雷的情况
					DisplayBoard(min, ROW, COL);
					break;
				}
				if (shar[x][y] != '*')
				{
					printf("输入坐标重已显示,请重新输入\n");
					break;
				}
				//x,y坐标不是雷
				spand(min, shar,x, y,ROW,COL, &win);
				DisplayBoard(shar, ROW, COL);
		}
		else
		{
			printf("输入坐标错误,请重新输入\n");
		}

		if (win == ROW * COL - MIN_NUM)
			printf("恭喜你,成功过关\n");
	}
}

4.2扫雷时连续性展开

  • 你有没有发现在我们玩扫雷的时候,有时候我们点了一个它就会给你蹦出来好多的没有雷的格子。
  • 而它的原理就是一个格子不是雷,而且这个格子周围的格子也没有雷就展开。
  • 所以这里我们就可以用到递归的思想。
  • 而递归的条件又三点
  1. 这个坐标不是雷。
  2. 这个坐标周围的坐标不是雷
  3. (重点)用过了坐标不需要再递归。
    其中第三点最为重要,如果处理不当的会很容易陷入死递归。
    及比如:
    在这里插入图片描述
    我们刚开始遍历了黄色的圈,以这个圈展开再以这个圈周围不是雷的坐标开始递归,我们拿出一个来讲,就比如上面的红色的圈。这个红色的圈不是雷我们又开始以这个红色的圈为中心,判断周围的坐标是不是雷,但是我们要知道的是我们的黄色的圈也是再红色圈的范围的,如果再次进行递归,这样就形成了死递归了。所以我们得外加一条判断语句。
void spand(char min[ROWS][COLS],char shar[ROWS][COLS], int x, int y,int row,int col, int* count)
{
	//防止越界
	if (x >= 1 && x <= row && y >= 1 && y <= col)
	{
		int ret = TheMieCount(min, x, y);
		if (ret == 0)
		{
			shar[x][y] = ' ';
			(*count)++;
			int i = 0;
			for (i = x - 1; i <= x + 1; i++)
			{
				int j = 0;
				for (j = y - 1; j <= y + 1; j++)
				{
					if (shar[i][j] == '*')//避免已经递归过的再次递归,以放置死递归
					{
						spand(min, shar, i, j, ROW, COL,count);
					}
				}
			}
		}
		else
		{
			shar[x][y] = ret + '0';
			(*count)++;
		}
	}
}

4.3展示玩法

5.整体代码展示

5.1 game.h头文件展示

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

#define ROW 9
#define COL 9

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

#define MIN_NUM 10
//初始化棋盘
void Initboard(char board[ROWS][COLS], int rows, int cols, char ret);
//展示棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);
//布置雷
void SetMin(char min[ROWS][COLS],int row,int col);
//开始扫雷
void PlayGame(char min[ROWS][COLS],char shar[ROWS][COLS],int rows,int cols);

5.2 game.c源文件展示

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

void Initboard(char board[ROWS][COLS], int rows, int cols, char ret)
{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			board[i][j] = ret;
		}
	}
}

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

}

void SetMin(char min[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int count = MIN_NUM;
	while (count)
	{
		x = rand() % row + 1;
		y = rand() % col + 1;
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (min[x][y] == '0')
			{
				min[x][y] = '1';
				count--;
			}
		}
	}
	//DisplayBoard(min, ROW, COL);
}
int TheMieCount(char min[ROWS][COLS], int x, int y)
{
	return (min[x - 1][y] + min[x - 1][y - 1] + min[x][y - 1] +
		min[x - 1][y + 1] + min[x + 1][y] + min[x + 1][y + 1] +
		min[x][y + 1]+min[x+1][y-1] - 8 * '0');
}

//实现扩展
void spand(char min[ROWS][COLS],char shar[ROWS][COLS], int x, int y,int row,int col, int* count)
{
	//防止越界
	if (x >= 1 && x <= row && y >= 1 && y <= col)
	{
		int ret = TheMieCount(min, x, y);
		if (ret == 0)
		{
			shar[x][y] = ' ';
			(*count)++;
			int i = 0;
			for (i = x - 1; i <= x + 1; i++)
			{
				int j = 0;
				for (j = y - 1; j <= y + 1; j++)
				{
					if (shar[i][j] == '*')
					{
						spand(min, shar, i, j, ROW, COL,count);
					}
				}
			}
		}
		else
		{
			shar[x][y] = ret + '0';
			(*count)++;
		}
	}
}
void PlayGame(char min[ROWS][COLS], char shar[ROWS][COLS], int row, int col)
{
	int win = 0;
	while (win<ROW*COL-MIN_NUM)
	{
		int x = 0;
		int y = 0;
		printf("请输入坐标,中间用空格隔开>:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
				if (min[x][y] == '1')
				{
					printf("抱歉,你被炸死了\n");
					DisplayBoard(min, ROW, COL);
					break;
				}
				if (shar[x][y] != '*')
				{
					printf("输入坐标重已显示,请重新输入\n");
					break;
				}
				//x,y坐标不是雷
				spand(min, shar,x, y,ROW,COL, &win);
				DisplayBoard(shar, ROW, COL);
		}
		else
		{
			printf("输入坐标错误,请重新输入\n");
		}

		if (win == ROW * COL - MIN_NUM)
			printf("恭喜你,成功过关\n");
	}
}

5.3 text.c源文件展示

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

void menu()
{
	printf("***********************\n");
	printf("******** 1.play *******\n");
	printf("******** 0.exit *******\n");
	printf("***********************\n");
}
void game()
{
	//初始化棋盘
	char min[ROWS][COLS];
	char shar[ROWS][COLS];
	//存放雷的棋盘
	Initboard(min, ROWS, COLS,'0');
	//展示的棋盘
	Initboard(shar, ROWS, COLS,'*');

	//打印棋盘
	//DisplayBoard(min, ROW, COL);
	DisplayBoard(shar, ROW, COL);

	//布置雷
	SetMin(min, ROW, COL);

	//开始玩,输入坐标
	//计算雷的个数
	PlayGame(min, shar, ROW, COL);
}
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("开始游戏\n\n");
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
			printf("选择错误,请重新选择:>");
		default:
			break;
		}
	} while (input);
	return 0;
}

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

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

相关文章

了解 XML结构(一)

文章目录 1 XML定义2 了解XML结构3 XML节点类型4 加载读取XML5 小结 1 XML定义 XML是一种可扩展标记语言&#xff08;Extensible Markup Language, XML&#xff09;,可以用来标记数据&#xff0c;定义数据类型&#xff0c;是一种允许用户对自己的标记语言进行定义的源语言。 …

数据治理是一个部门的工作还是全业务体系的工作?_光点科技

随着互联网时代的到来&#xff0c;数据已成为企业生产和经营的重要资源。但是&#xff0c;随着数据量的不断增加和数据形态的多样化&#xff0c;如何管理和利用数据也成为了企业面临的一个重要问题。在这个过程中&#xff0c;数据治理成为了一个备受关注的话题。 那么&#xff…

ChatGPT1论文解读《Improving Language Understanding by Generative Pre-Training》

论文总结 以下是我阅读完整篇论文做的个人总结&#xff0c;基本包含了chatGPT1设计的完整框架思路&#xff0c;可以仅看【论文总结】章节。 在GPT1实现的核心架构中&#xff0c;包含两个阶段。 第一阶段 在第一阶段基于一个包含7000本书籍内容的海量未标注文本数据集进行无…

IP-Guard能否支持通过审批后才能发送邮件?

支持,但目前暂时只支持带有附件的邮件通过申请审批或者自我备案放开策略控制发送出去。 使用方式: 1、申请审批:设置了禁止发送邮件的邮件控制策略后,在申请权限-发送邮件中,设置允许发送,设置相关审批流程,管理员审批完成后即可发送。 -申请权限-审批流程 2、自我备案:…

SSM框架学习-注解开发第三方bean管理

1. 复习xml配置文件管理第三方bean 在Spring中&#xff0c;可以使用依赖注入&#xff08;Dependency Injection&#xff09;来管理和使用第三方Bean。Spring提供了多种方式来进行依赖注入&#xff0c;比如构造函数注入、Setter方法注入、字段注入等。下面以Setter方法注入为例&…

pycharm 常用插件,常用插件推荐

1. Key Promoter X 如果让我给新手推荐一个 PyCharm 必装插件&#xff0c;那一定是 Key Promoter X 。 它就相当于一个快捷键管理大师&#xff0c;它时刻地在&#xff1a; 教导你&#xff0c;当下你的这个操作&#xff0c;应该使用哪个快捷操作来提高效率&#xff1f;提醒你…

Scala学习(二)

文章目录 1.Scala的运算符1.1 Scala中的equals和 2.流程控制2.1 if2.2 Scala中的三目运算符2.3 for循环 3.循环中断 1.Scala的运算符 1.1 Scala中的equals和 回顾Java中的运算符 equals和,equals比较的为值&#xff0c; 比较的为地址 String a1new String("hi");…

【数据结构】线性表——带头双向循环链表

文章目录 带头双向循环链表带头双向循环链表主体结构带头双向循环链表操作函数介绍带头双向循环链表操作函数实现带头双向循环链表的初始化函数&#xff1a;打印函数带头双向循环链表插入函数&#xff1a;指定结点后插入和查找函数头插尾插 带头双向循环链表删除函数指定结点删…

2022东南大学网安916专硕上岸经验帖

本文目录 第一部分简单介绍我的一些选择 第二部分寒假大三下学期小学期暑假及大四上学期考前准备及考试过程考后估分与真实分数复试准备与复试过程复试结果导师选择经验对自己考研情况的评价一些建议 第一部分 简单介绍 最近忙完了毕业设计论文和教师资格证面试&#xff0c;终…

pc端项目的h5页面运行在手机浏览器使用vconsole查看页面元素、控制台、请求等信息

文章目录 一、vconsole介绍1. 作用2. 优势 二、使用1、jq项目和js项目2、vue项目 三、使用介绍1. 使用成功&#xff0c;在页面右下角会出现如下图的vConsole2. 常用功能&#xff08;控制台、请求、元素、存储器&#xff09; 一、vconsole介绍 1. 作用 使用vconsole来查看h5页…

怎么自学python?为什么选择python

自然是因为Python简单易学且应用领域广 Python近段时间一直涨势迅猛&#xff0c;在各大编程排行榜中崭露头角&#xff0c;得益于它多功能性和简单易上手的特性&#xff0c;让它可以在很多不同的工作中发挥重大作用。 正因如此&#xff0c;目前几乎所有大中型互联网企业都在使…

python写完程序怎么运行

python有两种运行方式&#xff0c;一种是在python交互式命令行下运行; 另一种是使用文本编辑器直接在命令行上运行。 注&#xff1a;以上两种运行方式均由CPython解释器编译运行。 当然&#xff0c;也可以将python代码写入eclipse中&#xff0c;用JPython解释器运行&#xff0c…

ACM - 字符串 - 基础(KMP)

字符串 一、KMP1、模板题 HDU1711 Number Sequence2、求最大匹配数 Ⅰ&#xff1a; HDU 2087 剪花布条&#xff08;子串不重叠&#xff09;3、求最大匹配数 Ⅱ&#xff1a;AcWing 831. KMP字符串&#xff08;子串可重叠&#xff09;4、s2 是不是 s1 的翻转&#xff1a;Leetcode…

draw.io二次开发(3)从删删减减开始定制自己的drawio

经过克隆代码、配置IntelliJ/IDEA和Tomcat、以及本地部署&#xff08;详见前几篇&#xff09;之后&#xff0c;终于到了上手改代码的环节了。 首先需要强调的一点是&#xff1a;千万不要去改 *.min.js 文件中的代码&#xff0c;这些文件都是生成的压缩代码&#xff0c;我们一定…

MySQL原理(四):事务

前言 上一篇介绍了 MySQL 的索引&#xff0c;这一篇将介绍事务相关的内容。 在 MySQL 的使用场景中&#xff0c;经常会有一个操作包含多个 SQL 语句&#xff0c;比如转账这个操作&#xff0c;至少包含从甲的账户中扣除金额和给乙的账户中增加金额这两个更新语句。那假如 MySQ…

如何优化VPS服务器性能,提升网站访问速度?

随着互联网的发展&#xff0c;越来越多的企业开始使用VPS服务器来托管其网站。然而&#xff0c;一些企业经常会遇到网站速度慢、响应时间长等问题&#xff0c;这不仅会影响用户的体验&#xff0c;还会导致客户流失。因此&#xff0c;优化VPS服务器的性能&#xff0c;提升网站访…

好程序员:Java培训班包就业靠谱吗?Java培训机构怎么选?

好程序员本身就是培训机构&#xff0c;现在已经10年多了。说句实在话&#xff0c;包就业的机构几乎没有&#xff0c;凡是给你说包就业的机构大多都不靠谱。你还得看机构的培训能力和就业率&#xff0c;其实能否找到工作还得看你自己在培训班学的怎么样了对吧&#xff0c;找工作…

CIAA 网络安全模型 — TLS v1.3 和 HTTPS 协议

目录 文章目录 目录SSL/TLSTLS 1.21. client_hello2. server_hello server_certificate sever_hello_done3. Certificate authentication4. client_key_exchange change_cipher_spec encrypted_handshake_message5. change_cipher_spec encrypted_handshake_message TLS 1…

portraiture3.5.6免费版PS图片磨皮软件

Portraiture是专注于图像后期处理软件研发的 Imagenomic, LLC重头产品之一&#xff0c;在摄影爱好者中极负盛名。Portraiture 可以将繁琐复杂的人像磨皮操作极致简化&#xff0c;不论是普通爱好者或专业后期处理人员&#xff0c;均能一键完成&#xff0c;被称为人像磨皮神器。 …

1. 跨域学习

1. 跨域学习 1.1 什么是跨域 出于浏览器的同源策略限制。同源策略&#xff08;Sameoriginpolicy&#xff09;是一种约定&#xff0c;它是浏览器最核心也最基本的安全功能&#xff0c;如果缺少了同源策略&#xff0c;则浏览器的正常功能可能都会受到影响。可以说Web是构建在同…