扫雷-包含空白展开,标记功能,游戏界面优化-控制台全力复刻

目录

引入

思路

涉及头文件索引

主函数

分支函数功能实现

代码总和---CV可游玩

引入

这两天偶然间玩到了扫雷的游戏,下的是微软旗下的扫雷,感觉比起以前简陋的界面好了太多

扫雷-包含空白展开,标记功能,游戏界面优化-控制台全力复刻_第1张图片

感觉扫雷找到规律也可以玩的很有意思,仔细一想,扫雷不就一二维数组,给我也完全可以实现啊。便开始了我的设计扫雷之旅。 

由于本人想兼顾扫雷的灵活性和与原版的功能相似性,我还是花了些时间去完善这些功能,标题也说了,包括空白展开,标记等。以下开始我们的讲解吧!

思路

主要思路是创建两个数组,一个用来记录扫雷的后台数据包括:雷的位置,并记录各个位置周围雷的数量。一个用来展示玩家能看到的界面--展示界面,根据玩家输入展示想给其展示的内容,我画张图来方便大家理解

用户输入一个地址,就将后台数组的数据传入展示数组并打印,这样就完成了对格子的探测。

如果选中的是雷,则判断游戏结束并退出,这样实现了失败的判定。

如果 总格子个数-排除的非雷个数=等于雷的个数,则完成了游戏胜利的判断。

如果选中的是0,则用一个递归函数展开,则完成了空白展开的功能。

将展示的内容根据传入地址将*改成$,则完成了对未知位置的标记。

以上便是主要的代码功能概述,下面详细讲解。

涉及头文件索引

在进行讲解之前,我想做一个多数博主都不会做的事,就是,把用到的较生僻头文件和功能都简单介绍下,见代码

#include
//输入输出头文件,这个都懂

#include
//srand生成种子和rand生成随机数的头文件
//rand生成的随机数是与srand生成的种子有关,而srand随机生成的种子又与time(NULL)有关

#include
//调用函数time()生成时间戳以及调用Sleep()函数表示停留时间

#include
//调用system("cls");函数,作用是清屏

 以上内容如果不太懂的朋友强烈建议专门去看看相关内容,了解透这些运用之后,相信一定会更容易理解我的调用。那么开始我们的代码内容吧!

主函数

这里直接把代码放到下面,旁边有注释,还是比较好理解的

#define _CRT_SECURE_NO_WARNINGS
#include "mine_sweep.h"//头文件和函数声明太多我就单独创了个头文件放进去了
int main()
{
	int x = 0, y = 0;//关于游戏界面大小——行-列
	char mine[105][105];//后台界面
	char show[105][105];//展示界面
	srand((unsigned int)time(NULL));//随机生成种子
	int input = 0;
	int digit_m = 10;//雷数量
	do {
	input=menu();//打印菜单
	if (input == 1) {
		printf("开始");
		printf("\n请输入扫雷棋盘大小(长:宽):");
		scanf("%d%d", &x, &y);
		printf("\n请输入设置雷的个数:");
		scanf("%d", &digit_m);
		Initboard(x, y, mine, '0');//初始化棋盘--后台区
		Initboard(x, y, show, '*');//初始化棋盘--展示曲
		Init_mine(x, y, mine,show, digit_m);//初始化雷
		playgame(x, y, digit_m, mine, show);//游戏运行函数
		Sleep(15000);	//结束界面展示停留
	}
	else if (input == 0);
	else { printf("输入错误"); Sleep(1000); }
	system("cls");	//清屏
	} while (input);//判断是否继续
	printf("退出游戏");
	return 0;
}

 分支函数功能实现

菜单函数

int menu()
{
	printf("************************\n");
	printf("******欢迎来到扫雷******\n");
	printf("*****   1.开始玩   *****\n");
	printf("*****              *****\n");
	printf("*****    0.退出    *****\n");
	printf("************************\n");
	printf("请选择:");
	int m;
	scanf("%d", &m);
	return m;
}

 也没啥好说的,就展示菜单以及一个返回值,通过返回值判断是否继续游戏

 初始化棋盘函数

