C/C++中国象棋程序入门与提高
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

4.4 简化合理位置数组

七种兵力,有五种合理位置数组,其实我们可以简化一下,用一个数组来表示。

各种棋子能到的位置设不同的值,如表4-1和表4-2所示。

表4-1 每个棋子能到达的位置特征值

注意:位置的值只能取2n的形式,便于组合,也便于进行运算

表4-2 多个棋子能到达的位置特征值

注意:多个棋子能到达的位置特征值是单个棋子能到达位置特征值进行加法运算。

所有棋子的合理位置数组简化为一个位置数组

          short LegalPosition[2][256] ={
          {//红方
              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
              0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0,
              0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0,
              0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0,
              0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0,
              0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0,
              0, 0, 0, 9, 1,25, 1, 9, 1,25, 1, 9, 0, 0, 0, 0,
              0, 0, 0, 9, 1, 9, 1, 9, 1, 9, 1, 9, 0, 0, 0, 0,
              0, 0, 0, 17, 1, 1, 7, 19, 7, 1, 1, 17, 0, 0, 0, 0,
              0, 0, 0, 1, 1, 1, 3, 7, 3, 1, 1, 1, 0, 0, 0, 0,
              0, 0, 0, 1, 1, 17, 7, 3, 7, 17, 1, 1, 0, 0, 0, 0,
              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
          },
          {//黑方
              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
              0, 0, 0, 1, 1, 17, 7, 3, 7, 17, 1, 1, 0, 0, 0, 0,
              0, 0, 0, 1, 1, 1, 3, 7, 3, 1, 1, 1, 0, 0, 0, 0,
              0, 0, 0, 17, 1, 1, 7, 19, 7, 1, 1, 17, 0, 0, 0, 0,
              0, 0, 0, 9, 1, 9, 1, 9, 1, 9, 1, 9, 0, 0, 0, 0,
              0, 0, 0, 9, 1,25, 1, 9, 1,25, 1, 9, 0, 0, 0, 0,
              0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0,
              0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0,
              0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0,
              0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0,
              0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0,
              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
              0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
          }
          };
          short PositionMask [7] = {2, 4, 16, 1, 1, 1, 8},

PositionMask数组表示的是每个棋子能到达的位置特征值,依次为将(帅)、士(仕)、象(相)、车、马、炮、卒(兵)。如果要判断一个位置是否是将的合理位置,只需要进行运算:LegalPosition[side][n] & PositionMask[0]

程序代码

          void KingMove(unsigned char p)
          {
              int k;
              unsigned char n;//下一步可能行走的位置
              int SideTag = 16 + side * 16;  //走棋方,红方16,黑方32
              for(k=0; k<4; k++)//4个方向
              {
                n = p + KingDir[k];//n为新的可能走到的位置
                if(LegalPosition[side][n] & PositionMask[0])   //将对应下标为0
                {
                    if( !(board[n] & SideTag)) //目标位置上没有本方棋子
                        SaveMove(p, n);
                }
              }
          }
          void AdvisorMove(unsigned char p)
          {
              int k;
              unsigned char n;//下一步可能行走的位置
              int SideTag = 16 + side * 16;  //走棋方,红方16,黑方32
              for(k=0; k<4; k++)//4个方向
              {
                n = p + AdvisorDir[k]; //n为新的可能走到的位置
                if(LegalPosition[side][n] & PositionMask[1])//士将对应下标为1
                {
                    if( !(board[n] & SideTag)) //目标位置上没有本方棋子
                        SaveMove(p, n);
                }
              }
          }
          void BishopMove(unsigned char p)
          {
              int k;
              unsigned char n;//下一步可能行走的位置
              unsigned char m;//象眼位置
              int SideTag = 16 + side * 16;  //走棋方,红方16,黑方32
              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)) //目标位置上没有本方棋子
                            SaveMove(p, n);
                    }
                }
              }
          }
          void KnightMove(unsigned char p)
          {
              int k;
              unsigned char n;//下一步可能行走的位置
              unsigned char m;//马腿位置
              int SideTag = 16 + side * 16;  //走棋方,红方16,黑方32
              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)) //目标位置上没有本方棋子
                            SaveMove(p, n);
                    }
                }
              }
          }
          void RookMove(unsigned char p)
          {
              int k,j;
              unsigned char n;//下一步可能行走的位置
              int SideTag = 16 + side * 16;  //走棋方,红方16,黑方32
              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] )//目标位置上无子
                        SaveMove(p, n);
                    else if ( board[n] & SideTag)  //目标位置上有本方棋子
                        break;
                    else    //目标位置上有对方棋子
                    {
                        SaveMove(p, n);
                        break;
                    }
                }
              }
          }
          void CannonMove(unsigned char p)
          {
              int k,j;
              unsigned char n;//下一步可能行走的位置
              int SideTag = 16 + side * 16;  //走棋方,红方16,黑方32
              int OverFlag;
              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)   //未翻山
                            SaveMove(p, n);
                        //已翻山则不做处理,自动考察向下一个位置
                    }
                    else//目标位置上有子
                    {
                        if (!OverFlag)  //未翻山则置翻山标志
                            OverFlag = 1;
                        else    //已翻山
                        {
                            if(! (board[n] & SideTag))//对方棋子
                                SaveMove(p, n);
                            break;  //不论吃不吃子,都退出此方向搜索
                        }
                    }
                }
              }
          }
          void PawnMove(unsigned char p)
          {
              int k;
              unsigned char n;//下一步可能行走的位置
              int SideTag = 16 + side * 16;  //走棋方,红方16,黑方32
              for(k=0; k<3; k++)//3个方向
              {
                n = p + PawnDir[side][k];  //n为新的可能走到的位置
                if(LegalPosition[side][n] & PositionMask[6])//卒士将对应下标为6
                {
                    if( !(board[n] & SideTag)) //目标位置上没有本方棋子
                        SaveMove(p, n);
                }
              }
          }