X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=moves.c;h=5f4b3f9670cab33d0b4a7dfe65cad41f8d34a5c2;hb=2d0f4769e69d228d9593c574014c634706edea97;hp=093df638014350dfc9e0aaf172c15ae04808b383;hpb=d9d4e462f10fe222828adcc7ba6adfa833259208;p=xboard.git diff --git a/moves.c b/moves.c index 093df63..5f4b3f9 100644 --- a/moves.c +++ b/moves.c @@ -5,7 +5,7 @@ * Massachusetts. * * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006, - * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. + * 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. * * Enhancements Copyright 2005 Alessandro Scotti * @@ -72,21 +72,21 @@ int PosFlags(int index); extern signed char initialRights[BOARD_FILES]; /* [HGM] all rights enabled, set in InitPosition */ int quickFlag; -int WhitePiece(piece) - ChessSquare piece; +int +WhitePiece (ChessSquare piece) { return (int) piece >= (int) WhitePawn && (int) piece < (int) BlackPawn; } -int BlackPiece(piece) - ChessSquare piece; +int +BlackPiece (ChessSquare piece) { return (int) piece >= (int) BlackPawn && (int) piece < (int) EmptySquare; } #if 0 -int SameColor(piece1, piece2) - ChessSquare piece1, piece2; +int +SameColor (ChessSquare piece1, ChessSquare piece2) { return ((int) piece1 >= (int) WhitePawn && /* [HGM] can be > King ! */ (int) piece1 < (int) BlackPawn && @@ -109,15 +109,15 @@ char pieceToChar[] = { 'x' }; char pieceNickName[EmptySquare]; -char PieceToChar(p) - ChessSquare p; +char +PieceToChar (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 +PieceToNumber (ChessSquare p) /* [HGM] holdings: count piece type, ignoring non-participating piece types */ { int i=0; ChessSquare start = (int)p >= (int)BlackPawn ? BlackPawn : WhitePawn; @@ -126,8 +126,8 @@ int PieceToNumber(p) /* [HGM] holdings: count piece type, ignoring non-particip return i; } -ChessSquare CharToPiece(c) - int c; +ChessSquare +CharToPiece (int c) { int i; if(c == '.') return EmptySquare; @@ -138,21 +138,22 @@ ChessSquare CharToPiece(c) return EmptySquare; } -void CopyBoard(to, from) - Board to, from; +void +CopyBoard (Board to, Board from) { int i, j; for (i = 0; i < BOARD_HEIGHT; i++) for (j = 0; j < BOARD_WIDTH; j++) to[i][j] = from[i][j]; - for (j = 0; j < BOARD_FILES-1; j++) // [HGM] gamestate: copy castling rights and ep status + for (j = 0; j < BOARD_FILES; j++) // [HGM] gamestate: copy castling rights and ep status + to[VIRGIN][j] = from[VIRGIN][j], to[CASTLING][j] = from[CASTLING][j]; to[HOLDINGS_SET] = 0; // flag used in ICS play } -int CompareBoards(board1, board2) - Board board1, board2; +int +CompareBoards (Board board1, Board board2) { int i, j; @@ -173,12 +174,9 @@ int CompareBoards(board1, board2) EP_UNKNOWN if we don't know and want to allow all e.p. captures. Promotion moves generated are to Queen only. */ -void GenPseudoLegal(board, flags, callback, closure, filter) - Board board; - int flags; - MoveCallback callback; - VOIDSTAR closure; - ChessSquare filter; // [HGM] speed: only do moves with this piece type +void +GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, ChessSquare filter) +// speed: only do moves with this piece type { int rf, ff; int i, j, d, s, fs, rs, rt, ft, m; @@ -723,12 +721,8 @@ extern void GenLegalCallback P((Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure)); -void GenLegalCallback(board, flags, kind, rf, ff, rt, ft, closure) - Board board; - int flags; - ChessMove kind; - int rf, ff, rt, ft; - VOIDSTAR closure; +void +GenLegalCallback (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure) { register GenLegalClosure *cl = (GenLegalClosure *) closure; @@ -736,7 +730,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); @@ -775,12 +777,8 @@ typedef struct { true if castling is not yet ruled out by a move of the king or rook. Return TRUE if the player on move is currently in check and F_IGNORE_CHECK is not set. [HGM] add castlingRights parameter */ -int GenLegal(board, flags, callback, closure, filter) - Board board; - int flags; - MoveCallback callback; - VOIDSTAR closure; - ChessSquare filter; +int +GenLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, ChessSquare filter) { GenLegalClosure cl; int ff, ft, k, left, right, swap; @@ -964,12 +962,8 @@ extern void CheckTestCallback P((Board board, int flags, ChessMove kind, VOIDSTAR closure)); -void CheckTestCallback(board, flags, kind, rf, ff, rt, ft, closure) - Board board; - int flags; - ChessMove kind; - int rf, ff, rt, ft; - VOIDSTAR closure; +void +CheckTestCallback (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure) { register CheckTestClosure *cl = (CheckTestClosure *) closure; @@ -988,10 +982,8 @@ void CheckTestCallback(board, flags, kind, rf, ff, rt, ft, closure) back rank is not accounted for (i.e., we still return nonzero), as this is illegal anyway. Return value is the number of times the king is in check. */ -int CheckTest(board, flags, rf, ff, rt, ft, enPassant) - Board board; - int flags; - int rf, ff, rt, ft, enPassant; +int +CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant) { CheckTestClosure cl; ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing; @@ -1003,16 +995,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, @@ -1039,30 +1033,29 @@ 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 } -ChessMove LegalDrop(board, flags, piece, rt, ft) - Board board; - int flags; - ChessSquare piece; - int rt, ft; +ChessMove +LegalDrop (Board board, int flags, ChessSquare piece, int rt, int ft) { // [HGM] put drop legality testing in separate routine for clarity int n; if(appData.debugMode) fprintf(debugFP, "LegalDrop: %d @ %d,%d)\n", piece, ft, rt); if(board[rt][ft] != EmptySquare) return ImpossibleMove; // must drop to empty square n = PieceToNumber(piece); - if(gameInfo.holdingsWidth == 0 || (flags & F_WHITE_ON_MOVE ? board[n][BOARD_WIDTH-1] : board[BOARD_HEIGHT-1-n][0]) != piece) + if((gameInfo.holdingsWidth == 0 || (flags & F_WHITE_ON_MOVE ? board[n][BOARD_WIDTH-1] : board[BOARD_HEIGHT-1-n][0]) != piece) + && gameInfo.variant != VariantBughouse) // in bughouse we don't check for availability, because ICS doesn't always tell us return ImpossibleMove; // piece not available if(gameInfo.variant == VariantShogi) { // in Shogi lots of drops are forbidden! if((piece == WhitePawn || piece == WhiteQueen) && rt == BOARD_HEIGHT-1 || @@ -1092,41 +1085,27 @@ extern void LegalityTestCallback P((Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure)); -void LegalityTestCallback(board, flags, kind, rf, ff, rt, ft, closure) - Board board; - int flags; - ChessMove kind; - int rf, ff, rt, ft; - VOIDSTAR closure; +void +LegalityTestCallback (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR 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(board[rt][ft] != EmptySquare || kind==WhiteCapturesEnPassant || kind==BlackCapturesEnPassant) cl->captures++; // [HGM] losers: count legal captures if (rf == cl->rf && ff == cl->ff && rt == cl->rt && ft == cl->ft) cl->kind = kind; } -ChessMove LegalityTest(board, flags, rf, ff, rt, ft, promoChar) - Board board; - int flags; - int rf, ff, rt, ft, promoChar; +ChessMove +LegalityTest (Board board, int flags, int rf, int ff, int rt, int ft, int promoChar) { - LegalityTestClosure cl; ChessSquare piece, filterPiece, *castlingRights = board[CASTLING]; + LegalityTestClosure cl; ChessSquare piece, filterPiece; 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; - 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] 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 || @@ -1149,9 +1128,11 @@ ChessMove LegalityTest(board, flags, rf, ff, rt, ft, promoChar) if(gameInfo.variant == VariantSChess && promoChar && promoChar != '=' && board[rf][ff] != WhitePawn && board[rf][ff] != BlackPawn) { if(board[rf][ff] < BlackPawn) { // white if(rf != 0) return IllegalMove; // must be on back rank + if(!(board[VIRGIN][ff] & VIRGIN_W)) return IllegalMove; // non-virgin if(board[PieceToNumber(CharToPiece(ToUpper(promoChar)))][BOARD_WIDTH-2] == 0) return ImpossibleMove;// must be in stock } else { if(rf != BOARD_HEIGHT-1) return IllegalMove; + if(!(board[VIRGIN][ff] & VIRGIN_B)) return IllegalMove; // non-virgin if(board[BOARD_HEIGHT-1-PieceToNumber(CharToPiece(ToLower(promoChar)))][1] == 0) return ImpossibleMove; } } else @@ -1224,12 +1205,8 @@ extern void MateTestCallback P((Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure)); -void MateTestCallback(board, flags, kind, rf, ff, rt, ft, closure) - Board board; - int flags; - ChessMove kind; - int rf, ff, rt, ft; - VOIDSTAR closure; +void +MateTestCallback (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure) { register MateTestClosure *cl = (MateTestClosure *) closure; @@ -1237,9 +1214,8 @@ void MateTestCallback(board, flags, kind, rf, ff, rt, ft, closure) } /* Return MT_NONE, MT_CHECK, MT_CHECKMATE, or MT_STALEMATE */ -int MateTest(board, flags) - Board board; - int flags; +int +MateTest (Board board, int flags) { MateTestClosure cl; int inCheck, r, f, myPieces=0, hisPieces=0, nrKing=0; @@ -1254,7 +1230,6 @@ int MateTest(board, flags) else hisPieces++; } } - if(appData.debugMode) fprintf(debugFP, "MateTest: K=%d, my=%d, his=%d\n", nrKing, myPieces, hisPieces); switch(gameInfo.variant) { // [HGM] losers: extinction wins case VariantShatranj: if(hisPieces == 1) return myPieces > 1 ? MT_BARE : MT_DRAW; @@ -1273,7 +1248,7 @@ int MateTest(board, flags) return inCheck ? MT_CHECK : MT_NONE; } else { if(gameInfo.holdingsWidth && gameInfo.variant != VariantSuper && gameInfo.variant != VariantGreat - && gameInfo.variant != VariantGrand) { // drop game + && gameInfo.variant != VariantSChess && gameInfo.variant != VariantGrand) { // drop game int r, f, n, holdings = flags & F_WHITE_ON_MOVE ? BOARD_WIDTH-1 : 0; for(r=0; rpromoCharIn; @@ -1348,11 +1317,6 @@ void Disambiguate(board, flags, closure) closure->count = closure->captures = 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 : '-'); - } 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 @@ -1371,14 +1335,23 @@ void Disambiguate(board, flags, closure) GenLegal(board, flags|F_IGNORE_CHECK, DisambiguateCallback, (VOIDSTAR) closure, closure->pieceIn); 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; jpieceIn != EmptySquare) { + int f, r; // if there is only a single piece of the requested type on the board, use that + closure->rt = closure->rtIn, closure->ft = closure->ftIn; + for(r=0; rpieceIn) closure->count++, closure->rf = r, closure->ff = f; + if(closure->count > 1) illegal = 0; // ambiguous + } + if(closure->count == 0) { + if (appData.debugMode) { int i, j; + for(i=BOARD_HEIGHT-1; i>=0; i--) { + for(j=0; jpiece != WhitePawn && closure->piece != BlackPawn) { if(closure->piece < BlackPawn) { // white if(closure->rf != 0) closure->kind = IllegalMove; // must be on back rank + if(!(board[VIRGIN][closure->ff] & VIRGIN_W)) closure->kind = IllegalMove; // non-virgin if(board[PieceToNumber(CharToPiece(ToUpper(c)))][BOARD_WIDTH-2] == 0) closure->kind = ImpossibleMove;// must be in stock } else { if(closure->rf != BOARD_HEIGHT-1) closure->kind = IllegalMove; + if(!(board[VIRGIN][closure->ff] & VIRGIN_B)) closure->kind = IllegalMove; // non-virgin if(board[BOARD_HEIGHT-1-PieceToNumber(CharToPiece(ToLower(c)))][1] == 0) closure->kind = ImpossibleMove; } } else @@ -1449,11 +1424,6 @@ void Disambiguate(board, flags, closure) */ closure->kind = IllegalMove; } - 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:'-'); - } } @@ -1472,12 +1442,8 @@ extern void CoordsToAlgebraicCallback P((Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure)); -void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure) - Board board; - int flags; - ChessMove kind; - int rf, ff, rt, ft; - VOIDSTAR closure; +void +CoordsToAlgebraicCallback (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure) { register CoordsToAlgebraicClosure *cl = (CoordsToAlgebraicClosure *) closure; @@ -1506,12 +1472,8 @@ void CoordsToAlgebraicCallback(board, flags, kind, rf, ff, rt, ft, closure) /* Convert coordinates to normal algebraic notation. promoChar must be NULLCHAR or 'x' if not a promotion. */ -ChessMove CoordsToAlgebraic(board, flags, rf, ff, rt, ft, promoChar, out) - Board board; - int flags; - int rf, ff, rt, ft; - int promoChar; - char out[MOVE_LEN]; +ChessMove +CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int promoChar, char out[MOVE_LEN]) { ChessSquare piece; ChessMove kind; @@ -1535,8 +1497,6 @@ ChessMove CoordsToAlgebraic(board, flags, rf, ff, rt, ft, promoChar, out) 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: @@ -1566,8 +1526,6 @@ ChessMove CoordsToAlgebraic(board, flags, rf, ff, rt, ft, promoChar, out) } /* Use promotion suffix style "=Q" */ *outp = NULLCHAR; - 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! */ @@ -1755,12 +1713,8 @@ extern void AtacksCallback P((Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure)); -void AttacksCallback(board, flags, kind, rf, ff, rt, ft, closure) - Board board; - int flags; - ChessMove kind; - int rf, ff, rt, ft; - VOIDSTAR closure; +void +AttacksCallback (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure) { // For adding captures that can lead to chase indictment to the chaseStack if(board[rt][ft] == EmptySquare) return; // non-capture if(board[rt][ft] == WhitePawn && rt < BOARD_HEIGHT/2) return; // Pawn before river can be chased @@ -1779,12 +1733,8 @@ extern void ExistingAtacksCallback P((Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure)); -void ExistingAttacksCallback(board, flags, kind, rf, ff, rt, ft, closure) - Board board; - int flags; - ChessMove kind; - int rf, ff, rt, ft; - VOIDSTAR closure; +void +ExistingAttacksCallback (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure) { // for removing pre-exsting captures from the chaseStack, to be left with newly created ones int i; register ChaseClosure *cl = (ChaseClosure *) closure; //closure tells us the move played in the repeat loop @@ -1808,12 +1758,8 @@ extern void ProtectedCallback P((Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure)); -void ProtectedCallback(board, flags, kind, rf, ff, rt, ft, closure) - Board board; - int flags; - ChessMove kind; - int rf, ff, rt, ft; - VOIDSTAR closure; +void +ProtectedCallback (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure) { // for determining if a piece (given through the closure) is protected register ChaseClosure *cl = (ChaseClosure *) closure; // closure tells us where to recapture @@ -1824,7 +1770,8 @@ void ProtectedCallback(board, flags, kind, rf, ff, rt, ft, closure) extern char moveList[MAX_MOVES][MOVE_LEN]; -int PerpetualChase(int first, int last) +int +PerpetualChase (int first, int last) { // this routine detects if the side to move in the 'first' position is perpetually chasing (when not checking) int i, j, k, tail; ChaseClosure cl;