初始化棋盘函数对后台和展示棋盘都适用,根据传入的参数初始化相应的二维数组,见代码

void Initboard(int x,int y,char arr[105][105],char ch)
{
	for (int i = 0; i <= x+1; i++)
		for (int j = 0; j <= y+1; j++)
			arr[i][j] = ch;//将数组各个元素初始化为ch
}

初始化雷函数

雷的初始化就涉及到随机生成数字和种子了,随机生成种子在主函数中已经提前完成,在这里就只用 生成随机数就行,不过建议也要注意一下生成特定随机数范围的方式,见代码

void Init_mine(int x, int y, char mine[105][105],char show[105][105], int digit)
{
	int mine_x, mine_y;
	for (int i = 0; i < digit; i++) {//随机生成数字
	start:;
		mine_x = rand() % x + 1;
		mine_y = rand() % y + 1;
		if (mine[mine_x][mine_y] == '0')//防止两个雷生成在同一位置
			mine[mine_x][mine_y] = '*';
		else goto start;
	}
	for (int i = 1; i <= x; i++) {//处理雷周围的数字,放到mine中,便于后期调用
		for (int j = 1; j <= y; j++) {
			if (mine[i][j] == '*')continue;
			if (mine[i - 1][j] == '*')mine[i][j]++;
			if (mine[i + 1][j] == '*')mine[i][j]++;
			if (mine[i][j + 1] == '*')mine[i][j]++;
			if (mine[i][j - 1] == '*')mine[i][j]++;
			if (mine[i - 1][j - 1] == '*')mine[i][j]++;
			if (mine[i + 1][j - 1] == '*')mine[i][j]++;
			if (mine[i - 1][j + 1] == '*')mine[i][j]++;
			if (mine[i + 1][j + 1] == '*')mine[i][j]++;
		}
	}
}

建议大家都注意下后台数组的处理方式,对编写扫雷代码很有帮助,方便处理数据 

游戏运行函数

其实也没有多复杂,就是对两个数组的处理而已,见代码

void playgame(int x, int y, int digit_m, char mine[105][105], char show[105][105])
{
	int x1, y1, judge;
	int m = 0;
	int* blank = &m;
	while (*blank < x * y - digit_m) {
		system("cls");
		Showboard(x, y, show);
		printf("或者输入标记的格子(1 行 列)\n");
		printf("请输入要探测格子的位置(0 行 列):");
		scanf("%d%d%d", &judge, &x1, &y1);
		if (mine[x1][y1] == '*'&&judge!=1) { *blank = 0; break; }
		else if (x1<1 && x1>x && y1<1 && y1>y) {
			printf("\n输入错误,请重新输入!");
			continue;
		}
		if (judge == 0) {
			blank_unfold(x, y, x1, y1, mine, show, blank);
		}
		else if (show[x1][y1] != '*' && judge == 1) { printf("已展示格子不可标记!"); Sleep(1500); }
		else if (judge == 1)show[x1][y1] = '$';
		else { printf("输入错误!"); Sleep(1500); }
	}
	system("cls");
	Showboard(x, y, mine);
	if (*blank) { 
		win_maliao();
	}
	else { 
		printf("\n踩到雷了,游戏结束!\n");
		printf("15秒后返回初始界面。\n");
	}
}

其中还涉及到了胜利界面展示,展示界面函数和空白展开函数,下面进行讲解

界面展示函数

 对于界面的展示还是很重要的,有时一个游戏的美观与舒适与否很大程度决定了一个游戏的品质,见代码

