* 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, 2013 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;
+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;
}
-int SameColor(piece1, piece2)
- ChessSquare piece1, piece2;
+#if 0
+int
+SameColor (ChessSquare piece1, ChessSquare piece2)
{
return ((int) piece1 >= (int) WhitePawn && /* [HGM] can be > King ! */
(int) piece1 < (int) BlackPawn &&
(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',
'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;
return i;
}
-ChessSquare CharToPiece(c)
- int c;
+ChessSquare
+CharToPiece (int c)
{
int i;
if(c == '.') return EmptySquare;
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;
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;
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 );
}
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:
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]))
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 )
} 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));
-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;
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<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);
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;
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 */
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;
- 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)
+ }
}
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;
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,
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 ||
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(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 ||
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
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;
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;
}
/* 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;
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;
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; 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
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;
}
}
int rf, int ff, int rt, int ft,
VOIDSTAR closure));
-void DisambiguateCallback(board, flags, kind, rf, ff, rt, ft, closure)
- Board board;
- int flags;
- ChessMove kind;
- int rf, ff, rt, ft;
- VOIDSTAR closure;
+void
+DisambiguateCallback (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOIDSTAR closure)
{
register DisambiguateClosure *cl = (DisambiguateClosure *) closure;
int wildCard = FALSE; ChessSquare piece = board[rf][ff];
}
}
-void Disambiguate(board, flags, closure)
- Board board;
- int flags;
- DisambiguateClosure *closure;
+void
+Disambiguate (Board board, int flags, DisambiguateClosure *closure)
{
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;
- 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
+ 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 */
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; j<BOARD_WIDTH; j++)
- fprintf(debugFP, "%3d", (int) board[i][j]);
- fprintf(debugFP, "\n");
- }
- }
+ if(!appData.testLegality && closure->pieceIn != 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; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++)
+ if(board[r][f] == closure->pieceIn) 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; j<BOARD_WIDTH; j++)
+ fprintf(debugFP, "%3d", (int) board[i][j]);
+ fprintf(debugFP, "\n");
+ }
+ }
return;
+ }
}
}
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
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) ) {
*/
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:'-');
- }
}
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;
/* 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;
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:
}
/* 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! */
/* [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);
}
*outp = NULLCHAR;
return cl.kind;
-
+
case EmptySquare:
/* Moving a nonexistent piece */
break;
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
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
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
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;
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<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);
}
+ 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
}