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++知识库]扫雷思路及代码

在有了制作三子棋的经验后,做起扫雷也更加得心应手了。

大致思路:

首先扫雷全部都不知道雷在哪里,然后选择一个位置(这时候就可以设计二维数组来实现了)后该位置会显示有多少个雷,没有踩到雷游戏继续(再一次进入循环),然后如果踩到雷游戏结束(结束跳出循环),而我们要使得知道玩家选择的位置有没有雷,要先埋雷(随机位置),而且玩家看到的是被蒙着的游戏棋盘,而玩家选择的位置要与我们埋雷的位置对应,所以这时候需要两个棋盘,一个是玩家看到的,一个是我们自己埋雷的(也是用来判断玩家选不选得到雷的棋盘)。

但是两个棋盘里面要放置什么类型的元素呢?

我们可以用0和1来表示有无雷,0就不是雷,1表示有雷,而这个0与1使用字符类型还是int类型?

若用int类型来表示有无雷,在后续我们排查周围一圈,若玩家选择了一个位置,其周围有一个雷,那么玩家选择的位置会显示int型数字1,但是同时我们的雷也是用int型1来表示,我们要怎么来分辨这两个1之中哪一个是雷呢?就如下图情况:

综上,为了避免有分不出来的情况,我们都用char类型来创造数组,以便后续在排查有无雷的时候不会分辨不出是雷还是雷的数量显示。

具体做法:

1.创造三个文件

创建三个文件,分别命名为game.h? ?game.c? ?text.c。

  • text.c用来测试游戏的进程。
  • game.c用来编写游戏实现所需要的函数。
  • game.h用来声明函数名。

这样分开编写能使我们的思路更加清晰,在之后有bug需要修改时也不会难以查找。

2.游戏进程

? ? ? Ⅰ:打印出游戏开始界面——menu()

? ? ? Ⅱ:若玩家选择开始游戏,则进入游戏,若选择退出,结束程序

? ? ? Ⅲ:创造两个棋盘,用char型二维数组表示。

? ? ? Ⅳ:将埋雷的棋盘初始化为‘0’,玩家看到的棋盘初始化为‘*’——initializedboard()? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?coverboard()

? ? ? Ⅴ:开始埋雷——set_mine()

? ? ? Ⅵ:打印coverboard()棋盘——displayboard()

? ? ? Ⅶ:让玩家选择位置并显示出其周围雷数,并判断是否踩雷以及游戏是否胜利,若踩雷或游戏? ? ? ? ? ? ? ?胜利,则结束此次游戏。

3.函数的具体实现

前提:在game.h内先设定以下常量:

//game.h
#include <stdio.h>
//这里设定左右上下都多一行是为了让玩家后续选择扫边边的雷也可以判断周围雷数
#define ROWS 11
#define COLS 11
//这里才是真实的棋盘大小
#define row 9
#define col 9

设置以下常量以便在之后调试程序是否成功的时候可以修改棋盘大小,以方便调试。

Ⅰ:制作游戏界面——menu()

? ? ?只需做出简单的页面即可,如下图:

由于玩家可能会重复游玩,界面可能要重复打印,为了方便使用,我们创造一个void函数来实现,代码如下:

void menu()//在text.c内
{
	printf("******************************\n");
	printf("*****       1.play       *****\n");
	printf("*****       0.exit       *****\n");
	printf("******************************\n");
}

?Ⅱ:让玩家选择是否开始游戏

打印出菜单后玩家可输入是否进行游戏,如果选择1,就进入游戏,如果选择0,就退出游戏,这个过程用switch来实现,又因为可能玩家玩完又要再玩一次,在整个过程用循环来实现,直至玩家选择0才跳出循环。

int main()//在text.c内
{
	srand((unsigned int)time(NULL));
	int input = 0;//创造一个变量,为之后跳出循环做准备
	do
	{
		menu();//打印菜单
		scanf("%d", &input);//这个过程让玩家选择,如果选1,打开开关1,进入游戏,若选择0,打印出游戏结束后同时变成while(0),跳出循环
		switch (input)
		{
		case 1:
		{
			game();//这个是选择1后才游戏实现的过程的函数,之后再实现。
			break;
		}
		case 0:
		{
			printf("游戏结束\n");
			break;
		}
		default://玩家有可能会输入错误,若输入的数既不是1也不是0就让循环重来一次。
		{
			printf("输入错误,请重新输入\n");
			break;
		}
		}
	} while (input);
	return 0;
}

