一个会自动排空的扫雷游戏,不来看看吗?

目录

前言

一.游戏介绍

二.简单的设计思路

1.菜单与主函数

2.数组的创建与初始化

3.列表

4.游戏主体

(1).雷的排布

(2).对应数字的计算

 (3).玩家点击

(4).胜利的判断

三.初步的程序

头文件

源文件1

源文件2

四.自动排空与避免“开局杀”

1.自动排空

2.“开局杀”

五.最终代码

1.头文件

2.源文件1

3.源文件2


前言

之前,我们通过数组的知识完成了三子棋游戏的设计,同样是利用二维数组,我们是不是也就可以设计出一个扫雷游戏呢?



一.游戏介绍

扫雷游戏,是在一个m*n的格子区间内具有一定数量的雷,而没有雷的格子会根据附近3*3区间的雷的数量来产生相应的数字,而我们便需要通过观察点击格子所出现的数字来将所有雷的位置找出来。

那么,在知道游戏是如何运转之后,我们就可以着手来实现这个游戏。



二.简单的设计思路

1.菜单与主函数

任何游戏都需要有游戏菜单的指引,那么我们便再次设计一个简单的菜单

int menu()
{
	int input=0; 
	printf("1---开始游戏            2---退出\n");
	scanf("%d",&input);
	return input;
}

而选择具有返回值的自定义函数,可以让我们通过返回值决定下一步游戏的进行

而根据返回值,我们可以确立出我们的主函数,并将剩余函数打包进入game()函数中

int main()
{
	while(1)
	{
		int begin=menu(); 
		if(begin==1)
		{
			printf("加载中---\n");
			sleep(2);
			system("cls");
			game();
			break;
		}
		else if(begin==2)
			break;
		else
		{
			printf("输入错误,请重新输入\n");
			continue;
		}
	}
	
	return 0;
}

2.数组的创建与初始化

类似于三子棋,我们需要使用二维数组来存放雷与数字

由于二维数组的行和列只能为常量表达式,所以我们选择在头文件中用“#define“”定义全局变量ROW、COL、M作为二维数组的行和列、以及雷的个数。

以下的代码我们选择这样的数据(谁能拒绝高级的扫雷呢)

#define ROW 16
#define COL 30
#define M 99

但与三子棋不同的是,这些雷与数字在游戏的初期便已经决定好了,而我们一开始是看不到的,所以我们选择使用两个二维数组,第一个用来存放所有的雷和数字第二个为空白,当我们选择要点击的坐标时,再将第一个数组中对应位置的雷和数字赋予第二个数组。

因此,我们首先要完成数组的创建与初始化

	char arr1[ROW][COL]; 
	char arr2[ROW][COL];
	init(arr2);
void init(char arr[ROW][COL])
{
	int i,j;
	for(i=0;i<ROW;i++)
	{
		for(j=0;j<COL;j++)
		{
			arr[i][j]=' ';
		}
	}
}

3.列表

而我们将二维数组放置在一个列表中可以让我们的程序更加美观简洁

void list(char arr[ROW][COL])
{
	int i,j;
	printf("    ");
	for(j=1;j<=COL;j++)
	{
		if(j<10)
			printf("  %d ",j);
		else if(j>=10&&j<COL)
			printf(" %d ",j);
		else
			printf(" %d  \n",j);
	}
	printf("----");
	for(j=0;j<COL;j++)
	{
		if(j<COL-1)
			printf("|---");
		else
			printf("|---|\n");
	}
	for(i=0;i<ROW;i++)
	{
		for(j=0;j<=COL;j++)
		{
			if(i<9&&j==0)
				printf("  %d ",i+1);
			else if(i>=9&&j==0)
				printf(" %d ",i+1);
			else if(j<COL)
				printf("| %c ",arr[i][j-1]);
			else if(j==COL)
			{
				printf("| %c |\n",arr[i][j-1]);
				for(j=0;j<COL+1;j++)
				{
					if(j==0)
						printf("----");
					else if(j>0&&j<COL)
						printf("|---");
					else
						printf("|---|\n");
				}
			}
			else
				printf(" %c \n",arr[i][j-1]);
		}
	}
}

这样我们便可以得到一个这样的列表


4.游戏主体

(1).雷的排布

在游戏开始之前,我们先要将M个雷随机分布在arr1这个数组中。(我们这里将字符‘X’当做雷)

既然要随机分布,我们就又要利用时间戳来作随机数

首先将srand函数放在game函数的开始

srand((unsigned int) time(NULL));

之后我们进行雷的排布

