C语言从零起步分析《象眼》象棋引擎的源码(24)
											因为熟悉了底层函数,所以分析起来挺顺利的;
下面是生成所有下法函数:

程序代码:
// 生成所有走法
int PositionStruct::GenerateMoves(int *mvs) const {
//下法数组int mvs[128](在外部),*msv就是下法数组地址
  int i, j, nGenMoves, nDelta, sqSrc, sqDst;
  int pcSelfSide, pcOppSide, pcSrc, pcDst;
  // 生成所有走法,需要经过以下几个步骤:
  nGenMoves = 0;//下法计数器
  pcSelfSide = SIDE_TAG(sdPlayer);//取本方红8黑16
  pcOppSide = OPP_SIDE_TAG(sdPlayer);//取对方边红16黑8
  for (sqSrc = 0; sqSrc < 256; sqSrc ++) {//扫描棋盘的每个角落
    // 1. 找到一个本方棋子,再做以下判断:
    pcSrc = ucpcSquares[sqSrc];//取这1格的棋子编号
    if ((pcSrc & pcSelfSide) == 0) {
//pcSelfSide=8或16,仅仅检查二进制的第4或第5位;
        //如果不是我方棋子
      continue;
      //则忽略下面,并继续扫描
    }
    // 2. 根据棋子确定走法
    switch (pcSrc - pcSelfSide) {//pcSrc - pcSelfSide为棋子编号0-6
    case PIECE_KING://0//将(帅)
      for (i = 0; i < 4; i ++) {//将(帅)的4个方向
        sqDst = sqSrc + ccKingDelta[i];//计算取得终点
        // 帅(将)的步长static const char ccKingDelta[4] = {-16, -1, 1, 16};
        if (!IN_FORT(sqDst)) {//终点不在九宫
// 判断棋子是否在九宫中inline BOOL IN_FORT(int sq) { return ccInFort[sq] != 0;}
//ccInFort:在九宫的数组
          continue;//忽略以下(for以内)
        }
        pcDst = ucpcSquares[sqDst];//取终点棋子编号
        if ((pcDst & pcSelfSide) == 0) {//如果不是我方棋子
          mvs[nGenMoves] = MOVE(sqSrc, sqDst);//添加一步下法
          nGenMoves ++;
        }
      }
      break;
    case PIECE_ADVISOR://1//士
      for (i = 0; i < 4; i ++) {//士的4个方向
        sqDst = sqSrc + ccAdvisorDelta[i];//基于起点计算终点
// 仕(士)的步长static const char ccAdvisorDelta[4] = {-17, -15, 15, 17};
        if (!IN_FORT(sqDst)) {//终点不在九宫
          continue;//忽略以下(for以内)
        }
        pcDst = ucpcSquares[sqDst];//取终点棋子编号
        if ((pcDst & pcSelfSide) == 0) {//如果不是我方棋子
          mvs[nGenMoves] = MOVE(sqSrc, sqDst);//添加一步下法
          nGenMoves ++;
        }
      }
      break;
    case PIECE_BISHOP://2//象
      for (i = 0; i < 4; i ++) {//象的4个方向
        sqDst = sqSrc + ccAdvisorDelta[i];//这里也是计算士的步
        if (!(IN_BOARD(sqDst) && HOME_HALF(sqDst, sdPlayer) && ucpcSquares[sqDst] == 0)) {
            //(在棋盘范围之内 并且 终点未过河 并且 终点无子 )之否定,
            //即在棋盘之外,或者,终点过河 ,或者终点有子;
            //注意:这里终点有棋子,是压象眼的!
          continue;//忽略以下(for以内)
        }
        sqDst += ccAdvisorDelta[i];//再加士的步长,+2次士的步,就是象的步了;
        pcDst = ucpcSquares[sqDst];//取终点棋子编号
        if ((pcDst & pcSelfSide) == 0) {//如果不是我方棋子
          mvs[nGenMoves] = MOVE(sqSrc, sqDst);//添加一步下法
          nGenMoves ++;
        }
      }
      break;
      //帅0士1象2马3车4炮5兵6
    case PIECE_KNIGHT://3//马
      for (i = 0; i < 4; i ++) {//第一层,4次循环
        sqDst = sqSrc + ccKingDelta[i];//取将的步长,憋足处
// 帅(将)的步长static const char ccKingDelta[4] = {-16, -1, 1, 16};
        if (ucpcSquares[sqDst] != 0) {//憋足处有子
          continue;//忽略下,并继续上面的for循环
        }
        for (j = 0; j < 2; j ++) {//第2层,2次循环
          sqDst = sqSrc + ccKnightDelta[i][j];//基于起点计算终点
// 马的步长,以帅(将)的步长作为马腿static const char ccKnightDelta[4][2] = {{-33, -31}, {-18, 14}, {-14, 18}, {31, 33}};
          if (!IN_BOARD(sqDst)) {//棋盘之外
            continue;//忽略以下继续循环
          }
          pcDst = ucpcSquares[sqDst];//取终点棋子编号
          if ((pcDst & pcSelfSide) == 0) {//如果不是我方棋子
            mvs[nGenMoves] = MOVE(sqSrc, sqDst);//添加一步下法
            nGenMoves ++;
          }
        }
      }
      break;
    case PIECE_ROOK://4//车
      for (i = 0; i < 4; i ++) {//车的4个方向
        nDelta = ccKingDelta[i];// 帅(将)的步长
        sqDst = sqSrc + nDelta;//前进一步
        while (IN_BOARD(sqDst)) {//棋盘内
          pcDst = ucpcSquares[sqDst];//取格子棋子编号
          if (pcDst == 0) {//空位,则加下法
              mvs[nGenMoves] = MOVE(sqSrc, sqDst);
              nGenMoves ++;
          } else {//非空(有子)
            if ((pcDst & pcOppSide) != 0) {//如果是对方子
            //pcOppSide红16黑8,(pcDst & pcOppSide)位与运算,是对方子则非0;
              mvs[nGenMoves] = MOVE(sqSrc, sqDst);//添加下法
              nGenMoves ++;
            }
            break;//遇到子,则结束本方向的扫描;
          }
          sqDst += nDelta;//继续前进
        }
      }
      break;
    case PIECE_CANNON://5//炮
      for (i = 0; i < 4; i ++) {//炮的4个方向
        nDelta = ccKingDelta[i];// 帅(将)的步长
        sqDst = sqSrc + nDelta;//前进一步
        while (IN_BOARD(sqDst)) {//棋盘内
          pcDst = ucpcSquares[sqDst];
          if (pcDst == 0) {//空位,则加下法
            mvs[nGenMoves] = MOVE(sqSrc, sqDst);
            nGenMoves ++;
          } else {
            break;//遇到子,则结束while;
          }
          sqDst += nDelta;//继续前进
        }
        sqDst += nDelta;//再前进一步
        while (IN_BOARD(sqDst)) {//还在棋盘之内,炮扫隔子
          pcDst = ucpcSquares[sqDst];//取子编号
          if (pcDst != 0) {//非空
            if ((pcDst & pcOppSide) != 0) {//如果是对方子
              mvs[nGenMoves] = MOVE(sqSrc, sqDst);//加下法
              nGenMoves ++;
            }
            break;//结束while;
          }
          sqDst += nDelta;//是空,则继续前进
        }
      }
      break;
    case PIECE_PAWN://6//兵或卒
      sqDst = SQUARE_FORWARD(sqSrc, sdPlayer);// 纵向前进一步
      if (IN_BOARD(sqDst)) {//棋盘内
        pcDst = ucpcSquares[sqDst];//取格子中棋子编号
        if ((pcDst & pcSelfSide) == 0) {//如果不是自己的子
          mvs[nGenMoves] = MOVE(sqSrc, sqDst);//添加下法
          nGenMoves ++;
        }
      }
      if (AWAY_HALF(sqSrc, sdPlayer)) {//如果起点已过河
        for (nDelta = -1; nDelta <= 1; nDelta += 2) {//-1,1两次循环
          sqDst = sqSrc + nDelta;//计算终点
          if (IN_BOARD(sqDst)) {//棋盘内
            pcDst = ucpcSquares[sqDst];//取格子中棋子编号
            if ((pcDst & pcSelfSide) == 0) {//如果不是自己的子
              mvs[nGenMoves] = MOVE(sqSrc, sqDst);//添加下法
              nGenMoves ++;
            }
          }
        }
      }
      break;
    }
  }
  return nGenMoves;//返回下法的个数
}
[此贴子已经被作者于2016-3-28 16:23编辑过]