[ C语言 ] 扫雷 ——> 用C语言实现game2


前言

本篇文章使用C语言实现简单小游戏---扫雷。(文章最后有完整代码链接

想必大多数人都玩过或者了解过扫雷的游戏规则,但是在这里,我们在一起重温一下扫雷的游戏规则,也更好的让我们了解程序的实现目的。

扫雷:扫雷就是要把所有非地雷的格子揭开即胜利;踩到地雷格子就算失败。游戏主区域由很多个方格组成。使用鼠标左键随机点击一个方格,方格即被打开并显示出方格中的数字;方格中数字则表示其周围的8个方格隐藏了几颗雷。

在了解游戏规则后,我们就用C语言来实现这个简单小游戏。

这是我们解决资源管理器内所创建的文件,下来我们就进入代码内部。


一,游戏使用到的头文件和游戏声明

1.头文件的包含

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

2.符号的声明

#define ROW 9
#define COL 9

#define ROWS ROW+2
#define COLS COL+2

#define EASY_COUNT 10

3.函数的声明

初始化棋盘

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 FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row,int col);

二,游戏测试

1. 主函数

和三子棋一样,主函数仍然简单,函数内部调用test()测试函数。

int main()
{
    test();

    return 0;

}

2.test()函数

void test()
{
	int input = 0;
	srand((unsigned int )time(NULL));
	do
	{
		menu();// 游戏菜单
		printf("请选择>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			// 扫雷游戏
			game();
			break;
		case 0:
			printf("退出游戏n");
			break;
		default:
			printf("选择错误n");
			break;
		}
	} while (input);

}

解析test()函数内部:

A. srand((unsigned int )time(NULL))  

利用时间戳,形成随机数,主要目的是实现游戏中地雷的随机埋放。

B.menu() 游戏菜单

void menu()// 游戏菜单
{
	printf("********************n");
	printf("****  1. play  *****n");
	printf("****  0. exit  *****n");
	printf("********************n");
}

创建菜单,实现效果演示:

 C:switch case 选择语句:

使用此语句实现玩家的自主选择,当输入1时进行扫雷游戏,当输入0时,退出游戏。显示效果如下:

     

3.game()函数

game()函数是主要游戏实现函数,以下是game函数主要是实现逻辑图和实现顺序

 这里先让大家看一下完整代码,实现顺序如上所示:

下面主要进入我们的游戏实现逻辑当中......划重点

三,游戏实现

1.创建棋盘

// 创建数组
	// 创建雷的数组(mine)   显示的数组(show)    两个数组一样规模 一样类型
	char mine[ROWS][COLS] = { 0 }; // 存放布置好的雷的信息
	char show[ROWS][COLS] = { 0 }; // 存放排查出的雷的信息

在这里我们需要创建2个相同大小,相同类型的二维数组。

问:我们为什么要创建2个相同的数组呢?
答:是因为我们在玩扫雷的时候我们首先看到的是一个未知得棋盘,不知道哪里埋放着雷,如果我们触碰到雷结束游戏后,我们需要给玩家呈现这局游戏所有点位的情况,这样以便于玩家清楚所有雷都在那里,为什么死,因此我们需要两个棋盘才能完成这项任务。

在这里我们创建了11X11大小的棋盘,但是只显示9X9大小的棋盘也就是81个格子,打算埋放10颗雷,玩家可以在头文件自行更改雷的个数。

问:我们显示9X9大小的棋盘,为什么创建11X11大小的棋盘?

答:这是因为扫雷游戏规则中,我们在排雷的过程中,会显示周围8个格子的雷的个数,如果创建一个9X9的格子,那当我们在边角的时候,我们周围的格子不够8个,但是我们还要访问周围8个格子,这时候我们必然会造成数组越界问题,具体情况如下图所示,这时候我们如果创建11X11的棋盘,对11X11的棋盘都初始化为字符' 0 ', 我们只显示内部的9X9的格子,我们依然不会影响游戏,并且也解决了数组越界的问题。

如图所示,我们假设要查找坐标为(9,9)格子周围8个格子的雷的个数,如果我们还只是9X9的格子,我们图中的红色阴影区域就处于数组的范围之外,因为我们需要创建11X11的棋盘,就可以轻松化解这个问题。

2.初始化棋盘

    // 初始化mine数组为全'0'
	InitBoard(mine,ROWS,COLS,'0');//初始化--->棋盘函数
	// 初始化show数组为全'*'
	InitBoard(show,ROWS,COLS,'*');//初始化--->棋盘函数

和三子棋一样,我们依然自定义函数InitBoard(),具体代码如下:

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

在这里我们对第一块mine棋盘全部初始化为字符 ' 0 ' (注意这里是字符0,不是数字0),我们对第二块show棋盘全部初始化为字符' * ' ,最终玩家首先会看到一幅全是字符' * '的棋盘,这样也符合游戏规则。

3.打印棋盘

