C语言实现扫雷

  扫雷是一个非常经典地小游戏。今天我用c语言来实现它。

  首先明确扫雷地思路:

  1.用一个二维数组来存放雷的位置(arr2),用另一个二维数组来存放棋盘(arr1)。

  2.我输入arr1中的某个位置坐标,计算机去计算这个位置周围一圈的雷数,并把这个这个点打印成雷数。如果是0,则打印成空白,并将周围一圈的点作为一个新的位置点,去计算,这样可以实现拓展空白的功能。

那我要完成这么多,就需要实现这几个函数:1.打印函数,打印棋盘。2.埋雷函数,计算机随机埋雷。3.接收指令函数,让计算机明白我是想要扫雷,还是标记雷,还是取消标记雷。4.扫雷函数,给计算机一个坐标,去判断有没有被炸死,没有炸死那这个地方有多少雷,如果是0,则向外拓展。5.标记雷函数,给出坐标,计算机把这个雷标记起来,这个点就不能再被扫描了。6.取消标记雷函数,就是取消标记。7.拓展函数,拓展函数实现对空白的拓展,因为是要扫描周围一圈,所以在雷盘(arr1)上,我们最多只能去扫描角落的点,那么它会去扫描周围一圈有多少雷,这样就超出了雷盘的大小,所以我们的arr2需要比arr1大一圈,再用函数递归实现拓展。

首先,写出菜单函数

void menu()
{
	system("title 扫雷");
	system("color f0");
	system("date /T");
	system("TIME /T");
	printf("-----------------------------\n");
	printf("******  1.开始游戏    *******\n");
	printf("******  0.退出游戏    *******\n");
	printf("-----------------------------\n");
	int input = 0;
	char arr1[HANG][LIE] = { 0 };
	char arr2[HANG + 2][LIE + 2] = { 0 };
	printf("请选择:");
	do
	{
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game(arr1,arr2,HANG,LIE);
			break;
		case 0:
			printf("退出游戏");
			return;
		default:
			printf("错误,重新输入:");
		}
	}while (input);
}

然后写出两个初始化函数,对arr1和arr2进行初始化

void chushihua2(char arr[HANG+2][LIE+2],int hang,int lie,char a)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < hang; i++)
		for (j = 0; j < lie; j++)
			arr[i][j] = a;
}
void chushihua(char arr[HANG][LIE], int hang, int lie,char a)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < hang; i++)
		for (j = 0; j < lie; j++)
			arr[i][j] = a;
}

然后写出打印函数

void display(char arr[HANG][LIE], int hang, int lie)
{
	//system("cls");
	int i = 0;
	int j = 0;
	for (i = 0; i < hang; i++)
		printf("  %d ", i + 1);
	printf("\n");
	for (i = 0; i < hang; i++)
	{
		printf("%d", i + 1);
		for (j = 0; j < lie - 1; j++)
		{
			printf(" %c |", arr[i][j]);
		}
		printf(" %c\n ", arr[i][j]);
		if (i < hang - 1)
		{
			for (j = 0; j < lie - 1; j++)
				printf("---|");
			printf("---\n");
		}
	}
}

接着写出游戏主题,game函数

void game(char arr1[HANG][LIE],char arr2[HANG+2][LIE+2],int hang,int lie)
{
	flag = 0;
	// arr1 棋盘 arr2 答案
	chushihua(arr1, HANG, LIE,'#');
	chushihua2(arr2, HANG + 2, LIE + 2,'0');
	put_lei(arr2, HANG + 2, LIE + 2);
	while (1)
	{
		display(arr1,hang,lie);
		jieguo(arr1,arr2,hang,lie);
		put_order(arr1,arr2,hang,lie);
	}
}

然后是填雷函数

void put_lei(char arr[HANG + 2][LIE + 2], int hang, int lie)
{
	int count = 0;
	printf("计算机正在埋雷\n");
	while (count < NUM)
	{
		int i = rand() % (hang - 2) + 1;
		srand((unsigned int)(time(NULL)));
		int j = rand() % (lie - 2) + 1;
		if (arr[i][j] == '0')
		{
			arr[i][j] = '1';
			count++;
		}
	}
}

然后是给出指令函数 为了方便测bug 多加了一个调试模式

