* Massachusetts.
*
* Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
- * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+ * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
*
* Enhancements Copyright 2005 Alessandro Scotti
*
#ifdef WIN32
#include <windows.h>
-int flock(int f, int code);
-#define LOCK_EX 2
-#define SLASH '\\'
+ int flock(int f, int code);
+# define LOCK_EX 2
+# define SLASH '\\'
+
+# ifdef ARC_64BIT
+# define EGBB_NAME "egbbdll64.dll"
+# else
+# define EGBB_NAME "egbbdll.dll"
+# endif
#else
-#include <sys/file.h>
-#define SLASH '/'
+# include <sys/file.h>
+# define SLASH '/'
+
+# include <dlfcn.h>
+# ifdef ARC_64BIT
+# define EGBB_NAME "egbbso64.so"
+# else
+# define EGBB_NAME "egbbso.so"
+# endif
+ // kludge to allow Windows code in back-end by converting it to corresponding Linux code
+# define CDECL
+# define HMODULE void *
+# define LoadLibrary(x) dlopen(x, RTLD_LAZY)
+# define GetProcAddress dlsym
#endif
#endif
#include "backendz.h"
#include "evalgraph.h"
+#include "engineoutput.h"
#include "gettext.h"
#ifdef ENABLE_NLS
#endif
ChessProgramState *WhitePlayer();
-void InsertIntoMemo P((int which, char *text)); // [HGM] kibitz: in engineo.c
int VerifyDisplayMode P(());
char *GetInfoFromComment( int, char * ); // [HGM] PV time: returns stripped comment
default:
break;
}
+ if(appData.fischerCastling) flags |= F_FRC_TYPE_CASTLING, flags &= ~F_ALL_CASTLE_OK; // [HGM] fischer
return flags;
}
ExitAnalyzeMode();
DoSleep( appData.delayBeforeQuit );
SendToProgram("quit\n", cps);
- DoSleep( appData.delayAfterQuit );
- DestroyChildProcess(cps->pr, cps->useSigterm);
+ DestroyChildProcess(cps->pr, 4 + cps->useSigterm);
}
cps->pr = NoProc;
if(appData.debugMode) fprintf(debugFP, "Unload %s\n", cps->which);
/* [HGM] debug */
cps->debug = FALSE;
+ cps->drawDepth = appData.drawDepth[n];
cps->supportsNPS = UNKNOWN;
cps->memSize = FALSE;
cps->maxCores = FALSE;
default:
break;
case MT_CHECK:
- if(gameInfo.variant != VariantShogi)
+ if(!IS_SHOGI(gameInfo.variant))
strcat(parseList[moveNum - 1], "+");
break;
case MT_CHECKMATE:
/* Added by Tord: Send castle moves in "O-O" in FRC games if required by
* the engine. It would be nice to have a better way to identify castle
* moves here. */
- if((gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom)
- && cps->useOOCastle) {
+ if(appData.fischerCastling && cps->useOOCastle) {
int fromX = moveList[moveNum][0] - AAA;
int fromY = moveList[moveNum][1] - ONE;
int toX = moveList[moveNum][2] - AAA;
} else if(strstr(buf+lineStart, "exclude:") == buf+lineStart) { // exclude moves clicked
ExcludeClick(origIndex - lineStart);
return FALSE;
+ } else if(!strncmp(buf+lineStart, "dep\t", 4)) { // column headers clicked
+ Collapse(origIndex - lineStart);
+ return FALSE;
}
ParsePV(buf+startPV, FALSE, gameMode != AnalyzeMode);
*start = startPV; *end = index-1;
oldh = gameInfo.holdingsWidth;
static int oldv;
- if(appData.icsActive) shuffleOpenings = FALSE; // [HGM] shuffle: in ICS mode, only shuffle on ICS request
+ if(appData.icsActive) shuffleOpenings = appData.fischerCastling = FALSE; // [HGM] shuffle: in ICS mode, only shuffle on ICS request
/* [AS] Initialize pv info list [HGM] and game status */
{
switch (gameInfo.variant) {
case VariantFischeRandom:
shuffleOpenings = TRUE;
+ appData.fischerCastling = TRUE;
default:
break;
case VariantShatranj:
break;
case VariantCapaRandom:
shuffleOpenings = TRUE;
+ appData.fischerCastling = TRUE;
case VariantCapablanca:
pieces = CapablancaArray;
gameInfo.boardWidth = 10;
promotionZoneSize = 3;
}
- // Treat Lance as Pawn when it is not representing Amazon
- if(gameInfo.variant != VariantSuper) {
+ // Treat Lance as Pawn when it is not representing Amazon or Lance
+ if(gameInfo.variant != VariantSuper && gameInfo.variant != VariantChu) {
if(piece == WhiteLance) piece = WhitePawn; else
if(piece == BlackLance) piece = BlackPawn;
}
// we either have a choice what to promote to, or (in Shogi) whether to promote
if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN) {
- *promoChoice = PieceToChar(BlackFerz); // no choice
+ ChessSquare p=BlackFerz; // no choice
+ while(p < EmptySquare) { //but make sure we use piece that exists
+ *promoChoice = PieceToChar(p++);
+ if(*promoChoice != '.') break;
+ }
return FALSE;
}
// no sense asking what we must promote to if it is going to explode...
/* Check if clicking again on the same color piece */
fromP = boards[currentMove][fromY][fromX];
toP = boards[currentMove][y][x];
- frc = gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom || gameInfo.variant == VariantSChess;
+ frc = appData.fischerCastling || gameInfo.variant == VariantSChess;
if( (killX < 0 || x != fromX || y != fromY) && // [HGM] lion: do not interpret igui as deselect!
((WhitePawn <= fromP && fromP <= WhiteKing &&
WhitePawn <= toP && toP <= WhiteKing &&
case MT_NONE:
default:
break;
+ case MT_STEALMATE:
case MT_STALEMATE:
case MT_STAINMATE:
reason = "Xboard adjudication: Stalemate";
return 0;
}
+typedef int (CDECL *PPROBE_EGBB) (int player, int *piece, int *square);
+typedef int (CDECL *PLOAD_EGBB) (char *path, int cache_size, int load_options);
+static int egbbCode[] = { 6, 5, 4, 3, 2, 1 };
+
+static int
+BitbaseProbe ()
+{
+ int pieces[10], squares[10], cnt=0, r, f, res;
+ static int loaded;
+ static PPROBE_EGBB probeBB;
+ if(!appData.testLegality) return 10;
+ if(BOARD_HEIGHT != 8 || BOARD_RGHT-BOARD_LEFT != 8) return 12;
+ if(gameInfo.holdingsSize && gameInfo.variant != VariantSuper && gameInfo.variant != VariantSChess) return 12;
+ if(loaded == 2 && forwardMostMove < 2) loaded = 0; // retry on new game
+ for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
+ ChessSquare piece = boards[forwardMostMove][r][f];
+ int black = (piece >= BlackPawn);
+ int type = piece - black*BlackPawn;
+ if(piece == EmptySquare) continue;
+ if(type != WhiteKing && type > WhiteQueen) return 12; // unorthodox piece
+ if(type == WhiteKing) type = WhiteQueen + 1;
+ type = egbbCode[type];
+ squares[cnt] = r*(BOARD_RGHT - BOARD_LEFT) + f - BOARD_LEFT;
+ pieces[cnt] = type + black*6;
+ if(++cnt > 5) return 11;
+ }
+ pieces[cnt] = squares[cnt] = 0;
+ // probe EGBB
+ if(loaded == 2) return 13; // loading failed before
+ if(loaded == 0) {
+ loaded = 2; // prepare for failure
+ char *p, *path = strstr(appData.egtFormats, "scorpio:"), buf[MSG_SIZ];
+ HMODULE lib;
+ PLOAD_EGBB loadBB;
+ if(!path) return 13; // no egbb installed
+ strncpy(buf, path + 8, MSG_SIZ);
+ if(p = strchr(buf, ',')) *p = NULLCHAR; else p = buf + strlen(buf);
+ snprintf(p, MSG_SIZ - strlen(buf), "%c%s", SLASH, EGBB_NAME);
+ lib = LoadLibrary(buf);
+ if(!lib) { DisplayError(_("could not load EGBB library"), 0); return 13; }
+ loadBB = (PLOAD_EGBB) GetProcAddress(lib, "load_egbb_xmen");
+ probeBB = (PPROBE_EGBB) GetProcAddress(lib, "probe_egbb_xmen");
+ if(!loadBB || !probeBB) { DisplayError(_("wrong EGBB version"), 0); return 13; }
+ p[1] = NULLCHAR; loadBB(buf, 64*1028, 2); // 2 = SMART_LOAD
+ loaded = 1; // success!
+ }
+ res = probeBB(forwardMostMove & 1, pieces, squares);
+ return res > 0 ? 1 : res < 0 ? -1 : 0;
+}
+
char *
SendMoveToBookUser (int moveNr, ChessProgramState *cps, int initial)
{ // [HGM] book: this routine intercepts moves to simulate book replies
char *bookHit = NULL;
+ if(cps->drawDepth && BitbaseProbe() == 0) { // [HG} egbb: reduce depth in drawn position
+ char buf[MSG_SIZ];
+ snprintf(buf, MSG_SIZ, "sd %d\n", cps->drawDepth);
+ SendToProgram(buf, cps);
+ }
//first determine if the incoming move brings opponent into his book
if(appData.usePolyglotBook && (cps == &first ? !appData.firstHasOwnBookUCI : !appData.secondHasOwnBookUCI))
bookHit = ProbeBook(moveNr+1, appData.polyglotBook); // returns move
GameEnds(machineWhite ? BlackWins : WhiteWins,
buf1, GE_XBOARD);
return;
- } else if(gameInfo.variant != VariantFischeRandom && gameInfo.variant != VariantCapaRandom)
+ } else if(!appData.fischerCastling)
/* [HGM] Kludge to handle engines that send FRC-style castling
when they shouldn't (like TSCP-Gothic) */
switch(moveType) {
default:
break;
case MT_CHECK:
- if(gameInfo.variant != VariantShogi)
+ if(!IS_SHOGI(gameInfo.variant))
strcat(parseList[boardIndex - 1], "+");
break;
case MT_CHECKMATE:
}
piece = board[toY][toX] = (ChessSquare) fromX;
} else {
- ChessSquare victim;
+// ChessSquare victim;
int i;
if( killX >= 0 && killY >= 0 ) // [HGM] lion: Lion trampled over something
- victim = board[killY][killX],
+// victim = board[killY][killX],
board[killY][killX] = EmptySquare,
board[EP_STATUS] = EP_CAPTURE;
board[toY][toX+1] = board[fromY][BOARD_LEFT];
board[fromY][BOARD_LEFT] = EmptySquare;
} else if ((board[fromY][fromX] == WhitePawn && gameInfo.variant != VariantXiangqi ||
- board[fromY][fromX] == WhiteLance && gameInfo.variant != VariantSuper && gameInfo.variant != VariantShogi)
+ board[fromY][fromX] == WhiteLance && gameInfo.variant != VariantSuper && gameInfo.variant != VariantChu)
&& toY >= BOARD_HEIGHT-promoRank && promoChar // defaulting to Q is done elsewhere
) {
/* white pawn promotion */
board[fromY][0] = EmptySquare;
board[toY][2] = BlackRook;
} else if ((board[fromY][fromX] == BlackPawn && gameInfo.variant != VariantXiangqi ||
- board[fromY][fromX] == BlackLance && gameInfo.variant != VariantSuper && gameInfo.variant != VariantShogi)
+ board[fromY][fromX] == BlackLance && gameInfo.variant != VariantSuper && gameInfo.variant != VariantChu)
&& toY < promoRank && promoChar
) {
/* black pawn promotion */
board[toY][toX] = EmptySquare;
}
}
+
if(gameInfo.variant == VariantSChess && promoChar != NULLCHAR && promoChar != '=' && piece != WhitePawn && piece != BlackPawn) {
board[fromY][fromX] = CharToPiece(piece < BlackPawn ? ToUpper(promoChar) : ToLower(promoChar)); // S-Chess gating
} else
default:
break;
case MT_CHECK:
- if(gameInfo.variant != VariantShogi)
+ if(!IS_SHOGI(gameInfo.variant))
strcat(parseList[forwardMostMove - 1], "+");
break;
case MT_CHECKMATE:
SWAP(fenOverride, p)
SWAP(NPS, h)
SWAP(accumulateTC, h)
+ SWAP(drawDepth, h)
SWAP(host, p)
}
ExitAnalyzeMode();
DoSleep( appData.delayBeforeQuit );
SendToProgram("quit\n", &first);
- DoSleep( appData.delayAfterQuit );
- DestroyChildProcess(first.pr, first.useSigterm);
+ DestroyChildProcess(first.pr, 4 + first.useSigterm);
first.reload = TRUE;
}
first.pr = NoProc;
if (second.pr != NoProc) {
DoSleep( appData.delayBeforeQuit );
SendToProgram("quit\n", &second);
- DoSleep( appData.delayAfterQuit );
- DestroyChildProcess(second.pr, second.useSigterm);
+ DestroyChildProcess(second.pr, 4 + second.useSigterm);
second.reload = TRUE;
}
second.pr = NoProc;
PackMove (int fromX, int fromY, int toX, int toY, ChessSquare promoPiece)
{
int sq = fromX + (fromY<<4);
- int piece = quickBoard[sq];
+ int piece = quickBoard[sq], rook;
quickBoard[sq] = 0;
moveDatabase[movePtr].to = pieceList[piece] = sq = toX + (toY<<4);
- if(piece == pieceList[1] && fromY == toY && (toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) {
+ if(piece == pieceList[1] && fromY == toY) {
+ if((toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) {
int from = toX>fromX ? BOARD_RGHT-1 : BOARD_LEFT;
moveDatabase[movePtr++].piece = Q_WCASTL;
quickBoard[sq] = piece;
piece = quickBoard[from]; quickBoard[from] = 0;
moveDatabase[movePtr].to = pieceList[piece] = sq = toX>fromX ? sq-1 : sq+1;
+ } else if((rook = quickBoard[sq]) && pieceType[rook] == WhiteRook) { // FRC castling
+ quickBoard[sq] = 0; // remove Rook
+ moveDatabase[movePtr].to = sq = (toX>fromX ? BOARD_RGHT-2 : BOARD_LEFT+2); // King to-square
+ moveDatabase[movePtr++].piece = Q_WCASTL;
+ quickBoard[sq] = pieceList[1]; // put King
+ piece = rook;
+ moveDatabase[movePtr].to = pieceList[rook] = sq = toX>fromX ? sq-1 : sq+1;
+ }
} else
- if(piece == pieceList[2] && fromY == toY && (toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) {
+ if(piece == pieceList[2] && fromY == toY) {
+ if((toX > fromX+1 || toX < fromX-1) && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1) {
int from = (toX>fromX ? BOARD_RGHT-1 : BOARD_LEFT) + (BOARD_HEIGHT-1 <<4);
moveDatabase[movePtr++].piece = Q_BCASTL;
quickBoard[sq] = piece;
piece = quickBoard[from]; quickBoard[from] = 0;
moveDatabase[movePtr].to = pieceList[piece] = sq = toX>fromX ? sq-1 : sq+1;
+ } else if((rook = quickBoard[sq]) && pieceType[rook] == BlackRook) { // FRC castling
+ quickBoard[sq] = 0; // remove Rook
+ moveDatabase[movePtr].to = sq = (toX>fromX ? BOARD_RGHT-2 : BOARD_LEFT+2);
+ moveDatabase[movePtr++].piece = Q_BCASTL;
+ quickBoard[sq] = pieceList[2]; // put King
+ piece = rook;
+ moveDatabase[movePtr].to = pieceList[rook] = sq = toX>fromX ? sq-1 : sq+1;
+ }
} else
if(epOK && (pieceType[piece] == WhitePawn || pieceType[piece] == BlackPawn) && fromX != toX && quickBoard[sq] == 0) {
quickBoard[(fromY<<4)+toX] = 0;
DoSleep( appData.delayBeforeQuit );
SendToProgram("quit\n", &first);
- DoSleep( appData.delayAfterQuit );
- DestroyChildProcess(first.pr, 10 /* [AS] first.useSigterm */ );
+ DestroyChildProcess(first.pr, 4 + first.useSigterm /* [AS] first.useSigterm */ );
}
if (second.pr != NoProc) {
DoSleep( appData.delayBeforeQuit );
SendToProgram("quit\n", &second);
- DoSleep( appData.delayAfterQuit );
- DestroyChildProcess(second.pr, 10 /* [AS] second.useSigterm */ );
+ DestroyChildProcess(second.pr, 4 + second.useSigterm /* [AS] second.useSigterm */ );
}
if (first.isr != NULL) {
RemoveInputSource(first.isr);
first.maybeThinking = FALSE; /* avoid killing GNU Chess */
EngineOutputPopUp();
}
- if (!appData.icsEngineAnalyze) gameMode = AnalyzeMode;
+ if (!appData.icsEngineAnalyze) {
+ gameMode = AnalyzeMode;
+ ClearEngineOutputPane(0); // [TK] exclude: to print exclusion/multipv header
+ }
pausing = FALSE;
ModeHighlight();
SetGameInfo();
} else {
if(nrCastlingRights) {
q = p;
- if(gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) {
+ if(appData.fischerCastling) {
/* [HGM] write directly from rights */
if(boards[move][CASTLING][2] != NoRights &&
boards[move][CASTLING][0] != NoRights )
Boolean
ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize)
{
- int i, j, k, w=0;
+ int i, j, k, w=0, subst=0, shuffle=0;
char *p, c;
int emptycount, virgin[BOARD_FILES];
ChessSquare piece;
if (j + emptycount > gameInfo.boardWidth) return FALSE;
while (emptycount--)
board[i][(j++)+gameInfo.holdingsWidth] = EmptySquare;
+ } else if (*p == '<') {
+ if(i == BOARD_HEIGHT-1) shuffle = 1;
+ else if (i != 0 || !shuffle) return FALSE;
+ p++;
+ } else if (shuffle && *p == '>') {
+ p++; // for now ignore closing shuffle range, and assume rank-end
+ } else if (*p == '?') {
+ if (j >= gameInfo.boardWidth) return FALSE;
+ if (i != 0 && i != BOARD_HEIGHT-1) return FALSE; // only on back-rank
+ board[i][(j++)+gameInfo.holdingsWidth] = ClearBoard; p++; subst++; // placeHolder
} else if (*p == '+' || isalpha(*p)) {
if (j >= gameInfo.boardWidth) return FALSE;
if(*p=='+') {
/* [HGM] look for Crazyhouse holdings here */
while(*p==' ') p++;
if( gameInfo.holdingsWidth && p[-1] == '/' || *p == '[') {
+ int swap=0, wcnt=0, bcnt=0;
if(*p == '[') p++;
+ if(*p == '<') swap++, p++;
if(*p == '-' ) p++; /* empty holdings */ else {
if( !gameInfo.holdingsWidth ) return FALSE; /* no room to put holdings! */
/* if we would allow FEN reading to set board size, we would */
if( i >= gameInfo.holdingsSize ) return FALSE;
board[BOARD_HEIGHT-1-i][0] = piece; /* black holdings */
board[BOARD_HEIGHT-1-i][1]++; /* black counts */
+ bcnt++;
} else {
i = (int)piece - (int)WhitePawn;
i = PieceToNumber((ChessSquare)i);
if( i >= gameInfo.holdingsSize ) return FALSE;
board[i][BOARD_WIDTH-1] = piece; /* white holdings */
board[i][BOARD_WIDTH-2]++; /* black holdings */
+ wcnt++;
}
}
+ if(subst) { // substitute back-rank question marks by holdings pieces
+ for(j=BOARD_LEFT; j<BOARD_RGHT; j++) {
+ int k, m, n = bcnt + 1;
+ if(board[0][j] == ClearBoard) {
+ if(!wcnt) return FALSE;
+ n = rand() % wcnt;
+ for(k=0, m=n; k<gameInfo.holdingsSize; k++) if((m -= board[k][BOARD_WIDTH-2]) < 0) {
+ board[0][j] = board[k][BOARD_WIDTH-1]; wcnt--;
+ if(--board[k][BOARD_WIDTH-2] == 0) board[k][BOARD_WIDTH-1] = EmptySquare;
+ break;
+ }
+ }
+ if(board[BOARD_HEIGHT-1][j] == ClearBoard) {
+ if(!bcnt) return FALSE;
+ if(n >= bcnt) n = rand() % bcnt; // use same randomization for black and white if possible
+ for(k=0, m=n; k<gameInfo.holdingsSize; k++) if((n -= board[BOARD_HEIGHT-1-k][1]) < 0) {
+ board[BOARD_HEIGHT-1][j] = board[BOARD_HEIGHT-1-k][0]; bcnt--;
+ if(--board[BOARD_HEIGHT-1-k][1] == 0) board[BOARD_HEIGHT-1-k][0] = EmptySquare;
+ break;
+ }
+ }
+ }
+ subst = 0;
+ }
}
if(*p == ']') p++;
}
+ if(subst) return FALSE; // substitution requested, but no holdings
+
while(*p == ' ') p++;
/* Active color */
board[EP_STATUS] = EP_UNKNOWN;
for(i=0; i<nrCastlingRights; i++ ) {
board[CASTLING][i] =
- gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom ? NoRights : initialRights[i];
+ appData.fischerCastling ? NoRights : initialRights[i];
} /* assume possible unless obviously impossible */
if(initialRights[0]!=NoRights && board[castlingRank[0]][initialRights[0]] != WhiteRook) board[CASTLING][0] = NoRights;
if(initialRights[1]!=NoRights && board[castlingRank[1]][initialRights[1]] != WhiteRook) board[CASTLING][1] = NoRights;
while(*p==' ') p++;
if(nrCastlingRights) {
+ int fischer = 0;
if(gameInfo.variant == VariantSChess) for(i=0; i<BOARD_FILES; i++) virgin[i] = 0;
if(*p >= 'A' && *p <= 'Z' || *p >= 'a' && *p <= 'z' || *p=='-') {
/* castling indicator present, so default becomes no castlings */
}
}
while(*p=='K' || *p=='Q' || *p=='k' || *p=='q' || *p=='-' ||
- (gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom || gameInfo.variant == VariantSChess) &&
+ (appData.fischerCastling || gameInfo.variant == VariantSChess) &&
( *p >= 'a' && *p < 'a' + gameInfo.boardWidth) ||
( *p >= 'A' && *p < 'A' + gameInfo.boardWidth) ) {
int c = *p++, whiteKingFile=NoRights, blackKingFile=NoRights;
board[CASTLING][2] = whiteKingFile;
if(board[CASTLING][0] != NoRights) virgin[board[CASTLING][0]] |= VIRGIN_W;
if(board[CASTLING][2] != NoRights) virgin[board[CASTLING][2]] |= VIRGIN_W;
+ if(whiteKingFile != BOARD_WIDTH>>1|| i != BOARD_RGHT-1) fischer = 1;
break;
case'Q':
for(i=BOARD_LEFT; i<BOARD_RGHT && board[0][i]!=WhiteRook && i<whiteKingFile; i++);
board[CASTLING][2] = whiteKingFile;
if(board[CASTLING][1] != NoRights) virgin[board[CASTLING][1]] |= VIRGIN_W;
if(board[CASTLING][2] != NoRights) virgin[board[CASTLING][2]] |= VIRGIN_W;
+ if(whiteKingFile != BOARD_WIDTH>>1|| i != BOARD_LEFT) fischer = 1;
break;
case'k':
for(i=BOARD_RGHT-1; board[BOARD_HEIGHT-1][i]!=BlackRook && i>blackKingFile; i--);
board[CASTLING][5] = blackKingFile;
if(board[CASTLING][3] != NoRights) virgin[board[CASTLING][3]] |= VIRGIN_B;
if(board[CASTLING][5] != NoRights) virgin[board[CASTLING][5]] |= VIRGIN_B;
+ if(blackKingFile != BOARD_WIDTH>>1|| i != BOARD_RGHT-1) fischer = 1;
break;
case'q':
for(i=BOARD_LEFT; i<BOARD_RGHT && board[BOARD_HEIGHT-1][i]!=BlackRook && i<blackKingFile; i++);
board[CASTLING][5] = blackKingFile;
if(board[CASTLING][4] != NoRights) virgin[board[CASTLING][4]] |= VIRGIN_B;
if(board[CASTLING][5] != NoRights) virgin[board[CASTLING][5]] |= VIRGIN_B;
+ if(blackKingFile != BOARD_WIDTH>>1|| i != BOARD_LEFT) fischer = 1;
case '-':
break;
default: /* FRC castlings */
}
for(i=0; i<nrCastlingRights; i++)
if(board[CASTLING][i] != NoRights) initialRights[i] = board[CASTLING][i];
- if(gameInfo.variant == VariantSChess) for(i=0; i<BOARD_FILES; i++) board[VIRGIN][i] = virgin[i];
+ if(gameInfo.variant == VariantSChess)
+ for(i=0; i<BOARD_FILES; i++) board[VIRGIN][i] = shuffle ? VIRGIN_W | VIRGIN_B : virgin[i]; // when shuffling assume all virgin
+ if(fischer && shuffle) appData.fischerCastling = TRUE;
if (appData.debugMode) {
fprintf(debugFP, "FEN castling rights:");
for(i=0; i<nrCastlingRights; i++)
while(*p==' ') p++;
}
+ if(shuffle) SetUpShuffle(board, appData.defaultFrcPosition);
+
/* read e.p. field in games that know e.p. capture */
if(gameInfo.variant != VariantShogi && gameInfo.variant != VariantXiangqi &&
gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier &&