* Massachusetts.
*
* Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
- * 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
*
* Enhancements Copyright 2005 Alessandro Scotti
*
int PosFlags(int index);
extern signed char initialRights[BOARD_FILES]; /* [HGM] all rights enabled, set in InitPosition */
-
+int quickFlag;
int WhitePiece(piece)
ChessSquare piece;
return (int) piece >= (int) BlackPawn && (int) piece < (int) EmptySquare;
}
+#if 0
int SameColor(piece1, piece2)
ChessSquare 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',
int c;
{
int i;
+ if(c == '.') return EmptySquare;
for(i=0; i< (int) EmptySquare; i++)
if(pieceNickName[i] == c) return (ChessSquare) i;
for(i=0; i< (int) EmptySquare; i++)
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)
+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
{
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;
- 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 );
+ if(filter != EmptySquare && piece != filter) continue;
if(gameInfo.variant == VariantShogi)
piece = (ChessSquare) ( SHOGI piece );
- switch (piece) {
+ switch ((int)piece) {
/* case EmptySquare: [HGM] this is nonsense, and conflicts with Shogi cases */
default:
/* can't happen ([HGM] except for faries...) */
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 &&
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);
}
}
}
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 &&
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);
}
}
}
&& !SameColor(board[rf][ff], board[rt][ft]))
callback(board, flags, NormalMove,
rf, ff, rt, ft, closure);
+ if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier
+ || gameInfo.variant == VariantXiangqi) continue; // classical Alfil
+ rt = rf + rs; // in unknown variant we assume Modern Elephant, which can also do one step
+ ft = ff + fs;
+ if (!(rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT)
+ && !SameColor(board[rf][ff], board[rt][ft]))
+ callback(board, flags, NormalMove,
+ rf, ff, rt, ft, closure);
}
+ if(gameInfo.variant == VariantSpartan)
+ for(fs = -1; fs <= 1; fs += 2) {
+ ft = ff + fs;
+ if (!(ft < BOARD_LEFT || ft >= BOARD_RGHT) && board[rf][ft] == EmptySquare)
+ callback(board, flags, NormalMove, rf, ff, rf, ft, closure);
+ }
break;
+ /* Make Dragon-Horse also do Dababba moves outside Shogi, for better disambiguation in variant Fairy */
+ case WhiteCardinal:
+ case BlackCardinal:
+ for (d = 0; d <= 1; d++) // Dababba moves that Rook cannot do
+ for (s = -2; s <= 2; s += 4) {
+ rt = rf + s * d;
+ ft = ff + s * (1 - d);
+ if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT) continue;
+ if (SameColor(board[rf][ff], board[rt][ft])) continue;
+ callback(board, flags, NormalMove, rf, ff, rt, ft, closure);
+ }
+
/* Shogi Dragon Horse has to continue with Wazir after Bishop */
case SHOGI WhiteCardinal:
case SHOGI BlackCardinal:
}
break;
+ /* Make Dragon-King Dababba & Rook-like outside Shogi, for better disambiguation in variant Fairy */
+ case WhiteDragon:
+ case BlackDragon:
+ for (d = 0; d <= 1; d++) // Dababba moves that Rook cannot do
+ for (s = -2; s <= 2; s += 4) {
+ rt = rf + s * d;
+ ft = ff + s * (1 - d);
+ if (rt < 0 || rt >= BOARD_HEIGHT || ft < BOARD_LEFT || ft >= BOARD_RGHT || board[rf+rt>>1][ff+ft>>1] == EmptySquare) continue;
+ if (SameColor(board[rf][ff], board[rt][ft])) continue;
+ callback(board, flags, NormalMove, rf, ff, rt, ft, 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:
case WhiteMarshall:
case BlackMarshall:
m++;
+ m += (gameInfo.variant == VariantSpartan); // in Spartan Chess Chancellor is used for Dragon King.
/* Shogi Rooks are ordinary Rooks */
case SHOGI WhiteRook:
case SHOGI BlackRook:
case WhiteRook:
case BlackRook:
+ doRook:
for (d = 0; d <= 1; d++)
for (s = -1; s <= 1; s += 2)
for (i = 1;; i++) {
if (SameColor(board[rf][ff], board[rt][ft])) break;
callback(board, flags, NormalMove,
rf, ff, rt, ft, closure);
- if (board[rt][ft] != EmptySquare) break;
+ if (board[rt][ft] != EmptySquare || i == rookRange) break;
}
if(m==1) goto mounted;
if(m==2) goto finishSilver;
}
}
break;
+
+ Amazon:
+ /* First do Bishop,then continue like Chancellor */
+ for (rs = -1; rs <= 1; rs += 2)
+ for (fs = -1; fs <= 1; fs += 2)
+ for (i = 1;; i++) {
+ rt = rf + (i * rs);
+ ft = ff + (i * fs);
+ 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;
+ }
+ m++;
+ goto doRook;
+
+ // Use Lance as Berolina / Spartan Pawn.
+ case WhiteLance:
+ if(gameInfo.variant == VariantSuper) goto Amazon;
+ if (rf < BOARD_HEIGHT-1 && BlackPiece(board[rf + 1][ff]))
+ callback(board, flags,
+ rf >= BOARD_HEIGHT-1-promoRank ? WhitePromotion : NormalMove,
+ 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,
+ 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]))
+ callback(board, flags,
+ rf <= promoRank ? BlackPromotion : NormalMove,
+ 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,
+ 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 )
+ callback(board, flags, NormalMove, rf, ff, rf-2, ff + 2*s, closure);
+ }
+ break;
+
case WhiteFalcon: // [HGM] wild: for wildcards, self-capture symbolizes move to anywhere
case BlackFalcon:
case WhiteCobra:
case BlackCobra:
- case WhiteLance:
- case BlackLance:
callback(board, flags, NormalMove, rf, ff, rf, ff, closure);
break;
VOIDSTAR cl;
} 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,
VOIDSTAR closure));
{
register GenLegalClosure *cl = (GenLegalClosure *) closure;
- if (!(flags & F_IGNORE_CHECK) &&
- CheckTest(board, flags, rf, ff, rt, ft,
+ if(rFilter >= 0 && rFilter != rt || fFilter >= 0 && fFilter != ft) return; // [HGM] speed: ignore moves with wrong to-square
+
+ if (!(flags & F_IGNORE_CHECK) ) {
+ int check, promo = (gameInfo.variant == VariantSpartan && kind == BlackPromotion);
+ if(promo) {
+ int r, f, kings=0;
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++)
+ kings += (board[r][f] == BlackKing);
+ if(kings >= 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)) return;
+ kind == BlackCapturesEnPassant);
+ if(promo) board[rf][ff] = BlackLance;
+ if(check) return;
+ }
if (flags & F_ATOMIC_CAPTURE) {
if (board[rt][ft] != EmptySquare ||
kind == WhiteCapturesEnPassant || kind == BlackCapturesEnPassant) {
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)
+int GenLegal(board, flags, callback, closure, filter)
Board board;
int flags;
MoveCallback callback;
VOIDSTAR closure;
+ ChessSquare filter;
{
GenLegalClosure cl;
- int ff, ft, k, left, right;
+ 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;
- GenPseudoLegal(board, flags, GenLegalCallback, (VOIDSTAR) &cl);
+ 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 */
}
}
- if(flags & F_FRC_TYPE_CASTLING) {
+ if((swap = gameInfo.variant == VariantSChess) || flags & F_FRC_TYPE_CASTLING) {
/* generate all potential FRC castling moves (KxR), ignoring flags */
/* [HGM] test if the Rooks we find have castling rights */
+ /* In S-Chess we generate RxK for allowed castlings, for gating at Rook square */
if ((flags & F_WHITE_ON_MOVE) != 0) {
for(k=left; k<right && ft != NoRights; k++) /* then if not checked */
if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = NoRights;
if(ft != NoRights && board[0][ft] == WhiteRook)
- callback(board, flags, WhiteHSideCastleFR, 0, ff, 0, ft, closure);
+ callback(board, flags, WhiteHSideCastleFR, 0, swap ? ft : ff, 0, swap ? ff : ft, closure);
ft = castlingRights[1]; /* Rook file if we have A-side rights */
left = BOARD_LEFT+2;
for(k=left+1; k<=right && ft != NoRights; k++) /* then if not checked */
if(!ignoreCheck && CheckTest(board, flags, 0, ff, 0, k, FALSE)) ft = NoRights;
if(ft != NoRights && board[0][ft] == WhiteRook)
- callback(board, flags, WhiteASideCastleFR, 0, ff, 0, ft, closure);
+ callback(board, flags, WhiteASideCastleFR, 0, swap ? ft : ff, 0, swap ? ff : ft, closure);
}
} else {
ff = castlingRights[5]; /* King file if we have any rights */
for(k=left; k<right && ft != NoRights; k++) /* then if not checked */
if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = NoRights;
if(ft != NoRights && board[BOARD_HEIGHT-1][ft] == BlackRook)
- callback(board, flags, BlackHSideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);
+ callback(board, flags, BlackHSideCastleFR, BOARD_HEIGHT-1, swap ? ft : ff, BOARD_HEIGHT-1, swap ? ff : ft, closure);
ft = castlingRights[4]; /* Rook file if we have A-side rights */
left = BOARD_LEFT+2;
for(k=left+1; k<=right && ft != NoRights; k++) /* then if not checked */
if(!ignoreCheck && CheckTest(board, flags, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, k, FALSE)) ft = NoRights;
if(ft != NoRights && board[BOARD_HEIGHT-1][ft] == BlackRook)
- callback(board, flags, BlackASideCastleFR, BOARD_HEIGHT-1, ff, BOARD_HEIGHT-1, ft, closure);
+ callback(board, flags, BlackASideCastleFR, BOARD_HEIGHT-1, swap ? ft : ff, BOARD_HEIGHT-1, swap ? ff : 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)
+ }
}
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,
and we test only whether that one is in check. */
- cl.check = 0;
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) {
+ cl.check = 0;
if(gameInfo.variant == VariantXiangqi) {
/* [HGM] In Xiangqi opposing Kings means check as well */
int i, dir;
board[i][cl.fking] == (dir>0 ? BlackWazir : WhiteWazir) )
cl.check++;
}
-
- GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, CheckTestCallback, (VOIDSTAR) &cl);
- goto undo_move; /* 2-level break */
+ GenPseudoLegal(board, flags ^ F_WHITE_ON_MOVE, CheckTestCallback, (VOIDSTAR) &cl, EmptySquare);
+ if(gameInfo.variant != VariantSpartan || cl.check == 0) // in Spartan Chess go on to test if other King is checked too
+ goto undo_move; /* 2-level break */
}
}
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
}
if(board[r][ft] == piece) return IllegalMove; // or there already is a Pawn in file
// should still test if we mate with this Pawn
}
+ } else if(gameInfo.variant == VariantSChess) { // only back-rank drops
+ if (rt != (piece < BlackPawn ? 0 : BOARD_HEIGHT-1)) return IllegalMove;
} else {
if( (piece == WhitePawn || piece == BlackPawn) &&
(rt == 0 || rt == BOARD_HEIGHT -1 ) )
int flags;
int rf, ff, rt, ft, promoChar;
{
- LegalityTestClosure cl; ChessSquare piece, *castlingRights = board[CASTLING];
+ 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 = board[rf][ff];
+ 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] Lance, Cobra and Falcon are wildcard pieces; consider all their moves legal */
+ /* [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 ||
- piece == WhiteCobra || piece == BlackCobra ||
- piece == WhiteLance || piece == BlackLance)
+ piece == WhiteCobra || piece == BlackCobra)
return CheckTest(board, flags, rf, ff, rt, ft, FALSE) ? IllegalMove : NormalMove;
cl.rf = rf;
cl.ff = ff;
- cl.rt = rt;
- cl.ft = ft;
+ cl.rt = rFilter = rt; // [HGM] speed: filter on to-square
+ cl.ft = fFilter = ft;
cl.kind = IllegalMove;
cl.captures = 0; // [HGM] losers: prepare to count legal captures.
- GenLegal(board, flags, LegalityTestCallback, (VOIDSTAR) &cl);
+ if(flags & F_MANDATORY_CAPTURE) filterPiece = EmptySquare; // [HGM] speed: do not filter in suicide, to find all captures
+ GenLegal(board, flags, LegalityTestCallback, (VOIDSTAR) &cl, filterPiece);
if((flags & F_MANDATORY_CAPTURE) && cl.captures && board[rt][ft] == EmptySquare
&& cl.kind != WhiteCapturesEnPassant && cl.kind != BlackCapturesEnPassant)
return(IllegalMove); // [HGM] losers: if there are legal captures, non-capts are illegal
if(promoChar == 'x') promoChar = NULLCHAR; // [HGM] is this ever the case?
+ 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[PieceToNumber(CharToPiece(ToUpper(promoChar)))][BOARD_WIDTH-2] == 0) return ImpossibleMove;// must be in stock
+ } else {
+ if(rf != BOARD_HEIGHT-1) return IllegalMove;
+ if(board[BOARD_HEIGHT-1-PieceToNumber(CharToPiece(ToLower(promoChar)))][1] == 0) return ImpossibleMove;
+ }
+ } else
if(gameInfo.variant == VariantShogi) {
/* [HGM] Shogi promotions. '=' means defer */
if(rf != DROP_RANK && cl.kind == NormalMove) {
promoChar = '+'; // allowed ICS notations
if(appData.debugMode)fprintf(debugFP,"SHOGI promoChar = %c\n", promoChar ? promoChar : '-');
if(promoChar != NULLCHAR && promoChar != '+' && promoChar != '=')
- cl.kind = IllegalMove;
+ 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) ) {
if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 ||
piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */
- cl.kind = promoChar == '=' ? IllegalMove : WhitePromotion;
- else /* promotion optional, default is promote */
- cl.kind = promoChar == '=' ? WhiteNonPromotion : WhitePromotion;
- } else cl.kind = (promoChar == NULLCHAR || promoChar == '=') ? NormalMove : IllegalMove;
+ cl.kind = promoChar == '=' ? IllegalMove : WhitePromotion;
+ else /* promotion optional, default is defer */
+ cl.kind = promoChar == '+' ? WhitePromotion : WhiteNonPromotion;
+ } else cl.kind = promoChar == '+' ? IllegalMove : NormalMove;
} else {
if( (int) piece < (int) BlackWazir && (rf < BOARD_HEIGHT/3 || rt < BOARD_HEIGHT/3) ) {
if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||
piece == BlackKnight && rt < 2 ) /* promotion obligatory */
- cl.kind = promoChar == '=' ? IllegalMove : BlackPromotion;
- else /* promotion optional, default is promote */
- cl.kind = promoChar == '=' ? BlackNonPromotion : BlackPromotion;
-
- } else cl.kind = (promoChar == NULLCHAR || promoChar == '=') ? NormalMove : IllegalMove;
+ cl.kind = promoChar == '=' ? IllegalMove : BlackPromotion;
+ else /* promotion optional, default is defer */
+ cl.kind = promoChar == '+' ? BlackPromotion : BlackNonPromotion;
+ } else cl.kind = promoChar == '+' ? IllegalMove : NormalMove;
}
}
} else
if (promoChar != NULLCHAR) {
if(promoChar == '=') cl.kind = IllegalMove; else // [HGM] shogi: no deferred promotion outside Shogi
if (cl.kind == WhitePromotion || cl.kind == BlackPromotion) {
- if(CharToPiece(promoChar) == EmptySquare) cl.kind = ImpossibleMove; // non-existing piece
+ ChessSquare piece = CharToPiece(flags & F_WHITE_ON_MOVE ? ToUpper(promoChar) : ToLower(promoChar));
+ if(piece == EmptySquare)
+ cl.kind = ImpossibleMove; // non-existing piece
+ if(gameInfo.variant == VariantSpartan && cl.kind == BlackPromotion ) {
+ if(promoChar != PieceToChar(BlackKing)) {
+ if(CheckTest(board, flags, rf, ff, rt, ft, FALSE)) cl.kind = IllegalMove; // [HGM] spartan: only promotion to King was possible
+ if(piece == BlackLance) cl.kind = ImpossibleMove;
+ } else { // promotion to King allowed only if we do not haave two yet
+ int r, f, kings = 0;
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) kings += (board[r][f] == BlackKing);
+ if(kings == 2) cl.kind = IllegalMove;
+ }
+ } else if(piece == WhitePawn && rt == BOARD_HEIGHT-1 ||
+ piece == BlackPawn && rt == 0) cl.kind = IllegalMove; // cannot stay Pawn on last rank in any variant
+ else if((piece == WhiteUnicorn || piece == BlackUnicorn) && gameInfo.variant == VariantKnightmate)
+ cl.kind = IllegalMove; // promotion to Royal Knight not allowed
+ else if((piece == WhiteKing || piece == BlackKing) && gameInfo.variant != VariantSuicide && gameInfo.variant != VariantGiveaway)
+ cl.kind = IllegalMove; // promotion to King usually not allowed
} else {
cl.kind = IllegalMove;
}
if(myPieces == 1) return MT_BARE;
}
cl.count = 0;
- inCheck = GenLegal(board, flags, MateTestCallback, (VOIDSTAR) &cl);
+ inCheck = GenLegal(board, flags, MateTestCallback, (VOIDSTAR) &cl, EmptySquare);
// [HGM] 3check: yet to do!
if (cl.count > 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 != VariantSChess && gameInfo.variant != VariantGrand) { // drop game
int r, f, n, holdings = flags & F_WHITE_ON_MOVE ? BOARD_WIDTH-1 : 0;
for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) if(board[r][f] == EmptySquare) // all empty squares
for(n=0; n<BOARD_HEIGHT; n++) // all pieces in hand
if(board[n][holdings] != EmptySquare) {
int moveType = LegalDrop(board, flags, board[n][holdings], r, f);
- if(moveType == WhiteDrop || moveType == BlackDrop) return MT_CHECK; // we can resolve check by legal drop
+ if(moveType == WhiteDrop || moveType == BlackDrop) return (inCheck ? MT_CHECK : MT_NONE); // we have legal drop
}
}
if(gameInfo.variant == VariantSuicide) // [HGM] losers: always stalemate, since no check, but result varies
// [HGM] wild: for wild-card pieces rt and rf are dummies
if(piece == WhiteFalcon || piece == BlackFalcon ||
- piece == WhiteCobra || piece == BlackCobra ||
- piece == WhiteLance || piece == BlackLance)
+ piece == WhiteCobra || piece == BlackCobra)
wildCard = TRUE;
if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]
cl->ft = wildCard ? cl->ftIn : ft;
cl->kind = kind;
}
- cl->captures += (board[cl->rt][cl->ft] != EmptySquare); // [HGM] oneclick: count captures
+ cl->captures += (board[rt][ft] != EmptySquare); // [HGM] oneclick: count captures
}
}
{
int illegal = 0; char c = closure->promoCharIn;
+ 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;
closure->pieceIn,closure->ffIn,closure->rfIn,closure->ftIn,closure->rtIn,
closure->promoCharIn, closure->promoCharIn >= ' ' ? closure->promoCharIn : '-');
}
- GenLegal(board, flags, DisambiguateCallback, (VOIDSTAR) 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 */
illegal = 1;
- GenLegal(board, flags|F_IGNORE_CHECK, DisambiguateCallback, (VOIDSTAR) 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;
}
if (c == 'x') c = NULLCHAR; // get rid of any 'x' (which should never happen?)
+ 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[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[BOARD_HEIGHT-1-PieceToNumber(CharToPiece(ToLower(c)))][1] == 0) closure->kind = ImpossibleMove;
+ }
+ } else
if(gameInfo.variant == VariantShogi) {
- /* [HGM] Shogi promotions. On input, '=' means defer, NULL promote. Afterwards, c is set to '+' for promotions, NULL other */
+ /* [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) {
ChessSquare piece = closure->piece;
if (c == 'd' && (piece == WhiteRook || piece == BlackRook) ||
c == 'h' && (piece == WhiteBishop || piece == BlackBishop) ||
c == 'g' && (piece <= WhiteFerz || piece <= BlackFerz && piece >= BlackPawn) )
c = '+'; // allowed ICS notations
- if(c != NULLCHAR && c != '+' && c != '=')
- closure->kind = IllegalMove; // the only allowed cases are '+', '='.
+ if(c != NULLCHAR && c != '+' && c != '=') closure->kind = IllegalMove; // otherwise specifying a piece is illegal
else if(flags & F_WHITE_ON_MOVE) {
if( (int) piece < (int) WhiteWazir &&
(closure->rf >= BOARD_HEIGHT-(BOARD_HEIGHT/3) || closure->rt >= BOARD_HEIGHT-(BOARD_HEIGHT/3)) ) {
if( (piece == WhitePawn || piece == WhiteQueen) && closure->rt > BOARD_HEIGHT-2 ||
piece == WhiteKnight && closure->rt > BOARD_HEIGHT-3) /* promotion mandatory */
- closure->kind = c == '=' ? IllegalMove : WhitePromotion;
- else /* promotion optional, default is promote */
- closure->kind = c == '=' ? WhiteNonPromotion : WhitePromotion;
- } else closure->kind = (c == NULLCHAR || c == '=') ? NormalMove : IllegalMove;
+ closure->kind = c == '=' ? IllegalMove : WhitePromotion;
+ else /* promotion optional, default is defer */
+ 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) ) {
if( (piece == BlackPawn || piece == BlackQueen) && closure->rt < 1 ||
piece == BlackKnight && closure->rt < 2 ) /* promotion obligatory */
- closure->kind = c == '=' ? IllegalMove : BlackPromotion;
- else /* promotion optional, default is promote */
- closure->kind = c == '=' ? BlackNonPromotion : BlackPromotion;
- } else closure->kind = (c == NULLCHAR || c == '=') ? NormalMove : IllegalMove;
+ closure->kind = c == '=' ? IllegalMove : BlackPromotion;
+ else /* promotion optional, default is defer */
+ closure->kind = c == '+' ? BlackPromotion : BlackNonPromotion;
+ } else closure->kind = c == '+' ? IllegalMove : NormalMove;
}
}
- c = (closure->kind == WhitePromotion || closure->kind == BlackPromotion) ? '+' : NULLCHAR;
+ if(closure->kind == WhitePromotion || closure->kind == BlackPromotion) c = '+'; else
+ if(closure->kind == WhiteNonPromotion || closure->kind == BlackNonPromotion) c = '=';
} else
if (closure->kind == WhitePromotion || closure->kind == BlackPromotion) {
- if(c == NULLCHAR) c = 'q'; // even in Shatranj, Courier, Makruk, as Apply move corrects this to Ferz (how messy!)
+ if(c == NULLCHAR) { // missing promoChar on mandatory promotion; use default for variant
+ if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk)
+ 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
} else if (c != NULLCHAR) closure->kind = IllegalMove;
closure->promoChar = ToLower(c); // this can be NULLCHAR! Note we keep original promoChar even if illegal.
- if(c != '+' && c != NULLCHAR && CharToPiece(c) == EmptySquare) closure->kind = ImpossibleMove; // but we cannot handle non-existing piece types!
+ if(c != '+' && c != '=' && c != NULLCHAR && CharToPiece(flags & F_WHITE_ON_MOVE ? ToUpper(c) : ToLower(c)) == EmptySquare)
+ closure->kind = ImpossibleMove; // but we cannot handle non-existing piece types!
if (closure->count > 1) {
closure->kind = AmbiguousMove;
}
register CoordsToAlgebraicClosure *cl =
(CoordsToAlgebraicClosure *) closure;
- if (rt == cl->rt && ft == cl->ft &&
+ if ((rt == cl->rt && ft == cl->ft || rt == rf && ft == ff) && // [HGM] null move matches any toSquare
(board[rf][ff] == cl->piece
|| PieceToChar(board[rf][ff]) == '~' &&
(ChessSquare) (DEMOTED board[rf][ff]) == cl->piece)
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++ = '@';
((ff == BOARD_WIDTH>>1 && (ft == BOARD_LEFT+2 || ft == BOARD_RGHT-2)) ||
(ff == (BOARD_WIDTH-1)>>1 && (ft == BOARD_LEFT+1 || ft == BOARD_RGHT-3)))) {
if(ft==BOARD_LEFT+1 || ft==BOARD_RGHT-2)
- safeStrCpy(out, "O-O", MOVE_LEN);
+ snprintf(out, MOVE_LEN, "O-O%c%c", promoChar ? '/' : 0, ToUpper(promoChar));
else
- safeStrCpy(out, "O-O-O", MOVE_LEN);
+ snprintf(out, MOVE_LEN, "O-O-O%c%c", promoChar ? '/' : 0, ToUpper(promoChar));
/* This notation is always unambiguous, unless there are
kings on both the d and e files, with "wild castling"
/* Piece move */
cl.rf = rf;
cl.ff = ff;
- cl.rt = rt;
- cl.ft = ft;
+ cl.rt = rFilter = rt; // [HGM] speed: filter on to-square
+ cl.ft = fFilter = ft;
cl.piece = piece;
cl.kind = IllegalMove;
cl.rank = cl.file = cl.either = 0;
- GenLegal(board, flags, CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
+ c = PieceToChar(piece) ;
+ GenLegal(board, flags, CoordsToAlgebraicCallback, (VOIDSTAR) &cl, c!='~' ? piece : (DEMOTED piece)); // [HGM] speed
if (cl.kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {
/* Generate pretty moves for moving into check, but
still return IllegalMove.
*/
- GenLegal(board, flags|F_IGNORE_CHECK, CoordsToAlgebraicCallback, (VOIDSTAR) &cl);
+ GenLegal(board, flags|F_IGNORE_CHECK, CoordsToAlgebraicCallback, (VOIDSTAR) &cl, c!='~' ? piece : (DEMOTED piece));
if (cl.kind == IllegalMove) break;
cl.kind = IllegalMove;
}
else "N1f3" or "N5xf7",
else "Ng1f3" or "Ng5xf7".
*/
- c = PieceToChar(piece) ;
if( c == '~' || c == '+') {
/* [HGM] print nonexistent piece as its demoted version */
piece = (ChessSquare) (DEMOTED piece);
if(rt+ONE <= '9')
*outp++ = rt + ONE;
else { *outp++ = (rt+ONE-'0')/10 + '0';*outp++ = (rt+ONE-'0')%10 + '0'; }
- *outp = NULLCHAR;
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-(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;
- else cl.kind = WhitePromotion; /* promotion optional */
- } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?
- NormalMove : IllegalMove;
- } else {
- if( (int) cl.piece < (int) BlackWazir && (rf < BOARD_HEIGHT/3 || rt < BOARD_HEIGHT/3) ) {
- if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 ||
- piece == BlackKnight && rt < 2 ) /* promotion obligatory */
- cl.kind = promoChar == '=' ? IllegalMove : BlackPromotion;
- else cl.kind = BlackPromotion; /* promotion optional */
- } else cl.kind = (promoChar == NULLCHAR || promoChar == 'x' || promoChar == '=') ?
- NormalMove : IllegalMove;
- }
- if(cl.kind == WhitePromotion || cl.kind == BlackPromotion) {
- /* 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;
- }
- }
+ *outp++ = promoChar; // Don't bother to correct move type, return value is never used!
+ }
+ else if (gameInfo.variant != VariantSuper && promoChar &&
+ (piece == WhiteLance || piece == BlackLance) ) { // Lance sometimes represents Pawn
+ *outp++ = '=';
+ *outp++ = ToUpper(promoChar);
}
+ else if (gameInfo.variant == VariantSChess && promoChar) { // and in S-Chess we have gating
+ *outp++ = '/';
+ *outp++ = ToUpper(promoChar);
+ }
+ *outp = NULLCHAR;
return cl.kind;
-
- /* [HGM] Always long notation for fairies we don't know */
- case WhiteFalcon:
- case BlackFalcon:
- case WhiteLance:
- case BlackLance:
- case WhiteGrasshopper:
- case BlackGrasshopper:
+
case EmptySquare:
/* Moving a nonexistent piece */
break;
a piece of the same color.
*/
outp = out;
+ c = 0;
if (piece != EmptySquare && piece != WhitePawn && piece != BlackPawn) {
+ int r, f;
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<=BOARD_RGHT; f++)
+ c += (board[r][f] == piece); // count on-board pieces of given type
*outp++ = ToUpper(PieceToChar(piece));
}
+ if(c != 1) { // [HGM] but if there is only one piece of the mentioned type, no from-square, thank you!
*outp++ = ff + AAA;
if(rf+ONE <= '9')
*outp++ = rf + ONE;
else { *outp++ = (rf+ONE-'0')/10 + '0';*outp++ = (rf+ONE-'0')%10 + '0'; }
+ }
if (board[rt][ft] != EmptySquare) *outp++ = 'x';
*outp++ = ft + AAA;
if(rt+ONE <= '9')
int preyStackPointer, chaseStackPointer;
struct {
-char rf, ff, rt, ft;
+unsigned char rf, ff, rt, ft;
} chaseStack[100];
struct {
-char rank, file;
+unsigned char rank, file;
} preyStack[100];
if(appData.debugMode) fprintf(debugFP, "judge position %i\n", i);
chaseStackPointer = 0; // clear stack that is going to hold possible chases
// determine all captures possible after the move, and put them on chaseStack
- GenLegal(boards[i+1], PosFlags(i), AttacksCallback, &cl);
+ GenLegal(boards[i+1], PosFlags(i), AttacksCallback, &cl, EmptySquare);
if(appData.debugMode) { int n;
for(n=0; n<chaseStackPointer; n++)
fprintf(debugFP, "%c%c%c%c ", chaseStack[n].ff+AAA, chaseStack[n].rf+ONE,
cl.ff = moveList[i][0]-AAA+BOARD_LEFT;
cl.rt = moveList[i][3]-ONE;
cl.ft = moveList[i][2]-AAA+BOARD_LEFT;
- GenLegal(boards[i], PosFlags(i), ExistingAttacksCallback, &cl);
+ 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<chaseStackPointer; n++)
fprintf(debugFP, "%c%c%c%c ", chaseStack[n].ff+AAA, chaseStack[n].rf+ONE,
}
// the attack is on a lower piece, or on a pinned or blocked equal one
+ CopyBoard(xqCheckers, nullBoard); xqCheckers[EP_STATUS] = 1;
+ CheckTest(boards[i+1], PosFlags(i+1), -1, -1, -1, -1, FALSE); // if we deliver check with our move, the checkers get marked
// test if the victim is protected by a true protector. First make the capture.
captured = boards[i+1][chaseStack[j].rt][chaseStack[j].ft];
boards[i+1][chaseStack[j].rt][chaseStack[j].ft] = boards[i+1][chaseStack[j].rf][chaseStack[j].ff];
if(appData.debugMode) {
fprintf(debugFP, "test if we can recapture %c%c\n", cl.ft+AAA, cl.rt+ONE);
}
- GenLegal(boards[i+1], PosFlags(i+1), ProtectedCallback, &cl); // try all moves
+ xqCheckers[EP_STATUS] = 2; // causes GenLegal to ignore the checks we delivered with the move, in real life evaded before we captured
+ GenLegal(boards[i+1], PosFlags(i+1), ProtectedCallback, &cl, EmptySquare); // try all moves
+ xqCheckers[EP_STATUS] = 0; // disable quasi-legal moves again
// unmake the capture
boards[i+1][chaseStack[j].rf][chaseStack[j].ff] = boards[i+1][chaseStack[j].rt][chaseStack[j].ft];
boards[i+1][chaseStack[j].rt][chaseStack[j].ft] = captured;
}
}
}
- return preyStackPointer; // if any piece was left on preyStack, it has been perpetually chased
+ return preyStackPointer ? 256*(preyStack[preyStackPointer].file - BOARD_LEFT + AAA) + (preyStack[preyStackPointer].rank + ONE)
+ : 0; // if any piece was left on preyStack, it has been perpetually chased,and we return the
}