X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=moves.c;h=3ea2ab0d9ad9627fea055eeece2f2a101009f5a3;hb=29f26a97a226db6e7bdd0927e67cf5a5ce3dd065;hp=dcb430022bbfbcf16c06fee0b8200c0950fc5ee1;hpb=b8bd259a053aef05b8f0ee07886702b5870234cf;p=xboard.git diff --git a/moves.c b/moves.c index dcb4300..3ea2ab0 100644 --- a/moves.c +++ b/moves.c @@ -70,7 +70,7 @@ int SameColor P((ChessSquare, ChessSquare)); int PosFlags(int index); extern signed char initialRights[BOARD_FILES]; /* [HGM] all rights enabled, set in InitPosition */ - +int quickFlag; int WhitePiece(piece) ChessSquare piece; @@ -84,6 +84,7 @@ int BlackPiece(piece) return (int) piece >= (int) BlackPawn && (int) piece < (int) EmptySquare; } +#if 0 int SameColor(piece1, piece2) ChessSquare piece1, piece2; { @@ -96,6 +97,9 @@ int SameColor(piece1, piece2) (int) piece2 >= (int) BlackPawn && (int) piece2 < (int) EmptySquare); } +#else +#define SameColor(piece1, piece2) (piece1 < EmptySquare && piece2 < EmptySquare && (piece1 < BlackPawn) == (piece2 < BlackPawn)) +#endif char pieceToChar[] = { 'P', 'N', 'B', 'R', 'Q', 'F', 'E', 'A', 'C', 'W', 'M', @@ -179,18 +183,16 @@ void GenPseudoLegal(board, flags, callback, closure, filter) int rf, ff; int i, j, d, s, fs, rs, rt, ft, m; int epfile = (signed char)board[EP_STATUS]; // [HGM] gamestate: extract ep status from board - int promoRank = gameInfo.variant == VariantMakruk ? 3 : 1; + int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand ? 3 : 1; for (rf = 0; rf < BOARD_HEIGHT; rf++) for (ff = BOARD_LEFT; ff < BOARD_RGHT; ff++) { ChessSquare piece; - int rookRange = 1000; + int rookRange; - if (flags & F_WHITE_ON_MOVE) { - if (!WhitePiece(board[rf][ff])) continue; - } else { - if (!BlackPiece(board[rf][ff])) continue; - } + if(board[rf][ff] == EmptySquare) continue; + if ((flags & F_WHITE_ON_MOVE) != (board[rf][ff] < BlackPawn)) continue; // [HGM] speed: wrong color + rookRange = 1000; m = 0; piece = board[rf][ff]; if(PieceToChar(piece) == '~') piece = (ChessSquare) ( DEMOTED piece ); @@ -228,12 +230,12 @@ void GenPseudoLegal(board, flags, callback, closure, filter) rf >= BOARD_HEIGHT-1-promoRank ? WhitePromotion : NormalMove, rf, ff, rf + 1, ff, closure); } - if (rf == 1 && board[2][ff] == EmptySquare && + if (rf <= (BOARD_HEIGHT>>1)-3 && board[rf+1][ff] == EmptySquare && // [HGM] grand: also on 3rd rank on 10-board gameInfo.variant != VariantShatranj && /* [HGM] */ gameInfo.variant != VariantCourier && /* [HGM] */ - board[3][ff] == EmptySquare ) { + board[rf+2][ff] == EmptySquare ) { callback(board, flags, NormalMove, - rf, ff, 3, ff, closure); + rf, ff, rf+2, ff, closure); } for (s = -1; s <= 1; s += 2) { if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT && @@ -243,13 +245,13 @@ void GenPseudoLegal(board, flags, callback, closure, filter) rf >= BOARD_HEIGHT-1-promoRank ? WhitePromotion : NormalMove, rf, ff, rf + 1, ff + s, closure); } - if (rf == BOARD_HEIGHT-4) { + if (rf >= BOARD_HEIGHT+1>>1) {// [HGM] grand: 4th & 5th rank on 10-board if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT && - (epfile == ff + s || epfile == EP_UNKNOWN) && - board[BOARD_HEIGHT-4][ff + s] == BlackPawn && - board[BOARD_HEIGHT-3][ff + s] == EmptySquare) { + (epfile == ff + s || epfile == EP_UNKNOWN) && rf < BOARD_HEIGHT-3 && + board[rf][ff + s] == BlackPawn && + board[rf+1][ff + s] == EmptySquare) { callback(board, flags, WhiteCapturesEnPassant, - rf, ff, 5, ff + s, closure); + rf, ff, rf+1, ff + s, closure); } } } @@ -278,12 +280,12 @@ void GenPseudoLegal(board, flags, callback, closure, filter) rf <= promoRank ? BlackPromotion : NormalMove, rf, ff, rf - 1, ff, closure); } - if (rf == BOARD_HEIGHT-2 && board[BOARD_HEIGHT-3][ff] == EmptySquare && + if (rf >= (BOARD_HEIGHT+1>>1)+2 && board[rf-1][ff] == EmptySquare && // [HGM] grand gameInfo.variant != VariantShatranj && /* [HGM] */ gameInfo.variant != VariantCourier && /* [HGM] */ - board[BOARD_HEIGHT-4][ff] == EmptySquare) { + board[rf-2][ff] == EmptySquare) { callback(board, flags, NormalMove, - rf, ff, BOARD_HEIGHT-4, ff, closure); + rf, ff, rf-2, ff, closure); } for (s = -1; s <= 1; s += 2) { if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT && @@ -293,13 +295,13 @@ void GenPseudoLegal(board, flags, callback, closure, filter) rf <= promoRank ? BlackPromotion : NormalMove, rf, ff, rf - 1, ff + s, closure); } - if (rf == 3) { + if (rf < BOARD_HEIGHT>>1) { if (ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT && - (epfile == ff + s || epfile == EP_UNKNOWN) && - board[3][ff + s] == WhitePawn && - board[2][ff + s] == EmptySquare) { + (epfile == ff + s || epfile == EP_UNKNOWN) && rf > 2 && + board[rf][ff + s] == WhitePawn && + board[rf-1][ff + s] == EmptySquare) { callback(board, flags, BlackCapturesEnPassant, - rf, ff, 2, ff + s, closure); + rf, ff, rf-1, ff + s, closure); } } } @@ -715,6 +717,7 @@ typedef struct { } GenLegalClosure; int rFilter, fFilter; // [HGM] speed: sorry, but I get a bit tired of this closure madness +Board xqCheckers, nullBoard; extern void GenLegalCallback P((Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, @@ -733,7 +736,15 @@ void GenLegalCallback(board, flags, kind, rf, ff, rt, ft, closure) if (!(flags & F_IGNORE_CHECK) ) { int check, promo = (gameInfo.variant == VariantSpartan && kind == BlackPromotion); - if(promo) board[rf][ff] = BlackKing; // [HGM] spartan: promote to King before check-test + if(promo) { + int r, f, kings=0; + for(r=0; r= 2) + promo = 0; + else + board[rf][ff] = BlackKing; // [HGM] spartan: promote to King before check-test + } check = CheckTest(board, flags, rf, ff, rt, ft, kind == WhiteCapturesEnPassant || kind == BlackCapturesEnPassant); @@ -783,14 +794,15 @@ int GenLegal(board, flags, callback, closure, filter) int ff, ft, k, left, right, swap; int ignoreCheck = (flags & F_IGNORE_CHECK) != 0; ChessSquare wKing = WhiteKing, bKing = BlackKing, *castlingRights = board[CASTLING]; + int inCheck = !ignoreCheck && CheckTest(board, flags, -1, -1, -1, -1, FALSE); // kludge alert: this would mark pre-existing checkers if status==1 cl.cb = callback; cl.cl = closure; + xqCheckers[EP_STATUS] *= 2; // quasi: if previous CheckTest has been marking, we now set flag for suspending same checkers if(filter == EmptySquare) rFilter = fFilter = -1; // [HGM] speed: do not filter on square if we do not filter on piece GenPseudoLegal(board, flags, GenLegalCallback, (VOIDSTAR) &cl, filter); - if (!ignoreCheck && - CheckTest(board, flags, -1, -1, -1, -1, FALSE)) return TRUE; + if (inCheck) return TRUE; /* Generate castling moves */ if(gameInfo.variant == VariantKnightmate) { /* [HGM] Knightmate */ @@ -969,7 +981,11 @@ void CheckTestCallback(board, flags, kind, rf, ff, rt, ft, closure) { register CheckTestClosure *cl = (CheckTestClosure *) closure; - if (rt == cl->rking && ft == cl->fking) cl->check++; + if (rt == cl->rking && ft == cl->fking) { + if(xqCheckers[EP_STATUS] >= 2 && xqCheckers[rf][ff]) return; // checker is piece with suspended checking power + cl->check++; + xqCheckers[rf][ff] = xqCheckers[EP_STATUS] & 1; // remember who is checking (if status == 1) + } } @@ -995,16 +1011,18 @@ int CheckTest(board, flags, rf, ff, rt, ft, enPassant) if(gameInfo.variant == VariantKnightmate) king = flags & F_WHITE_ON_MOVE ? WhiteUnicorn : BlackUnicorn; - if (rf >= 0) { + if (rt >= 0) { if (enPassant) { captured = board[rf][ft]; board[rf][ft] = EmptySquare; } else { captured = board[rt][ft]; } - board[rt][ft] = board[rf][ff]; - board[rf][ff] = EmptySquare; - } else board[rt][ft] = ff; // [HGM] drop + if(rf == DROP_RANK) board[rt][ft] = ff; else { // [HGM] drop + board[rt][ft] = board[rf][ff]; + board[rf][ff] = EmptySquare; + } + } /* For compatibility with ICS wild 9, we scan the board in the order a1, a2, a3, ... b1, b2, ..., h8 to find the first king, @@ -1031,15 +1049,16 @@ int CheckTest(board, flags, rf, ff, rt, ft, enPassant) undo_move: - if (rf >= 0) { - board[rf][ff] = board[rt][ft]; + if (rt >= 0) { + if(rf != DROP_RANK) // [HGM] drop + board[rf][ff] = board[rt][ft]; if (enPassant) { board[rf][ft] = captured; board[rt][ft] = EmptySquare; } else { board[rt][ft] = captured; } - } else board[rt][ft] = EmptySquare; // [HGM] drop + } return cl.fking < BOARD_RGHT ? cl.check : 1000; // [HGM] atomic: return 1000 if we have no king } @@ -1109,6 +1128,7 @@ ChessMove LegalityTest(board, flags, rf, ff, rt, ft, promoChar) { LegalityTestClosure cl; ChessSquare piece, filterPiece, *castlingRights = board[CASTLING]; + if(quickFlag) flags = flags & ~1 | quickFlag & 1; // [HGM] speed: in quick mode quickFlag specifies side-to-move. if(rf == DROP_RANK) return LegalDrop(board, flags, ff, rt, ft); piece = filterPiece = board[rf][ff]; if(PieceToChar(piece) == '~') filterPiece = DEMOTED piece; @@ -1194,7 +1214,8 @@ if(appData.debugMode)fprintf(debugFP,"SHOGI promoChar = %c\n", promoChar ? promo for(r=0; r 0) { return inCheck ? MT_CHECK : MT_NONE; } else { - if(gameInfo.holdingsWidth && gameInfo.variant != VariantSuper && gameInfo.variant != VariantGreat) { // drop game + if(gameInfo.holdingsWidth && gameInfo.variant != VariantSuper && gameInfo.variant != VariantGreat + && gameInfo.variant != VariantGrand) { // drop game int r, f, n, holdings = flags & F_WHITE_ON_MOVE ? BOARD_WIDTH-1 : 0; for(r=0; rpromoCharIn; + if(quickFlag) flags = flags & ~1 | quickFlag & 1; // [HGM] speed: in quick mode quickFlag specifies side-to-move. closure->count = closure->captures = 0; closure->rf = closure->ff = closure->rt = closure->ft = 0; closure->kind = ImpossibleMove; @@ -1343,6 +1366,15 @@ void Disambiguate(board, flags, closure) } rFilter = closure->rtIn; // [HGM] speed: only consider moves to given to-square fFilter = closure->ftIn; + if(quickFlag) { // [HGM] speed: try without check test first, because if that is not ambiguous, we are happy + GenLegal(board, flags|F_IGNORE_CHECK, DisambiguateCallback, (VOIDSTAR) closure, closure->pieceIn); + if(closure->count > 1) { // gamble did not pay off. retry with check test to resolve ambiguity + closure->count = closure->captures = 0; + closure->rf = closure->ff = closure->rt = closure->ft = 0; + closure->kind = ImpossibleMove; + GenLegal(board, flags, DisambiguateCallback, (VOIDSTAR) closure, closure->pieceIn); // [HGM] speed: only pieces of requested type + } + } else GenLegal(board, flags, DisambiguateCallback, (VOIDSTAR) closure, closure->pieceIn); // [HGM] speed: only pieces of requested type if (closure->count == 0) { /* See if it's an illegal move due to check */ @@ -1408,6 +1440,8 @@ void Disambiguate(board, flags, closure) c = PieceToChar(BlackFerz); else if(gameInfo.variant == VariantGreat) c = PieceToChar(BlackMan); + else if(gameInfo.variant == VariantGrand) + closure->kind = closure->rt != 0 && closure->rt != BOARD_HEIGHT-1 ? NormalMove : AmbiguousMove; // no default in Grand Chess else c = PieceToChar(BlackQueen); } else if(c == '=') closure->kind = IllegalMove; // no deferral outside Shogi @@ -1496,6 +1530,7 @@ ChessMove CoordsToAlgebraic(board, flags, rf, ff, rt, ft, promoChar, out) CoordsToAlgebraicClosure cl; if (rf == DROP_RANK) { + if(ff == EmptySquare) { strncpy(outp, "--",3); return NormalMove; } // [HGM] pass /* Bughouse piece drop */ *outp++ = ToUpper(PieceToChar((ChessSquare) ff)); *outp++ = '@'; @@ -1823,7 +1858,9 @@ int PerpetualChase(int first, int last) cl.ff = moveList[i][0]-AAA+BOARD_LEFT; cl.rt = moveList[i][3]-ONE; cl.ft = moveList[i][2]-AAA+BOARD_LEFT; + CopyBoard(xqCheckers, nullBoard); xqCheckers[EP_STATUS] = 1; // giant kludge to make GenLegal ignore pre-existing checks GenLegal(boards[i], PosFlags(i), ExistingAttacksCallback, &cl, EmptySquare); + xqCheckers[EP_STATUS] = 0; // disable the generation of quasi-legal moves again if(appData.debugMode) { int n; for(n=0; n