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

4.2 车炮马象(相)士(仕)卒(兵)将(帅)走法生成

每种棋子都有自己的行走规则,计算机程序进行走法生成,都是先穷举再排除。即先列举出全部可能的位置,再一个一个除去不合规则的走法,剩下的就是合理的走法。

不同棋子走法生成的共同点是:

● 找出棋子的下一可能位置n。

● 判断n是否在棋盘上。

● 判断n是否被本方棋子占据。

不同棋子应考虑的特殊问题:

● 将、士是否走出九宫。

● 象是否过河,象眼是否被堵。

● 马是否蹩脚。

● 炮要翻山吃子。

● 兵过河前只能前进,过河后可以前进和左右移动。

4.2.1 马的走法生成

马有八个可能行走的位置,其特殊点在于起点与终点之间的马腿位置不能被其他棋子占据。如图4-1所示为马的走棋规则示意图。

图4-1 马走法示意图

图中黑三角形位置是马腿位置,1、2位置的马腿位置相同,3和4,5和6,7和8的马腿位置也相同。由于马是固定最多有八个可能位置,所以可以将这八个位置用一个数组保存走来。同样,每一个可能位置的马腿位置也是固定的,也用一个数组保存起来,而且它与方向数组相对应。

八个可行方向的数组表示

          KnightDir[8] ={ +0x0e, -0x12,-0x21,-0x1f, -0x0e, +0x12,+0x1f,+0x21},

每个方向对应的马腿位置数组表示

          KnightCheck[8] = {-0x01, -0x01,-0x10,-0x10, +0x01, +0x01,+0x10,+0x10},

KnightDir[i]位置对应的马腿位置即为KnightCheck[i]。

算法4-1:生成马的走法

          输入:马的位置p
          输出:马的所有可能走法
          1现在位置p
          2八个可行方向(i=0 … 7)
              3计算下一位置n
              4 n是否在棋盘上
            是,转第5步
            不是,转第2步
              5 从p到n的马腿位置m上是否有棋子
            有,转第2步
            没有,转第6步
              6 n是否被本方棋子占据
            是,转第2步
            不是,保存可行的走法,考虑下一位置转第2步

程序代码

          typedef struct {
              unsigned char  from, to;
          }move;
          move MoveArray[128];//走法数组
          int MoveNum;//走法总数
          void InitGen()//清空走法
          {
              MoveNum = 0;
          }
          void SaveMove(unsigned char from, unsigned char to)//保存走法
          {
              MoveArray[MoveNum].from = from;
              MoveArray[MoveNum].to = to;
              MoveNum++;
          }
          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(KnightPosition[n])//是否在棋盘上
                {
                    m = p + KnightCheck[k];
                    if(!board[m])   //马腿位置无棋子占据
                    {
                        if( !(board[n] & SideTag)) //目标位置上没有本方棋子
                            SaveMove(p, n);
                    }
                }
              }
          }

代码技巧

下一位置n:n = p+ KnightDir [i]

如何判断n是否在棋盘上:

横坐标x = n /16(整除)

纵坐标y = n % 16

x>=3 && x<=12 && y>=3 && y<=11

要做两个除法运算,四个逻辑判断运算,效率比较低。

可以设置一个辅助数组,表示哪些位置是马在棋盘上的合理位置。

          const char KnightPosition[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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
            0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
            0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
            0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
            0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
            0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
            0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
            0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
            0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
            0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 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
          };

要判断n是否在棋盘上,则只需要运算if(KnightPosition [n])

马腿位置m: m = p + KnightCheck[i]

马腿位置m上是否有棋子:if(board[m])

n是否被本方棋子占据:对红方:board[n] & 16 !=0即被本方棋子占据;对黑方:board[n]& 32 !=0即被本方棋子占据。在本程序中设置一个SideTag,走棋为红方时SideTag=16,走棋为黑方时SideTag=32

算法描述中,生成的走法作为算法的输出。生成的走法不只一个,函数不可能返回多个值。在实际程序设计时,用数组来保存生成的所有走法。并且将这个走法定义为一个全局的变量。设一维数组move gen[1024]表示走法,设整型变量int num表示生成走法个数。一旦生成一个走法,保存走法则执行下面三行代码。

          Gen[num].from = p; gen[num].to = n; num++;

4.2.2 将(帅)的走法生成

将有四个可能走的位置,如图4-2所示为将走法示意图。

图4-2 将走法示意图

把这四个方向用一个数组表示起来。

KingDir[8] ={-0×10, +0×01, +0×10, -0×01, 0, 0, 0, 0}

算法4-2:生成将的走法

          输入:将的位置p
          输出:将的所有可能走法
          1现在位置p
          2四个可行方向
              3计算下一位置n
              4 n是否在九宫内
                是,转第5步
                不是,转第2步
              5 n是否被本方棋子占据
                是,转第2步
                不是,保存可行的走法,考虑下一位置转第2步

程序代码

          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(KingPosition[n])
                {
                    if( !(board[n] & SideTag)) //目标位置上没有本方棋子
                        SaveMove(p, n);
                }
              }
          }

