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编辑过]