【C语言】扫雷游戏(可展开)——超细教学

这篇具有很好参考价值的文章主要介绍了【C语言】扫雷游戏(可展开)——超细教学。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🚩纸上得来终觉浅, 绝知此事要躬行。
🌟主页:June-Frost
🚀专栏:C语言

🔥该篇将运用数组来实现 扫雷游戏。

🌟思路框架

测试

通过迭代保证每次玩完游戏后可以再来一局或者退出。

【C语言】扫雷游戏(可展开)——超细教学,c语言,c语言,游戏,学习,扫雷,数组


游戏

说明:

1 .  实现扫雷,首先需要布置雷,通过一个二维数组就可以很容易的将雷的信息存储下来。只需要将二维数组的元素赋予两个不同的值,例如,’1’ ——雷,’0‘ ——无雷,或者 ‘#’ ——雷,’ * ’ ——无雷,只不过这两种在后续排查雷中操作不同(通过一个循环前者可以加起来计算出周围有几个雷,后者可以通过比较来判定有多少雷)。

【C语言】扫雷游戏(可展开)——超细教学,c语言,c语言,游戏,学习,扫雷,数组
 如上图,对于 排查雷(周围有多少雷),如果只有一个数组,那么在周围如果只有一个雷的情况下(’1‘——表示雷,’0‘——表示无雷),该位置的数组元素就会被赋值为1,在最后展示棋盘的时候,这个1就会造成歧义,就会不知道这个’1‘究竟是雷,还是周围雷的个数。
所以,通过建立另一个数组,来记录周围雷的数量。
如图:
【C语言】扫雷游戏(可展开)——超细教学,c语言,c语言,游戏,学习,扫雷,数组

3.
【C语言】扫雷游戏(可展开)——超细教学,c语言,c语言,游戏,学习,扫雷,数组
但是我们可以将其逻辑统一:
【C语言】扫雷游戏(可展开)——超细教学,c语言,c语言,游戏,学习,扫雷,数组

  1.  为了简便操作,我们将两个数组规定为同类型同大小(两个都扩充一圈)。
  • 优点1:可以方便数组操作,下标一样,不需要重新计算对应数组元素的下标。
  • 优点2:同类型意味着可以使用同一个函数,不需要一个功能写两次。

【C语言】扫雷游戏(可展开)——超细教学,c语言,c语言,游戏,学习,扫雷,数组

每个部分都是单独的函数体,下面将会单独对每个函数体进行实现。


🌟测试部分函数实现

  • 选择是否玩游戏

 与三子棋一样,该板块的循环部分将会使用do while 循环来实现(保证一开始可以选择,运行完游戏部分后还可以继续选择)。

#define _CRT_SECURE_NO_WARNINGS 1
#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;
}

🌟 游戏部分函数实现

 首先我们根据游戏部分的思路框架,将整个游戏的逻辑写在game()函数中。
 前提:

#define ROW 9
#define COL 9

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

定义两种,可以在后续分别用于不同的函数。

  • 游戏逻辑
void game()
{
	char mine[ROWS][COLS] = { 0 };//存放雷
	char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
	//初始化
	InitBoard(mine, ROWS, COLS, '0');//都先初始化为无雷
	InitBoard(show, ROWS, COLS, '*');
	//布置雷
	SetMine(mine, ROW, COL);
	//打印第二个棋盘
	DisplayBoard(show, ROW, COL);
	//排查雷
	FineMine(mine, show, ROW, COL);
}
  • 初始化

 由于想使用一个函数就可以将两个棋盘初始化,所以在参数上需要增加一个变量用于接收初始化的值。

void InitBoard(char board[ROWS][COLS], int row, int col, char set)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			board[i][j] = set;
		}
	}
}
  • 布置雷

 前提:#define Set_Mine 10;//需要布置雷的数量
 布置雷是随机的,所以我们采用伪随机数,将下标在合法范围内随机,如果该坐标下是无雷的,就赋值‘1’,定为有雷。

void SetMine(char board[ROWS][COLS], int row, int col)
{
	int count = Set_Mine;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (board[x][y] == '0')
			{
				board[x][y] = '1';
				count--;//布置成功,雷数减少1
			}
		}
	}
}
  • 打印棋盘

 为了方便玩家定位坐标,在打印棋盘的时候,可以将行和列打印出来。并且展示出来的,是中间的区域(不展示扩容区域)

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	printf("--------扫雷游戏-------\n");
	int i = 0;
	for (i = 0; i <= col; i++)//打印列
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);//打印行
		int j = 0;
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}
  • 排查雷