void put_order(char arr1[HANG][LIE],char arr2[HANG+2][LIE+2],int hang,int lie)
{
	if (max == 1)
	{
		int i = 1;
		while (i)
		{
			int x = 0;
			int y = 0;
			printf("打印棋盘(1) or 打印藏雷盘(2) or 打印所有雷的坐标(3) or 退出调试(4):");
			scanf("%d", &i);
			switch (i)
			{
			case 1:
				for (x = 0; x < HANG; x++)
				{
					for (y = 0; y < LIE; y++)
						printf("%c ", arr1[x][y]);
					printf("\n");
				}
				break;
			case 2:
				for (x = 0; x < HANG+2; x++)
				{
					for (y = 0; y < LIE+2; y++)
						printf("%c ", arr2[x][y]);
					printf("\n");
				}
				break;
			case 3:
				for (x = 0; x < HANG + 2; x++)
				{
					for (y = 0; y < LIE + 2; y++)
					{
						if (arr2[x][y] == '1')
							printf("%d ,%d \n", x, y);
					}
				}
				break;
			case 4:
				max = 0;
				return;
			default:
				printf("错误,重新输入:");
			}
		}
	}
	if (max == 0)
	{
		printf("扫雷(1) or 标记雷(2) or 取消标记雷(3) or 提示(4) or 调试模式(5):");
		int input = 0;
		while (1)
		{
			scanf("%d", &input);
			switch (input)
			{
			case 1:
				saolei(arr1, arr2, hang, lie);
				return;
			case 2:
				biaojilei(arr1, hang, lie);
				return;
			case 3:
				quxiaobiaojilei(arr1, hang, lie);
				return;
			case 4:
				tishi(arr1, arr2, hang, lie);
				return;
			case 5:
				max = 1;
				return;
			default:
				printf("错误,重新输入:");
			}
		}
	}
}

接着写出标记 取消标记 提示函数。标记函数需要创建一个全局变量flag(已标记的数量),如果flag=0,那就不能取消标记,因为没有标记过。如果flag = NUM(雷的个数),那就不能再标记了,因为如果把整个棋盘都标记,那样可以直接取得胜利。

void biaojilei(char arr[HANG][LIE],int hang,int lie)
{
	if (flag == NUM)
	{
		printf("标记雷个数达到上线\n");
		return;
	}
	int i = 0;
	int j = 0;
	printf("输入标记坐标:");
	while (1)
	{
		scanf("%d %d", &i, &j);
		if (i<1 || i>hang || j<1 || j> lie)
		{
			printf("错误,重新输入:");
			continue;
		}
		if (arr[i - 1][j - 1] =='@')
		{
			printf("该坐标已被标记,重新输入:");
			continue;
		}
		if (arr[i - 1][j - 1] != '#')
		{
			printf("该坐标已被扫描,重新输入:");
			continue;
		}
		arr[i - 1][j - 1] = '@';
		flag++; 
		break;
	}
}
void quxiaobiaojilei(char arr[HANG][LIE],int hang,int lie)
{
	if (flag == 0)
	{
		printf("还没有标记雷,不能取消标记\n");
		return;
	}
	int i = 0;
	int j = 0;
	printf("输入标记的坐标:");
	while (1)
	{
		scanf("%d %d", &i, &j);
		if (i<1 || i>hang || j<1 || j> lie)
		{
			printf("错误,重新输入:");
			continue;
		}
		if(arr[i-1][j-1] != '@')
		{
			printf("此位置没有被标记,无法取消标记,重新输入:");
			continue;		
		}
		else
		{
			arr[i - 1][j - 1] = '#';
			flag--;
			break;
		}
	}
}
void tishi(char arr1[HANG][LIE], char arr2[HANG + 2][LIE + 2], int hang, int lie)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < hang; i++)
		for (j = 0; j < lie; j++)
		{
			if (arr2[i+1][j+1] == '1' && arr1[i][j] == '#')
			{
				arr1[i][j] = '@';
				flag++;
				return;
			}
		}
}

接下来是扫雷与拓展空白函数