自定义函数DisplayBoard(),具体代码如下:

void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0, j = 0;
	//列号的打印
	for (i = 0; i <= col; i++)
	{
		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");
	}
}

这样通过调用DisplayBoard()函数我们可以检查一下,我们刚才所创建和初始化的棋盘是否符合我们的要求,我们打印棋盘演示如下:

 我们发现,打印出来的棋盘也完全符合我们的要求,我们也只需要最终将show棋盘显示给玩家即可。

4.布置雷

在这里我们自定义函数SetMine()函数,具体代码如下:

// 布置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
	int count = EASY_COUNT;

	while (count) 
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;

		if (mine[x][y] == '0')
		{
			mine[x][y] = '1';
			count--;
		}
	}
}

我们对此代码进行分析:

A:如何实现随机布雷?

答:我们创建rand函数,利用时间戳生成随机数,因为我们所创建的棋盘大小是9X9大小,我们我们只需要给生成的随机数模上row(col)即可得到0~row-1 ,因此我们再 +1 即可得到一个在0~row(col)的随机数,从而实现随机布雷。

我们设定count个雷,如果我们埋下一颗雷,我们就count-1,同时我们将初始化的字符' 0 ' 变成字符' 1 ' , 只有我们识别到目标格子是字符 ' 0 ' 时才会埋雷,这也解决了在同一位置重复埋雷的问题。 

假设我们随机埋下10颗雷,演示一下棋盘:

 我们发现,我们随机埋下了10颗雷,并且也改成了字符' 1 '

5.排雷

自定义函数FindMine(),具体代码如下所示:

// 排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0, y = 0;
	int win = 0;
	while (win<ROW*COL- EASY_COUNT) {
		printf("请输入要排查的坐标:>");
		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
			{
				//计算x,y坐标周围有几个雷
				int n = get_mine_count(mine,x,y);
				show[x][y] = n+'0'; // 数字+'0'可以转换成对应的ASCII
				DisplayBoard(show, row, col);
				win++;
			}
		}
		else
		{
			printf("输入坐标非法,无法排雷,请重新输入n");
		}
	}
	if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功n");
		DisplayBoard(mine, row,col);
	}
}

其中调用了get_mine_count函数,其代码如下:

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

接下来对这两段代码进行分析:

当我们输入需要排查的坐标的时候,我们所输入的坐标也必须合法,必须在1~row(col)之间的数字,如果在此之外,我们将会提醒玩家“输入坐标非法,无法排雷,请重新输入”字样。

当我们输入正确的坐标时候,我们需要对这个坐标下所对应的字符进行判断,如果是字符' 1 ' ,说明踩中雷,说明游戏结束,这时候我们将完整棋盘打印出来,玩家也可以了解本局游戏的情况。

如果是字符 ' 0 ' ,说明玩家没有踩中雷,根据游戏规,我们需要显示这个格子周围8个格子中存在雷的个数,这时候我们调用了get_mine_count函数,我们先看一下统计周围雷的个数的代码:

	return mine[x - 1][y] +
		mine[x - 1][y - 1] +
		mine[x][y - 1] +
		mine[x + 1][y - 1] +
		mine[x + 1][y] +
		mine[x + 1][y + 1] +
		mine[x][y + 1] +
		mine[x - 1][y + 1] - 8 * '0';

我们发现,此代码将周围8个格子的字符全部加了起来,我们知道如果是字符 ' 0 ' 和字符 ' 1 '所对应的ASCII码值相差1,我们可以通过ASCII码值来进行判断,我们将周围8个字符相加,然后再减去8个字符' 0 ' 的和,这样,我们就可以得到周围8个格子中有多少个字符 ' 1 ' 的格子,也就是雷的个数。

为了方便大家理解,我们假定有10个雷,我们将Mine棋盘和show棋盘都显示,我们根据棋盘制定输入,看是否可以得到我们想要的结果:

如果我们排除万难,最终将81个格子排完,我们将会获得胜利,具体判断代码如下:

if (win == row * col - EASY_COUNT)
	{
		printf("恭喜你,排雷成功n");
		DisplayBoard(mine, row,col);
	}

我们这里假定有80个雷,我们显示一下:

 至此,我们扫雷小游戏也写完了,完整代码我也放在我的Gitee仓库,链接如下:

C语言: C语言代码学习-练习 - Gitee.com

其中这3个对应资源管理器3个文件



总结

本节内容主要用C语言实现了小游戏---> 扫雷,大家可以拷贝到编译器里面玩一玩,如果大家觉得还不错有收获的话,点赞收藏走一波呗~ 

由于我的个人技术水平有限,各位大佬发现错误及时指出哦~

这里是 用C语言实现《三子棋 》 小游戏的链接,大家有兴趣也可以看看哦:

[ C语言 ] 用C语言实现小游戏 ---- 三子棋 代码 + 解析_小白又菜的博客-CSDN博客

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>