这两步与上一三子棋案例无太多的不同。

Ⅲ:创造两个棋盘

在text.c里创建数组,这里我们创造的数组设置为全局,进入函数后再重新初始化就好,这样在以后如果需要修改数组样式便会十分方便。实现代码如下:

//text.c
#include <stdio.h>//引用头文件,以便之后用printf打印出菜单
#include "game.h"//引用game.h头文件,为了之后可使用常量ROWS COLS row col
char mineboard[ROWS][COLS] = { 0 };//放置雷的数组
char realboard[ROWS][COLS] = { 0 };//玩家看到的数组

Ⅳ:将埋雷的棋盘初始化为‘0’,玩家看到的棋盘初始化为‘*’

设置两个函数,名字分别为initializeboard()与coverboard(),前者实现全部初始化为‘0’,以便后续放置雷与检验雷,后者用来初始化数组为‘*’,让玩家看的一个棋盘。这两个函数都需要放在game()函数里,代表当游戏开始时,我们就开始创造这俩个棋盘。具体代码如下:

//text.c
void game()
{
	initializeboard(mineboard,row,col);
	coverboard(realboard, row, col);
}
//game.h
void initializeboard(char arr[ROWS][COLS], int rows, int cols);
void coverboard(char arr[ROWS][COLS], int rows, int cols);
//game.c
void initializeboard(char arr[ROWS][COLS], int rows, int cols)
{
	int i = 0;
	int j = 0;
//这里用for循环遍历数组里每一个元素,并将其元素替换为字符‘0’
	for (i = 0; i < ROWS; i++)
	{
		for (j = 0; j < COLS; j++)
		{
			arr[i][j] = '0';
		}
	}
}

void coverboard(char arr[ROWS][COLS], int rows, int cols)
{
	int i = 0;
	int j = 0;
//这里用for循环遍历数组里每一个元素,并将其元素替换为字符‘*’
	for (i = 0; i < ROWS; i++)
	{
		for (j = 0; j < COLS; j++)
		{
			arr[i][j] = '*';
		}
	}
}

Ⅴ:开始埋雷

设置一个void类型函数名为set_mine()的函数,用来随机放置雷(将雷位置换为字符‘1’),这时候就要使用到随机数,随机生成x,y数,并且让其在数组大小范围内,一直埋雷,直到埋雷数达到我们需要的数量(用while实现)。具体代码及分析如下:

//game.h
//用来声明函数先
void set_mine(char arr[ROWS][COLS], int rows, int cols);
//text.c
//这里要注意,生成随机数要引用两个库函数:<stdlib.h>和<time.h>
#include "game.h"
#include <stdlib.h>
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;
}
//game.c
void set_mine(char arr[ROWS][COLS], int rows, int cols)
{
	int num = 0;
//设置一个num值初始值为0,每次埋完一个雷,num的数量就加一,直至埋完十个雷
	while (num < 10)
	{
        //设置坐标
		int i = rand() % row + 1;
		int j = rand() % col + 1;
		if (arr[i][j] == '0')
		{
			arr[i][j] = '1';
			num += 1;
		}
	}
}

Ⅵ:打印coverboard()棋盘

设置一个void类型函数名为displayboard()的棋盘,实现把数组的每一个元素都打印出来,具体代码及解释如下:

//game.h
void displayboard(char arr[ROWS][COLS], int rows, int cols);
//text.c
void game()
{
	initializeboard(mineboard,row,col);
	coverboard(realboard, row, col);
	set_mine(mineboard, row, col);
}
//game.c
void displayboard(char arr[ROWS][COLS], int rows, int cols)
{
	int i = 0;
	int j = 0;
//这里打印出行数和列数,为了让玩家更加方便找坐标
	int heng = 0;
	int shu = 0;
	for (heng = 0; heng <= row; heng++)
	{
		printf("%d ", heng);//注意这里要打印出%d和一个空格,才会有比较整齐的排列效果
	}
	printf("\n");
	for (i = 1; i <= rows; i++)
	{
		printf("%d ", i);//注意这里要打印出%d和一个空格
		for (j = 1; j <= cols; j++)
		{
			printf("%c ", arr[i][j]);//注意这里要打印出%c和一个空格
		}
		printf("\n");//每把一行的元素全部打印完后换行再打印下一行
	}
}

