C语言玩转小游戏(2)----扫雷小游戏


扫雷小游戏是我们经常在电脑上玩的一个小游戏,非常的考验人的耐心和智力,这次我们用C语言将其实现一下,因为我还没有掌握关于C语言插入图片或者用鼠标点击的阶段,因此这次只是实现一个比较基础的版本,后面会继续的完善。

概述

在电脑上的扫雷小游戏是分难度等级的,难度越高,棋盘越大,地雷的数量也就越多,因此我也按照这样的思路,设置了不同的难度和不同的地雷数,我将三个等级分别用不同的头文件和.c文件来写的,可能有些笨拙,但是我会随着知识的不断掌握,不断的去完善。

主函数

//菜单函数
void menu()
{
	printf("**********************************\n");
	printf("**********    1. play    *********\n");
	printf("**********    0. exit    *********\n");
	printf("**********************************\n");
}

int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;

	do
	{
		menu();
		printf("请输入选项:>\n");
		scanf("%d", &input);
		getchar();
		switch (input)
		{
		case 1:
		{
			char n = 0;
			printf("请选择难度:>\n");
			printf("l代表低级,m代表中级,h代表高级\n");
			scanf("%c", &n);
			switch (n)
			{
			case 'l':
				low_game();
				break;
			case 'm':
				middle_game();
				break;
			case 'h':
				high_game();
				break;
			}
			//game();
			break;
		}

		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误,请重新选择\n");
			break;
		}

	} while (input);

	return 0;

}

主函数包括了显示菜单和选择游戏难度,菜单函数比较简单,就是将选项打印出来。选项的选择和难度的选择是通过switch语句来实现的,我用了两个嵌套的switch语句来进行游戏选项和难度的选项。
这里不同的游戏难度对应不同的函数,三个难度的游戏函数整体上是一样的,我将其封装了三个不同的文件方便修改。

游戏函数

这里我只展示一下初级的游戏难度,其他的只是稍作改动,我会将源码放在GitHub中方便大家阅读。

整个玩游戏的思路是这样的:我们需要两个棋盘,一个用来放置地雷,另一个是将每一次玩家输入坐标之后的棋盘信息实时的显示出来。

首先我们需要将两个棋盘进行初始化,放置地雷的棋盘初始化为字符’0’,这样初始化的原因在后面详细解释,这有关排雷函数的方便运算;显示实时信息的棋盘初始化为字符‘ * ’,这样子可以使棋盘更像是扫雷小游戏的棋盘。

代码实现如下:

void low_InitBoard(char board[LOW_ROWS][LOW_COLS], int row, int col, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = set;//将数组定义初始化为想要的字符set
		}
	}
}

因为初始化的字符不同,为了能够整合在一个函数中,所以将要初始化的字符作为参数传给初始化函数。

打印函数

我们在初始化完成之后,要将展示实时信息的棋盘给玩家展示,因此需要一个打印函数。

代码实现:

void low_DisplayBoard(char board[LOW_ROWS][LOW_COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i <= row; i++)
	{
		if (0 == i)
		{
			printf("  ");
			continue;
		}
		printf("%d ", i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ", i);
		for (j = 1; j <= col; j++)
		{
			printf("%c ", board[i][j]);

		}
		printf("\n");
	}
}

为了方便玩家的坐标输入,我们在棋盘的周围对行和列进行了标识,增加了游戏的可玩性。

布雷函数

布置地雷我们用随机数来进行地雷坐标的选择,因为是随机数,所以每次玩游戏地雷的位置都是不同的,也就保证了游戏的可玩性。地雷用字符’1’来表示,具体原因同样在后面解释。

代码实现:

void low_Put_Mine(char board[LOW_ROWS][LOW_COLS], int row, int col)
{
	int count = EASY_COUNT;
	int x = 0;
	int y = 0;
	while (count > 0)
	{
		x = rand() % row + 1;
		y = rand() % col + 1;
		if (board[x][y] == '0')//只有防雷成功,count减一
		{
			board[x][y] = '1';
			count--;
		}
	}
}

这个里面有一点要注意,就是count变量是用来存放要布置的地雷数量的,每一次布置雷之后,count要减一,这里面需要一个判断,就是说当布置地雷的坐标是空的,才能够布置地雷成功,如果没有这个判断,布置雷的数量可能会有问题。

排雷函数

整个游戏的核心就是这个排雷函数,要根据玩家输入的坐标来判断该坐标周围的雷数并计算,然后返回给玩家,方便玩家根据这个信息来进行下一步的选择,因此,排雷是非常关键的,这个函数如果出错的话,就会给玩家错误信息,使游戏出现重大失误。

排雷的方法是这样的:就是计算输入坐标周围的8个地方的雷数,但是如何计算能够更加的方便呢?
这就是前面将地雷位置和非地雷位置设置为字符‘1’和字符‘0’的原因。我们在计算坐标周围的雷数时,可以将周围的8个坐标的所有字符加起来,然后减去8个字符‘0’,因为计算的时ASCII码值,这样子计算下来就可以计算出周围地雷的数量,非常的方便。如果设置为‘ * ’和‘ # ’,计算的话就要将8个位置都判断一次,就非常的没有效率。

代码实现:

void low_Sweep(char mine[LOW_ROWS][LOW_COLS], char show[LOW_ROWS][LOW_COLS], int x, int y)
{
	int count = 0;
	count = mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y - 1] +
		mine[x - 1][y] + mine[x + 1][y] + mine[x - 1][y + 1] +
		mine[x][y + 1] + mine[x + 1][y + 1] - 8 * '0';
	if (0 == count)
	{
		int i = 0;
		int j = 0;
		show[x][y] = ' ';
		for (i = -1; i <= 1; i++)
		{
			for (j = -1; j <= 1; j++)
			{
				//用两组for循环来进行递归,进入递归的条件是在数组能够到达的范围内,并且用show数组中*来减少已经遍历过的元素
				if ((x + i) >= 1 && (x + i) <= LOW_ROW && (y + j) >= 1 && (y + j) <= LOW_COL && show[x + i][y + j] == '*')
				{
					low_Sweep(mine, show, x + i, y + j);
				}
			}
		}
	}
	else
	{
		show[x][y] = count + '0';
	}
}