计数:
【C语言】扫雷游戏(可展开)——超细教学,c语言,c语言,游戏,学习,扫雷,数组

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

排雷:

void FineMine(char mine[ROWS][COLS], char show[ROWS][COLS],int row,int col)
{
	int win = 0;//如果要赢 需要的有检查的次数,例如:9*9棋盘,有10个雷,检查出71个地区不是雷,就意味着获胜。
	while (win<ROW*COL-Set_Mine)
	{
		int x = 0;
		int y = 0;
		printf("请输入坐标,中间用空格:> ");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标合法
		{
			//踩到雷
			if (mine[x][y] == '1')
			{
				printf("很遗憾,已踩到雷\n");
				DisplayBoard(mine, ROW, COL);
				break;
			}
			//没猜到雷
			else
			{
				Unfold(mine,show, ROW, COL, x, y,&win);//递归展开
				DisplayBoard(show, ROW, COL);//展示棋盘
			}
		}
		else
		{
			printf("输入非法,需要重新输入\n");
		}

	}
	if (win == ROW * COL - Set_Mine)
	{
		printf("游戏获胜\n");
		DisplayBoard(mine, ROW, COL);
	}
}

展开:
【C语言】扫雷游戏(可展开)——超细教学,c语言,c语言,游戏,学习,扫雷,数组
如何实现上面的展开效果呢?
当我们点击一个坐标后,看是否满足3个条件:
1.这个坐标不是雷(如果按照博主的排雷逻辑,这个条件不需要判断,因为坐标下不是雷的时候才会调用展开函数)
2.周围没有雷
3.没有被递归过(防止死递归)
 这时被点击的地方就可以被赋值为空,并对周围的8个区块看是否符合这样的条件,8个区块也按照这个逻辑,如果满足三个条件,被赋空并且遍历周围,如果不满足就显示周围有多少雷,或者不做任何反应,按照这样的逻辑一直延续下去。这种情况我们可以使用递归去解决。

void Unfold(char mine[ROWS][COLS], char show[ROWS][COLS],int row,int col,int x,int y, int* count_w)
{
	if (x >= 1 && x <= row && y >= 1 && y <= col)//判断合法
	{
		if (!GetMineCount(mine, x, y) && show[x][y] != ' ')//周围没有雷并且该位置没有被递归过
		{
			show[x][y] = ' ';
			int i = 0;
			int j =0;
			int ret = 0;
			//直接遍历9个,至于中间的那个坐标,最后一个else if 会处理
			for (i = x - 1; i <= x + 1; i++)
			{
				for (j = y - 1; j <= y + 1; j++)
				{
					Unfold(mine, show, row,col,i, j, count_w);
					(* count_w)++;
				}
			}
		}
		else if (GetMineCount(mine, x, y))//周围有雷
		{
			int count = GetMineCount(mine, x, y);
			show[x][y] = count + '0';
			(* count_w)++;
		}
		else if (show[x][y] == ' ')//被递归过
		{
			;//不需要操作
		}
	}
	//不合法的函数不需要任何处理
}

这里需要判断合法性,因为扩容出去的那一圈的元素不可以递归,而且也不可以计算 (不然按照GetMineCount的逻辑会越界访问,而且就会可以计算出,也不会打印这个区域,所以可以直接不用管,递归这些地方的时候,函数会什么都不处理)。


🌟完整的代码

game .h

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

#define ROW 9
#define COL 9

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

#define Set_Mine 10//需要布置雷的数量
//游戏逻辑
void game();
//初始化
void InitBoard(char board[ROWS][COLS], int row, int col, char set);
//埋雷
void SetMine(char board[ROWS][COLS], int row, int col);
//展示棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col); 
//排雷
void FineMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