void Showboard(int x, int y, char arr[105][105])
{
	printf("%d |", 0);
	for (int i = 1; i <= y; i++)
		printf(" %d |", i);
	printf("\n");
	for (int i = 0; i <= y; i++)
		printf("----");
	printf("\n");
	for (int i = 1; i <= x; i++) {
		printf("%d ", i);
		
		for (int j = 1; j <= y; j++) {
			if (arr[i][j] == '*' || arr[i][j] == '$')
				printf("| %c ", arr[i][j]);
			else printf("| %d ", arr[i][j] - '0');
		}
		printf("|");
		printf("\n");
		for (int b = 0; b <= y; b++)
			printf("----");
		printf("\n");
	}
}

主要用|和-符号来优化界面,最后的效果是这样的,见下图

扫雷-包含空白展开,标记功能,游戏界面优化-控制台全力复刻_第2张图片

空白展开函数

空白展开在这里算是个拓展功能,不实现的话其实也玩的动,但是有的话会大大提高其可玩性,主要运用到函数的递归,由于有标记功能,这里的代码也需要有一定改动,见代码

void blank_unfold(int x, int y, int x1, int y1, char mine[105][105], char show[105][105], int* blank)
{
	if (x1<1 || x1>x || y1<1 || y1>y)return;//当输入超出范围时返回
	if (show[x1][y1] == '0' || (show[x1][y1] != '*' && show[x1][y1] != '$'))
        return; //在位置已被探测时返回
	else if (mine[x1][y1] != '0') {//在位置不是空白时展开返回
		show[x1][y1] = mine[x1][y1];
		(*blank)++;
		return;
	}
	else {    //递归同时将空白展开
		show[x1][y1] = '0';
		(*blank)++;
		blank_unfold(x, y, x1 - 1, y1, mine, show,blank);
		blank_unfold(x, y, x1 + 1, y1, mine, show,blank);
		blank_unfold(x, y, x1, y1 - 1, mine, show,blank);
		blank_unfold(x, y, x1, y1 + 1, mine, show,blank);
		blank_unfold(x, y, x1 - 1, y1 - 1, mine, show, blank);
		blank_unfold(x, y, x1 - 1, y1 + 1, mine, show, blank);
		blank_unfold(x, y, x1 + 1, y1 - 1, mine, show, blank);
		blank_unfold(x, y, x1 + 1, y1 + 1, mine, show, blank);
	}
}

彩蛋函数(胜利界面展示) 

皮一下,闲着的时候弄得马里奥,胜利的时候免费批发

void win_maliao()
{
	printf("\n恭喜获得胜利!\n");
	printf("送你个马里奥\n");
	printf("                ********\n");
	printf("               ************\n");
	printf("               ####....#.\n");
	printf("             #..###.....##....\n");
	printf("             ###.......######              ###            ###\n");
	printf("                ...........               #...#          #...#\n");
	printf("               ##*#######                 #.#.#          #.#.#\n");
	printf("            ####*******######             #.#.#          #.#.#\n");
	printf("           ...#***.****.*###....          #...#          #...#\n");
	printf("           ....**********##.....           ###            ###\n");
	printf("           ....****    *****....\n");
	printf("             ####        ####\n");
	printf("           ######        ######\n");
	printf("##############################################################\n");
	printf("#...#......#.##...#......#.##...#......#.##------------------#\n");
	printf("###########################################------------------#\n");
	printf("#..#....#....##..#....#....##..#....#....#####################\n");
	printf("##########################################    #----------#\n");
	printf("#.....#......##.....#......##.....#......#    #----------#\n");
	printf("##########################################    #----------#\n");
	printf("#.#..#....#..##.#..#....#..##.#..#....#..#    #----------#\n");
	printf("##########################################    ############\n");
	printf("15秒后返回初始界面。\n");
}

 代码总和---CV可游玩

到这里差不多就要结束了,以上代码涉及了很多头文件,想来整合运行会比较困难,这些工作我就代大家做了,也是希望大家能玩玩我编的扫雷,见代码

