X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=0af55faa788916612927535698fbc539bc5f5f5a;hb=36a3483dd6f8361b0ccb7c5648e83922883bb9a6;hp=b440060ac72a9d2a6356579ee087da7d378e33b7;hpb=979194fe7ecabbb75e280bab38165a23b7d48584;p=xboard.git diff --git a/backend.c b/backend.c index b440060..0af55fa 100644 --- a/backend.c +++ b/backend.c @@ -5,7 +5,7 @@ * 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 * @@ -55,14 +55,32 @@ #ifdef WIN32 #include -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 -#define SLASH '/' +# include +# define SLASH '/' + +# include +# 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 @@ -130,6 +148,7 @@ extern int gettimeofday(struct timeval *, struct timezone *); #endif #include "backendz.h" #include "evalgraph.h" +#include "engineoutput.h" #include "gettext.h" #ifdef ENABLE_NLS @@ -232,7 +251,6 @@ static int NonStandardBoardSize P((VariantClass v, int w, int h, int s)); #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 @@ -397,6 +415,7 @@ PosFlags (index) default: break; } + if(appData.fischerCastling) flags |= F_FRC_TYPE_CASTLING, flags &= ~F_ALL_CASTLE_OK; // [HGM] fischer return flags; } @@ -759,8 +778,7 @@ UnloadEngine (ChessProgramState *cps) 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); @@ -845,6 +863,7 @@ InitEngine (ChessProgramState *cps, int n) /* [HGM] debug */ cps->debug = FALSE; + cps->drawDepth = appData.drawDepth[n]; cps->supportsNPS = UNKNOWN; cps->memSize = FALSE; cps->maxCores = FALSE; @@ -4813,7 +4832,7 @@ ParseBoard12 (char *string) default: break; case MT_CHECK: - if(gameInfo.variant != VariantShogi) + if(!IS_SHOGI(gameInfo.variant)) strcat(parseList[moveNum - 1], "+"); break; case MT_CHECKMATE: @@ -5075,8 +5094,7 @@ SendMoveToProgram (int moveNum, ChessProgramState *cps) /* 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; @@ -5629,6 +5647,9 @@ LoadMultiPV (int x, int y, char *buf, int index, int *start, int *end, int pane) } 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; @@ -5950,7 +5971,7 @@ InitPosition (int redraw) 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 */ { @@ -5991,6 +6012,7 @@ InitPosition (int redraw) switch (gameInfo.variant) { case VariantFischeRandom: shuffleOpenings = TRUE; + appData.fischerCastling = TRUE; default: break; case VariantShatranj: @@ -6021,6 +6043,7 @@ InitPosition (int redraw) break; case VariantCapaRandom: shuffleOpenings = TRUE; + appData.fischerCastling = TRUE; case VariantCapablanca: pieces = CapablancaArray; gameInfo.boardWidth = 10; @@ -6501,8 +6524,8 @@ HasPromotionChoice (int fromX, int fromY, int toX, int toY, char *promoChoice, i 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; } @@ -6553,7 +6576,11 @@ HasPromotionChoice (int fromX, int fromY, int toX, int toY, char *promoChoice, i // 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... @@ -7419,7 +7446,7 @@ LeftClick (ClickType clickType, int xPix, int yPix) /* 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 && @@ -8030,6 +8057,7 @@ Adjudicate (ChessProgramState *cps) case MT_NONE: default: break; + case MT_STEALMATE: case MT_STALEMATE: case MT_STAINMATE: reason = "Xboard adjudication: Stalemate"; @@ -8268,11 +8296,66 @@ Adjudicate (ChessProgramState *cps) 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= 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 @@ -8546,7 +8629,7 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h 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) { @@ -9705,7 +9788,7 @@ ParseGameHistory (char *game) default: break; case MT_CHECK: - if(gameInfo.variant != VariantShogi) + if(!IS_SHOGI(gameInfo.variant)) strcat(parseList[boardIndex - 1], "+"); break; case MT_CHECKMATE: @@ -9842,7 +9925,7 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) 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 */ @@ -9903,7 +9986,7 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) 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 */ @@ -10016,6 +10099,7 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) 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 @@ -10146,7 +10230,7 @@ MakeMove (int fromX, int fromY, int toX, int toY, int promoChar) default: break; case MT_CHECK: - if(gameInfo.variant != VariantShogi) + if(!IS_SHOGI(gameInfo.variant)) strcat(parseList[forwardMostMove - 1], "+"); break; case MT_CHECKMATE: @@ -10720,6 +10804,7 @@ SwapEngines (int n) SWAP(fenOverride, p) SWAP(NPS, h) SWAP(accumulateTC, h) + SWAP(drawDepth, h) SWAP(host, p) } @@ -11271,8 +11356,7 @@ GameEnds (ChessMove result, char *resultDetails, int whosays) 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; @@ -11297,8 +11381,7 @@ GameEnds (ChessMove result, char *resultDetails, int whosays) 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; @@ -12115,22 +12198,40 @@ void 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; @@ -13876,14 +13977,12 @@ ExitEvent (int status) 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); @@ -14114,7 +14213,10 @@ AnalyzeModeEvent () 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(); @@ -17546,7 +17648,7 @@ PositionToFEN (int move, char *overrideCastling, int moveCounts) } 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 ) @@ -17782,7 +17884,7 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize) board[EP_STATUS] = EP_UNKNOWN; for(i=0; i= 'a' && *p < 'a' + gameInfo.boardWidth) || ( *p >= 'A' && *p < 'A' + gameInfo.boardWidth) ) { int c = *p++, whiteKingFile=NoRights, blackKingFile=NoRights;