Allow hide/show of columns in Engine Output
[xboard.git] / backend.c
index b7c3246..ec6b5fc 100644 (file)
--- 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
  *
 #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
 
@@ -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
@@ -759,8 +777,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 +862,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;
@@ -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;
@@ -6501,8 +6522,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;
     }
@@ -8034,6 +8055,7 @@ Adjudicate (ChessProgramState *cps)
              case MT_NONE:
              default:
                break;
+             case MT_STEALMATE:
              case MT_STALEMATE:
              case MT_STAINMATE:
                reason = "Xboard adjudication: Stalemate";
@@ -8272,11 +8294,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<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
@@ -10725,6 +10802,7 @@ SwapEngines (int n)
     SWAP(fenOverride, p)
     SWAP(NPS, h)
     SWAP(accumulateTC, h)
+    SWAP(drawDepth, h)
     SWAP(host, p)
 }
 
@@ -11276,8 +11354,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;
@@ -11302,8 +11379,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;
@@ -12120,22 +12196,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;
@@ -13881,14 +13975,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);