巧用数组之扫雷(超详细注释!!!)

首先,在搭建扫雷在这个游戏之前,小伙伴们需要先了解扫雷的规则:巧用数组之扫雷(超详细注释!!!)_第1张图片

 这里呢,up建议小伙伴们先去体验几盘扫雷,这有利于理解代码哦!!

up这里给上扫雷的网页版链接,小伙伴们可以先去体验体验~~

扫雷游戏在线玩 - Minesweeper (saolei123.com)

那么在了解完扫雷的规则之后呢,小伙伴们就要跟随up一起共同探索如何用c实现扫雷游戏啦!

 巧用数组之扫雷(超详细注释!!!)_第2张图片

# 知识补充

1.首先,在构建游戏前,up想带着小伙伴们一起认识以下几个函数:

【1】srand函数

---引用时需要引用头文件,即#include

---为rand函数生成随机值而提供先决条件,返回值为unsigned int类型,通常与time函数一起使用,即srand((unsigned int)time(NULL));

【2】rand函数

---引用时需要引用头文件,即#include

---达到生成随机数的目的,通常将其返回值存到变量里,即int ret=rand();

【3】time函数

---引用时需要引用头文件,即#include

---为rand函数生成随机值而提供先决条件,通常作为无参函数与srand函数一起使用,即srand((unsigned int)time(NULL));

【4】Sleep函数

    ---引用时需要引用头文件,即#include

    ---Sleep();括号里写具体想要停滞的时间,单位为ms,达到停滞界面的效果

【5】cls函数

---引用时需要调用头文件,即#include

---system("cls");达到清屏的目的

# 函数实现

2.其次,搭建这么一个游戏,必然是需要分模块实现的

!!!up这里分为game.c和test.c两个源文件,以及game.h这个头文件。那么为啥需要这么做呢?原因就是可以使得整体布局更清晰直观,达到分工明确的目的。那么,话不多说,上代码!!

【1】:game.h头文件

//game.h


#include
#include
#include
#include

//在构建扫雷游戏之前,小伙伴们需要先明白扫雷游戏的原理,
//那么在了解扫雷的原理后,要干些啥呢?
//=>既然要排雷=>那么自然也就要装雷
//怎么装雷呢?拿什么装雷?
//=>拿表格装雷,常见的扫雷图是9x9,那么up也以9x9作为范例
//so,要先创建表格,又考虑到扫雷时边界的问题,为了防止数组越界访问而造成扫雷时的程序错误,就要创建更大的数组,
//=>即搭建11x11的表格,对11x11的表格进行初始化(使其得以可控),再对9x9表格进行扫雷操作即可
//所以,滤清思路,步骤为:
//创建表格=>初始化表格=>装雷=>排雷=>判断被炸or排雷成功

#define ROWS 11
#define COLS 11
#define ROW  9
#define COL  9
#define NUM  10  //宏定义雷的数目,便于修改

//表格初始化
void ini(char chart[ROWS][COLS], int row, int col,char ch);

//装雷
void set_mychart(char chart[ROW][COL], int row, int col);

//打印输出表格
void print(char chart[ROWS][COLS], int row, int col);

//排雷
void find_bomb(char showchart[ROWS][COLS],char mychart[ROWS][COLS], int row,int col);

//判断周围有几个雷
int how_many(char mychart[ROWS][COLS], int x, int y);

【2】.game.c源文件


//game.c


#include"game.h"

void ini(char chart[ROWS][COLS], int row, int col, char ch)
{
	int i = 0;
	int j = 0;                    //需要注意的是:
	for (i = 0; i < ROWS ; i++)  //考虑到9x9扫雷时的边界问题,边界以外不是扫雷区,自然无雷,但为了使排雷时判断统一,
	{                            //因此设置11x11的棋盘,并给其初始化,但在打印棋盘的时候,只打印9x9的棋盘
		for (j = 0; j < COLS ; j++)
		{
			chart[i][j] = ch;
		}
	}

}
 