while(count<M)//当所排雷的个数小于预期个数进行循环
	{
		int a,b,i=0;
		a=rand()%ROW;
		b=rand()%COL;
		if(arr1[a][b]!='X')//避免重复排雷
		{
			arr1[a][b]='X';
			count++;//每成功排一个雷,count++
			continue;
		}
		else
		continue;
	} 

(当我们初步完成程序的编写时,我们会将雷的分布进一步改进,避免第一步直接选择到雷,这一部分我们将放在第四个大板块来讲)

(2).对应数字的计算

当我们完成雷的排布之后,我们便可以通过雷的个数来计算数组各个位置数字的大小

void num_set(char arr[ROW][COL])
{
	int x,y,m,n,count=0;
	for(x=0;x<ROW;x++)
	{
		for(y=0;y<COL;y++)//循环判断每一个数组位置
		{
			if(arr[x][y]=='X')//位置为雷时不做变化
				;
			else
			{
				int lx=x-1,ly=y-1,rx=x+1,ry=y+1;
				if(x==0)
					lx=0;
				if(y==0)
					ly=0;
				if(x==ROW)
					rx=x;
				if(y==COL)
					ry=y;
				count=0;
				for(m=lx;m<=rx;m++)
				{
					for(n=ly;n<=ry;n++)//对每个位置3*3区域内(边缘位置稍作改变)的雷进行查找
					{
						if(arr[m][n]=='X')
							count++;//循环结束count的值为周围雷的个数
					}
				}
				arr[x][y]=count+48;//将数字转化为ASCII码值
			}
		}
	}
}

在数字计算完毕后,arr1在列表中便会是以下形式

 (3).玩家点击

在arr2赋值完成后,我们便可以开始设计游戏过程

玩家要做的是选择一个坐标

	int x,y; 
	printf("请输入坐标=>\n");
	scanf("%d %d",&x,&y);

在玩家选择坐标之后,我们就要根据所输入的坐标选择将arr2哪些位置赋值给arr1

根据扫雷游戏可知

当玩家选择雷时,游戏失败

当玩家选择非0数字时,显示该位置数字

当玩家选择数字0时,显示周围3*3范围内的数字

(游戏本身是如果在3*3范围内存在数字0时继续在新的位置进行判断,我们简称自动排空。但我们这是只是进行简单的思路设计,就先跳过,会在第四个大板块介绍)

知道以上规则后,我们便可以进行设计一个judge()函数

int judge(char arr1[ROW][COL],char arr2[ROW][COL],int x,int y)
{	
	if(arr1[x][y]=='X')//当选择的是雷
	{
		arr1[x][y]='!';
		list(arr1);//失败后将雷变作!提示玩家并列出列表
		return 2;//返回值为2时判断为失败
	}	
	else if(arr1[x][y]=='0'&&arr2[x][y]==' ') 
	{
		int m,n; 
		int lx=x-1,ly=y-1,rx=x+1,ry=y+1;
		if(x==0)
			lx=0;
		if(y==0)
			ly=0;
		if(x==ROW)
			rx=x;
		if(y==COL)
			ry=y;
		for(m=lx;m<=rx;m++)
		{
			for(n=ly;n<=ry;n++)
			{
					arr2[m][n]=arr1[m][n];//对3*3范围内的arr2进行赋值
			}
		}
		return 1; //返回值为1时继续游戏
	} 
	else  //当选择的是非0数字
	{
		arr2[x][y]=arr1[x][y];
		return 1;//返回值为1时继续游戏
	}
}

(4).胜利的判断

当arr2中空格位置在arr1中都是雷,即所有数字被赋值给arr2时,游戏胜利

首先在game函数中写一个循环进行玩家的选择和胜利的判断

	while(1)
	{
		printf("请输入坐标=>\n");
		scanf("%d %d",&x,&y);
		re=judge(arr1,arr2,x-1,y-1);
		if(re==2)
		{
			printf("defeat");
			break;
		}
		else if(re==1)
		{
			system("cls");
			list(arr2); 
			w=win(arr2);
			if(w==1)
			{
				printf("you win");
				break; 
			}
			else
				continue;
		}
	}

之后进行win()函数的设计

int win(char arr[ROW][COL])
{
	int i,j,count=ROW*COL-M;//总数-雷数=数字的个数
	for(i=0;i<ROW;i++)
	{
		for(j=0;j<COL;j++)
		{
			if (arr[i][j]!=' ')//一个位置不为' ',意思便是被赋予了数字
			    count--;//每当上述条件成立,count-1
		}
	}	
	if(count==0)//当count被减到0,即所有非雷位置都被赋予了数字
		return 1;
}

