优化的扫雷

994 阅读4分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

扫雷

还是那个熟悉的味道,优化的扫雷,无限接近真正的扫雷。

test.c

还是从main入手,本人不太喜欢直接上代码,感觉那样的话博友会看不懂,我喜欢分开来讲解。废话不多说,直接上代码(哈哈开个玩笑)。

main

{
	int input = 0;
	int num = 3;//不可连续选错的次数
	int flag = 1;//这个我不想说了,三子棋里面有,就是次数标记
	srand((unsigned)time(NULL));//随机数起点,与rand()搭配使用
    /*别的不说,这游戏不管你玩不玩,总之你得玩一把,先和你说一声30个雷*/
	do
	{
		Meun();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			if (flag == 0)
			{
				flag = 1;  //标记取反
				num = 3;   //次数充满
			}
			game();        //玩游戏
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			if (flag == 1)
			{
				flag = 0;   //标记警告
			}
			num--;
			if (num == 0)   //到这里你就没机会了
			{
				printf("你已经没有机会了。\n");
				break;
			}
			printf("选错了,你还有%d次机会\n", num);
			break;
		}
 
	} while (input&&num);    //输入0或次数没了就退出游戏
	return 0;
}

Meun菜单函数

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

game游戏函数

{
	char mine[ROWS][COLS];//地雷数组
	char show[ROWS][COLS];//排查雷数组
	InitBoard(mine, ROWS, COLS,'0');//初始化放雷棋盘
	InitBoard(show,ROWS,COLS,'*');  //初始化排查雷棋盘
 
	//DisplayBoard(mine, ROW, COL);//打印放雷棋盘
	DisplayBoard(show, ROW, COL);//打印排雷棋盘
 
	SetMine(mine, ROW, COL);     //布置雷
	//DisplayBoard(mine, ROW, COL);//打印放雷棋盘
	FindBoard(mine,show, ROW, COL);   //排查雷
 
 
}

game.c文件

InitBoard初始化棋盘函数

棋盘初始化,这里到底初始化是么样的字符呢?写死'0',show数组不行。写死'*',mine数组也不行,那怎么办呢?所以我这里全都不要,我用一个参数set来承接,你要初始化什么样,你传给我的参数,然后再操作。

{
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		int j = 0;
		for (j = 0; j < cols; j++)
		{
			board[i][j] = set;//set参数,你来啥我接啥
		}
	}
}

DisplayBoard打印棋盘参数

打印棋盘,这里打印就是我们所见的棋盘,那个为了防止数组溢出的外面一圈就不需要了。虽然我们这里虽然操作的是99的数组,但是我们传数组的时候还是1111的数组,所以用board这个11*11的数组来接收

{
	int i = 0;
	printf("---------------------------------------\n");
	/*这个循环是在打印列之前把序号打印出来*/
	for (i = 0; i <= col; i++)
	{
		printf("%2d ", i);//为了看的方便,格式对齐所以用%2d 
	}
	printf("\n");
	for (i = 0; i <= col; i++)
	{
		if (0 == i)
			printf("   ");
		else
		    printf("---");		
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		int j = 0;
		printf("%2d|",i);//打印行之前把序号打印出来
		for (j = 1; j <= col; j++)
		{
			printf(" %c ",board[i][j]);
		}
		printf("|");//行结束后打印个|分割线
		printf("\n");
	}
	for (i = 0; i <= col; i++)//列结束后打印分割线---
	{
		if (0 == i)
			printf("   ");//0下面不需要分割线
		else
			printf("---");
	}
	printf("\n");
	printf("---------------------------------------\n");
}

SetMine放置雷函数

布置雷,把雷放到mine数组里面

{
	int count = EASY_COUNT;
	while (count)
	{
		//布置雷生成随机下标(1-9)
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		//如果board[x][y]不是雷才能把雷放进去,不然会少雷
		if (board[x][y] != '*')
		{
			board[x][y] = '*';
			count--;
		}
	}
}

GetMineCount得到雷数函数

得到雷个数函数,因为我们放雷数组初始化是'0',雷是' ',但我们从排查雷及其周围是定死33的数组,所以我们用循环把9个字符加起来再减9个'0'就能得到总共'*'-'0'的整数了,再除以它就可以得到count

{
	int i = 0;
	int sum = 0;
	int count = 0;
	for (i = x - 1; i <= x + 1; i++)
	{
		int j = 0;
		for (j = y - 1; j <= y + 1; j++)
		{
			sum = sum + (board[i][j] - '0');
		}
	}
	return count = sum / ('*' - '0');//我们要灵活运用字符型和整型之间的切换
}

PutOneMine放单雷函数

放一个雷,防止第一步及之后连续踩雷就被炸死,这个代码就是保护那些脸黑的,怕他们没有游戏体验

