五子棋(人机)-粗暴版AI

根据五子棋黑白子的摆法,大致分为下列几种情况:

A为黑(白)子,X为空格

成五:AAAAA
活四:XAAAAX
死四:XAAAA或AAAAX
活三:XAAAX
死三:XAAA或AAAX
活二:XAAX
死二:XAA或AAX
活一:A
死一:XA或AX

--------------------------------------------------------------------我是分隔线-------------------------------------------------------------------------------

假设电脑执【白子】,玩家执【黑子】。轮到电脑落子的时候,电脑将对每一个空子计算一个评估值(这个评估值越大,这个空子就越有价值让电脑的白子下在这儿),取出评估值最大的一个空子,作为电脑将要落子的位置。

评估函数:评估每个棋盘上的空子,被评估的空子将被填【白子】(因为是电脑落子么),填了白子后,需要评估【1】多少白子练成线(因为越多白子练成线,对电脑越有利)【2】多少将要练成线的黑子,被这个白子打断了(还要考虑填了这个子后,电脑对人所落的子的破坏力)。这两个评估值相加所得的和越大,对电脑越有利。

粗暴版AI返回的是:遇到的第一个评估值最高的空子。

由上面可以得出:这版的AI只顾眼前这一步的最好情况,他并不考虑后几步将会出现的情况。

-----------------------------------------------------------------------------我是分隔线---------------------------------------------------------------------------

计分表如下:

白子连成五子 +10000 阻碍黑子连成五子 +1000
白子连成活四 +200 阻碍黑子连成活四 +100
白子连成死四 +50 阻碍黑子连成死四 +20
白子连成活三 +30 阻碍黑子连成活三 +10
白子连成死三 +8 阻碍黑子连成死三 +5
白子成成活二 +2 阻碍黑子连成活二 +1
白子连成死二 +2 阻碍黑子连成死二 +1
白子连成活一 +1 阻碍黑子连成活一 +0
白子连成活二 +1 阻碍黑子连成死一 +0

-----------------------------------------------------------------------------我是分隔线---------------------------------------------------------------------------

棋盘为16*16,电脑执白子(为2),玩家执黑子(为1)评估函数+选择函数如下:对空子的横、竖、正斜、反斜进行评估,这里为了代码简短,四条线上重复计算了两遍

void evaluate_naive()	//每个空子的评估函数。需要对人落子和电脑已落子进行评价。人落子电脑要堵,电脑自己落子要做成5子 
{		 
	memset(score,0,sizeof(score));
	int number1,number2,empty;
	for(int x=0;x<16;++x)
		for(int y=0;y<16;++y)
			if(pos[x][y]==0)//评估每个空子
				for(int i=-1;i<=1;++i) 
					for(int j=-1;j<=1;++j)
						if(!(i==0&&j==0))//0,0不动不用算 
						{
							number1=0,number2=0,empty=0;
							//对人落子评分(要对人所下的子进行围堵,玩家在这儿落子后的估分越高,电脑就越有必要下在这儿,来打破玩家的意图) 
							for(int k=1;k<=5;++k)
								if(x+i*k>=0&&x+i*k<=15&&y+j*k>=0&&y+j*k<=15&&pos[x+i*k][y+j*k]==1)	++number1;
								else if(x+i*k>=0&&x+i*k<=15&&y+j*k>=0&&y+j*k<=15&&pos[x+i*k][y+j*k]==0)	{++empty;break;}
								else	break;
							for(int k=-1;k>=-5;--k)
								if(x+i*k>=0&&x+i*k<=15&&y+j*k>=0&&y+j*k<=15&&pos[x+i*k][y+j*k]==1)	++number1;
								else if(x+i*k>=0&&x+i*k<=15&&y+j*k>=0&&y+j*k<=15&&pos[x+i*k][y+j*k]==0)	{++empty;break;}
								else	break;
							if(number1==1)	score[x][y]+=1;	//人若下该空子,就两子了,那么不管死活都是+1
							else if(number1==2) 
							{
								if(empty==1)	score[x][y]+=5;	//三子,死,+5
								else if(empty==2)	score[x][y]+=10;//三子,活,+10	 
							}
							else if(number1==3)
							{
								if(empty==1)	score[x][y]+=20;//四子,死,+20
								else if(empty==2)	score[x][y]+=100;//四子,活,+100 
							}
							else if(number1==4) score[x][y]+=1000;//五子,+1000
							//对电脑落子评分(我自己下了这个空子,会怎样)
							empty=0;
							for(int k=1;k<=5;++k)
								if(x+i*k>=0&&x+i*k<=15&&y+j*k>=0&&y+j*k<=15&&pos[x+i*k][y+j*k]==2)	++number2;
								else if(x+i*k>=0&&x+i*k<=15&&y+j*k>=0&&y+j*k<=15&&pos[x+i*k][y+j*k]==0)	{++empty;break;}
								else	break;
							for(int k=-1;k>=-5;--k)
								if(x+i*k>=0&&x+i*k<=15&&y+j*k>=0&&y+j*k<=15&&pos[x+i*k][y+j*k]==2)	++number2;
								else if(x+i*k>=0&&x+i*k<=15&&y+j*k>=0&&y+j*k<=15&&pos[x+i*k][y+j*k]==0)	{++empty;break;}
								else	break;
							if(number2==0)	score[x][y]+=1;	//电脑若下了该空子,就一子了,那么不管死活都是+1 
							else if(number2==1)	score[x][y]+=2;	//两子,+2 
							else if(number2==2) 
							{
								if(empty==1)	score[x][y]+=8;	//三子,死,+8
								else if(empty==2)	score[x][y]+=30;//三子,活,+30	
							}	 
							else if(number2==3)
							{
								if(empty==1)	score[x][y]+=50;//四子,死,+50 
								else if(empty==2)	score[x][y]+=200;//四子,活,+200 
							}
							else if(number2==4) score[x][y]+=10000;	//五子,+10000 
						}
}
void Chess::chess_ai_naive(int &x,int &y)//使用暴力法获取得分最高的空子 
{//搜的是当前的第一个最优解 
	evaluate_naive();
	int maxpos=0;
	for(int i=0;i<16;++i)
		for(int j=0;j<16;++j)	
			if(score[i][j]>maxpos)
			{
				maxpos=score[i][j];
				x=i;
				y=j;
			}
}


你可能感兴趣的:(五子棋(人机)-粗暴版AI)