最后我们便可以将所有代码整合优化,完成这个简单的扫雷游戏



三.初步的程序

头文件

#define ROW 16
#define COL 30
#define M 99
int menu();
void game();
void init(char arr[ROW][COL]);
void list(char arr[ROW][COL]);
void num_set(char arr[ROW][COL]);
int judge(char arr1[ROW][COL],char arr2[ROW][COL],int x,int y);
int win(char arr[ROW][COL]);

源文件1

#include<stdio.h>
#include"test.h"
#include<windows.h>
void game()
{
	srand((unsigned int) time(NULL));
	int count=0;
	char arr1[ROW][COL]; 
	char arr2[ROW][COL];
	init(arr2);
	list(arr2);  
	while(count<M)
	{
		int a,b,i=0;
		a=rand()%ROW;
		b=rand()%COL;
		if(arr1[a][b]!='X')
		{
			arr1[a][b]='X';
			count++;
			continue;
		}
		else
		continue;
	} 
	num_set(arr1);
	list(arr2); 
	int re,x,y;
	while(1)
	{
		printf("请输入坐标=>\n");
		scanf("%d %d",&x,&y);
		re=judge(arr1,arr2,x-1,y-1);
		if(re==2)
		{
			printf("defeat");
			break;
		}
		else if(re==1)
		{
			system("cls");
			list(arr2); 
			if(win(arr2))
			{
				printf("you win");
				break; 
			}
			else
				continue;
		}
	}
}
int main()
{
	while(1)
	{
		int begin=menu(); 
		if(begin==1)
		{
			printf("加载中---\n");
			sleep(2);
			system("cls");
			game();
			break;
		}
		else if(begin==2)
			break;
		else
		{
			printf("输入错误,请重新输入\n");
			continue;
		}
	}
	
	return 0;
}

源文件2

#include<stdio.h>
#include"test.h"
int menu()
{
	int input=0; 
	printf("1---开始游戏            2---退出\n");
	scanf("%d",&input);
	return input;
}
void init(char arr[ROW][COL])
{
	int i,j;
	for(i=0;i<ROW;i++)
	{
		for(j=0;j<COL;j++)
		{
			arr[i][j]=' ';
		}
	}
}
void list(char arr[ROW][COL])
{
	int i,j;
	printf("    ");
	for(j=1;j<=COL;j++)
	{
		if(j<10)
			printf("  %d ",j);
		else if(j>=10&&j<COL)
			printf(" %d ",j);
		else
			printf(" %d  \n",j);
	}
	printf("----");
	for(j=0;j<COL;j++)
	{
		if(j<COL-1)
			printf("|---");
		else
			printf("|---|\n");
	}
	for(i=0;i<ROW;i++)
	{
		for(j=0;j<COL+1;j++)
		{
			if(i<9&&j==0)
				printf("  %d ",i+1);
			else if(i>=9&&j==0)
				printf(" %d ",i+1);
			else if(j<COL)
				printf("| %c ",arr[i][j-1]);
			else if(j==COL)
			{
				printf("| %c |\n",arr[i][j-1]);
				for(j=0;j<=COL;j++)
				{
					if(j==0)
						printf("----");
					else if(j>0&&j<COL)
						printf("|---");
					else
						printf("|---|\n");
				}
			}
			else
				printf(" %c \n",arr[i][j-1]);
		}
	}
}
void num_set(char arr[ROW][COL])
{
	int x,y,m,n,count=0;
	for(x=0;x<ROW;x++)
	{
		for(y=0;y<COL;y++)
		{
			if(arr[x][y]=='X')
				;
			else
			{
				int lx=x-1,ly=y-1,rx=x+1,ry=y+1;
				if(x==0)
					lx=0;
				if(y==0)
					ly=0;
				if(x==ROW)
					rx=x;
				if(y==COL)
					ry=y;
				count=0;
				for(m=lx;m<=rx;m++)
				{
					for(n=ly;n<=ry;n++)
					{
						if(arr[m][n]=='X')
							count++;
					}
				}
				arr[x][y]=count+48;

			}
		}
	}
}
int win(char arr[ROW][COL])
{
	int i,j,count=0;
	for(i=0;i<ROW;i++)
	{
		for(j=0;j<COL;j++)
		{
			if (arr[i][j]==' ')
			count++;
		}
	}	
	if(count==M)
		return 1;
    else
        return 0;
}
int judge(char arr1[ROW][COL],char arr2[ROW][COL],int x,int y)
{	
	if(arr1[x][y]=='X')
	{
		arr1[x][y]='!';
		list(arr1);
		return 2;
	}	
	else if(arr1[x][y]=='0'&&arr2[x][y]==' ') 
	{
		int m,n; 
		arr2[x][y]=arr1[x][y];
			int lx=x-1,ly=y-1,rx=x+1,ry=y+1;
			if(x==0)
				lx=0;
			if(y==0)
				ly=0;
			if(x==ROW)
				rx=x;
			if(y==COL)
				ry=y;
			for(m=lx;m<=rx;m++)
			{
				for(n=ly;n<=ry;n++)
				{
						arr2[m][n]=arr1[m][n];
				}
			}
		return 1; 
	} 
	else  
	{
		arr2[x][y]=arr1[x][y];
		return 1;
	}
}