{
	while (1)
	{
		int x = rand() % ROW + 1;
		int y = rand() % COL + 1;
		if (board[x][y] != '*')
		{
			board[x][y] = '*';//把雷放进去就跳出
			break;
		}
	}
}

ShowSpread显示展开函数

显示展开函数,也就是递归展开排雷,这个函数大大增加了游戏的可玩性,我欲八面来风层层递归

{
	int count = 0;//计算雷个数
	count = GetMineCount(mine, x, y);
	if (count == 0)
	{
		/*这里非常重要不然会死递归,很像对冲击波那样*/
		show[x][y] = ' ';
		if ((x - 1) > 0 && (y - 1) > 0 && show[x - 1][y - 1] == '*')
			ShowSpread(mine, show, x - 1, y - 1);
		if((y-1)>0&&show[x][y-1] == '*')
			ShowSpread(mine, show, x , y - 1);
		if ((x + 1) <= ROW && (y - 1) > 0 && show[x - 1][y - 1] == '*')
			ShowSpread(mine, show, x + 1, y - 1);
		if ((x - 1) > 0&& show[x - 1][y] == '*')
			ShowSpread(mine, show, x - 1, y);
		if ((x + 1) <= ROW&& show[x + 1][y] == '*')
			ShowSpread(mine, show, x + 1, y);
		if ((x - 1) > 0 && (y + 1) <= COL && show[x - 1][y + 1] == '*')
			ShowSpread(mine, show, x - 1, y + 1);
		if ((y + 1) <= COL && show[x][y + 1] == '*')
			ShowSpread(mine, show, x, y + 1);
		if ((x + 1) <= ROW && (y + 1) <= COL && show[x + 1][y + 1] == '*')
			ShowSpread(mine, show, x + 1, y + 1);
	}
	else
	{
		show[x][y] = count + '0';
	}
 
}

FindBoard排查雷函数

排查雷,我们是通过排查mine数组,然后把信息传到show数组里面,我们还是操作99数组,但mine show一直都是1111的数组,为了防止查雷是溢出

{
	int x = 0;
	int y = 0;
	int num = 3;
	int flag = 1;
	int mine_flag = 1;
	int win = 0;
	while (num&&(win<row*col-EASY_COUNT))
	{
		printf("请输入你要排查的目标:>");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (flag == 0)
			{
				flag = 1;
				num = 3;
			}
			if (mine[x][y] == '*')
			{
				if (mine_flag == 1)
				{
					mine[x][y] = '0';
					PutOneMine(mine);
					//DisplayBoard(mine, ROW, COL);
					/*这步是更新周围雷数的*/
					int count = GetMineCount(mine, x, y);
					show[x][y] = count + '0';//把得到的数给show数组,但count是整型,所以转成字符型(字符型-'0'=整型)
					DisplayBoard(show, ROW, COL);
					
				}
				else
				{
					printf("很遗憾,你被炸死了\n");
					DisplayBoard(mine, ROW, COL);
					break;
				}
				
			}
			else
			{/*如果不是雷,我们就搜索该位置周围8个位置的雷的情况*/
				win++;
				mine_flag = 0;//到了这里雷标记就没有了
 
				if (mine[x][y] == '0' && show[x][y] == '*')
				{
					ShowSpread(mine, show, x, y);//显示展开
					DisplayBoard(show, ROW, COL);
				}
				//int count = GetMineCount(mine,x,y);
				//show[x][y] = count + '0';//把得到的数给show数组,但count是整型,所以转成字符型(字符型-'0'=整型)
				//DisplayBoard(show, ROW, COL);
			}
		}
		else
		{
			if (flag == 1)
			{
				flag = 0;
			}
			num--;
			if (num == 0)
			{
				printf("你已经没有机会了");
				break;
			}
			printf("输入坐标错误,你还有%d的输入机会", num);
		}
	}
	if (win == row * col - EASY_COUNT)
		printf("恭喜你排雷成功。\n");
}

game.h

上面的讲解是简易棋盘9乘9的,这里我就直接来个中等难度的15乘15的

#define COL 15
 
#define ROWS ROW+2
#define COLS COL+2
 
#define EASY_COUNT 30  //简单版本的地雷数

函数申明

 
void DisplayBoard(char board[ROWS][COLS], int row, int col);
 
void SetMine(char board[ROWS][COLS], int row, int col);
 
void FindBoard(char mine[ROWS][COLS], char show[ROWS][COLS],int row, int col);
 
int GetMineCount(char board[ROWS][COLS], int x, int y);
 
void PutOneMine(char board[ROWS][COLS]);
 
void ShowSpread(char mine[ROWS][COLS],char show[ROWS][COLS], int x, int y);

测试图

次数限制

炸死


第一步开始连续踩雷,泉水无敌效应坐标2 3是有雷的

但为了防止刚开始就死,看两幅图2 3雷被移走了,之后只要不是连续踩雷就不会出现这个情况

 赢了

9 2是唯一一个没有雷的