game .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 InitBoard(char board[ROWS][COLS], int row, int col, char set)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			board[i][j] = set;
		}
	}
}
//布置雷
void SetMine(char board[ROWS][COLS], int row, int col)
{
	int count = Set_Mine;
	while (count)
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (board[x][y] == '0')
			{
				board[x][y] = '1';
				count--;//布置成功,雷数减少1
			}
		}
	}
}
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	printf("--------扫雷游戏-------\n");
	int i = 0;
	for (i = 0; i <= col; i++)//打印列
	{
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);//打印行
		int j = 0;
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}
//计数
int GetMineCount(char board[ROWS][COLS], int x, int y)
{
	int i = x - 1;
	int j = y - 1;
	int ret = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
		for (j = y - 1; j <= y + 1; j++)
		{
			ret += board[i][j];
		}
	}
	return ret - 9 * '0';
}

//展开
void Unfold(char mine[ROWS][COLS], char show[ROWS][COLS],int row,int col,int x,int y, int* count_w)
{
	if (x >= 1 && x <= row && y >= 1 && y <= col)
	{
		if (!GetMineCount(mine, x, y) && show[x][y] != ' ')//周围没有雷并且该位置没有被递归过
		{
			show[x][y] = ' ';
			int i = 0;
			int j =0;
			int ret = 0;
			for (i = x - 1; i <= x + 1; i++)
			{
				for (j = y - 1; j <= y + 1; j++)
				{
					Unfold(mine, show, row,col,i, j, count_w);
					(* count_w)++;
				}
			}
		}
		else if (GetMineCount(mine, x, y))//周围有雷
		{
			int count = GetMineCount(mine, x, y);
			show[x][y] = count + '0';
			(* count_w)++;
		}
		else if (show[x][y] == ' ')//被递归过
		{
			;
		}
	}
}
//排雷
void FineMine(char mine[ROWS][COLS], char show[ROWS][COLS],int row,int col)
{
	int win = 0;
	while (win<ROW*COL-Set_Mine)
	{
		int x = 0;
		int y = 0;
		printf("请输入坐标,中间用空格:> ");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//踩到雷
			if (mine[x][y] == '1')
			{
				printf("很遗憾,已踩到雷\n");
				DisplayBoard(mine, ROW, COL);
				break;
			}
			//没猜到雷
			else
			{
				Unfold(mine,show, ROW, COL, x, y,&win);//递归展开
				DisplayBoard(show, ROW, COL);//展示棋盘
			}
		}
		else
		{
			printf("输入非法,需要重新输入\n");
		}

	}
	if (win == ROW * COL - Set_Mine)
	{
		printf("游戏获胜\n");
		DisplayBoard(mine, ROW, COL);
	}
}

