C/C++中国象棋程序入门与提高
上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。