代码技巧

判断是否在九宫:设置一个数组,表示将所有合理的位置

          const char KingPisition[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, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 1, 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, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 1, 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
          };

判断是否在九宫,即只需执行if(KingPosition[n])。

对生成走法的保存处理与前面一样。

4.2.3 士(仕)的走法生成

士有四个可能走的位置,如图4-3的示为士走法示意图。

图4-3 士走法示意图

把这四个方向用一个数组表示起来。

Advisor Dir[8]={-0×11, -0×0f, +0×11, +0×0f, 0, 0, 0, 0}

算法4-3:生成士的走法

      输入:士的位置p
      输出:士的所有可能走法
      1现在位置p
      2四个可行方向
          3计算下一位置n
          4 n是否在九宫内
              是,转第5步
              不是,转第2步
          5 n是否被本方棋子占据
              是,转第2步
              不是,保存可行的走法,考虑下一位置转第2步

程序代码

          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(AdvisorPisition[n])
                {
                    if( !(board[n] & SideTag)) //目标位置上没有本方棋子
                        SaveMove(p, n);
                }
              }
          }

代码技巧

判断士是否在九宫:设置一个数组,表示将所有合理的位置

          const char AdvisorPisition[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, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 1, 0, 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, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 1, 0, 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
          };

判断士是否在九宫,即只需执行if(AdvisorPosition[n])

4.2.4 象(相)的走法生成

象有四个可能走的位置,如图4-4所示。

图4-4 象走法示意图

黑三角形位置就是对应位置的象眼。象眼被棋子占住,俗称象眼被塞,不能走到对应的位置。

把象的可行方向及对应的象眼位置分别用数组存储。

四个可行方向

          BishopDir[8]={ -0×22,  -0×1e, +0×22, +0×1e, 0,  0,  0,  0}

四个方向对应的象眼位置

          BishopCheck[8] = {-0×11,-0×0f, +0×11,+0×0f, 0,0,0,0},

算法4-4:生成象的走法

          输入:象的位置p
          输出:象的所有可能走法
          1现在位置p
          2四个可行方向
              3计算下一位置n
              4 n是否在棋盘上
                是,转第5步
                不是,转第2步
              5 从p到n的象眼位置m上是否有棋子
                有,转第2步
                没有,转第6步
              6 n是否被本方棋子占据
                是,转第2步
                不是,保存可行的走法,考虑下一位置转第2步

程序代码

          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(BishopPosition[n])
                {
                    m = p + BishopCheck[k];
                    if(!board[m])   //象眼位置无棋子占据
                    {
                        if( !(board[n] & SideTag)) //目标位置上没有本方棋子
                            SaveMove(p, n);
                    }
                }
              }
          }

代码技巧

设置数组表示象的合理位置

          const char BishopPosition[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, 0, 0, 1, 0, 0, 0, 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, 1, 0, 0, 0, 1, 0, 0, 0, 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, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 1, 0, 0, 0, 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, 1, 0, 0, 0, 1, 0, 0, 0, 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, 1, 0, 0, 0, 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
          };

4.2.5 车的走法生成

如图4-5所示车可以沿着四条直线走,每个方向可一直向前走,直到:

1. 走出棋盘

2. 碰到本方棋子

3. 吃掉对方棋子。

在上图4-5中,1、4位置表示一直走到边界,2位置表示遇到本方棋子,3位置表示遇到对方棋子。

同样,把车的四个可行方向用数组存储起来

          RookDir[8]={-0×01, -0×10, +0×01, +0×10, 0,  0,  0,  0},

但是,车沿着这个方向可以一直向前走,直到走出棋盘/碰到本方棋子/吃掉对方棋子。这样在算法或程序的处理时,与马、象等是有区别的。

图4-5 车走法示意图

算法4-5:生成车的走法

      输入:车的位置p
      输出:车的所有可能走法
      1现在位置p
      2四个可行方向   //第一重循环
          3沿这个方向继续前进一步(最多前进9步) //第二重循环
              4计算下一位置n
              5 n是否在棋盘上
                  是,转第6步
                  不是,转第2步
              6 n位置上是否有棋子
                  没有,保存可行的走法,考虑下一位置转第3步(不吃子走法)
                  有棋子则,该棋子是本方棋子
                      是,转第3步
                      不是,保存可行的走法,考虑下一位置转第3步(吃子走法)

程序代码

          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(! KnightPosition[n])//不合理的位置
                        break;
                    if(! board[n] )//目标位置上无子
                        SaveMove(p, n);
                    else if ( board[n] & SideTag)  //目标位置上有本方棋子
                        break;
                    else    //目标位置上有对方棋子
                    {
                        SaveMove(p, n);
                        break;
                    }
                }
              }
          }

代码技巧

车的算法中有两重循环,因为沿每一方向都可有很多的位置可走。

车能走到的地方,也是马可以到达的地方,所以判断车的位置是否合理的数组与马的相同。

4.2.6 炮的走法生成

如图4-6所示炮也是沿着四条直线走,每个可行方向可一直向前走,直到走出棋盘、碰到棋子后可再向前吃掉对方棋子。