//对输入坐标周围的雷数进行计算
void low_Calu_Mine(char mine[LOW_ROWS][LOW_COLS], char show[LOW_ROWS][LOW_COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int count = row*col - EASY_COUNT;
	printf("请输入选择的坐标:\n");
	while (count)
	{
		scanf("%d%d", &x, &y);
		printf("\n");

		if (x >= 1 && x <= row&&y >= 1 && y <= col)
		{
			if (mine[x][y] == '1')
			{
				printf("很遗憾,此处有雷,光荣牺牲\n");
				low_DisplayBoard(mine, LOW_ROW, LOW_COL);
				break;
			}
			else
			{
				low_Sweep(mine, show, x, y);
				low_DisplayBoard(show, LOW_ROW, LOW_COL);
				count = low_get_mine(show, LOW_ROW, LOW_COL) - EASY_COUNT;
			}
		}
		else
		{
			printf("输入坐标错误,请重新输入\n");
		}
	}
	if (0 == count)
	{
		printf("排雷成功\n");
		low_DisplayBoard(mine, LOW_ROW, LOW_COL);
	}
}

再从函数内部详细的讲解一下:
1.在排雷函数的开始要让用户对坐标进行输入,输入这一块就要考虑几个问题。
首先是坐标的合法性,坐标的输入要在棋盘的范围之内,如果输入超出了边界,就要重新输入;并且扫雷游戏只需要玩家不断的输入坐标,然后电脑计算地雷数,输入是不间断的,直到玩家排雷成功或者踩到地雷才结束,因此输入这一块要用循环来完成。
2.排雷并不只是标识出输入的坐标周围的雷数,按照电脑上扫雷小游戏的玩法,要能够扩展出一片,如下图:
在这里插入图片描述

也就是说,如果输入的坐标周围没有地雷,就需要去遍历周围的8个位置,如果其中某一个位置的周围也没有地雷,那么就继续向外遍历,直到遇到一个坐标周围出现地雷,这部分需要用递归来完成。通俗点解释:就是如果计算出坐标周围地雷数是0,就去向外扩展。
在这部分编写的时候有一些复杂,主要问题就是:在向外扩展的时候,如果是边界的坐标,向外不断扩展就会导致数组越界,因此递归时需要有判断条件,就是遍历的数组坐标要限制在合理的范围内。
3.排雷的结果判定
踩到地雷很容易判断,就是输入坐标的所在是字符‘1’;
但是判断排雷成功就需要去遍历整个数组,每输入一次遍历一次数组,计算没有输入的坐标个数,直到没有输入的坐标个数变为0.就是说能够输入的坐标已经没有了,并且还没有踩到地雷,这就是排雷成功了。

运行结果

菜单界面
在这里插入图片描述

初级
在这里插入图片描述
中级
在这里插入图片描述
高级
在这里插入图片描述
踩到地雷
在这里插入图片描述
排雷成功
在这里插入图片描述

总结

这就是扫雷小游戏的基本思路,但是我认为还有一些地方可以改善:
1.现在只是最基本的程序,使用输入坐标来完成的,我觉得可以修改为用鼠标点击进行选择,这样子可以提高玩家的游戏体验。
2.我觉得如果可以上升到图形化界面,可以将字符‘0’和字符‘1’定义为其他的图案,不需要修改程序。

Github链接:https://github.com/YJYCXD/dream/tree/master/Hanoi

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值