X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=moves.c;h=8cd34348d5ed29deb95f661034086e60629a04fe;hb=30ded7c1180da9dc3dc703d92f4c0617ea092647;hp=02ced64abf0d8456e63a96f8c3f5ccf139abd377;hpb=4e062d14429ed3a3a251c971690bade4c8cba946;p=xboard.git diff --git a/moves.c b/moves.c index 02ced64..8cd3434 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, 2012 Free Software Foundation, Inc. + * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. * * Enhancements Copyright 2005 Alessandro Scotti * @@ -146,7 +146,8 @@ CopyBoard (Board to, Board from) 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 } @@ -519,7 +520,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, } if(gameInfo.variant == VariantSpartan) rookRange = 2; // in Spartan Chess restrict range to modern Dababba goto doRook; - + /* Shogi Dragon King has to continue as Ferz after Rook moves */ case SHOGI WhiteDragon: case SHOGI BlackDragon: @@ -572,7 +573,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, /* Shogi Pawn and Silver General: first the Pawn move, */ /* then the General continues like a Ferz */ case WhiteMan: - if(gameInfo.variant != VariantMakruk) goto commoner; + if(gameInfo.variant != VariantMakruk && gameInfo.variant != VariantASEAN) goto commoner; case SHOGI WhitePawn: case SHOGI WhiteFerz: if (rf < BOARD_HEIGHT-1 && @@ -583,7 +584,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, break; case BlackMan: - if(gameInfo.variant != VariantMakruk) goto commoner; + if(gameInfo.variant != VariantMakruk && gameInfo.variant != VariantASEAN) goto commoner; case SHOGI BlackPawn: case SHOGI BlackFerz: if (rf > 0 && @@ -672,14 +673,14 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, rf, ff, rf + 1, ff, closure); for (s = -1; s <= 1; s += 2) { if (rf < BOARD_HEIGHT-1 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT && board[rf + 1][ff + s] == EmptySquare) - callback(board, flags, + callback(board, flags, rf >= BOARD_HEIGHT-1-promoRank ? WhitePromotion : NormalMove, rf, ff, rf + 1, ff + s, closure); if (rf == 1 && ff + 2*s >= BOARD_LEFT && ff + 2*s < BOARD_RGHT && board[3][ff + 2*s] == EmptySquare ) callback(board, flags, NormalMove, rf, ff, 3, ff + 2*s, closure); } break; - + case BlackLance: if(gameInfo.variant == VariantSuper) goto Amazon; if (rf > 0 && WhitePiece(board[rf - 1][ff])) @@ -688,7 +689,7 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, rf, ff, rf - 1, ff, closure); for (s = -1; s <= 1; s += 2) { if (rf > 0 && ff + s >= BOARD_LEFT && ff + s < BOARD_RGHT && board[rf - 1][ff + s] == EmptySquare) - callback(board, flags, + callback(board, flags, rf <= promoRank ? BlackPromotion : NormalMove, rf, ff, rf - 1, ff + s, closure); if (rf == BOARD_HEIGHT-2 && ff + 2*s >= BOARD_LEFT && ff + 2*s < BOARD_RGHT && board[rf-2][ff + 2*s] == EmptySquare ) @@ -720,7 +721,7 @@ extern void GenLegalCallback P((Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure)); -void +void GenLegalCallback (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure) { register GenLegalClosure *cl = (GenLegalClosure *) closure; @@ -1053,7 +1054,8 @@ LegalDrop (Board board, int flags, ChessSquare piece, int rt, int ft) 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 || @@ -1088,9 +1090,6 @@ LegalityTestCallback (Board board, int flags, ChessMove kind, int rf, int ff, in { 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) @@ -1100,18 +1099,13 @@ LegalityTestCallback (Board board, int flags, ChessMove kind, int rf, int ff, in 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(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 || @@ -1134,9 +1128,11 @@ LegalityTest (Board board, int flags, int rf, int ff, int rt, int ft, int promoC 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 @@ -1155,7 +1151,7 @@ if(appData.debugMode)fprintf(debugFP,"SHOGI promoChar = %c\n", promoChar ? promo return CharToPiece(promoChar) == EmptySquare ? ImpossibleMove : IllegalMove; else if(flags & F_WHITE_ON_MOVE) { if( (int) piece < (int) WhiteWazir && - (rf >= BOARD_HEIGHT*2/3 || rt >= BOARD_HEIGHT*2/3) ) { + (rf >= BOARD_HEIGHT - BOARD_HEIGHT/3 || rt >= BOARD_HEIGHT - BOARD_HEIGHT/3) ) { if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 || piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */ cl.kind = promoChar == '=' ? IllegalMove : WhitePromotion; @@ -1234,7 +1230,6 @@ MateTest (Board board, int 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; @@ -1269,7 +1264,7 @@ MateTest (Board board, int flags) else if(gameInfo.variant == VariantGiveaway) return MT_STEALMATE; // no check exists, stalemated = win return inCheck ? MT_CHECKMATE - : (gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj) ? + : (gameInfo.variant == VariantXiangqi || gameInfo.variant == VariantShatranj || gameInfo.variant == VariantShogi) ? MT_STAINMATE : MT_STALEMATE; } } @@ -1322,11 +1317,6 @@ Disambiguate (Board board, int flags, DisambiguateClosure *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 @@ -1345,14 +1335,23 @@ Disambiguate (Board board, int flags, DisambiguateClosure *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 @@ -1382,7 +1383,7 @@ Disambiguate (Board board, int flags, DisambiguateClosure *closure) piece == WhiteKnight && closure->rt > BOARD_HEIGHT-3) /* promotion mandatory */ closure->kind = c == '=' ? IllegalMove : WhitePromotion; else /* promotion optional, default is defer */ - closure->kind = c == '+' ? WhitePromotion : WhiteNonPromotion; + closure->kind = c == '+' ? WhitePromotion : WhiteNonPromotion; } else closure->kind = c == '+' ? IllegalMove : NormalMove; } else { if( (int) piece < (int) BlackWazir && (closure->rf < BOARD_HEIGHT/3 || closure->rt < BOARD_HEIGHT/3) ) { @@ -1399,7 +1400,8 @@ Disambiguate (Board board, int flags, DisambiguateClosure *closure) } else if (closure->kind == WhitePromotion || closure->kind == BlackPromotion) { if(c == NULLCHAR) { // missing promoChar on mandatory promotion; use default for variant - if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk) + if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || + gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN) c = PieceToChar(BlackFerz); else if(gameInfo.variant == VariantGreat) c = PieceToChar(BlackMan); @@ -1423,11 +1425,6 @@ Disambiguate (Board board, int flags, DisambiguateClosure *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:'-'); - } } @@ -1501,8 +1498,6 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p 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: @@ -1532,8 +1527,6 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p } /* 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! */ @@ -1637,7 +1630,7 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p /* [HGM] in Shogi non-pawns can promote */ *outp++ = promoChar; // Don't bother to correct move type, return value is never used! } - else if (gameInfo.variant != VariantSuper && promoChar && + else if (gameInfo.variant != VariantSuper && promoChar && (piece == WhiteLance || piece == BlackLance) ) { // Lance sometimes represents Pawn *outp++ = '='; *outp++ = ToUpper(promoChar); @@ -1648,7 +1641,7 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p } *outp = NULLCHAR; return cl.kind; - + case EmptySquare: /* Moving a nonexistent piece */ break;