IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c语言实现扫雷(含循环递归展开) -> 正文阅读

[C++知识库]c语言实现扫雷(含循环递归展开)

c语言实现扫雷(含循环递归展开)

🍉博客主页: 🍁如风暖阳🍁

🍉欢迎点赞 👍 收藏 ?留言评论 📝私信必回哟😁

🍉本文由 【如风暖阳】 原创,首发于 CSDN🙉

🍉博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言

🍉博客中涉及源码及博主日常练习代码均已上传码云(gitee)

??前言??

本笔记通过c语言实现扫雷小游戏(包含递归展开)

游戏实现逻辑位于test.c文件,整个游戏头文件位于game.h,游戏进程的具体操作于game.c中实现。?

🍅1.游戏概述

该游戏有9*9个格子(在头文件game.h中玩家可通过改变ROW COL的值来改变棋盘行列数),格子中已随机布置生成10颗雷(玩家也可通过改变EASY_COUNT的值来自行改变雷的数目),test.c中的文件实时记录已经排查过的格子个数,当玩家把雷全部找出且没有选中雷时,游戏胜利,否则,游戏失败!

🍅2.游戏设计

本游戏代码设计通过两个棋盘来完成,在mine棋盘中存储雷的信息,0表示非雷,1表示为类;在show棋盘中初始状态全为’*‘,当玩家开始游戏后,排查出的不是雷的位置有两种情况,1是该位置为数字,即表示该位置周围的雷的数量,2是空格,即表示该位置周围没有雷

🍅3.代码实现

请读者先按照test.c文件来理清游戏逻辑,再去game.c文件中进一步探究步骤的具体实现(game.h只是头文件及函数的声明)

🍎?test.c

该文件的阅读请从main函数开始梳理游戏逻辑