四.自动排空与避免“开局杀”

1.自动排空

在完成初步的设计后,我们便可以针对自动排空作进一步的改进

扫雷游戏本身是在初步判断时如果在3*3范围内存在数字0时继续在新的位置进行判断

我们可以很容易想到这很符合递归

因此我们便可以利用递归来完成这个功能

else if(arr1[x][y]=='0'&&arr2[x][y]==' ') 
	{
		int m,n; 
		arr2[x][y]=arr1[x][y];
			int lx=x-1,ly=y-1,rx=x+1,ry=y+1;
			if(x==0)
				lx=0;
			if(y==0)
				ly=0;
			if(x==ROW)
				rx=x;
			if(y==COL)
				ry=y;
			for(m=lx;m<=rx;m++)
			{
				for(n=ly;n<=ry;n++)
				{
					if(arr1[m][n]=='0')
					{ 
						judge(arr1,arr2,m,n);//递归进行不断的判断
					}
					else
						arr2[m][n]=arr1[m][n];
				}
			}
		return 1; 
	} 

可以看到,我们在两层for循环内添加了分支的判断与递归

这便可以很好的完成自动排空的功能

可以看到当我们选择数字为0的坐标时,不只是显示周围3*3的数字,而是根据周围是否存在0来作不断的延伸。


2.“开局杀”

其实想要解决“开局杀”这个问题,我们只需要将雷的排布放置在第一次点击之后并根据第一次点击做出一些改变就可以了。

	int x,y; 
	printf("请输入坐标=>\n");
	scanf("%d %d",&x,&y);
	arr1[x-1][y-1]='Y';
	while(count<M)
	{
		int a,b,c,d,i=0;
		c=a=rand()%ROW;
		d=b=rand()%COL;
		if(arr1[a][b]!='X'&&arr1[a][b]!='Y')//避免在第一次选择的坐标上放置雷
		{
			arr1[a][b]='X';
			count++;
			continue;
		}
		else
		continue;
	} 
	num_set(arr1);
	judge(arr1,arr2,x-1,y-1);
	system("cls");
	list(arr2); 
	int re=2;
	while(1)
	{
		printf("请输入坐标=>\n");
		scanf("%d %d",&x,&y);
		re=judge(arr1,arr2,x-1,y-1);
		if(re==2)
		{
			printf("defeat");
			break;
		}
		else if(re==1)
		{
			system("cls");
			list(arr2); 
			if(win(arr2))
			{
				printf("you win");
				break; 
			}
			else
				continue;
		}
	}
}

可以看到,我们在排雷之前添加了第一次坐标的选择,由于此时为进行数字的计算,我们暂时将这个位置赋值为‘Y’,之后对if的判断语句做出相应的改变,就完成了“开局杀”的避免。后续就可以按照原本的代码进行了。



五.最终代码

1.头文件

#define ROW 16
#define COL 30
#define M 99
int menu();
void game();
void init(char arr[ROW][COL]);
void list(char arr[ROW][COL]);
void num_set(char arr[ROW][COL]);
int judge(char arr1[ROW][COL],char arr2[ROW][COL],int x,int y);
int win(char arr[ROW][COL]);

2.源文件1