void set_mychart(char chart[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	int count = NUM;
	while (count)
	{
		x = rand() % row + 1;//取用1~9的数
		y = rand() % col + 1;
		if (chart[x][y] == '0')
		{
			chart[x][y] = '1';//装雷处设为'1',为啥设'1'呢?后文会讲到,是为了方便统计
			count--;
		}
	}
}

void print(char chart[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < ROWS - 1; i++)
	{
		printf("%d ", i);
	}
	printf("\n"); //这里都是布置棋盘,达到美观的效果,铁子们运行一下就知道具体啥效果了
	for (i = 1; i < ROWS-1; i++)
	{
		printf("%d ", i);
		for (j = 1; j < COLS-1; j++)
		{
			printf("%c ", chart[i][j]);
		}
		printf("\n");
	}
}

void find_bomb(char showchart[ROWS][COLS], char mychart[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int count = 0;
	int win = 0;
	while ((ROW * COL - NUM) - win > 0)
	{
		printf("请小主输入想要排查的坐标:>");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
		{
			if ('*'==showchart[x][y])
			{
				if ('1' == mychart[x][y])
				{
					printf("可怜的小主被炸死了555\n");
					print(mychart, row, col);
					break;
				}
				else
				{
					count = how_many(mychart, x, y);
					showchart[x][y] = '0' + count;//字符-字符=整型数,所以字符+整型数=字符
					print(showchart, ROW, COL);//如'1'-'0'=49-1=1,所以'0'+2='2'
					win++; //成功排雷一次,就win++
				}
			}
			else
				printf("小主输入的坐标重复,请重新输入!\n");
		}
		else
			printf("小主输入的坐标不在棋盘内,请重新输入!\n");
	}
	if (win == (ROW * COL - NUM))
		printf("恭喜小主排雷成功!!小主赛高!!\n");
}

int how_many(char mychart[ROWS][COLS], int x, int y)
{
	return (mychart[x - 1][y] + mychart[x - 1][y + 1]
		+ mychart[x][y + 1] + mychart[x + 1][y + 1] + mychart[x + 1][y]
		+ mychart[x + 1][y - 1] + mychart[x][y - 1] + mychart[x - 1][y - 1]) - 8 * '0';
	//为啥这么做呢?字符数据相减,对应其ASCII相减,如'1'-'1'=0,这也就是为啥装雷的时候要把雷设成'1',就是为了方便统计排雷处周围的雷数
	
}

【3】.test.c源文件

//test.c




#include"game.h"
void menu();
void game();

int main()
{
	int choice = 0;
	do
	{
		menu();
		printf("请小主输入选项:>");
		scanf("%d", &choice);
		switch (choice)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("小主输入有误,请检查后重新输入\n");
			break;
		}
	} while (choice);
}

void menu()
{
	printf("          1.play           \n");
	printf("          0.exit           \n");
}

void game()
{    //为啥设置两个数组呢?
	//根据扫雷游戏设置,首先要对放雷在棋盘里,也就意味着棋盘里所对应的数组元素是会存放数据(倘若是字符数据)的,那么在给玩家排雷的时候,
	//显示的一定是都为同一字符的内容,如都为'*',一个数组元素里至多存放一个字符,如果仅设置一个棋盘,又要达到初始化棋盘的目的,
	//还要达到存雷的目的,那怎么可能呢??难道说一个数组元素可以同时存两个字符变量?显然是不可以的。因此,要设置两个数组。
	//一个数组用于设置雷,另一个数组用于给玩家排雷,排到的地方与设置雷的数组进行比较,进而确定用于排雷处的周围有多少个雷。

	char mychart[ROWS][COLS] = { 0 };//mychart数组用于放雷(电脑随机在棋盘里放雷),showchart数组用于显示(给玩家看)和排雷(给玩家排)
	char showchart[ROWS][COLS] = { 0 };
	ini(mychart, ROWS, COLS,'0');//调用初始化函数对两个棋盘进行初始化
	ini(showchart, ROWS, COLS,'*');//mychart用'0'初始化,showchart用'*'初始化
	set_mychart(mychart, ROW, COL);//调用装雷函数对mychart棋盘进行装雷
	print(showchart, ROWS, COLS);//调用函数对showchart棋盘进行打印输出
	find_bomb(showchart, mychart,ROW,COL);//调用排雷函数对排雷处进行判断
	Sleep(5000);
	system("cls");
}

制作不易,还请小老板们留下3连再走吧~~~

制作不易,还请小老板们留下3连再走吧~~~

制作不易,还请小老板们留下3连再走吧~~~

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