#include//各种头文件
#include
#include
#include
#include
void Initboard(int x,int y, char arr[105][105],char ch);//初始棋盘函数
void Showboard(int x, int y, char arr[105][105]);//打印界面函数
int menu();//菜单初始化函数
void Init_mine(int x, int y, char arr[105][105],char show[105][105], int digit);//随机初始化雷函数
void playgame(int x,int y,int digit_m, char mine[105][105], char show[105][105]);//游戏运行函数
void blank_unfold(int x, int y, int x1, int y1, char mine[105][105], char show[105][105],int* blank);//空白展开函数
void win_maliao();//胜利界面展示
void Initboard(int x,int y,char arr[105][105],char ch)
{
	for (int i = 0; i <= x+1; i++)
		for (int j = 0; j <= y+1; j++)
			arr[i][j] = ch;
}
void Showboard(int x, int y, char arr[105][105])
{
	printf("%d |", 0);
	for (int i = 1; i <= y; i++)
		printf(" %d |", i);
	printf("\n");
	for (int i = 0; i <= y; i++)
		printf("----");
	printf("\n");
	for (int i = 1; i <= x; i++) {
		printf("%d ", i);
		
		for (int j = 1; j <= y; j++) {
			if (arr[i][j] == '*' || arr[i][j] == '$')
				printf("| %c ", arr[i][j]);
			else printf("| %d ", arr[i][j] - '0');
		}
		printf("|");
		printf("\n");
		for (int b = 0; b <= y; b++)
			printf("----");
		printf("\n");
	}
}
int menu()
{
	printf("************************\n");
	printf("******欢迎来到扫雷******\n");
	printf("*****   1.开始玩   *****\n");
	printf("*****              *****\n");
	printf("*****    0.退出    *****\n");
	printf("************************\n");
	printf("请选择:");
	int m;
	scanf("%d", &m);
	return m;
}
void Init_mine(int x, int y, char mine[105][105],char show[105][105], int digit)
{
	int mine_x, mine_y;
	for (int i = 0; i < digit; i++) {
	start:;
		mine_x = rand() % x + 1;
		mine_y = rand() % y + 1;
		if (mine[mine_x][mine_y] == '0')
			mine[mine_x][mine_y] = '*';
		else goto start;
	}
	for (int i = 1; i <= x; i++) {
		for (int j = 1; j <= y; j++) {
			if (mine[i][j] == '*')continue;
			if (mine[i - 1][j] == '*')mine[i][j]++;
			if (mine[i + 1][j] == '*')mine[i][j]++;
			if (mine[i][j + 1] == '*')mine[i][j]++;
			if (mine[i][j - 1] == '*')mine[i][j]++;
			if (mine[i - 1][j - 1] == '*')mine[i][j]++;
			if (mine[i + 1][j - 1] == '*')mine[i][j]++;
			if (mine[i - 1][j + 1] == '*')mine[i][j]++;
			if (mine[i + 1][j + 1] == '*')mine[i][j]++;
		}
	}
}
void playgame(int x, int y, int digit_m, char mine[105][105], char show[105][105])
{
	int x1, y1, judge;
	int m = 0;
	int* blank = &m;
	while (*blank < x * y - digit_m) {
		system("cls");
		Showboard(x, y, show);
		printf("或者输入标记的格子(1 行 列)\n");
		printf("请输入要探测格子的位置(0 行 列):");
		scanf("%d%d%d", &judge, &x1, &y1);
		if (mine[x1][y1] == '*'&&judge!=1) { *blank = 0; break; }
		else if (x1<1 && x1>x && y1<1 && y1>y) {
			printf("\n输入错误,请重新输入!");
			continue;
		}
		if (judge == 0) {
			blank_unfold(x, y, x1, y1, mine, show, blank);
		}
		else if (show[x1][y1] != '*' && judge == 1) { printf("已展示格子不可标记!"); Sleep(1500); }
		else if (judge == 1)show[x1][y1] = '$';
		else { printf("输入错误!"); Sleep(1500); }
	}
	system("cls");
	Showboard(x, y, mine);
	if (*blank) { 
		win_maliao();
	}
	else { 
		printf("\n踩到雷了,游戏结束!\n");
		printf("15秒后返回初始界面。\n");
	}
}

