⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 decision.cpp

📁 在linux下使用qt来开发的五子棋
💻 CPP
字号:

#include "decision.h"
#include "analysechess.h"

/* 功能:空格位置填子进行预测,空格棋子附近两个格内有棋子才是合法字节点(10个子内,合法落子点为1个空格范围内) */
/* 传入参数 */

void Decision::BlankFilter( char (*realgrid)[15], char (*legalblank)[15] )
{
	//计算当前棋子总数
	int chessnum = 0;
	for( int i=0; i<15; i++)
	{
		for( int j=0; j<15; j++)
		{
			if ( realgrid[i][j] == 'W' || realgrid[i][j] == 'B' )
			{
				chessnum++;
			}
		}
	}
	
	//行和列遍历计算的范围,初始置为-2、+2,表示不在棋盘边缘时,计算方圆两个格有没有棋子
	int row1, row2, line1, line2;		

	//遍历整个棋盘空格
	for( int i=0; i<15; i++)
	{
		for( int j=0; j<15; j++)
		{
			//每个空格处搜索方面两个格内有没有已下的棋子
			if( realgrid[i][j] != 'W' && realgrid[i][j] != 'B')
			{
				//判断该空格在棋盘中的位置

				//计算方圆1个格有没有棋子,(10个子内,合法落子点为1个空格范围内)
				if( chessnum <= 10 )
				{
					//判断行
					switch( i ){
						case 0 : 
							{ row1 = 0; row2 = 1;break;}				//节点在第0行(1)
						case 14 : 
							{ row1 = -1; row2 = 0;break;}				//节点在第14行(15)
						default:
							{ row1 = -1; row2 = 1;}
					}
					//判断列
					switch( j ){
						case 0 : 
							{ line1 = 0; line2 = 1;break;}				//节点在第0列(1)
						case 14 : 
							{ line1 = -1; line2 = 0;break;}				//节点在第14列(15)
						default:
							{ line1 = -1; line2 = 1;break;}
					}
				}
				else
				{
					//判断行
					switch( i ){
						case 0 : 
							{ row1 = 0; row2 = 2;break;}				//节点在第0行(1)
						case 1 : 
							{ row1 = -1; row2 = 2;break;}				//节点在第1行(2)
						case 13 : 
							{ row1 = -2; row2 = 1;break;}				//节点在第13行(14)
						case 14 : 
							{ row1 = -2; row2 = 0;break;}				//节点在第14行(15)
						default:
							{ row1 = -2; row2 = 2;}
					}
					//判断列
					switch( j ){
						case 0 : 
							{ line1 = 0; line2 = 2;break;}				//节点在第0列(1)
						case 1 : 
							{ line1 = -1; line2 = 2;break;}				//节点在第1列(2)
						case 13 : 
							{ line1 = -2; line2 = 1;break;}				//节点在第13列(14)
						case 14 : 
							{ line1 = -2; line2 = 0;break;}				//节点在第14列(15)
						default:
							{ line1 = -2; line2 = 2;break;}
					}
				}

				//根据行和列遍历计算的范围row1、row2、line1、line2计算合法空格
				int countchess = 0;									//方圆两个格内棋子总数
				int countblank = 0;									//方圆两个格内棋子总数
				for( int m=row1; m<=row2; m++)
				{
					for( int n=line1; n<=line2; n++)
					{
						if( realgrid[i+m][j+n] == 'W' || realgrid[i+m][j+n] == 'B')
						{
							countchess++;
						}
						else
						{
							countblank++;
						}
					}
				}
				//根据方圆两个格内棋子总数(最小为1,节点自身),确定是否为有效空格
				if( countchess > 0 && countblank > 0 )
				{
					legalblank[i][j] = 'T';
				}

			}
            
		}
	}

}


//自己进攻的机会,权重加
//计算有没有三三,冲四,三四
/* 其实判断棋子胜利用的是递归,这里再用搜索的方法有点重复,但是考虑到统一查找方法的复杂度,暂时用两种方法来实现 */
/* 两种方法也不完全一样,分开算更容易理解 */
/* 方法1:递归。判断胜利时只找同色棋子,其两个相对的方向上结果相加 */
/* 方法2:数组循环。判断是否有连,这个连可以间隔一个空格,而且不能两个方向上递归相加,因为空格处没有对象,递归中断 */
/* 经分析,用两种方法比较好,方法2用1、0、-1表示三种棋,好计算 */