在上图4-6中,1表示一直走到边界,2位置翻山后遇到本方棋子,3表示翻山后遇到对方棋子,4表示翻山后走到边界。

图4-6 炮走法示意图

同样,把炮的四个可行方向用数组存储起来

          CannonDir[8]={-0×01,   +0×01, -0×10, +0×10, 0,  0,  0,  0},

炮与车行棋规则既相似,又不同。炮也可以沿着一个方向一直向前走,遇到一个棋子后,如果是对方棋子炮不能直接吃掉。不论遇到的是何方棋子,炮可以翻过去向前,俗称翻山。翻山后,炮只能吃对方的棋子,不能落到空的位置,当然也不能吃掉本方棋子。

算法4-6:生成炮的走法

      输入:炮的位置p
      输出:炮的所有可能走法
      1现在位置p
      2四个可行方向   //第一重循环
          翻山标志置0, OverFlag =0
          3沿这个方向继续前进一步(最多前进9步) //第二重循环
              4计算下一位置n
              5 n是否在棋盘上
                  是,转第6步
                  不是,转第2步
              6 n位置上是否有棋子
                  没有棋子
                      如果OverFlag==0,保存可行的走法(不吃子走法),转第3步
                      否则,转第3步
                  有棋子则,
                      如果OverFlag==0,则令OverFlag=1。(翻山)
                      否则,如果该棋子是本方棋子
                          不是,保存可行的走法(吃子走法),转第2步
                          是,转第2步。

程序代码

          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(!KnightPosition[n]) //不合理的位置
                        break;
                    if(! board[n] )//目标位置上无子
                    {
                        if(!OverFlag)   //未翻山
                            SaveMove(p, n);
                        //已翻山则不做处理,自动考察向下一个位置
                    }
                    else//目标位置上有子
                    {
                        if (!OverFlag)  //未翻山则置翻山标志
                            OverFlag = 1;
                        else    //已翻山
                        {
                            if(! (board[n] & SideTag))//对方棋子
                                SaveMove(p, n);
                            break;  //不论吃不吃子,都退出此方向搜索
                        }
                    }
                }
              }
          }

代码技巧

炮的算法中有两重循环,因为沿每一方向都可有很多的位置可走。炮的算法与车的不同之处在于,炮沿一个方向行进碰到一棋子,不是直接吃掉,而是越过此棋子继续向前行进。一旦越过一棋子,则只能吃掉下一棋子,而不能停留在没有棋子的位置上。所以,在向一个方向前进时,必须增加一个变量int OverFlag,用以表示当前是否已经翻山。炮行进时没有翻山时只能停留在空闲的交叉点上,而翻山后只能落在被对方棋子占据的交叉点上并吃掉对方的棋子。

炮能走到的地方,也是马可以到达的地方,判断炮的位置是否合理的数组与马的相同。

4.2.7 卒(兵)的走法生成

兵未过河之间只能向前,过河之后可以横向移动,如图4-7所示。

兵的走法与前面所有的棋子走法有一个最大的区别就是,红兵和黑卒是不一样的。红马和黑马的走法是没有区别的,在同一个位置,红马可以去的地方,黑马也可以去。士象将虽然也有红黑之分,即红相能到的地方,黑象是绝对到不了的,红仕能到的地方,黑士是绝对到不了的,红帅能到的地方,黑将是绝对到不了的。但是就其行进的方位来讲是相同的,象是前后左右四个田字,士是四个斜线方向,将是上下左右四个方向。

图4-7 红兵走法示意图

站在红方的角度,红兵前进的方向,就是黑卒后退的方向。所以黑卒与红兵一定得分开处理。用一个二维数组表示它们不同的方向。

          PawnDir[2][8]={{-0×01, +0×01, -0×10, 0,  0,  0,  0,  0},
          {-0×01, +0×01, +0×10, 0,  0,  0,  0,  0}},

PawnDir[0]表示红方的方向,PawnDir[1]表示黑方的方向。

算法4-7:生成兵的走法

          输入:兵的位置p
          输出:兵的所有可能走法
          1现在位置p
          2三个可行方向
              3计算下一位置n = p + PawnDir[side][n];
              4 n是否在棋盘上
            是,转第5步
            不是,转第2步
              5 是否未过河横向移动
            是,转第2步
            不是,转第6步
              6 n是否被本方棋子占据
            是,转第2步
            不是,保存可行的走法,考虑下一位置转第2步

程序代码

          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(PawnPosition[side][n])
                {
                    if( !(board[n] & SideTag)) //目标位置上没有本方棋子
                        SaveMove(p, n);
                }
              }
          }

代码技巧

同样可以设置兵的合理位置数组

          short PawnPosition[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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
              0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
              0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
              0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
              0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
              0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0,
              0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 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, 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, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0,
              0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0,
              0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
              0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
              0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
              0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
              0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 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
              }
          };

黑卒位置是否在棋盘上及是否未过河横向移动,均可用此数组判断。

          If (PawnPosition[1][n]) 则是合理的移动位置
          红兵则是If (PawnPosition[0][n])