//游戏逻辑
void game()
{
	char mine[ROWS][COLS] = { 0 };//存放雷
	char show[ROWS][COLS] = { 0 };//存放排查出的雷的信息
	//初始化
	InitBoard(mine, ROWS, COLS, '0');//都先初始化为无雷
	InitBoard(show, ROWS, COLS, '*');
	//布置雷
	SetMine(mine, ROW, COL);
	//打印第二个棋盘
	DisplayBoard(show, ROW, COL);
	DisplayBoard(mine, ROW, COL);
	//排查雷
	FineMine(mine, show, ROW, COL);
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"

int main()
{
	int input = 0;
	srand((unsigned)time(NULL));
	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;
}

❤️ 结语

文章到这里就结束了,如果对你有帮助,你的点赞将会是我的最大动力,如果大家有什么问题或者不同的见解,欢迎大家的留言~文章来源地址https://www.toymoban.com/news/detail-669876.html

到了这里,关于【C语言】扫雷游戏(可展开)——超细教学的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言小项目 -- 扫雷游戏完整代码(递归展开 + 选择标记)

    大家好,今天我们将一起用C语言实现一个经典小游戏 – 扫雷,Let is go ! 扫雷游戏相信大家都玩过,上图就是一个网页版的扫雷,它的规则是玩家选择一个方格,若此方格没有地雷,那么该方格会显示与它相邻的八个方格中雷的个数,若此方格有地雷,那么游戏失败,当玩

    2024年02月05日
    浏览(54)
  • C语言之扫雷小游戏的实现【含递归展开】

    扫雷游戏是1992年发行的一款大众类益智游戏,对于许多80后、90后来说都是童年的回忆。如今三十年过去了,这款游戏依旧受到很多网友的喜爱,今天我们一起来模拟实现一下扫雷游戏。 本文所用的编译器是VS2022 这里我们使用模块化设计,模块化设计就是把各个模块的代码分

    2024年02月02日
    浏览(53)
  • 【C语言】万字教学,带你分步实现扫雷游戏(内含递归函数解析),剑指扫雷,一篇足矣

    君兮_的个人主页 勤时当勉励 岁月不待人 C/C++ 游戏开发 Hello,这里是君兮_,今天更新一篇关于利用C语言实现扫雷游戏的博客。对于初学者来说,这也是一个非常容易上手的小项目,看完不妨自己试试哦! 废话不多说,我们直接开始吧! 相信很多人在小时候都玩过扫雷游戏,但

    2024年02月11日
    浏览(42)
  • C语言之详解数组【附三子棋和扫雷游戏实战】

    1、数组的创建 数组是一组相同类型元素的集合。 数组的创建方式: 首先我们就来看看数组如何创建~~ 对于整型、字符型、浮点型的数据可以创建 [] 内的数字便是这个数组的大小,表示这个数组中可以存放多少元素。 除了数字也可以是一个表达式放里面 虽然指定数组大小可

    2024年02月03日
    浏览(35)
  • 入门C语言第三话:数组之实战篇——扫雷(进阶版——图形化界面,递归展开,播放音乐与音效,标记取消雷,记录雷的个数,鼠标点击,文末附有完整代码)

     不为模糊不清的未来过分担忧,只为清清楚楚的现在奋发图强。  如果思路不是特别清晰的兄弟,建议多看一下基础版扫雷:数组之实战篇——带你从0到1实现扫雷(简易版)  如果EasyX图形库不是特别明白:可以看一下这篇文章:入门EasyX图形库(带你进入不一样的程序

    2024年02月09日
    浏览(46)
  • “纯C”实现——扫雷游戏(递归实现展开功能)

    📺游戏动画演示 🚀扫雷实现思路 🚀棋盘实现 🚀布置雷实现 🚀玩家扫雷实现 🚀带展开功能的扫雷 🚀小结语 🚗text.c文件 🚗game.h文件 🚗game.c文件 游戏实现完成的模样: 实现扫雷游戏的前提是要知道: 扫雷游戏的玩法 (会玩的跳过这步) 扫雷游戏也就是排雷,让玩家点

    2024年02月03日
    浏览(46)
  • 小游戏扫雷实现教学(详解)

    目录  【前言】 一、模块化程序设计(多文件编程)介绍 1.概述 2.传统编程的方式 3.模块化程序设计的方法 二、扫雷代码设计思路 三、扫雷代码设计 1.创建菜单函数  2.实现9x9扫雷 3.初始化棋盘  4.打印棋盘  5.随机布置雷的位置 6.排查雷的信息  7.回到步骤1,重新选择进入

    2024年02月12日
    浏览(36)
  • C语言实现扫雷(包含递归展开)

    目录 一:扫雷游戏的基础逻辑 二:关于扫雷相关的信息存储 三:游戏大体实现逻辑 四:具体实现 (1)初始化 (2)打印 (3)布置雷 (4)查雷 五:全部代码 (1)game.h (2)game.c (3)test.c 六:实际效果演示 扫雷游戏逻辑如下: 1. 游戏开始时,玩家将看到一个方格棋盘,每个方格上有一个数

    2024年02月05日
    浏览(42)
  • C语言初阶之扫雷代码详解(含递归展开)

    主要分为下面几个过程: 1、建立棋盘 2、初始化棋盘 3、设置棋盘雷数 4、打印棋盘 5、玩家找雷 6、判定胜负 文件名:game.h 代码如下: 在game头文件中,首先包含会使用到的库头文件,这里的ROW以及COL是雷区的行和列大小,也就是说这是玩家实际能看到的行数及列数,而RO

    2024年02月03日
    浏览(36)
  • C语言300行代码实现扫雷(可展开+可标记+可更改困难级别+内附图形界面版本)

    扫雷是一个经典的游戏,是一个益智类小游戏,在80、90年代曾风靡一时,当然现在也是十分受欢迎; 废话不多说; 让我们来了解一下如何用C语言去实现它吧!!!(❁´◡`❁) 运行环境:VS2019 图形化界面版本 先实现一个初级版本的: 1、我们得有一个9*9的棋盘; 2、我们在棋

    2024年01月25日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包