X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=moves.c;h=58cbfc008c47f8f794aa83acc0ebb1fe348d2bbf;hb=fa76217dec3666d46e537483a60ea7b9e9568e33;hp=2070ef37c6c9b2dfaf606e82947a90f5bd1d1409;hpb=7e4f4f5718bf4efee8be4abfc981d18cfd6f8438;p=xboard.git diff --git a/moves.c b/moves.c index 2070ef3..58cbfc0 100644 --- a/moves.c +++ b/moves.c @@ -117,102 +117,45 @@ ChessSquare PromoPiece(moveType) return WhiteKing; case BlackPromotionKing: return BlackKing; -#ifdef FAIRY case WhitePromotionChancellor: return WhiteMarshall; case BlackPromotionChancellor: return BlackMarshall; case WhitePromotionArchbishop: - return WhiteCardinal; + return WhiteAngel; case BlackPromotionArchbishop: - return BlackCardinal; -#endif - } -} - -ChessMove PromoCharToMoveType(whiteOnMove, promoChar) - int whiteOnMove; - int promoChar; -{ - if (whiteOnMove) { - switch (promoChar) { - case 'n': - case 'N': - return WhitePromotionKnight; - case 'b': - case 'B': - return WhitePromotionBishop; - case 'r': - case 'R': - return WhitePromotionRook; -#ifdef FAIRY - case 'a': - case 'A': - return WhitePromotionArchbishop; - case 'c': - case 'C': - return WhitePromotionChancellor; -#endif - case 'q': - case 'Q': - return WhitePromotionQueen; - case 'k': - case 'K': - return WhitePromotionKing; - case NULLCHAR: - default: - return NormalMove; - } - } else { - switch (promoChar) { - case 'n': - case 'N': - return BlackPromotionKnight; - case 'b': - case 'B': - return BlackPromotionBishop; - case 'r': - case 'R': - return BlackPromotionRook; -#ifdef FAIRY - case 'a': - case 'A': - return BlackPromotionArchbishop; - case 'c': - case 'C': - return BlackPromotionChancellor; -#endif - case 'q': - case 'Q': - return BlackPromotionQueen; - case 'k': - case 'K': - return BlackPromotionKing; - case NULLCHAR: - default: - return NormalMove; - } + return BlackAngel; + case WhitePromotionCentaur: + return WhiteSilver; + case BlackPromotionCentaur: + return BlackSilver; } } char pieceToChar[] = { - 'P', 'N', 'B', 'R', 'Q', -#ifdef FAIRY - 'F', 'W', 'E', 'H', 'A', 'C', 'G', 'O', 'M', 'U', -#endif - 'K', 'p', 'n', 'b', 'r', 'q', -#ifdef FAIRY - 'f', 'w', 'e', 'h', 'a', 'c', 'g', 'o', 'm', 'u', -#endif - 'k', 'x' - }; + 'P', 'N', 'B', 'R', 'Q', 'F', 'E', 'A', 'C', 'W', 'M', + 'O', 'H', 'I', 'J', 'G', 'D', 'V', 'L', 's', 'U', 'K', + 'p', 'n', 'b', 'r', 'q', 'f', 'e', 'a', 'c', 'w', 'm', + 'o', 'h', 'i', 'j', 'g', 'd', 'v', 'l', 's', 'u', 'k', + 'x' }; char PieceToChar(p) ChessSquare p; { + if((int)p < 0 || (int)p >= (int)EmptySquare) return('x'); /* [HGM] for safety */ return pieceToChar[(int) p]; } +int PieceToNumber(p) /* [HGM] holdings: count piece type, ignoring non-participating piece types */ + ChessSquare p; +{ + int i=0; + ChessSquare start = (int)p >= (int)BlackPawn ? BlackPawn : WhitePawn; + + while(start++ != p) if(pieceToChar[(int)start-1] != '.') i++; + return i; +} + ChessSquare CharToPiece(c) int c; { @@ -220,48 +163,52 @@ ChessSquare CharToPiece(c) for(i=0; i< (int) EmptySquare; i++) if(pieceToChar[i] == c) return (ChessSquare) i; return EmptySquare; -/* [HGM] code marked for deletion - switch (c) { - default: - case 'x': return EmptySquare; - case 'P': return WhitePawn; - case 'R': return WhiteRook; - case 'N': return WhiteKnight; - case 'B': return WhiteBishop; - case 'Q': return WhiteQueen; - case 'K': return WhiteKing; - case 'p': return BlackPawn; - case 'r': return BlackRook; - case 'n': return BlackKnight; - case 'b': return BlackBishop; - case 'q': return BlackQueen; - case 'k': return BlackKing; -#ifdef FAIRY - case 'A': return WhiteCardinal; - case 'C': return WhiteMarshall; - case 'F': return WhiteFerz; - case 'H': return WhiteNightrider; - case 'E': return WhiteAlfil; - case 'W': return WhiteWazir; - case 'U': return WhiteUnicorn; - case 'O': return WhiteCannon; - case 'G': return WhiteGrasshopper; - case 'M': return WhiteMan; - - case 'a': return BlackCardinal; - case 'c': return BlackMarshall; - case 'f': return BlackFerz; - case 'h': return BlackNightrider; - case 'e': return BlackAlfil; - case 'w': return BlackWazir; - case 'u': return BlackUnicorn; - case 'o': return BlackCannon; - case 'g': return BlackGrasshopper; - case 'm': return BlackMan; - -#endif - } -*/ +} + +ChessMove PromoCharToMoveType(whiteOnMove, promoChar) + int whiteOnMove; + int promoChar; +{ /* [HGM] made dependent on CharToPiece to alow alternate piece letters */ + ChessSquare piece = CharToPiece(whiteOnMove ? ToUpper(promoChar) : ToLower(promoChar) ); + if(promoChar == NULLCHAR) return NormalMove; + + switch(piece) { + case WhiteQueen: + return WhitePromotionQueen; + case WhiteRook: + return WhitePromotionRook; + case WhiteBishop: + return WhitePromotionBishop; + case WhiteKnight: + return WhitePromotionKnight; + case WhiteKing: + return WhitePromotionKing; + case WhiteAngel: + return WhitePromotionArchbishop; + case WhiteMarshall: + return WhitePromotionChancellor; + case WhiteSilver: + return WhitePromotionCentaur; + case BlackQueen: + return BlackPromotionQueen; + case BlackRook: + return BlackPromotionRook; + case BlackBishop: + return BlackPromotionBishop; + case BlackKnight: + return BlackPromotionKnight; + case BlackKing: + return BlackPromotionKing; + case BlackAngel: + return BlackPromotionArchbishop; + case BlackMarshall: + return BlackPromotionChancellor; + case BlackSilver: + return BlackPromotionCentaur; + default: + // not all promotion implemented yet! Take Queen for those we don't know. + return (whiteOnMove ? WhitePromotionQueen : BlackPromotionQueen); + } } void CopyBoard(to, from) @@ -316,9 +263,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) if (!BlackPiece(board[rf][ff])) continue; } m = 0; piece = board[rf][ff]; - if(gameInfo.variant == VariantCrazyhouse && - ( (int) piece > (int) WhiteQueen && (int) piece < (int) WhiteKing - || (int) piece > (int) BlackQueen && (int) piece < (int) BlackKing )) + if(PieceToChar(piece) == '~') piece = (ChessSquare) ( DEMOTED piece ); if(gameInfo.variant == VariantShogi) piece = (ChessSquare) ( SHOGI piece ); @@ -329,8 +274,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) /* can't happen ([HGM] except for faries...) */ break; - case WhitePawn: -#ifdef FAIRY + case WhitePawn: if(gameInfo.variant == VariantXiangqi) { /* [HGM] capture and move straight ahead in Xiangqi */ if (rf < BOARD_HEIGHT-1 && @@ -349,7 +293,6 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) } break; } -#endif if (rf < BOARD_HEIGHT-1 && board[rf + 1][ff] == EmptySquare) { callback(board, flags, rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove, @@ -383,7 +326,6 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) break; case BlackPawn: -#ifdef FAIRY if(gameInfo.variant == VariantXiangqi) { /* [HGM] capture straight ahead in Xiangqi */ if (rf > 0 && !SameColor(board[rf][ff], board[rf - 1][ff]) ) { @@ -401,7 +343,6 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) } break; } -#endif if (rf > 0 && board[rf - 1][ff] == EmptySquare) { callback(board, flags, rf == 1 ? BlackPromotionQueen : NormalMove, @@ -434,10 +375,8 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) } break; -#ifdef FAIRY case WhiteUnicorn: case BlackUnicorn: -#endif case WhiteKnight: case BlackKnight: mounted: @@ -454,13 +393,11 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) } break; -#ifdef FAIRY case SHOGI WhiteKnight: for (s = -1; s <= 1; s += 2) { if (rf < BOARD_HEIGHT-2 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT && !SameColor(board[rf][ff], board[rf + 2][ff + s])) { - callback(board, flags, - rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove, + callback(board, flags, NormalMove, rf, ff, rf + 2, ff + s, closure); } } @@ -470,8 +407,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) for (s = -1; s <= 1; s += 2) { if (rf > 1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT && !SameColor(board[rf][ff], board[rf - 2][ff + s])) { - callback(board, flags, - rf == 1 ? BlackPromotionQueen : NormalMove, + callback(board, flags, NormalMove, rf, ff, rf - 2, ff + s, closure); } } @@ -508,8 +444,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) for (s = -1; s <= 1; s += 2) { if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT && !SameColor(board[rf][ff], board[rf + 1][ff + s])) { - callback(board, flags, - rf == BOARD_HEIGHT-2 ? WhitePromotionQueen : NormalMove, + callback(board, flags, NormalMove, rf, ff, rf + 1, ff + s, closure); } } @@ -523,8 +458,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) for (s = -1; s <= 1; s += 2) { if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT && !SameColor(board[rf][ff], board[rf - 1][ff + s])) { - callback(board, flags, - rf == 1 ? BlackPromotionQueen : NormalMove, + callback(board, flags, NormalMove, rf, ff, rf - 1, ff + s, closure); } } @@ -567,14 +501,13 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) m++; /* Capablanca Archbishop continues as Knight */ - case WhiteCardinal: - case BlackCardinal: + case WhiteAngel: + case BlackAngel: m++; /* Shogi Bishops are ordinary Bishops */ case SHOGI WhiteBishop: case SHOGI BlackBishop: -#endif case WhiteBishop: case BlackBishop: for (rs = -1; rs <= 1; rs += 2) @@ -593,7 +526,6 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) /* Bishop falls through */ break; -#ifdef FAIRY /* Shogi Lance is unlike anything, and asymmetric at that */ case SHOGI WhiteQueen: for(i = 1;; i++) { @@ -620,8 +552,8 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) break; /* Shogi Dragon King has to continue as Ferz after Rook moves */ - case SHOGI WhiteMarshall: - case SHOGI BlackMarshall: + case SHOGI WhiteDragon: + case SHOGI BlackDragon: m++; /* Capablanca Chancellor sets flag to continue as Knight */ @@ -632,7 +564,6 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) /* Shogi Rooks are ordinary Rooks */ case SHOGI WhiteRook: case SHOGI BlackRook: -#endif case WhiteRook: case BlackRook: for (d = 0; d <= 1; d++) @@ -647,7 +578,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) if (board[rt][ft] != EmptySquare) break; } if(m==1) goto mounted; - if(m==2) goto walking; + if(m==2) goto finishGold; break; case WhiteQueen: @@ -667,7 +598,6 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) } break; -#ifdef FAIRY /* Shogi Pawn and Silver General: first the Pawn move, */ /* then the General continues like a Ferz */ case SHOGI WhitePawn: @@ -695,7 +625,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) for (fs = -1; fs <= 1; fs += 2) { rt = rf + rs; ft = ff + fs; - if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break; + if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue; if (!SameColor(board[rf][ff], board[rt][ft]) && (gameInfo.variant != VariantXiangqi || InPalace(rt, ft) ) ) callback(board, flags, NormalMove, @@ -703,11 +633,13 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) } break; + case WhiteSilver: + case BlackSilver: + m++; // [HGM] superchess: use for Centaur case WhiteMan: case BlackMan: case SHOGI WhiteKing: case SHOGI BlackKing: -#endif case WhiteKing: case BlackKing: walking: @@ -721,7 +653,26 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) callback(board, flags, NormalMove, rf, ff, rt, ft, closure); } + if(m==1) goto mounted; + break; + + case WhiteNightrider: + case BlackNightrider: + for (i = -1; i <= 1; i += 2) + for (j = -1; j <= 1; j += 2) + for (s = 1; s <= 2; s++) { int k; + for(k=1;; k++) { + rt = rf + k*i*s; + ft = ff + k*j*(3-s); + if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) break; + if (SameColor(board[rf][ff], board[rt][ft])) break; + callback(board, flags, NormalMove, + rf, ff, rt, ft, closure); + if (board[rt][ft] != EmptySquare) break; + } + } break; + } } } @@ -789,8 +740,9 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure) VOIDSTAR closure; { GenLegalClosure cl; - int ff, ft; + int ff, ft, k, left, right; int ignoreCheck = (flags & F_IGNORE_CHECK) != 0; + ChessSquare wKing = WhiteKing, bKing = BlackKing; cl.cb = callback; cl.cl = closure; @@ -800,10 +752,14 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure) CheckTest(board, flags, -1, -1, -1, -1, FALSE)) return TRUE; /* Generate castling moves */ + if(gameInfo.variant == VariantKnightmate) { /* [HGM] Knightmate */ + wKing = WhiteUnicorn; bKing = BlackUnicorn; + } + for (ff = BOARD_WIDTH>>1; ff >= (BOARD_WIDTH-1)>>1; ff-- /*ics wild 1*/) { if ((flags & F_WHITE_ON_MOVE) && (flags & F_WHITE_KCASTLE_OK) && - board[0][ff] == WhiteKing && + board[0][ff] == wKing && board[0][ff + 1] == EmptySquare && board[0][ff + 2] == EmptySquare && board[0][BOARD_RGHT-3] == EmptySquare && @@ -814,15 +770,16 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure) (ignoreCheck || (!CheckTest(board, flags, 0, ff, 0, ff + 1, FALSE) && !CheckTest(board, flags, 0, ff, 0, BOARD_RGHT-3, FALSE) && + (gameInfo.variant != VariantJanus || !CheckTest(board, flags, 0, ff, 0, BOARD_RGHT-2, FALSE)) && !CheckTest(board, flags, 0, ff, 0, ff + 2, FALSE)))) { callback(board, flags, - ff==4 ? WhiteKingSideCastle : WhiteKingSideCastleWild, - 0, ff, 0, ff + ((gameInfo.boardWidth+2)>>2), closure); + ff==BOARD_WIDTH>>1 ? WhiteKingSideCastle : WhiteKingSideCastleWild, + 0, ff, 0, ff + ((gameInfo.boardWidth+2)>>2) + (gameInfo.variant == VariantJanus), closure); } if ((flags & F_WHITE_ON_MOVE) && (flags & F_WHITE_QCASTLE_OK) && - board[0][ff] == WhiteKing && + board[0][ff] == wKing && board[0][ff - 1] == EmptySquare && board[0][ff - 2] == EmptySquare && board[0][BOARD_LEFT+2] == EmptySquare && @@ -832,7 +789,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure) ( castlingRights[2] == ff || castlingRights[6] == ff ) && (ignoreCheck || (!CheckTest(board, flags, 0, ff, 0, ff - 1, FALSE) && - !CheckTest(board, flags, 0, ff, 0, BOARD_LEFT+3, FALSE) && + !CheckTest(board, flags, 0, ff, 0, BOARD_LEFT+3, FALSE) && !CheckTest(board, flags, 0, ff, 0, ff - 2, FALSE)))) { callback(board, flags, @@ -841,7 +798,7 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure) } if (!(flags & F_WHITE_ON_MOVE) && (flags & F_BLACK_KCASTLE_OK) && - board[BOARD_HEIGHT-1][ff] == BlackKing && + board[BOARD_HEIGHT-1][ff] == bKing && board[BOARD_HEIGHT-1][ff + 1] == EmptySquare && board[BOARD_HEIGHT-1][ff + 2] == EmptySquare && board[BOARD_HEIGHT-1][BOARD_RGHT-3] == EmptySquare && @@ -852,15 +809,16 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure) (ignoreCheck || (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 1, FALSE) && !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_RGHT-3, FALSE) && + (gameInfo.variant != VariantJanus || !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_RGHT-2, FALSE)) && !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + 2, FALSE)))) { callback(board, flags, ff==BOARD_WIDTH>>1 ? BlackKingSideCastle : BlackKingSideCastleWild, - BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + ((gameInfo.boardWidth+2)>>2), closure); + BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff + ((gameInfo.boardWidth+2)>>2) + (gameInfo.variant == VariantJanus), closure); } if (!(flags & F_WHITE_ON_MOVE) && (flags & F_BLACK_QCASTLE_OK) && - board[BOARD_HEIGHT-1][ff] == BlackKing && + board[BOARD_HEIGHT-1][ff] == bKing && board[BOARD_HEIGHT-1][ff - 1] == EmptySquare && board[BOARD_HEIGHT-1][ff - 2] == EmptySquare && board[BOARD_HEIGHT-1][BOARD_LEFT+2] == EmptySquare && @@ -870,8 +828,8 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure) ( castlingRights[5] == ff || castlingRights[7] == ff ) && (ignoreCheck || (!CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 1, FALSE) && - !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_LEFT+3, FALSE) && - !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 1, FALSE)))) { + !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, BOARD_LEFT+3, FALSE) && + !CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ff - 2, FALSE)))) { callback(board, flags, ff==BOARD_WIDTH>>1 ? BlackQueenSideCastle : BlackQueenSideCastleWild, @@ -879,41 +837,71 @@ int GenLegal(board, flags, epfile, castlingRights, callback, closure) } } - /* PUSH Fabien */ + if(gameInfo.variant == VariantFischeRandom) { /* generate all potential FRC castling moves (KxR), ignoring flags */ - /* [HGM] Tord! Help requested! */ - - if ((flags & F_WHITE_ON_MOVE) != 0) { + /* [HGM] test if the Rooks we find have castling rights */ - for (ff = BOARD_LEFT+1; ff < BOARD_RGHT-1; ff++) { - if (board[0][ff] == WhiteKing) { - for (ft = BOARD_LEFT+0; ft < BOARD_RGHT; ft++) { - if (board[0][ft] == WhiteRook) { - callback(board, flags, - (ft > ff) ? WhiteHSideCastleFR : WhiteASideCastleFR, - 0, ff, 0, ft, closure); - } - } - } - } + if ((flags & F_WHITE_ON_MOVE) != 0) { + ff = castlingRights[2]; /* King file if we have any rights */ + if(ff > 0 && board[0][ff] == WhiteKing) { + if (appData.debugMode) { + fprintf(debugFP, "FRC castling, %d %d %d %d %d %d\n", + castlingRights[0],castlingRights[1],ff,castlingRights[3],castlingRights[4],castlingRights[5]); + } + ft = castlingRights[0]; /* Rook file if we have H-side rights */ + left = ff+1; + right = BOARD_RGHT-2; + if(ff == BOARD_RGHT-2) left = right = ff-1; /* special case */ + for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */ + if(k != ft && board[0][k] != EmptySquare) ft = -1; + for(k=left; k= 0; k++) /* then if not checked */ + if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = -1; + if(ft >= 0 && board[0][ft] == WhiteRook) + callback(board, flags, WhiteHSideCastleFR, 0, ff, 0, ft, closure); + + ft = castlingRights[1]; /* Rook file if we have A-side rights */ + left = BOARD_LEFT+2; + right = ff-1; + if(ff <= BOARD_LEFT+2) { left = ff+1; right = BOARD_LEFT+3; } + for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */ + if(k != ft && board[0][k] != EmptySquare) ft = -1; + if(ff > BOARD_LEFT+2) + for(k=left+1; k<=right && ft >= 0; k++) /* then if not checked */ + if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = -1; + if(ft >= 0 && board[0][ft] == WhiteRook) + callback(board, flags, WhiteASideCastleFR, 0, ff, 0, ft, closure); + } } else { - - for (ff = BOARD_LEFT+1; ff < BOARD_RGHT-1; ff++) { - if (board[BOARD_HEIGHT-1][ff] == BlackKing) { - for (ft = BOARD_LEFT+0; ft < BOARD_RGHT; ft++) { - if (board[BOARD_HEIGHT-1][ft] == BlackRook) { - callback(board, flags, - (ft > ff) ? BlackHSideCastleFR : BlackASideCastleFR, - BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure); - } - } - } - } + ff = castlingRights[5]; /* King file if we have any rights */ + if(ff > 0 && board[BOARD_HEIGHT-1][ff] == BlackKing) { + ft = castlingRights[3]; /* Rook file if we have H-side rights */ + left = ff+1; + right = BOARD_RGHT-2; + if(ff == BOARD_RGHT-2) left = right = ff-1; /* special case */ + for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */ + if(k != ft && board[BOARD_HEIGHT-1][k] != EmptySquare) ft = -1; + for(k=left; k= 0; k++) /* then if not checked */ + if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = -1; + if(ft >= 0 && board[BOARD_HEIGHT-1][ft] == BlackRook) + callback(board, flags, BlackHSideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure); + + ft = castlingRights[4]; /* Rook file if we have A-side rights */ + left = BOARD_LEFT+2; + right = ff-1; + if(ff <= BOARD_LEFT+2) { left = ff+1; right = BOARD_LEFT+3; } + for(k=left; k<=right && ft >= 0; k++) /* first test if blocked */ + if(k != ft && board[BOARD_HEIGHT-1][k] != EmptySquare) ft = -1; + if(ff > BOARD_LEFT+2) + for(k=left+1; k<=right && ft >= 0; k++) /* then if not checked */ + if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = -1; + if(ft >= 0 && board[BOARD_HEIGHT-1][ft] == BlackRook) + callback(board, flags, BlackASideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure); + } } - /* POP Fabien */ + } return FALSE; } @@ -983,6 +971,17 @@ int CheckTest(board, flags, rf, ff, rt, ft, enPassant) for (cl.fking = BOARD_LEFT+0; cl.fking < BOARD_RGHT; cl.fking++) for (cl.rking = 0; cl.rking < BOARD_HEIGHT; cl.rking++) { if (board[cl.rking][cl.fking] == king) { + if(gameInfo.variant == VariantXiangqi) { + /* [HGM] In Xiangqi opposing Kings means check as well */ + int i, dir; + dir = (king >= BlackPawn) ? -1 : 1; + for( i=cl.rking+dir; i>=0 && i=0 && i0 ? BlackWazir : WhiteWazir) ) + cl.check++; + } + GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, -1, CheckTestCallback, (VOIDSTAR) &cl); goto undo_move; /* 2-level break */ @@ -1018,9 +1017,9 @@ void LegalityTestCallback(board, flags, kind, rf, ff, rt, ft, closure) { register LegalityTestClosure *cl = (LegalityTestClosure *) closure; - if (appData.debugMode) { - fprintf(debugFP, "Legality test: %c%c%c%c\n", ff+AAA, rf+ONE, ft+AAA, rt+ONE); - } +// if (appData.debugMode) { +// fprintf(debugFP, "Legality test: %c%c%c%c\n", ff+AAA, rf+ONE, ft+AAA, rt+ONE); +// } if (rf == cl->rf && ff == cl->ff && rt == cl->rt && ft == cl->ft) cl->kind = kind; } @@ -1031,14 +1030,61 @@ ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, pro int rf, ff, rt, ft, promoChar; char castlingRights[]; { - LegalityTestClosure cl; + LegalityTestClosure cl; ChessSquare piece = board[rf][ff]; + if (appData.debugMode) { + int i; + for(i=0; i<6; i++) fprintf(debugFP, "%d ", castlingRights[i]); + fprintf(debugFP, "Legality test? %c%c%c%c\n", ff+AAA, rf+ONE, ft+AAA, rt+ONE); + } + /* [HGM] Lance, Cobra and Falcon are wildcard pieces; consider all their moves legal */ + /* (perhaps we should disallow moves that obviously leave us in check?) */ + if(piece == WhiteFalcon || piece == BlackFalcon || + piece == WhiteCobra || piece == BlackCobra || + piece == WhiteLance || piece == BlackLance) + return NormalMove; + cl.rf = rf; cl.ff = ff; cl.rt = rt; cl.ft = ft; cl.kind = IllegalMove; GenLegal(board, flags, epfile, castlingRights, LegalityTestCallback, (VOIDSTAR) &cl); + + if(gameInfo.variant == VariantShogi) { + /* [HGM] Shogi promotions. '=' means defer */ + if(rf != DROP_RANK && cl.kind == NormalMove) { + ChessSquare piece = board[rf][ff]; + + if(promoChar == PieceToChar(BlackQueen)) promoChar = NULLCHAR; /* [HGM] Kludge */ + if(promoChar != NULLCHAR && promoChar != 'x' && + promoChar != '+' && promoChar != '=' && + ToUpper(PieceToChar(PROMOTED piece)) != ToUpper(promoChar) ) + cl.kind = IllegalMove; + else if(flags & F_WHITE_ON_MOVE) { + if( (int) piece < (int) WhiteWazir && + (rf > BOARD_HEIGHT-4 || rt > BOARD_HEIGHT-4) ) { + if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 || + piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */ + cl.kind = promoChar == '=' ? IllegalMove : WhitePromotionKnight; + else /* promotion optional, default is promote */ + cl.kind = promoChar == '=' ? NormalMove : WhitePromotionQueen; + + } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ? + NormalMove : IllegalMove; + } else { + if( (int) piece < (int) BlackWazir && (rf < 3 || rt < 3) ) { + if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 || + piece == BlackKnight && rt < 2 ) /* promotion obligatory */ + cl.kind = promoChar == '=' ? IllegalMove : BlackPromotionKnight; + else /* promotion optional, default is promote */ + cl.kind = promoChar == '=' ? NormalMove : BlackPromotionQueen; + + } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ? + NormalMove : IllegalMove; + } + } + } else if (promoChar != NULLCHAR && promoChar != 'x') { if (cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) { cl.kind = @@ -1047,6 +1093,7 @@ ChessMove LegalityTest(board, flags, epfile, castlingRights, rf, ff, rt, ft, pro cl.kind = IllegalMove; } } + /* [HGM] For promotions, 'ToQueen' = optional, 'ToKnight' = mandatory */ return cl.kind; } @@ -1084,7 +1131,7 @@ int MateTest(board, flags, epfile, castlingRights) if (cl.count > 0) { return inCheck ? MT_CHECK : MT_NONE; } else { - return inCheck || gameInfo.variant == VariantXiangqi ? + return inCheck || gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj ? MT_CHECKMATE : MT_STALEMATE; } } @@ -1103,14 +1150,17 @@ void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure) { register DisambiguateClosure *cl = (DisambiguateClosure *) closure; - if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]) && + if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff] + || PieceToChar(board[rf][ff]) == '~' + && cl->pieceIn == (ChessSquare)(DEMOTED board[rf][ff]) + ) && (cl->rfIn == -1 || cl->rfIn == rf) && (cl->ffIn == -1 || cl->ffIn == ff) && (cl->rtIn == -1 || cl->rtIn == rt) && (cl->ftIn == -1 || cl->ftIn == ft)) { cl->count++; - cl->piece = board[rf][ff]; + cl->piece = board[rf][ff]; cl->rf = rf; cl->ff = ff; cl->rt = rt; @@ -1124,10 +1174,15 @@ void Disambiguate(board, flags, epfile, closure) int flags, epfile; DisambiguateClosure *closure; { - int illegal = 0; + int illegal = 0; char c = closure->promoCharIn; closure->count = 0; closure->rf = closure->ff = closure->rt = closure->ft = 0; closure->kind = ImpossibleMove; + if (appData.debugMode) { + fprintf(debugFP, "Disambiguate in: %d(%d,%d)-(%d,%d) = %d (%c)\n", + closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn, + closure->promoCharIn, closure->promoCharIn >= ' ' ? closure->promoCharIn : '-'); + } GenLegal(board, flags, epfile, initialRights, DisambiguateCallback, (VOIDSTAR) closure); if (closure->count == 0) { /* See if it's an illegal move due to check */ @@ -1136,9 +1191,62 @@ void Disambiguate(board, flags, epfile, closure) (VOIDSTAR) closure); if (closure->count == 0) { /* No, it's not even that */ + if (appData.debugMode) { int i, j; + for(i=BOARD_HEIGHT-1; i>=0; i--) { + for(j=0; jkind = IllegalMove; + else if(flags & F_WHITE_ON_MOVE) { +#if 0 + if (appData.debugMode) { + fprintf(debugFP, "Disambiguate B: %d(%d,%d)-(%d,%d) = %d (%c)\n", + closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn, + closure->promoCharIn,closure->promoCharIn); + } +#endif + if( (int) piece < (int) WhiteWazir && + (closure->rf > BOARD_HEIGHT-4 || closure->rt > BOARD_HEIGHT-4) ) { + if( (piece == WhitePawn || piece == WhiteQueen) && closure->rt > BOARD_HEIGHT-2 || + piece == WhiteKnight && closure->rt > BOARD_HEIGHT-3) /* promotion mandatory */ + closure->kind = c == '=' ? IllegalMove : WhitePromotionKnight; + else /* promotion optional, default is promote */ + closure->kind = c == '=' ? NormalMove : WhitePromotionQueen; + + } else closure->kind = (c == NULLCHAR || c == 'x' || c == '=') ? + NormalMove : IllegalMove; + } else { + if( (int) piece < (int) BlackWazir && (closure->rf < 3 || closure->rt < 3) ) { + if( (piece == BlackPawn || piece == BlackQueen) && closure->rt < 1 || + piece == BlackKnight && closure->rt < 2 ) /* promotion obligatory */ + closure->kind = c == '=' ? IllegalMove : BlackPromotionKnight; + else /* promotion optional, default is promote */ + closure->kind = c == '=' ? NormalMove : BlackPromotionQueen; + + } else closure->kind = (c == NULLCHAR || c == 'x' || c == '=') ? + NormalMove : IllegalMove; + } + } + } else if (closure->promoCharIn != NULLCHAR && closure->promoCharIn != 'x') { if (closure->kind == WhitePromotionQueen || closure->kind == BlackPromotionQueen) { @@ -1149,7 +1257,17 @@ void Disambiguate(board, flags, epfile, closure) closure->kind = IllegalMove; } } - closure->promoChar = ToLower(PieceToChar(PromoPiece(closure->kind))); +#if 0 + if (appData.debugMode) { + fprintf(debugFP, "Disambiguate C: %d(%d,%d)-(%d,%d) = %d (%c)\n", + closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn, + closure->promoCharIn,closure->promoCharIn); + } +#endif + /* [HGM] returns 'q' for optional promotion, 'n' for mandatory */ + if(closure->promoCharIn != '=') + closure->promoChar = ToLower(closure->promoCharIn); + else closure->promoChar = '='; if (closure->promoChar == 'x') closure->promoChar = NULLCHAR; if (closure->count > 1) { closure->kind = AmbiguousMove; @@ -1161,6 +1279,14 @@ void Disambiguate(board, flags, epfile, closure) */ closure->kind = IllegalMove; } + if(closure->kind == IllegalMove) + /* [HGM] might be a variant we don't understand, pass on promotion info */ + closure->promoChar = ToLower(closure->promoCharIn); + if (appData.debugMode) { + fprintf(debugFP, "Disambiguate out: %d(%d,%d)-(%d,%d) = %d (%c)\n", + closure->piece,closure->ff,closure->rf,closure->ft,closure->rt,closure->promoChar, + closure->promoChar >= ' ' ? closure->promoChar:'-'); + } } @@ -1190,7 +1316,10 @@ void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure) (CoordsToAlgebraicClosure *) closure; if (rt == cl->rt && ft == cl->ft && - board[rf][ff] == cl->piece) { + (board[rf][ff] == cl->piece + || PieceToChar(board[rf][ff]) == '~' && + (ChessSquare) (DEMOTED board[rf][ff]) == cl->piece) + ) { if (rf == cl->rf) { if (ff == cl->ff) { cl->kind = kind; /* this is the move we want */ @@ -1220,7 +1349,7 @@ ChessMove CoordsToAlgebraic(board, flags, epfile, { ChessSquare piece; ChessMove kind; - char *outp = out; + char *outp = out, c; CoordsToAlgebraicClosure cl; if (rf == DROP_RANK) { @@ -1232,12 +1361,15 @@ ChessMove CoordsToAlgebraic(board, flags, epfile, *outp++ = rt + ONE; else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; } *outp = NULLCHAR; - AlphaRank(out, 5); return (flags & F_WHITE_ON_MOVE) ? WhiteDrop : BlackDrop; } if (promoChar == 'x') promoChar = NULLCHAR; piece = board[rf][ff]; + if(PieceToChar(piece)=='~') piece = (ChessSquare)(DEMOTED piece); + + if (appData.debugMode) + fprintf(debugFP, "CoordsToAlgebraic, piece=%d (%d,%d)-(%d,%d) %c\n", (int)piece,ff,rf,ft,rt,promoChar >= ' ' ? promoChar : '-'); switch (piece) { case WhitePawn: case BlackPawn: @@ -1267,12 +1399,19 @@ ChessMove CoordsToAlgebraic(board, flags, epfile, else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; } } /* Use promotion suffix style "=Q" */ - if (promoChar != NULLCHAR && promoChar != 'x') { - *outp++ = '='; - *outp++ = ToUpper(promoChar); - } *outp = NULLCHAR; - AlphaRank(out, 10); + if (appData.debugMode) + fprintf(debugFP, "movetype=%d, promochar=%d=%c\n", (int)kind, promoChar, promoChar >= ' ' ? promoChar : '-'); + if (promoChar != NULLCHAR) { + if(gameInfo.variant == VariantShogi) { + /* [HGM] ... but not in Shogi! */ + *outp++ = promoChar == '=' ? '=' : '+'; + } else { + *outp++ = '='; + *outp++ = ToUpper(promoChar); + } + *outp = NULLCHAR; + } return kind; @@ -1338,8 +1477,14 @@ ChessMove CoordsToAlgebraic(board, flags, epfile, else "N1f3" or "N5xf7", else "Ng1f3" or "Ng5xf7". */ - *outp++ = ToUpper(PieceToChar(piece)); - + c = PieceToChar(piece) ; + if( c == '~' || c == '+') { + /* [HGM] print nonexistent piece as its demoted version */ + piece = (ChessSquare) (DEMOTED piece); + } + if(c=='+') *outp++ = c; + *outp++ = ToUpper(PieceToChar(piece)); + if (cl.file || (cl.either && !cl.rank)) { *outp++ = ff + AAA; } @@ -1357,16 +1502,52 @@ ChessMove CoordsToAlgebraic(board, flags, epfile, *outp++ = rt + ONE; else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; } *outp = NULLCHAR; - AlphaRank(out, 10); + if (gameInfo.variant == VariantShogi) { + /* [HGM] in Shogi non-pawns can promote */ + if(flags & F_WHITE_ON_MOVE) { + if( (int) cl.piece < (int) WhiteWazir && + (rf > BOARD_HEIGHT-4 || rt > BOARD_HEIGHT-4) ) { + if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 || + piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */ + cl.kind = promoChar == '=' ? IllegalMove : WhitePromotionKnight; + else cl.kind = WhitePromotionQueen; /* promotion optional */ + + } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ? + NormalMove : IllegalMove; + } else { + if( (int) cl.piece < (int) BlackWazir && (rf < 3 || rt < 3) ) { + if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 || + piece == BlackKnight && rt < 2 ) /* promotion obligatory */ + cl.kind = promoChar == '=' ? IllegalMove : BlackPromotionKnight; + else cl.kind = BlackPromotionQueen; /* promotion optional */ + } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ? + NormalMove : IllegalMove; + } + if(cl.kind == WhitePromotionQueen || cl.kind == BlackPromotionQueen) { + /* for optional promotions append '+' or '=' */ + if(promoChar == '=') { + *outp++ = '='; + cl.kind = NormalMove; + } else *outp++ = '+'; + *outp = NULLCHAR; + } else if(cl.kind == IllegalMove) { + /* Illegal move specifies any given promotion */ + if(promoChar != NULLCHAR && promoChar != 'x') { + *outp++ = '='; + *outp++ = ToUpper(promoChar); + *outp = NULLCHAR; + } + } + } return cl.kind; -#ifdef FAIRY - /* [HGM] Always long notation for fairies, don't know how they move */ - case WhiteNightrider: - case BlackNightrider: + /* [HGM] Always long notation for fairies we don't know */ + case WhiteFalcon: + case BlackFalcon: + case WhiteLance: + case BlackLance: case WhiteGrasshopper: case BlackGrasshopper: -#endif case EmptySquare: /* Moving a nonexistent piece */ break; @@ -1400,7 +1581,6 @@ ChessMove CoordsToAlgebraic(board, flags, epfile, } *outp = NULLCHAR; - AlphaRank(out, 0); return IllegalMove; }