#include<stdio.h>
#include"test.h"
#include"windows.h"
void game()
{
	srand((unsigned int) time(NULL));
	int count=0;
	char arr1[ROW][COL]; 
	char arr2[ROW][COL];
	init(arr2);
	list(arr2); 
	int x,y; 
	printf("请输入坐标=>\n");
	scanf("%d %d",&x,&y);
	arr1[x-1][y-1]='Y';
	while(count<M)
	{
		int a,b,c,d,i=0;
		c=a=rand()%ROW;
		d=b=rand()%COL;
		if(arr1[a][b]!='X'&&arr1[a][b]!='Y')
		{
			arr1[a][b]='X';
			count++;
			continue;
		}
		else
		continue;
	} 
	num_set(arr1);
	judge(arr1,arr2,x-1,y-1);
	system("cls");
	list(arr2); 
	int re=2;
	while(1)
	{
		printf("请输入坐标=>\n");
		scanf("%d %d",&x,&y);
		re=judge(arr1,arr2,x-1,y-1);
		if(re==2)
		{
			printf("defeat");
			break;
		}
		else if(re==1)
		{
			system("cls");
			list(arr2); 
			if(win(arr2))
			{
				printf("you win");
				break; 
			}
			else
				continue;
		}
	}
}
int main()
{
	while(1)
	{
		int begin=menu(); 
		if(begin==1)
		{
			printf("加载中---\n");
			Sleep(2);
			system("cls");
			game();
			break;
		}
		else if(begin==2)
			break;
		else
		{
			printf("输入错误,请重新输入\n");
			continue;
		}
	}
	
	return 0;
}

3.源文件2

#include<stdio.h>
#include"test.h"
int menu()
{
	int input=0; 
	printf("1---开始游戏            2---退出\n");
	scanf("%d",&input);
	return input;
}
void init(char arr[ROW][COL])
{
	int i,j;
	for(i=0;i<ROW;i++)
	{
		for(j=0;j<COL;j++)
		{
			arr[i][j]=' ';
		}
	}
}
void list(char arr[ROW][COL])
{
	int i,j;
	printf("    ");
	for(j=1;j<=COL;j++)
	{
		if(j<10)
			printf("  %d ",j);
		else if(j>=10&&j<COL)
			printf(" %d ",j);
		else
			printf(" %d  \n",j);
	}
	printf("----");
	for(j=0;j<COL;j++)
	{
		if(j<COL-1)
			printf("|---");
		else
			printf("|---|\n");
	}
	for(i=0;i<ROW;i++)
	{
		for(j=0;j<COL+1;j++)
		{
			if(i<9&&j==0)
				printf("  %d ",i+1);
			else if(i>=9&&j==0)
				printf(" %d ",i+1);
			else if(j<COL)
				printf("| %c ",arr[i][j-1]);
			else if(j==COL)
			{
				printf("| %c |\n",arr[i][j-1]);
				for(j=0;j<=COL;j++)
				{
					if(j==0)
						printf("----");
					else if(j>0&&j<COL)
						printf("|---");
					else
						printf("|---|\n");
				}
			}
			else
				printf(" %c \n",arr[i][j-1]);
		}
	}
}
void num_set(char arr[ROW][COL])
{
	int x,y,m,n,count=0;
	for(x=0;x<ROW;x++)
	{
		for(y=0;y<COL;y++)
		{
			if(arr[x][y]=='X')
				;
			else
			{
				int lx=x-1,ly=y-1,rx=x+1,ry=y+1;
				if(x==0)
					lx=0;
				if(y==0)
					ly=0;
				if(x==ROW)
					rx=x;
				if(y==COL)
					ry=y;
				count=0;
				for(m=lx;m<=rx;m++)
				{
					for(n=ly;n<=ry;n++)
					{
						if(arr[m][n]=='X')
							count++;
					}
				}
				arr[x][y]=count+48;

			}
		}
	}
}
int win(char arr[ROW][COL])
{
	int i,j,count=0;
	for(i=0;i<ROW;i++)
	{
		for(j=0;j<COL;j++)
		{
			if (arr[i][j]==' ')
			count++;
		}
	}	
	if(count==M)
		return 1;
	else
		return 0;
}
int judge(char arr1[ROW][COL],char arr2[ROW][COL],int x,int y)
{	
	if(arr1[x][y]=='X')
	{
		arr1[x][y]='!';
		list(arr1);
		return 2;
	}	
	else if(arr1[x][y]=='0'&&arr2[x][y]==' ') 
	{
		int m,n; 
		arr2[x][y]=arr1[x][y];
			int lx=x-1,ly=y-1,rx=x+1,ry=y+1;
			if(x==0)
				lx=0;
			if(y==0)
				ly=0;
			if(x==ROW)
				rx=x;
			if(y==COL)
				ry=y;
			for(m=lx;m<=rx;m++)
			{
				for(n=ly;n<=ry;n++)
				{
					if(arr1[m][n]=='0')
					{ 
						judge(arr1,arr2,m,n);
					}
					else
						arr2[m][n]=arr1[m][n];
				}
			}
		return 1; 
	} 
	else  
	{
		arr2[x][y]=arr1[x][y];
		return 1;
	}
}

如果大家还有更好的优化方案,欢迎评论

  • 35
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 31
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 31
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

finish_speech

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

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

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

打赏作者

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

抵扣说明:

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

余额充值