入门三个月不到的小白写的扫雷

有幸在鹏哥的指导下写出了扫雷游戏,相比于上一次的三子棋代码,扫雷代码更加考验一个程序员对于数组的灵活运用,也再一次激起了我对代码的兴趣和热情

在讲解扫雷代码前,先来介绍一下扫雷是个什么游戏,在没要用C语言写出扫雷之前我其实连扫雷是什么都不知道,儿时玩扫雷的时候就是一通瞎点,然后砰!的一下炸,游戏就失败了

扫雷的游戏界面是这样的:
在这里插入图片描述
最左边红色的数字就是这个棋盘里面埋了99个雷,右边红色的数字代表的是玩家所进行的时间

在这里插入图片描述
运气不好,点了两下就死掉了

调节一下游戏难度在这里插入图片描述
现在这就是一个10x10的一个边框,里面含有10个雷的棋盘

这里先点击一下,出现了一个1
在这里插入图片描述
这个1的意思就是指,以它为中心的八个格子中有一颗地雷在附近
(因为没有找到合适的效果就重开了一把,大概就是这样)
在这里插入图片描述

看!这个游戏已经失败了,显示出来的雷中在1的周围只有1个地雷,数字1的意思就是在1周围的8x8的格子周围中只有一个雷(红笔所标示的)

当将所有没有雷的地方全部猜中,棋盘空间里的地方只剩下来雷的时候,就代表这个游玩玩家胜利
在这里插入图片描述
如图所示,8个1里围着一块空间,那这个空间的就只能是雷,棋盘已经除了是雷的地方已经全部被占满了,系统也提示了“you win!”的提示

那讲到这,扫雷的大致游戏原理我们就已经差不多明白了,接下来就开始实现它

首先引用头文件,输入主函数,自定义函数SAOLEI(我是学西班牙语的,英语菜的和屎一样)

#include<stdio.h>
int main()
{
    
    
	SAOLEI();
	return 0;
}

在做这一款扫雷游戏前我们先要做出这个游戏的游戏菜单,用do…while循环和switch分支的写法,来达到玩家玩完游戏后再玩一次和提供玩家选择的菜单效果(具体的可以看我上一篇博客中写道的三子棋,这里简要代过)

void menu()
{
    
    
	printf("扫雷游戏\n");
	printf("1,开始游戏\n");
	printf("0,结束游戏\n");
}

