X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=moves.c;h=ad68656c38959888900e7618da2d21e3093a1ff0;hb=19322454d23ba4bd033d3578978db047bbd49c7d;hp=a458a8418830ee580a9904292c50045a17b33a05;hpb=19fb94c81f006ac504fdb3bf70ed34985de702cd;p=xboard.git diff --git a/moves.c b/moves.c index a458a84..ad68656 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 * @@ -98,7 +98,7 @@ SameColor (ChessSquare piece1, ChessSquare piece2) (int) piece2 < (int) EmptySquare); } #else -#define SameColor(piece1, piece2) (piece1 < EmptySquare && piece2 < EmptySquare && (piece1 < BlackPawn) == (piece2 < BlackPawn)) +#define SameColor(piece1, piece2) (piece1 < EmptySquare && piece2 < EmptySquare && (piece1 < BlackPawn) == (piece2 < BlackPawn) || piece1 == DarkSquare || piece2 == DarkSquare) #endif char pieceToChar[] = { @@ -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 ) @@ -696,6 +697,16 @@ GenPseudoLegal (Board board, int flags, MoveCallback callback, VOIDSTAR closure, } break; + case WhiteLion: + case BlackLion: + for(rt = rf - 2; rt <= rf + 2; rt++) for(ft = ff - 2; ft <= ff + 2; ft++) { + if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue; + if (!(ff == ft && rf == rt) && SameColor(board[rf][ff], board[rt][ft])) continue; + callback(board, flags, (rt-rf)*(rt-rf) + (ff-ft)*(ff-ft) < 3 && board[rt][ft] != EmptySquare ? FirstLeg : NormalMove, + rf, ff, rt, ft, closure); + } + break; + case WhiteFalcon: // [HGM] wild: for wildcards, self-capture symbolizes move to anywhere case BlackFalcon: case WhiteCobra: @@ -720,13 +731,15 @@ 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; if(rFilter >= 0 && rFilter != rt || fFilter >= 0 && fFilter != ft) return; // [HGM] speed: ignore moves with wrong to-square + if (board[EP_STATUS] == EP_IRON_LION && (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion)) return; //[HGM] lion + if (!(flags & F_IGNORE_CHECK) ) { int check, promo = (gameInfo.variant == VariantSpartan && kind == BlackPromotion); if(promo) { @@ -971,6 +984,9 @@ CheckTestCallback (Board board, int flags, ChessMove kind, int rf, int ff, int r cl->check++; xqCheckers[rf][ff] = xqCheckers[EP_STATUS] & 1; // remember who is checking (if status == 1) } + if( board[EP_STATUS] == EP_ROYAL_LION && (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion) + && (gameInfo.variant != VariantLion || board[rf][ff] != WhiteKing && board[rf][ff] != BlackKing) ) + cl->check++; // [HGM] lion: forbidden counterstrike against Lion equated to putting yourself in check } @@ -986,7 +1002,7 @@ 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; - ChessSquare captured = EmptySquare; + ChessSquare captured = EmptySquare, ep; /* Suppress warnings on uninitialized variables */ if(gameInfo.variant == VariantXiangqi) @@ -1005,6 +1021,14 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant board[rt][ft] = board[rf][ff]; board[rf][ff] = EmptySquare; } + ep = board[EP_STATUS]; + if( captured == WhiteLion || captured == BlackLion ) { // [HGM] lion: Chu Lion-capture rules + ChessSquare victim = killX < 0 ? EmptySquare : board[killY][killX]; + if( (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion) && // capturer is Lion + (ff - ft > 1 || ft - ff > 1 || rf - rt > 1 || rt - rf > 1) && // captures from a distance + (victim == EmptySquare || victim == WhitePawn || victim == BlackPawn) ) // no or worthless 'bridge' + board[EP_STATUS] = EP_ROYAL_LION; // on distant Lion x Lion victim must not be pseudo-legally protected + } } /* For compatibility with ICS wild 9, we scan the board in the @@ -1041,6 +1065,7 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant } else { board[rt][ft] = captured; } + board[EP_STATUS] = ep; } return cl.fking < BOARD_RGHT ? cl.check : 1000; // [HGM] atomic: return 1000 if we have no king @@ -1103,7 +1128,7 @@ LegalityTest (Board board, int flags, int rf, int ff, int rt, int ft, int promoC 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; /* [HGM] Cobra and Falcon are wildcard pieces; consider all their moves legal */ /* (perhaps we should disallow moves that obviously leave us in check?) */ @@ -1127,13 +1152,15 @@ 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 - if(gameInfo.variant == VariantShogi) { + if(IS_SHOGI(gameInfo.variant)) { /* [HGM] Shogi promotions. '=' means defer */ if(rf != DROP_RANK && cl.kind == NormalMove) { ChessSquare piece = board[rf][ff]; @@ -1148,7 +1175,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; @@ -1261,7 +1288,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; } } @@ -1356,12 +1383,17 @@ Disambiguate (Board board, int flags, DisambiguateClosure *closure) if(gameInfo.variant == VariantSChess && c && c != '=' && closure->piece != 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 + if(gameInfo.variant == VariantChu) { + if(c == '+') closure->kind = (flags & F_WHITE_ON_MOVE ? WhitePromotion : BlackPromotion); // for now, accept any + } else if(gameInfo.variant == VariantShogi) { /* [HGM] Shogi promotions. On input, '=' means defer, '+' promote. Afterwards, c is set to '+' for promotions, NULL other */ if(closure->rfIn != DROP_RANK && closure->kind == NormalMove) { @@ -1378,7 +1410,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) ) { @@ -1395,7 +1427,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); @@ -1522,7 +1555,7 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p /* Use promotion suffix style "=Q" */ *outp = NULLCHAR; if (promoChar != NULLCHAR) { - if(gameInfo.variant == VariantShogi) { + if(IS_SHOGI(gameInfo.variant)) { /* [HGM] ... but not in Shogi! */ *outp++ = promoChar == '=' ? '=' : '+'; } else { @@ -1620,11 +1653,11 @@ CoordsToAlgebraic (Board board, int flags, int rf, int ff, int rt, int ft, int p if(rt+ONE <= '9') *outp++ = rt + ONE; else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; } - if (gameInfo.variant == VariantShogi) { + if (IS_SHOGI(gameInfo.variant)) { /* [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); @@ -1635,7 +1668,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;