Ⅶ:让玩家选择位置并显示出其周围雷数,并判断是否踩雷以及游戏是否胜利,若踩雷? ? ? ? ?或游戏胜利,则结束此次游戏。

如何排查周围雷数:

我们要让玩家重复输入坐标,每一次输入坐标之后,我们要判断玩家输入的坐标会不会超出棋盘的大小,然后通过坐标对应的位置在我们用来放雷数组元素的周围一圈的排查,找出周围有多少个字符‘1’,创建一个int变量用来存放雷数,当检测到周围的一个位置中有一个字符‘1’,我们就让这个变量+1,在排除完一圈后,我们要把最终得出来的周围雷数放入玩家输入的坐标中显示,那么最终要怎么让这个类型为int类型的变量放入char类型数组里呢?

这里有一个想了很久才想到的小方法:

int a= 10;? ? ‘10‘ = 10 + ’0‘? ? ? ?10 = ’10‘ - ’0‘

其实int类型与char类型本质上没有太大区别,都可以互相转换的,在观察ascll码后我们可以知道任何int类型数字的ascll码值,在加上char类型’0‘的ascll码值之后,最终打印出的字符都会变为其int类型时本身的数字。

这样我们将int类型与char类型之间的转换就完成啦~

如何判断游戏胜利(即扫完所有雷):

制作一个循环,同时创造一个变量,当我们每一次进入循环,这个变量就增加一次,一直到

进入次数 = 棋盘大小-总埋雷数 的时候,就告诉玩家游戏胜利并跳出循环,若过程中踩雷,就告诉玩家游戏失败并跳出循环,然后再一次调用之前敲出的display()函数将我们的埋雷版本棋盘给玩家展示后就结束本次游戏。

下面是Ⅶ部分的代码:

//text.c
game()
{
	int time = 0;
//创造一个变量time,每次扫出一个雷(若扫到雷就跳出循环了,time不会增加),time就加一,直至扫出目标数量的雷,游戏结束标志胜利
	do
	{
		k = playeract(mineboard, realboard, row, col);//若有雷返还整形0给循环使循环中止。
		displayboard(realboard, row, col);
		time += 1;
//判断字符‘0’的数量有没有到达棋盘格子数减去雷的数量,若有达到,则游戏胜利
		if (time == row*col-10)
		{
			printf("恭喜,游戏胜利!\n");
			break;
		}
		else if (k == 0)
		{
			displayboard(mineboard, row, col);
		}
	} while (k);//若有雷返还整形0给循环使循环中止。
}
//game.c
int playeract(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int rows, int cols)
{
	int x = 0;
	int y = 0;
	int num = 0;
	int m = 0;
	printf("请输入坐标:");
	while (1)
	{
		while (1)//这里利用循环,做到让玩家输入正确的坐标,如果不输入正确坐标,就无法跳出循环
		{
			scanf_s("%d %d", &x, &y);
			if ((x > 0) && (x <= row) && (y > 0) && (y <= col))
			{
				break;
			}
			else
			{
				printf("超出范围,请重新输入坐标:");
			}
		}
		if (arr1[x][y] == '0')//判断有没有雷,如果没有雷要把附近一圈的给显示出来
		{
			if (arr1[x - 1][y - 1] == '1')
			{
				m += 1;
			}
			if (arr1[x][y - 1] == '1')
			{
				m += 1;
			}
			if (arr1[x + 1][y - 1] == '1')
			{
				m += 1;
			}
			if (arr1[x - 1][y ] == '1')
			{
				m += 1;
			}
			if (arr1[x + 1][y] == '1')
			{
				m += 1;
			}
			if (arr1[x - 1][y + 1] == '1')
			{
				m += 1;
			}
			if (arr1[x][y + 1] == '1')
			{
				m += 1;
			}
			if (arr1[x + 1][y + 1] == '1')
			{
				m += 1;
			}
			arr2[x][y] = m+'0';//这里就将检测出的雷个数(int型)换成周围雷的个数(char型)
			num = 1;
			return 1;
		}
		if (arr1[x][y] == '1')
		{
			arr2[x][y] = '1';
			printf("扫到地雷,游戏结束\n");
			num = 0;
			return 0;
		}
	}
}
//game.h
int playeract(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int rows, int cols);

那么来看看最终的代码吧