void blank_unfold(int x, int y, int x1, int y1, char mine[105][105], char show[105][105], int* blank)
{
	if (x1<1 || x1>x || y1<1 || y1>y)return;
	if (show[x1][y1] == '0' || (show[x1][y1] != '*' && show[x1][y1] != '$'))return;
	else if (mine[x1][y1] != '0') {
		show[x1][y1] = mine[x1][y1];
		(*blank)++;
		return;
	}
	else {
		show[x1][y1] = '0';
		(*blank)++;
		blank_unfold(x, y, x1 - 1, y1, mine, show,blank);
		blank_unfold(x, y, x1 + 1, y1, mine, show,blank);
		blank_unfold(x, y, x1, y1 - 1, mine, show,blank);
		blank_unfold(x, y, x1, y1 + 1, mine, show,blank);
		blank_unfold(x, y, x1 - 1, y1 - 1, mine, show, blank);
		blank_unfold(x, y, x1 - 1, y1 + 1, mine, show, blank);
		blank_unfold(x, y, x1 + 1, y1 - 1, mine, show, blank);
		blank_unfold(x, y, x1 + 1, y1 + 1, mine, show, blank);
	}
}
void win_maliao()
{
	printf("\n恭喜获得胜利!\n");
	printf("送你个马里奥\n");
	printf("                ********\n");
	printf("               ************\n");
	printf("               ####....#.\n");
	printf("             #..###.....##....\n");
	printf("             ###.......######              ###            ###\n");
	printf("                ...........               #...#          #...#\n");
	printf("               ##*#######                 #.#.#          #.#.#\n");
	printf("            ####*******######             #.#.#          #.#.#\n");
	printf("           ...#***.****.*###....          #...#          #...#\n");
	printf("           ....**********##.....           ###            ###\n");
	printf("           ....****    *****....\n");
	printf("             ####        ####\n");
	printf("           ######        ######\n");
	printf("##############################################################\n");
	printf("#...#......#.##...#......#.##...#......#.##------------------#\n");
	printf("###########################################------------------#\n");
	printf("#..#....#....##..#....#....##..#....#....#####################\n");
	printf("##########################################    #----------#\n");
	printf("#.....#......##.....#......##.....#......#    #----------#\n");
	printf("##########################################    #----------#\n");
	printf("#.#..#....#..##.#..#....#..##.#..#....#..#    #----------#\n");
	printf("##########################################    ############\n");
	printf("15秒后返回初始界面。\n");
}
int main()
{
	int x = 0, y = 0;
	char mine[105][105];//后台界面
	char show[105][105];//展示界面
	srand((unsigned int)time(NULL));
	int input = 0;
	int digit_m = 10;
	do {
	input=menu();//打印菜单
	if (input == 1) {
		printf("开始");
		printf("\n请输入扫雷棋盘大小(长:宽):");
		scanf("%d%d", &x, &y);
		printf("\n请输入设置雷的个数:");
		scanf("%d", &digit_m);
		Initboard(x, y, mine, '0');//初始化棋盘--后台区
		Initboard(x, y, show, '*');//初始化棋盘--展示曲
		Init_mine(x, y, mine,show, digit_m);//初始化雷
		playgame(x, y, digit_m, mine, show);//游戏运行函数
		Sleep(15000);	//结束界面展示
	}
	else if (input == 0);
	else { printf("输入错误"); Sleep(1000); }
	system("cls");	//清屏
	} while (input);//判断是否继续
	printf("退出游戏");
	return 0;
}

运行截图

 扫雷-包含空白展开,标记功能,游戏界面优化-控制台全力复刻_第3张图片

本篇文章已经代码制作编写不易,还请大家在走之前给一个小小的赞啊!!!

如果对你有帮助的话,别忘了放收藏夹关注我哦--比心(> - < )---♥

同时如果博主的文章有任何错误,都欢迎在评论区提出来,我会积极去改,也感谢大家对我的支持捏。

 

 

你可能感兴趣的:(游戏,c语言)