上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人
5.5 灵活性分值
车所在位置的重要性,通过位置分值已经体现。但即使是在同一位置,如果周围全是棋子,限制了棋子的灵活性,这样往往会陷于被动挨打的局面。车的价值为什么比马大,主要是因为车的控制范围大,行动灵活,而马仅有有限的八个位置可走,而且还常常被马腿蹩住,难于动弹。
由此可见,灵活性在行棋中还是占有相当重要的作用。应当把棋子的灵活性考虑在估值函数中。棋子越灵活,价值越高。可以给棋子的灵活性以一定分值的奖励。
灵活性的度量
棋子灵活性的度量只能以棋子能走棋步数来体现,能走的位置越多,灵活性越高。因此在估值函数中计算每一个棋子的行棋步数,然后再给以一定分值的奖励。
各个棋子的灵活性分值分别为:
将:2,士:2,象:2,马:5,车:4,炮:3,卒:2
棋子每有一种走法,就增加一个灵活性分值。
程序代码
short Eval(void) { short i,j,k,r; unsigned char p; //p:棋子位置 unsigned char n; //下一步可能行走的位置 unsigned char m; //马腿、象眼位置 int SideTag; //走棋方,红方16,黑方32 int OverFlag; //炮的翻山标志 short bValue,wValue; short fValue[2]={0,0}; //灵活性分值 bValue = wValue = 0; //计算固定位置分值 for(i=16; i<32; i++) { if(piece[i]>0) wValue = wValue + PositionValues[0][PieceNumToType[i]][piece[i]]; } for(i=32; i<48; i++)
{ if(piece[i]>0) bValue = bValue + PositionValues[1][PieceNumToType[i]][piece[i]]; } //计算灵活性分值 for(r=0;r<=1;r++) { SideTag = 16 + 16 * r; //将的灵活性 for(k=0; k<4; k++)//4个方向 { n = p + KingDir[k];//n为新的可能走到的位置 if(LegalPosition[side][n] & PositionMask[0]) //将对应下标为0 { if( !(board[n] & SideTag)) //目标位置上没有本方棋子 fValue[r]+=2; } } //士的灵活性 for(i=1; i<=2; i++) { p = piece[SideTag + i]; if(!p) continue; for(k=0; k<4; k++)//4个方向 { n = p + AdvisorDir[k]; //n为新的可能走到的位置 if(LegalPosition[side][n] & PositionMask[1]) //士将对应下标为1 { if( !(board[n] & SideTag)) //目标位置上没有本方棋子 fValue[r]+=2; } } } //象的走法灵活性 for(i=3; i<=4; i++) { p = piece[SideTag + i]; if(!p) continue; for(k=0; k<4; k++)//4个方向
{ n = p + BishopDir[k]; //n为新的可能走到的位置 if(LegalPosition[side][n] & PositionMask[2]) //象将对应下标为2 { m = p + BishopCheck[k]; if(!board[m]) //象眼位置无棋子占据 { if( !(board[n] & SideTag)) //目标位置上没有本方棋子 fValue[r]+=2; } } } } //马的灵活性 for(i=5; i<=6; i++) { p = piece[SideTag + i]; if(!p) continue; for(k=0; k<8; k++)//8个方向 { n = p + KnightDir[k]; //n为新的可能走到的位置 if(LegalPosition[side][n] & PositionMask[3]) //马将对应下标为3 { m = p + KnightCheck[k]; if(!board[m]) //马腿位置无棋子占据 { if( !(board[n] & SideTag)) //目标位置上没有本方棋子 fValue[r]+=5; } } } } //车的灵活性 for(i=7; i<=8; i++) { p = piece[SideTag + i]; if(!p) continue; for(k=0; k<4; k++) //4个方向 { for(j=1; j<10; j++)//横的最多有8个可能走的位置,纵向最多有9个位置
{ n = p + j * RookDir[k]; if(!(LegalPosition[side][n] & PositionMask[4])) //车士将对应下标为4 break;//不合理的位置 if(! board[n] )//目标位置上无子 { fValue[r]+=4; } else if ( board[n] & SideTag) //目标位置上有本方棋子 break; else //目标位置上有对方棋子 { fValue[r]+=4; break; } } } } //炮的灵活性 for(i=9; i<=10; i++) { p = piece[SideTag + i]; if(!p) continue; for(k=0; k<4; k++) //4个方向 { OverFlag = 0; for(j=1; j<10; j++)//横的最多有8个可能走的位置,纵向最多有9个位置 { n = p + j * CannonDir[k]; if(!(LegalPosition[side][n] & PositionMask[5])) //炮士将对应下标为5 break;//不合理的位置 if(! board[n] )//目标位置上无子 { if(!OverFlag) //未翻山 fValue[r]+=3; //已翻山则不做处理,自动考察向下一个位置 } else//目标位置上有子 { if (!OverFlag) //未翻山则置翻山标志 OverFlag = 1; else //已翻山
{ if(! (board[n] & SideTag))//对方棋子 fValue[r]+=3; break; //不论吃不吃子,都退出此方向搜索 } } } } } //卒的灵活性 for(i=11; i<=15; i++) { p = piece[SideTag + i]; if(!p) continue; for(k=0; k<3; k++)//3个方向 { n = p + PawnDir[side][k]; //n为新的可能走到的位置 if(LegalPosition[side][n] & PositionMask[6]) //卒士将对应下标为6 { if( !(board[n] & SideTag)) //目标位置上没有本方棋子 fValue[r]+=2; } } } } return fValue[0] - fValue[1] + wValue - bValue; }
代码技巧
灵活性计算类似于走法生成。走法生成时,每有一个合理走法,则保存到走法列表中。在灵活性计算中,每有一个合理走法,则在总分值中增加该棋子的一个灵活性分值。总的估值为红方灵活性值加上红方位置值,减去黑方灵活性值和黑方位置值。
参见程序5-4.cpp。