#include"game.h"
void menu()
{
	printf("****************\n");
	printf("*****1.play*****\n");
	printf("*****0.exit*****\n");
	printf("****************\n");
}
void game()
{
    //定义两个棋盘
	char mine[ROWS][COLS] = { 0 };//mine棋盘存放雷的信息
	char show[ROWS][COLS] = { 0 };//show棋盘存放排查情况
    //以下五个函数的具体实现在game.c文件中
    //初始化棋盘
	initBoard(mine, ROWS, COLS, '0');//0为非雷,1为雷
	initBoard(show, ROWS, COLS, '*');//‘*’表示未知,‘ ’或‘数字’均表示周围8个格子雷的数量
	displayBoard(show, ROW, COL);//打印棋盘
	setMine(mine, ROW, COL);//随机设置雷
	fineBoard(mine, show, ROW, COL);//玩家扫雷
}
int main()
{
	system("color f4");//实现输出框背景及字体的颜色改变,具体实现见博主博客:https://editor.csdn.net/md/?articleId=121968165
	srand((unsigned int)time(NULL));//此处不做解释,后边解释
	int input = 0;
	do//设置循环,玩家选择是否游戏
	{
		menu();//菜单打印
		printf("请选择>\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("游戏开始\n");
			game();//玩家选择1则进入游戏
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
}

🍎?game.h(该文件只是头文件引用及函数的声明,无需过多阅读)

#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 EASY_COUNT 10
void initBoard(char board[ROWS][COLS], int rows, int cols, char set);
void displayBoard(char board[ROWS][COLS], int row, int col);
void setMine(char mine[ROWS][COLS], int row, int col);
void fineBoard(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

🍎?game.c

🍓initBoard(初始化棋盘)

两个棋盘传过来棋盘数组及行列数进行初始化,还有一个字符参数用set变量接受,mine棋盘全部初始化为‘0’,show棋盘全部初始化为‘*’

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

🍓displayBoard(棋盘打印)

该部分就是通过循环将棋盘打印,以下为样图

在这里插入图片描述

void displayBoard(char board[ROWS][COLS], int row, int col)
{
	printf("---------------------------\n");
	printf("---------------------------\n");
	int i, j;
	for (j = 0; j <= COL; j++)
	{
		printf("|---");
	}
	printf("|\n");
	for (i = 0; i <= COL; i++)
	{
		printf("| %d ", i);
	}
	printf("|\n");
	for (i = 0; i < ROW; i++) {

		for (j = 0; j <= COL; j++) {
			printf("|---");
		}
		printf("|\n");
		printf("| %d ", i + 1);
		for (j = 0; j < COL; j++) {
			printf("| %c ", board[i+1][j+1]);

		}
		printf("|\n");

	}
	for (j = 0; j <= COL; j++) 
	{
		printf("|---");
	}
	printf("|\n");
}

🍓setMine(随机安放雷在mine棋盘上)

count为雷的数量,玩家可通过更改game.h文件中EASY_COUNT的值来自行改变雷的数目

void setMine(char mine[ROWS][COLS], int row, int col)
{
	int x = 0, y = 0, count = EASY_COUNT;
	while (count)
	{//此处解释srand((unsigned int)time(NULL)),是为了返回时间戳以随机生成坐标,将该位置设置为雷
		x = rand() % row + 1;
		y = rand() % col + 1;
		if (mine[x][y] == '0')
		{//如果该位置为0,将该位置置为1,count-1,因为可能随机生成同样的数字,所以,循环次数>=count
			mine[x][y] = '1';
			count--;
		}
	}
}

🍓fineBoard(玩家扫雷)

实现这一步需要三个函数fineBoard,expandBoard,getCount来共同完成

🍑fineBoard
void fineBoard(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	printf("请输入你要排查的位置>\n");
	int x, y;
	int win = 0;//win的值实时记录已知非雷格子数,当win的值与row*col-EASY_COUNT值相等时,雷被排完,游戏结束
	while (win<row*col-EASY_COUNT)//设置循环让玩家进行排雷,不断增加win的值
	{
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入坐标合法性
		{
			if (mine[x][y] == '1')//若为1,即被炸
			{
				printf("很遗憾,你被炸死了!\n");
				displayBoard(mine, ROW, COL);
				break;
			}
			else
			{
				expandBoard(mine, show, x, y,&win);//该函数下边解释
				displayBoard(show, ROW, COL);
			}

		}
		else
		{
			printf("你输入的坐标非法,请重新输入\n");
		}
	}
	if (win ==  row * col - EASY_COUNT)
	{
		printf("恭喜你获得胜利!\n");
		displayBoard(mine, ROW, COL);
	}
}
🍑expandBoard(设置循环递归展开)

进入该函数是因为该位置不是雷才会进入,如果该位置周围有雷则该位置对应show棋盘变为数字,不会进入递归,若周围无雷则才会经过判断后进行递归展开

static void expandBoard(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y,int*win)
{//因为需要通过递归展开,所以递归的位置每次进入时先判断位置的合法性
	if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
	{
		if (show[x][y] == ' ' || show[x][y] != '*')
			return;//排除已经检查过的点,避免形成死递归
		else if (getCount(mine, x, y) != 0)//getCount()函数下边解释
		{//若该位置周围有雷也不会进行递归,该位置对应show棋盘变为数字,win的值+1(也是排查了一个位置的情况)
			show[x][y] = getCount(mine, x, y) + '0';
			(*win)++;
			return;
		}
		else//该位置周围雷数量为0时才会进入这一步
		{
			show[x][y] = ' ';//将该位置置为‘ ’,并让win+1
			(*win)++;
			for (int i = -1; i <= 1; i++)//设置循环将该位置所在九宫格的所有格子进行递归
			{
				for (int j = -1; j <= 1; j++)
				{//当i=0,j=0时不会进入递归,因为此时该位置在循环上边已经将其置为‘ ’,避免形成死递归
					expandBoard(mine, show, x + i, y + j, win);
				}
			}
		}
	}
}
🍑getCount(计算当前位置周围雷的数量)

通过设置循环将该位置的周围八个位置计算,因为棋盘数组为字符,则需要通过-‘0’将其转变为int型

static int getCount(char mine[ROWS][COLS], int x, int y)
{
	int i, j;
	int count = 0;
	for (i = -1; i <= 1; i++)//该循环将该位置所在九宫格进行排查
	{
		for (j = -1; j <= 1; j++)
		{
			count = count+mine[x + i][y + j]-'0';
		}
	}
	return count;
}

以下为game.c文件全部源码

#include"game.h"
void initBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			board[i][j] = set;
		}
	}
}
void displayBoard(char board[ROWS][COLS], int row, int col)
{
	printf("---------------------------\n");
	printf("---------------------------\n");
	int i, j;
	for (j = 0; j <= COL; j++)
	{
		printf("|---");
	}
	printf("|\n");
	for (i = 0; i <= COL; i++)
	{
		printf("| %d ", i);
	}
	printf("|\n");
	for (i = 0; i < ROW; i++) {

		for (j = 0; j <= COL; j++) {
			printf("|---");
		}
		printf("|\n");
		printf("| %d ", i + 1);
		for (j = 0; j < COL; j++) {
			printf("| %c ", board[i+1][j+1]);

		}
		printf("|\n");

	}
	for (j = 0; j <= COL; j++) 
	{
		printf("|---");
	}
	printf("|\n");
}
void setMine(char mine[ROWS][COLS], int row, int col)
{
	int x = 0, y = 0, count = EASY_COUNT;
	while (count)
	{
		x = rand() % row + 1;
		y = rand() % col + 1;
		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}
static int getCount(char mine[ROWS][COLS], int x, int y)
{
	int i, j;
	int count = 0;
	for (i = -1; i <= 1; i++)
	{
		for (j = -1; j <= 1; j++)
		{
			count = count+mine[x + i][y + j]-'0';
		}
	}
	return count;
}
static void expandBoard(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y,int*win)
{
	if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
	{
		if (show[x][y] == ' ' || show[x][y] != '*')//排除已经检查过的点
			return;
		else if (getCount(mine, x, y) != 0)
		{
			show[x][y] = getCount(mine, x, y) + '0';
			(*win)++;
			return;
		}
		else
		{
			show[x][y] = ' ';
			(*win)++;
			for (int i = -1; i <= 1; i++)
			{
				for (int j = -1; j <= 1; j++)
				{
					expandBoard(mine, show, x + i, y + j, win);
				}
			}
		}
	}
}
void fineBoard(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	printf("请输入你要排查的位置>\n");
	int x, y;
	int win = 0;
	while (win<row*col-EASY_COUNT)
	{
		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
			{
				expandBoard(mine, show, x, y,&win);
				displayBoard(show, ROW, COL);
			}

		}
		else
		{
			printf("你输入的坐标非法,请重新输入\n");
		}
	}
	if (win ==  row * col - EASY_COUNT)
	{
		printf("恭喜你获得胜利!\n");
		displayBoard(mine, ROW, COL);
	}
}

??最后的话??

总结不易,希望uu们不要吝啬你们的👍哟(^U^)ノ~YO!!如有问题,欢迎评论区批评指正😁
在这里插入图片描述

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-01-25 10:24:21  更:2022-01-25 10:24:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:48:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码