扫雷小游戏 万字全网最详细(可展开一片空白)

扫雷对初学者来说是一个比较困难的小程序,今天的文章就教大家如何独立做出自己的扫雷游戏,如果您认为我写的不错,请给小陈点赞,收藏加关注,话不多说,让我们开始!

1.游戏的整体思路 

一个较为复杂的小程序一般有着不同的文件来负责不同的功能。我们只需要运用几个算法模块来实现,会分成game.h,test.c,game.c等几个模块来运行,为了方便可以创建多个项目来实现。我们这里需要新建三个文件。

1. test.c 负责游戏整体流程的实现

2. game.c 负责游戏内部复杂函数的实现

3. game.h 负责包含所有函数所需的头文件

需要注意的是,game.c和test.c文件创建时选择c++文件,而game.h选择头文件 


2.游戏菜单的创建

 首先是游戏菜单的创建

int main()
{
	int input;
	do
	{   
		scanf("%d", &input);
		switch (input)//用1来表示开始游戏,用0来表示退出游戏
//这样做的好处是,当输入为0时,input的值判断为假,则直接跳出循环
		{
		case 1:
		    game();
			break;
		case 0:printf("游戏结束\n");
			break;
		default:printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

只是这样太过单调,我们加入可视化的菜单,为此我们单独创建menu函数

void menu()
{
	printf("**************************\n");
	printf("********  1 play  ********\n");
	printf("********  0 exit  ********\n");
	printf("**************************\n");
}
int main()
{
	int input;
	
	do
	{   menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
		    game();
			break;
		case 0:printf("游戏结束\n");
			break;
		default:printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

3.棋盘的初始化

想要做出扫雷,首先要做出扫雷的底盘,它应该有以下的两个功能。

1.读取输入的排雷位置,并判断该位置有没有雷

2.在读取位置之后,在没爆炸的情况下显示出周围8个格子雷的个数

为了打印出棋盘,和三子棋类似,我们可以使用喜闻乐见的二维数组,如果我们想要实现9x9的扫雷游戏,难道我们要创建9x9的二维数组吗?答案是否定的,至于原因:

程序需要判断周围8个格子所含雷的个数,假如选择9X9的二维数组,在输入边缘位置时就会有数组越界的现象。那我们就要在9X9的边界多上一圈元素,也就要定义11X11的数组元素,

多出来的部分需要打印吗?答案是否定的,我们自己心里知道有这部分就行。

在game.h文件中定义行和列 ,在test.c中完成对数组的定义。

#define COLS 11
#define ROWS 11
#define EASY_COUNT 10//下面会讲
char mine[COLS][ROWS], show[COLS][ROWS];

在show数组中,用字符‘0’表示无雷区域,用字符‘1’表示有雷区域

在mine数组中,用’✳‘来覆盖然后来排雷,之后用数字来取代,数字代表其周围的雷的个数


3.1函数部分

我们使用InitBoard函数来打印出棋盘。

    void InitBoard(char a[COLS][ROWS], int col, int row, char set);
    InitBoard(mine, COLS, ROWS, '*');
	InitBoard(show, COLS, ROWS, '0');
void InitBoard(char a[COLS][ROWS], int col, int row, char set)
{
	int i, j;
	for (i = 0;i <=col;i++)
	{
		for (j = 0;j <=row;j++)
		{
			a[i][j] = set;
		}
	}
}

为了同时照顾到两个数组,我们定义出set,为两个数组分配不同的符号。

3.2棋盘的打印

我们定义出DisplayBoard函数来完成棋盘的打印,并贴心地打印出行号和列号 

void DisplayBoard(char a[COLS][ROWS], int col, int row)
{
	int i, j;
	printf("********扫雷*******\n");
	for (i = 0;i < 10;i++)
	{
		printf("%d ", i);//行号
	}printf("\n");
	for (i = 1;i < 10;i++)
	{
		printf("%d ", i);//列号
		for (j = 1;j < 10;j++)
		{
			printf("%c ", a[i][j]);
		}
		printf("\n");
	}
}

 打印出来的效果就是这样。


4.下棋功能的实现

打印出棋盘之后,接下来就轮到下棋的功能了。

为了实现其中的rand()函数,我们需要引用时间戳,在test.c文件中引用时间戳。

int main()
{
	int input;
	srand((unsigned int)time(NULL));//时间戳
	do
	{   menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
		    game();
			break;
		case 0:printf("游戏结束\n");
			break;
		default:printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

并在game.h中包含所需头文件

#include<stdlib.h>
#include<time.h>

接着是玩家下棋的部分。

void BreakBoard(char mine[COLS][ROWS],char show[COLS][ROWS], int col, int row)
{
	int x, y, set, k = 0;
	do
	{
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if (show[x][y] == '1')
			{
				DisplayBoard(show, COLS, ROWS);//打印棋盘让人死的明白
				printf("很遗憾,你被炸死\n");
				break;
			}
			else
			{
				open(mine, show, x, y);
				DisplayBoard(mine, COLS, ROWS);
				printf("未发现危险\n");
				k++;
			}
		}
		else
		{
			printf("重新输入\n");
		}
if (k == 71)
	{
		printf("恭喜你,扫雷成功!\n");
		break;
	}
	} while (k<=71);
	
}

 假设一共有10个雷,我们总共循环71=81-10次,当我们已经循环了71次后,就代表我们已经将所有非雷区域全部排除了,我们在前面定义了一个k如果我们排对了就++,当达到了71次就代表我们已经将所有非雷区域全部排除了,紧接着打印扫雷成功。


其中的open函数在下面讲解。

5.设计随机雷

我们设置雷的个数为10个。

其EASY_COUNT,在上面的宏定义部分有讲到,意思是我们选择了简单模式。

我们使用使用srand和rand函数生成随机数,使得雷的分布为随机位置。

void SetMine(char a[COLS][ROWS], int col, int row)
{
	int set = EASY_COUNT;
	do
	{
		int x = rand() % col + 1;
		int y = rand() % row + 1;//产生1~9的数字
		a[x][y] = '1';
		set--;
	} while (set != 0);
}

在show数组中,用字符‘0’表示无雷区域,用字符‘1’表示有雷区域,

至于rand函数,我在 “ 三子棋 ” 和 “ 猜数字 ”的博客中都有提到,大家可以去看看,支持一下,蟹蟹大家!!

6.统计周围雷的个数

int FindMine(char a[COLS][ROWS], int x, int y)
{
	return (a[x - 1][y - 1] + a[x - 1][y] + a[x - 1][y + 1] + a[x][y - 1] + a[x][y + 1] + a[x + 1][y - 1] + a[x + 1][y] + a[x + 1][y + 1] - 8 * '0');
}

show数组是字符类型的数组,我们将周围8格的数字加起来再减去8个字符零,就能得到雷数目。 

通过它统计已选位置周围八个位置中含有雷的个数,并在该位置上数字的形式打印出来。

7.当周围无雷时展开空白

 倘若我们只能一个一个格子来点,那会使游戏非常复杂,为此,当一个格子周围没有雷时,我们需要让它展开一片空白。我们将用递归来实现这样的操作。

void open(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	if (x >= 1 && x <= ROWS-2 && y >= 1 && y <= COLS-2)
	{
		int count = FindMine(show, x, y);
		if (count != 0) 
		{
			mine[x][y] = count + '0';//如果该格子周围雷的个数不为0,我们就把该格子周围雷的个数传到玩家玩的show棋盘对应的格子中,而如果是0,我们传入空格‘ ’ 
		}
		else if (mine[x][y] != ' ')
		{
			mine[x][y] = ' ';
			int i = 0;
			for (i = x - 1; i <= x + 1; i++)
			{
				int j = 0;
				for (j = y - 1; j <= y + 1; j++)
				{
					
					open(mine, show, i, j);//不停调用函数,直到周围有雷为止
				}
			}
		}
		else
				{
					return;
				}
	}
}

接下来让我们快乐地来上一局!

 

 接下来就愉快地被炸死了,过程太惨,就不发了。


最后,总结一下各部分文件。

game.h

#pragma once
#define COLS 11
#define ROWS 11
#define EASY_COUNT 10
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void InitBoard(char a[COLS][ROWS], int col, int row, char set);
void DisplayBoard(char a[COLS][ROWS], int col,int row);
void SetMine(char a[COLS][ROWS], int col, int row);
void BreakBoard(char mine[COLS][ROWS],char show[COLS][ROWS], int col, int row);
int FindMine(char a[COLS][ROWS], int col, int row);
void menu();
void open(char mine[COLS][ROWS],char show[COLS][ROWS], int col, int row);

 game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void InitBoard(char a[COLS][ROWS], int col, int row, char set)
{
	int i, j;
	for (i = 0;i <=col;i++)
	{
		for (j = 0;j <=row;j++)
		{
			a[i][j] = set;
		}
	}
}
void DisplayBoard(char a[COLS][ROWS], int col, int row)
{
	int i, j;
	printf("********扫雷*******\n");
	for (i = 0;i < 10;i++)
	{
		printf("%d ", i);
	}printf("\n");
	for (i = 1;i < 10;i++)
	{
		printf("%d ", i);
		for (j = 1;j < 10;j++)
		{
			printf("%c ", a[i][j]);
		}
		printf("\n");
	}
}
void SetMine(char a[COLS][ROWS], int col, int row)
{
	int set = EASY_COUNT;
	do
	{
		int x = rand() % col + 1;
		int y = rand() % row + 1;
		a[x][y] = '1';
		set--;
	} while (set != 0);
}
void BreakBoard(char mine[COLS][ROWS],char show[COLS][ROWS], int col, int row)
{
	int x, y, set, k = 0;
	do
	{
		scanf("%d%d", &x, &y);
		
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			
			if (show[x][y] == '1')
			{
				DisplayBoard(show, COLS, ROWS);
				printf("很遗憾,你被炸死\n");
				break;
			}
			else
			{
			
				open(mine, show, x, y);
				DisplayBoard(mine, COLS, ROWS);
				printf("未发现危险\n");
				k++;
			
			}
		}
		else
		{
			printf("重新输入\n");
		}
if (k == 71)
	{
		printf("恭喜你,扫雷成功!\n");
		break;
	}
	} while (k<71);
	
}
int FindMine(char a[COLS][ROWS], int x, int y)
{
	return (a[x - 1][y - 1] + a[x - 1][y] + a[x - 1][y + 1] + a[x][y - 1] + a[x][y + 1] + a[x + 1][y - 1] + a[x + 1][y] + a[x + 1][y + 1] - 8 * '0');
}

void open(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
	if (x >= 1 && x <= ROWS-2 && y >= 1 && y <= COLS-2)
	{
		int count = FindMine(show, x, y);
		if (count != 0) 
		{
			mine[x][y] = count + '0';
		}
		else if (mine[x][y] != ' ')
		{
			mine[x][y] = ' ';
			int i = 0;
			for (i = x - 1; i <= x + 1; i++)
			{
				int j = 0;
				for (j = y - 1; j <= y + 1; j++)
				{
					
					open(mine, show, i, j);
				}
			}
		}
		else
				{
					return;
				}
	}
}

 test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void game()
{
	char mine[COLS][ROWS], show[COLS][ROWS];
	
	InitBoard(mine, COLS, ROWS, '*');
	InitBoard(show, COLS, ROWS, '0');
	DisplayBoard(mine, COLS, ROWS);
	SetMine(show, COLS-2, ROWS - 2);
	//DisplayBoard(show, COLS, ROWS);
	BreakBoard(mine,show, COLS-2, ROWS-2);
	open(mine, show, COLS - 2, ROWS - 2);
}
void menu()
{
	printf("**************************\n");
	printf("********  1 play  ********\n");
	printf("********  0 exit  ********\n");
	printf("**************************\n");
}
int main()
{
	int input;
	srand((unsigned int)time(NULL));
	do
	{   menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
		    game();
			break;
		case 0:printf("游戏结束\n");
			break;
		default:printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

如果您觉得我写得好,不妨给我点赞,关注来鼓励我,我一定会继续努力的!

咱们下次再见!

 

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈大大陈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值