void SAOLEI()
{
    
    
	int inpunt = 0;
	srand((unsigned int)time(NULL));
	do
	{
    
    
		menu();
		printf("请输入数字");
		scanf("%d", &inpunt);
		switch (inpunt)
		{
    
    
		case 1:
			Saolei_s();
			break;
		case 0:
			printf("结束游戏\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}

	} while (inpunt);
}

测试一下,大概的效果就是这样在这里插入图片描述
在这里插入图片描述
可以根据自己的需求来制定界面,接下来就在case1的选项中自定义函数Saolei_s()来开始制作游戏内容

游戏内容我们分成两个步骤来进行说明:1,制作棋盘2,开始扫雷

我们这里来制作一个10x10的棋盘,但在这之前,我们先要搞清楚棋盘到底是一个什么样子的结构,通过我一开始的扫雷游戏讲解我们不难推出,扫雷这个游戏的棋盘组成是由两个棋盘构成的,分别是玩家输入的棋盘还有埋雷的棋盘
在这里插入图片描述
在这里插入图片描述
换一种理解方式的话,我们可以理解为:普通的笑脸是一个棋盘,而哭脸也是一个棋盘,我们把这两个棋盘都设置为数组,当输入的坐标是哭脸的雷的时候,我们就把它反映在笑脸的这个棋盘上,转成哭脸棋盘,就显示了失败的样子
同时我们还要注意的是,这个格子虽然看上去只有10x10,但要注意我们每输入一个坐标,就要显示周围的地雷数,如果就会显示出周围的地雷数,可如果我们输入的边框的坐标,就像这样:
在这里插入图片描述
那这里计算的也是他附近8x8的坐标,可是由于是边框位置的受限,它只计算了附近三个坐标的地雷数,实际上它计算的还是8个在这里插入图片描述
因此我们不难推出,这个棋盘实际的模样是这样的:
在这里插入图片描述
一个9x9的棋盘,我们需要一个11x11的棋盘来作为内棋盘(用来放置地雷和计算周围地雷数),还需要一个9x9的棋盘用来给玩家进行操作

首先再一次定义主函数

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

为了方便打印和更改数字,我们就将其提前定义,同理既然是在原莱的树上进行扩大,我们也在原来的数字上加2即可

接下来在刚刚菜单分支一中自定义函数Saolei_s

void Saolei_s()
{
    
    
	printf("开始游戏\n");
	//布置好棋盘
	char board[ROWS][COLS] = {
    
     0 };
	//布置好棋盘
	char show[ROWS][COLS] = {
    
     0 };
	boards(board, ROWS, COLS, '0');//初始化棋盘
	boards(show, ROWS, COLS, '*');
	//打印棋盘
	//DLYs_board(board, ROW, COL);这一个是内置雷区,用来布置雷
	DLYs(show, ROW, COL);//只需要打印中间的那一圈(9X9)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
	//布置地雷
	BUZHILEI(board, ROW, COL);
	/*DLYs(board, ROW, COL);*///打印确认一下是否已经布置完毕
	//扫描地雷
	POOMPOOMPOOM(board, show, ROW, COL);}
}

定义里面布满地雷的棋盘(下面简称为雷盘,board)和玩家游玩的棋盘(接下来称为玩盘,show),然后开始棋盘的初始化,我们将雷盘放满0,玩盘放满1

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

为了不定义两个函数这么浪费空间,我们在这个函数上多引用一个char来放置我们要给雷盘和玩盘放入的东西

接下来我们打印棋盘,自定义函数DLYs

这里要留意的是,我们引入的整形是row和col,因为雷出现的范围只能是在9x9的格子内,如果出现在11x11的盘子上,则会出现误导玩家的情况玩家的操作空间只能是在9x9中
我们这里操作的还是雷盘(board),注意后面跟着的是11x11

void BUZHILEI(char board[ROWS][COLS], int row, int col)
void DLYs(char board[ROWS][COLS], int row, int col)
{
    
    
	int i = 0;
	int j = 0;
	for (i = 1; i <= row; i++)
	{
    
    
		for (j = 1; j <= col; j++)
		{
    
    
			printf("%c ", board[i][j]);
		}
		printf("\n");
	}
}

i从1开始,小于等于row/col,就把棋盘限制在了9x9中

打印出来看看效果
在这里插入图片描述
这样看感觉目不接暇,很难第一眼就找出我想要的坐标,不如在打印这些棋盘前先打印出数字怎么样
修改代码

void DLYs(char board[ROWS][COLS], int row, int col)
{
    
    
	int i = 0;
	int j = 0;
	printf("  ");
	for (i = 1; 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");
	}
}

再来看看打印效果
在这里插入图片描述
测试没问题

接下来开始布置地雷,自定义函数BUZHILEI,,代入量和上面的一样
设ZD等于地雷的数量Poom,Poom放入头文件中定义,方便修改

void BUZHILEI(char board[ROWS][COLS], int row, int col)
{
    
    
	int ZD = Poom;
	while (ZD)
	{
    
    

		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (board[x][y] == '0')
		{
    
    
			board[x][y] = '1';//这里只有一个等于!
			ZD--;
		}

	}
}

引入时间戳和随机值

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define Poom 10

在定义x和y放入随机值,设置循环,循环里面放入ZD,因为雷盘中布置的全是0,所以只要随机值的坐标是0,就把雷放进去,然后ZD减去1,当ZD等于0的时候,循环跳出,雷就布置完毕

打印出来看看效果
在这里插入图片描述
接下来开始定义函数扫雷,用于玩家操作


void POOMPOOMPOOM(char board[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
    
    
	//先输入玩家的坐标
	int x = 0;
	int y = 0;
	int win = 0;
	
	while (win<row*col-Poom)
	{
    
    
		int count = 0;
		printf("请输入排查坐标:>");
		scanf("%d%d", &x, &y);
		
		//如果坐标存在
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
    
    
			if (board[x][y] == '1')//如果触发雷
			{
    
    
				show[x][y] = '1';
				printf("排查失败,你触发了地雷\n");
				DLYs(show, ROW, COL);
				DLYs(board, ROW, COL);
				break;
			}
			else//如果没有触发雷
			{
    
    
				//计算输入坐标周围的地雷数
				int count = get_mine(board, x, y);
				show[x][y] = count + '0';
				DLYs(show, ROW, COL);
				win++;
			
			}
		}
		else
		{
    
    
			printf("输入坐标错误,请重新输入\n");
		}
		
	}
	
	if (win==row * col - Poom)
	{
    
    
		printf("恭喜你,排雷成功!\n");
		DLYs(board, ROW, COL);
	}
}

这个函数比较复杂,我们一步一步讲

首先我们要把两个棋盘都放入函数中,并且放入row和col

设置三个变量,分别是x和y来给玩家输入坐标,设置win来做判断条件

设置while循环,如果win<row*col-poom,也就是说当win等于71的时候,我们就跳出循环,row和col还有Poom都是我们设的数字,71就是除了雷之外玩家可以排除的坐标(总共坐标有81个)

玩家输入的坐标有三种情况:输入坐标无雷,输入坐标有雷,输入坐标错误

先定义输入坐标有雷无雷的,设置条件,将x和y的范围限制在1和row/col之间,然后如果输入的坐标是雷盘的1,那就是触发地雷,失败

if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
    
    
			if (board[x][y] == '1')//如果触发雷
			{
    
    
				show[x][y] = '1';
				printf("排查失败,你触发了地雷\n");
				DLYs(show, ROW, COL);
				DLYs(board, ROW, COL);
				break;
			}

若不是,则打印出来周围的数字,定义变量count,将雷盘和xy放入自定义整形函数get_mine中

else//如果没有触发雷
			{
    
    
				//计算输入坐标周围的地雷数
				int count = get_mine(board, x, y);
int get_mine(char board[ROWS][COLS], int x, int y)
{
    
    
	return board[x - 1][y] + board[x - 1][y + 1] + board[x - 1][y - 1] +
		board[x][y + 1] + board[x][y - 1] + board[x + 1][y]+
		board[x + 1][y + 1] + board[x + 1][y - 1] - 8 * '0';//减去8个字符0
}

注意,函数内操作的是一个字符,根据阿斯克码表,每一个字符对应的数字是不一样的在这里插入图片描述
字符0对应的是48,1对应的是49…所以,为了能返回一个真确的数字,我们要减掉8个字符‘0’(因为旁白有8个格子),返回的是一个雷数,但是这个数字是一个字符

因为我们要显示出这个字符(根据扫雷玩法,我们要显示出这个坐标上周围的雷数),我们就要在玩盘上对应的坐标来打印出周围的雷数,因此

else//如果没有触发雷
			{
    
    
				//计算输入坐标周围的地雷数
				int count = get_mine(board, x, y);
				show[x][y] = count + '0';
				DLYs(show, ROW, COL);
				win++;
			
			}

当输入一个坐标且不是雷的时候,win就加1,来推动玩家的游戏进度(循环条件)
在循环内,若是玩家输入错误坐标(9x9的格子里不可能出现(10,10)的坐标,我们就给玩家提示)

else
		{
    
    
			printf("输入坐标错误,请重新输入\n");
		}

最后,当玩家跳出循环时,我们在函数内的循环外下给玩家庆祝:游戏胜利

if (win==row * col - Poom)
	{
    
    
		printf("恭喜你,排雷成功!\n");
		DLYs(board, ROW, COL);
	}

这样子,这个扫雷游戏就制作完毕,最后给大家分享一下源代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define Poom 10

void DLYs(char board[ROWS][COLS], int row, int col)
{
    
    
	int i = 0;
	int j = 0;
	printf("  ");
	for (i = 1; 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");
	}
}

int get_mine(char board[ROWS][COLS], int x, int y)
{
    
    
	return board[x - 1][y] + board[x - 1][y + 1] + board[x - 1][y - 1] +
		board[x][y + 1] + board[x][y - 1] + board[x + 1][y]+
		board[x + 1][y + 1] + board[x + 1][y - 1] - 8 * '0';//减去8个字符0
}

void POOMPOOMPOOM(char board[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
    
    
	//先输入玩家的坐标
	int x = 0;
	int y = 0;
	int win = 0;
	
	while (win<row*col-Poom)
	{
    
    
		int count = 0;
		printf("请输入排查坐标:>");
		scanf("%d%d", &x, &y);
		
		//如果坐标存在
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
    
    
			if (board[x][y] == '1')//如果触发雷
			{
    
    
				show[x][y] = '1';
				printf("排查失败,你触发了地雷\n");
				DLYs(show, ROW, COL);
				DLYs(board, ROW, COL);
				break;
			}
			else//如果没有触发雷
			{
    
    
				//计算输入坐标周围的地雷数
				int count = get_mine(board, x, y);
				show[x][y] = count + '0';
				DLYs(show, ROW, COL);
				win++;
			
			}
		}
		else
		{
    
    
			printf("输入坐标错误,请重新输入\n");
		}
		
	}
	
	if (win==row * col - Poom)
	{
    
    
		printf("恭喜你,排雷成功!\n");
		DLYs(board, ROW, COL);
	}
}
void BUZHILEI(char board[ROWS][COLS], int row, int col)
{
    
    
	int ZD = Poom;
	while (ZD)
	{
    
    

		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (board[x][y] == '0')
		{
    
    
			board[x][y] = '1';//这里只有一个等于!
			ZD--;
		}

	}
}



void boards(char board[ROWS][COLS], int rows, int cols, char ret)
{
    
    
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)
	{
    
    
		for (j = 0; j < cols; j++)
		{
    
    
			board[i][j] = ret;
		}
	}
}
void Saolei_s()
{
    
    
	int PD = 0;
	printf("开始游戏\n");
	//布置好棋盘
	char board[ROWS][COLS] = {
    
     0 };
	//布置好棋盘
	char show[ROWS][COLS] = {
    
     0 };
	boards(board, ROWS, COLS, '0');//初始化棋盘
	boards(show, ROWS, COLS, '*');
	//打印棋盘
	//DLYs_board(board, ROW, COL);这一个是内置雷区,用来布置雷
	DLYs(show, ROW, COL);//只需要打印中间的那一圈(9X9),需要将整个11X11提取出来
	//布置地雷
	BUZHILEI(board, ROW, COL);
	/*DLYs(board, ROW, COL);*///打印确认一下是否已经布置完毕
	//扫描地雷
	POOMPOOMPOOM(board, show, ROW, COL);

}
void menu()
{
    
    
	printf("扫雷游戏\n");
	printf("1,开始游戏\n");
	printf("0,结束游戏\n");
}

void SAOLEI()
{
    
    
	int inpunt = 0;
	srand((unsigned int)time(NULL));
	do
	{
    
    
		menu();
		printf("请输入数字");
		scanf("%d", &inpunt);
		switch (inpunt)
		{
    
    
		case 1:
			Saolei_s();
			break;
		case 0:
			printf("结束游戏\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}

	} while (inpunt);
}

int main()
{
    
    
	SAOLEI();
	return 0;
}

一个小小的扫雷,里面居然蕴含了如此丰富的知识和细节,flash player已在2020年12月不再支持,对于那个时候在网页上的游戏制作者创作出简陋的游戏可却趣味十足,在这里,深深对他们表示敬意和对我童年快乐的感谢
希望有一天,我也能像他们一样,写出可以让大家变得开心的程序

猜你喜欢

转载自blog.csdn.net/m0_54707823/article/details/112918596