//game.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROWS 11
#define COLS 11
#define row 9
#define col 9
void initializeboard(char arr[ROWS][COLS], int rows, int cols);
void displayboard(char arr[ROWS][COLS], int rows, int cols);
void set_mine(char arr[ROWS][COLS], int rows, int cols);
void coverboard(char arr[ROWS][COLS], int rows, int cols);
int playeract(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int rows, int cols);
//test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "game.h"
char mineboard[ROWS][COLS] = { 0 };
char realboard[ROWS][COLS] = { 0 };
void menu()
{
	printf("************************************\n");
	printf("********       1.play       ********\n");
	printf("********       0.exit       ********\n");
	printf("************************************\n");
}
void game()
{
	initializeboard(mineboard,row,col);
	coverboard(realboard, row, col);
	set_mine(mineboard, row, col);
	//displayboard(mineboard, row, col);
	//printf("\n");
	displayboard(realboard, row, col);
	int k = 0;
	/*k = playeract(mineboard, realboard, row, col);*/
	int time = 0;
	do
	{
		k = playeract(mineboard, realboard, row, col);
		displayboard(realboard, row, col);
		time += 1;
		if (time == row*col-10)
		{
			printf("恭喜,游戏胜利!\n");
			break;
		}
		else if (k == 0)
		{
			displayboard(mineboard, row, col);
		}
	} while (k);
	//if (k == 0)
	//{
	//	displayboard(mineboard, 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;
}
//game.c
#include "game.h"
#define _CRT_SECURE_NO_WARNINGS 1
void initializeboard(char arr[ROWS][COLS], int rows, int cols)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < ROWS; i++)
	{
		for (j = 0; j < COLS; j++)
		{
			arr[i][j] = '0';
		}
	}
}

void coverboard(char arr[ROWS][COLS], int rows, int cols)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < ROWS; i++)
	{
		for (j = 0; j < COLS; j++)
		{
			arr[i][j] = '*';
		}
	}
}



void displayboard(char arr[ROWS][COLS], int rows, int cols)
{
	int i = 0;
	int j = 0;
	int heng = 0;//
	int shu = 0;//
	for (heng = 0; heng <= row; heng++)//
	{
		printf("%d ", heng);
	}//
	printf("\n");//
	for (i = 1; i <= rows; i++)
	{
		printf("%d ", i);//
		for (j = 1; j <= cols; j++)
		{
			printf("%c ", arr[i][j]);
		}
		printf("\n");
	}
}

int playeract(char arr1[ROWS][COLS], char arr2[ROWS][COLS], int rows, int cols)
{
	int x = 0;
	int y = 0;
	//int num = 0;
	int m = 0;
	printf("请输入坐标:");
	while (1)
	{
		while (1)
		{
			scanf_s("%d %d", &x, &y);
			if ((x > 0) && (x <= row) && (y > 0) && (y <= col))
			{
				break;
			}
			else
			{
				printf("超出范围,请重新输入坐标:");
			}
		}
		if (arr1[x][y] == '0')//判断有没有雷,如果没有雷要把附近一圈的给显示出来
		{
			if (arr1[x - 1][y - 1] == '1')
			{
				m += 1;
			}
			if (arr1[x][y - 1] == '1')
			{
				m += 1;
			}
			if (arr1[x + 1][y - 1] == '1')
			{
				m += 1;
			}
			if (arr1[x - 1][y ] == '1')
			{
				m += 1;
			}
			if (arr1[x + 1][y] == '1')
			{
				m += 1;
			}
			if (arr1[x - 1][y + 1] == '1')
			{
				m += 1;
			}
			if (arr1[x][y + 1] == '1')
			{
				m += 1;
			}
			if (arr1[x + 1][y + 1] == '1')
			{
				m += 1;
			}
			arr2[x][y] = m+'0';//这里的‘0’应该被换成周围雷的个数
			//num = 1;
			return 1;
		}
		if (arr1[x][y] == '1')
		{
			arr2[x][y] = '1';
			printf("扫到地雷,游戏结束\n");
			//num = 0;
			return 0;
		}
	}
}

void set_mine(char arr[ROWS][COLS], int rows, int cols)
{
	int num = 0;
	while (num < 10)
	{
		int i = rand() % row + 1;
		int j = rand() % col + 1;
		if (arr[i][j] == '0')
		{
			arr[i][j] = '1';
			num += 1;
		}
	}
}

又是收获满满的一天~

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-14 21:25:37  更:2021-11-14 21:28:24 
 
开发: 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 7:57:08-

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