自动扫雷二(智能扫雷实现)

题目:

请继续编写程序,帮助(替代)玩家自动扫雷,用尽可能少的步数最快完成扫雷。请注意, 作为玩家,你的程序并不知道地雷的实际位置。本小题无需编写整个程序,只需实现如下函数:
void machine(int GamePanel[30][30], int n, int m, int &x, int &y);
该函数功能为读入当前游戏界面,并给出决策结果,即在当前游戏界面下,下一步应该点击哪个方格。其参数含义为:数组 GamePanel[][]存储 n 行 m 列整数,表示当前游戏界面,数组中数值的含义同(1)小题。x、y 表示下一步应点击的方格的行号和列号,0 <= x< n,0 <= y< m。也就是说,x 和 y 即本函数的决策结果,表示在当前游戏界面下,应该点击哪个方格。注
意在本题中,machine 函数并不知道后台地雷的实际位置,只能根据当前的游戏界面进行决策。本题不允许自行定义全局变量,且 machine 函数只能读 GamePanel 数组,不允许修改该数组, 即便修改了该数组,下次调用时修改信息也将丢失。

题解:

先开局在一定程度内随机点击格子,然后遍历棋盘,考虑以下几种情况:
①格子已被点开,则概率置1.
②该点该点旁边有雷,统计旁边雷数,并统计旁边未打开的格子数,若雷数等于未打开格子数,则把这些为打开的格子概率置1.
③统计旁边以打开是雷的数和非雷数,若以打开的雷数等于雷数(棋盘中该点旁边的雷数),那么该点旁边的非雷格子一定不是雷。
④统计旁边以打开是雷的数和非雷数,若以打开的雷数小于雷数(棋盘中该点旁边的雷数),那么该点的非雷格子就能计算出概率了。(GamePanel[i][j]-mine)/NoMine.

void machine(int (*GamePanel)[30],int n,int m,int& x,int& y)//根据棋盘判断下一步 
{
	int i,j;
	int sum=0; 
//	int flag=true; 
	for(i=0;i<n;i++)//棋局展开程度 
	{
		for(j=0;j<m;j++)
		{
			if(GamePanel[i][j]!=-1)
			{
//				flag=false;
//				break;
				sum++;
			}
		}
	}
	if(sum<n*m*0.02)//当棋局展开小于2%时,随机点开 
	{
		 
		x=rand()%n;
		y=rand()%m;
		return ;
	}
	double P[30][30];//定义概率数组 ,点击概率最小的那一点 。值越大是雷的概率越大 ,为-1一定不是雷 
	int MyMine[30][30]; //定义地雷数组  值为0是不确定是否为雷,为1一定是雷,为2一定不是雷 
	for(i=0;i<n;i++)//初始化概率数组 ,是否为雷和概率都不确定 
	{
		for(j=0;j<20;j++)
		{
			P[i][j]=0;
			MyMine[i][j]=0;
		}
	}
	for(i=0;i<n;i++)
	{
		for(j=0;j<m;j++)
		{
			if(GamePanel[i][j]!=-1)//如果该点已点开,则概率为1,就不会再点了; 
			{
				P[i][j]=1;
			}
			if(GamePanel[i][j]>0) //该点旁边有雷 
			{
				int sum=0;//定义周围未打开的格子数 
				for(int p=i-1;p<=i+1;p++)//统计周围未点开的格子数 
				{
					for(int q=j-1;q<=j+1;q++)
					{
						if(p>=0&&p<n&&q>=0&&q<m)
						{
							if(GamePanel[p][q]==-1)
							{
								sum++;
							}
						}
					}
				}
				if(GamePanel[i][j]==sum)//该点的数刚好为未点开的数,则未点开的全是雷 
				{
					for(int p=i-1;p<=i+1;p++)//把周围未点开的置为雷 
					{
						for(int q=j-1;q<=j+1;q++)
						{
							if(p>=0&&p<n&&q>=0&&q<m&&GamePanel[p][q]==-1)//GamePanel[p][q]一定为雷 
							{
								MyMine[p][q]=1;//一定为雷 
								P[p][q]=1;//概率为1,不能点 
							}		
						}
					}
				}
			} 
		}
	 }
	 for(i=0;i<n;i++)
	 {
	 	for(j=0;j<m;j++)
	 	{
	 		double mine=0;
	 		double NoMine=0;
	 		for(int p=i-1;p<=i+1;p++)
	 		{
	 			for(int q=j-1;q<=j+1;q++)
	 			{
	 				if(p>=0&&p<n&&q>=0&&q<m)
	 				{
	 					if(MyMine[p][q]==1)//统计周围的雷数 
	 					{
	 						mine++;
					 	}
					 	else if(MyMine[p][q]!=1)//统计周围的非雷数 
					 	{
					 		NoMine++;
					 	}
					}	
				 }
			 }
			 if(GamePanel[i][j]==mine&&NoMine>0)//如果该点数等于周围的雷数,并且周围非雷数大于0 
			 {
			 	for(int p=i-1;p<=i+1;p++)
			 	{
			 		for(int q=j-1;q<=j+1;q++)
			 		{
			 			if(p>=0&&p<n&&q>=0&&q<m&&MyMine[p][q]!=1)//非雷格一定不是雷 
			 			{
			 				P[p][q]=-1;
			 				MyMine[p][q]=2;
						 }
					}
				 }
			 }
			 else if(GamePanel[i][j]>mine&&NoMine>0)//如果该点数大于周围的雷数,并且周围非雷数大于0 
			 {
				double pro=(GamePanel[i][j]-mine)/NoMine;//求出该点周围非雷格是雷的概率 
				for(int p=i-1;p<=i+1;p++)
			 	{
			 		for(int q=j-1;q<=j+1;q++)
			 		{
			 			
			 			if(p>=0&&p<n&&q>=0&&q<m&&P[p][q]!=-1&&P[p][q]!=1)
			 			{
			 				if(P[p][q]==0)
			 				{
			 					P[p][q]=pro;
							 }
							 else if(P[p][q]<pro)
							 {
							 	P[p][q]=pro;
							 }
						}
					}
				 }
			 }
		 }
	  } 
	  for(i=0;i<n;i++)//找到一定不是雷的格子 
	  {
	  	for(j=0;j<m;j++)
	  	{
	  		if(GamePanel[i][j]==-1&&MyMine[i][j]==2)
	  		{
	  			x=i;
	  			y=j;
	  			return ;
			}
		  }
	   } 
	 bool fl=false;
	 int temp;
	 for(i=0;i<n;i++)//找到第一个未打开的格子。 
	 {
	 	for(j=0;j<m;j++)
	 	{
	 		if(GamePanel[i][j]==-1)
	 		{
	 			temp=P[i][j];
	 			x=i;
	 			y=j;
	 			fl=true;
	 			break;
			 }
			 if(fl)
			 {
			 	break;
			 }
		 }
	 }
	 for(i=0;i<n;i++)//找出未打开且为雷的概率最小的格 
	 {
	 	for(j=0;j<m;j++)
	 	{
	 		if(P[i][j]<temp&&GamePanel[i][j]==-1)
	 		{
	 			x=i;
	 			y=j;
	 			temp=P[i][j];
			 }
		 }
	  } 
	  return ;
 }

发布了39 篇原创文章 · 获赞 22 · 访问量 1152

猜你喜欢

转载自blog.csdn.net/M_L_Fighting/article/details/105150505
今日推荐