int jisuanleishu(char arr[HANG+2][LIE+2],int hang,int lie,int i,int j)
{
	int sz= arr[i - 1][j - 1] + arr[i - 1][j] + arr[i - 1][j + 1] + arr[i][j - 1] + arr[i][j + 1] + arr[i + 1][j - 1] + arr[i + 1][j] + arr[i + 1][j + 1] - 8 * '0';
	return sz;
}
void panduan(char arr1[HANG][LIE], char arr2[HANG + 2][LIE + 2], int hang, int lie,int i ,int j)
{
	int sz = jisuanleishu(arr2, hang, lie, i, j);
	if (sz == 0)
	{
		arr1[i - 1][j - 1] = ' ';
		if (i - 1 >= 1 && i - 1 <= hang && j - 1 >= 1 && j - 1 <= lie && arr1[i - 2][j - 2] == '#')
			panduan(arr1, arr2, hang, lie, i - 1, j - 1);
		if (i  >= 1 && i  <= hang && j - 1 >= 1 && j - 1 <= lie && arr1[i - 1][j - 2] == '#')
			panduan(arr1, arr2, hang, lie, i , j - 1);
		if (i + 1 >= 1 && i + 1 <= hang && j - 1 >= 1 && j - 1 <= lie && arr1[i][j - 2] == '#')
			panduan(arr1, arr2, hang, lie, i + 1, j - 1);
		if (i - 1 >= 1 && i - 1 <= hang && j  >= 1 && j  <= lie && arr1[i - 2][j - 1] == '#')
			panduan(arr1, arr2, hang, lie, i - 1, j );
		if (i + 1 >= 1 && i + 1 <= hang && j >= 1 && j <= lie && arr1[i][j - 1] == '#')
			panduan(arr1, arr2, hang, lie, i + 1, j);
		if (i - 1 >= 1 && i - 1 <= hang && j + 1 >= 1 && j + 1 <= lie && arr1[i - 2][j] == '#')
			panduan(arr1, arr2, hang, lie, i - 1, j + 1);
		if (i >= 1 && i <= hang && j + 1 >= 1 && j + 1 <= lie && arr1[i - 1][j] == '#')
			panduan(arr1, arr2, hang, lie, i , j + 1);
		if (i + 1 >= 1 && i + 1 <= hang && j + 1 >= 1 && j + 1 <= lie && arr1[i][j] == '#')
			panduan(arr1, arr2, hang, lie, i + 1, j + 1);
	}
	else
		arr1[i - 1][j - 1] = '0' + sz;
}
void saolei(char arr1[HANG][LIE],char arr2[HANG+2][LIE+2],int hang,int lie)
{
	int i = 0;
	int j = 0;
	printf("输入扫描的坐标:");
	while (1)
	{
		scanf("%d %d", &i, &j);
		if (i<1 || i>hang || j<1 || j> lie)
		{
			printf("错误,重新输入:");
			continue;
		}
		if (arr1[i - 1][j - 1] != '#')
		{
			printf("这个坐标不能扫描,因为不是未知点\n");
			printf("重新输入:");
			continue;
		}
		if (arr2[i][j] == '1')
		{
			printf("很遗憾,你被炸死了\n");
			printf("三秒后返回\n");
			Sleep(3000);
			system("cls");
			menu();
		}
		else
		{
			panduan(arr1, arr2, hang, lie, i, j);
			return;
		}
	}
}

最后需要一个判断出扫雷是否成功的函数

void jieguo(char arr1[HANG][LIE], char arr2[HANG+2][HANG+2],int hang,int lie)
{
	int i = 0;
	int j = 0;
	int x = 0;
	int y = 0;
	for (i = 0; i < hang; i++)
	{
		for (j = 0; j < lie; j++)
		{
			if (arr1[i][j] == '#' && arr2[i + 1][j + 1] != '1')
			{
				y = 0;
				break;
			}
			else
				y++;
		}
		if (y == 0)
			break;
	}
	for (i = 0; i < hang; i++)
	{
		for (j = 0; j < lie; j++)
		{
			if (arr1[i][j] == '@' && arr2[i + 1][j + 1] == '1')
				x++;
			if (x + y == NUM)
			{
				printf("扫雷成功!\n");
				printf("三秒后返回\n");
				Sleep(3000);
				system("cls");
				menu();
				return;
			}
		}
	}
}

至此,扫雷大部分已经完成

测试图如下

 

 gitee链接:RoseIsBlue/learning_c_language - Gitee.com

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

roseisbule

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值