float Decision::MyChance( char (*realgrid)[15], const int &m, const int &n )
{
	//把棋盘棋子放到数字数组中,以便于搜索
	int numbergrid[15][15];
	int i,j;
	for( i=0; i<15; i++ )
	{
		for( j=0; j<15; j++ )
		{
			if( realgrid[i][j] == 'W')
			{
				numbergrid[i][j] = 1;
			}
			else if( realgrid[i][j] == 'B')
			{
				numbergrid[i][j] = -1;
			}
			else
			{
				numbergrid[i][j] = 0;
			}
		}
	}
	//四个大方向,搜索棋子,统计有所少三三,四四,以确定权值
	int five = 0;					float a = 100;
	int four = 0;					float b = 40;
	int chongfour = 0;				float c = 6.5;
	int three = 0;					float d = 5;
	int chongthree = 0;				float e = 0.6;
	int two = 0;					float f = 1;
	int bantwo = 0;					float g = 0.8;
	int chongtwo = 0;				float h = 0.2;
	int dire;
	for( dire=0; dire<4; dire++ )
	{
		//判断5连,如果是5连跳出循环,不再判断4连、3连、2连
		if( AnalyseChess::Five( numbergrid, m, n, dire ) == 1 )
		{
			five++;
			continue;
		}
		//判断4连
		int checkfour = AnalyseChess::Four( numbergrid, m, n, dire );
		if( checkfour == 2 )
        {
			four++;
			continue;
		}
		else if( checkfour == 1 )
		{
			chongfour++;
			continue;
		}
		//判断3连
		int checkthree = AnalyseChess::Three( numbergrid, m, n, dire );
		if( checkthree == 2 )
        {
			three++;
			continue;
		}
		else if( checkthree == 1 )
		{
			chongthree++;
			continue;
		}
		//判断2连
		int checktwo = AnalyseChess::Two( numbergrid, m, n, dire );
		if( checktwo == 3 )
		{
			two++;
			continue;
		}
		else if( checktwo == 2 )
        {
			bantwo++;
			continue;
		}
		else if( checktwo == 1 )
		{
			chongtwo++;
			continue;
		}
	}

	//方法1,自己五连				(可堵可空)
	//方法2,自己冲四   (可隔一空)(有堵,有足够空格(可暂忽略))
	//方法3,自己三连   (可隔一空)(无堵,有足够空格(可暂忽略))
	//方法4,自己二连   (可隔一空)(无堵,有足够空格(可暂忽略))
	//方法5,自己冲三   (可隔一空)(有堵,至少有2个空格)
	//方法6,自己冲二   (可隔一空)(有堵,至少有3个空格)
	float nodeweight = five * a + four * b + chongfour * c + three * d + chongthree * e + two * f + bantwo * g + chongtwo * h;

	//权重调整
	if( chongfour >= 2 )
	{
		nodeweight = nodeweight *1.5;			//双冲四,权重增加
	}
	if( chongfour >= 1 && three >=1 )
	{
		nodeweight = nodeweight *1.5;			//冲四活三,权重增加
	}
	if( three >= 2 )
	{
		nodeweight = nodeweight *1.5;			//双活三,权重增加
	}
	return nodeweight;
}


//对手进攻的机会,权重减,同上
//realgrid不一样,点grid[m][n]处棋子置成相反色了,即把自己的子当成对方的棋子计算棋势和权值
float Decision::RivalChance( char (*realgrid)[15], const int &m, const int &n )		
{
	//把棋盘棋子放到数字数组中,以便于搜索
	int numbergrid[15][15];
	int i,j;
	for( i=0; i<15; i++ )
	{
		for( j=0; j<15; j++ )
		{
			if( realgrid[i][j] == 'W')
			{
				numbergrid[i][j] = 1;
			}
			else if( realgrid[i][j] == 'B')
			{
				numbergrid[i][j] = -1;
			}
			else
			{
				numbergrid[i][j] = 0;
			}
		}
	}
	//四个大方向,搜索棋子,统计有所少三三,四四,以确定权值
	int five = 0;					float a = 69;		//权值比对方的一半少1,因为五子棋优先进攻
	int four = 0;					float b = 9;		//权值比对方的一半少0.1,因为五子棋优先进攻,这样也能防止权值相同不好处理
	int chongfour = 0;				float c = 3;
	int three = 0;					float d = 1.9;
	int chongthree = 0;				float e = 0.2;
	int two = 0;					float f = 0.4;
	int bantwo = 0;					float g = 0.3;
	int chongtwo = 0;				float h = 0.05;
	int dire;
	for( dire=0; dire<4; dire++ )
	{
		//判断5连,如果是5连跳出循环,不再判断4连、3连、2连
		if( AnalyseChess::Five( numbergrid, m, n, dire ) == 1 )
		{
			five++;
			continue;
		}
		//判断4连
		int checkfour = AnalyseChess::Four( numbergrid, m, n, dire );
		if( checkfour == 2 )
        {
			four++;
			continue;
		}
		else if( checkfour == 1 )
		{
			chongfour++;
			continue;
		}
		//判断3连
		int checkthree = AnalyseChess::Three( numbergrid, m, n, dire );
		if( checkthree == 2 )
        {
			three++;
			continue;
		}
		else if( checkthree == 1 )
		{
			chongthree++;
			continue;
		}
		//判断2连
		int checktwo = AnalyseChess::Two( numbergrid, m, n, dire );
		if( checktwo == 3 )
		{
			two++;
			continue;
		}
		else if( checktwo == 2 )
        {
			bantwo++;
			continue;
		}
		else if( checktwo == 1 )
		{
			chongtwo++;
			continue;
		}
	}

	//方法1,自己五连				(可堵可空)
	//方法2,自己冲四   (可隔一空)(有堵,有足够空格(可暂忽略))
	//方法3,自己三连   (可隔一空)(无堵,有足够空格(可暂忽略))
	//方法4,自己二连   (可隔一空)(无堵,有足够空格(可暂忽略))
	//方法5,自己冲三   (可隔一空)(有堵,至少有2个空格)
	//方法6,自己冲二   (可隔一空)(有堵,至少有3个空格)
	float nodeweight = five * a + four * b + chongfour * c + three * d + chongthree * e + two * f + bantwo * g + chongtwo * h;
	
	//权重调整
	if( chongfour >= 2 )
	{
		nodeweight = nodeweight *1.5;			//双冲四,权重增加
	}
	if( chongfour >= 1 && three >=1 )
	{
		nodeweight = nodeweight *1.5;			//冲四活三,权重增加
	}
	if( three >= 2 )
	{
		nodeweight = nodeweight *1.5;			//双活三,权重增加
	}
	return nodeweight;
}



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -