summaryrefslogtreecommitdiff
path: root/src/probe.c
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2016-06-01 18:58:58 -0700
committerScott Gasch <[email protected]>2016-06-01 18:58:58 -0700
commit3fd43cd5fcb22bb65bf2a92a25d95d801b11c9e0 (patch)
tree9b6443235d16ba17f094a1a1c7ae53d2bcb9267b /src/probe.c
Initial checkin for typhoon chess engine.
Diffstat (limited to 'src/probe.c')
-rw-r--r--src/probe.c432
1 files changed, 432 insertions, 0 deletions
diff --git a/src/probe.c b/src/probe.c
new file mode 100644
index 0000000..2d8c43d
--- /dev/null
+++ b/src/probe.c
@@ -0,0 +1,432 @@
+/**
+
+Copyright (c) Scott Gasch
+
+Module Name:
+
+ probe.c
+
+Abstract:
+
+ Routines for probing endgame tablebases; much of this code is
+ "borrowed" from crafty.
+
+Author:
+
+ Scott Gasch ([email protected]) 02 Jul 2004
+
+Revision History:
+
+ $Id: probe.c 355 2008-07-01 15:46:43Z scott $
+
+**/
+
+#include "chess.h"
+
+#define XX (127) // sq not on the board
+#define C_PIECES (3) // max num pieces of one color
+
+ULONG g_uEgtbLock = 0;
+
+//
+// define INDEX type
+//
+#define T_INDEX64 // use 64 bit indexes
+#if defined (T_INDEX64) && defined (_MSC_VER)
+typedef unsigned __int64 INDEX;
+#elif defined (T_INDEX64)
+typedef unsigned long long INDEX;
+#else
+typedef unsigned long INDEX;
+#endif
+
+//
+// define square type and tb type
+//
+typedef unsigned int squaret;
+typedef signed char tb_t;
+
+//
+// define color
+//
+typedef int color;
+#define x_colorWhite 0
+#define x_colorBlack 1
+#define x_colorNeutral 2
+#define COLOR_DECLARED
+
+//
+// define pieces
+//
+typedef int piece;
+#define x_pieceNone 0
+#define x_piecePawn 1
+#define x_pieceKnight 2
+#define x_pieceBishop 3
+#define x_pieceRook 4
+#define x_pieceQueen 5
+#define x_pieceKing 6
+#define PIECES_DECLARED
+
+//
+// scores returned from egtb.cpp
+//
+#define pageL 65536
+#define tbbe_ssL ((pageL-4)/2)
+#define bev_broken (tbbe_ssL+1) /* illegal or busted */
+#define bev_mi1 tbbe_ssL /* mate in 1 move */
+#define bev_mimin 1 /* mate in max moves */
+#define bev_draw 0 /* draw */
+#define bev_limax (-1) /* mated in max moves */
+#define bev_li0 (-tbbe_ssL) /* mated in 0 moves */
+
+//
+// define PfnCalcIndex
+//
+typedef INDEX(TB_FASTCALL * PfnCalcIndex)(squaret *,
+ squaret *,
+ squaret,
+ int fInverse);
+
+//
+// prototypes for functions in egtb.cpp
+//
+extern int IDescFindFromCounters(int *);
+extern int FRegisteredFun(int, color);
+extern PfnCalcIndex PfnIndCalcFun(int, color);
+extern int TB_FASTCALL L_TbtProbeTable(int, color, INDEX);
+#define PfnIndCalc PfnIndCalcFun
+#define FRegistered FRegisteredFun
+extern int IInitializeTb(char *);
+extern int FTbSetCacheSize(void *buffer, unsigned long size);
+extern int TB_CRC_CHECK;
+
+//
+// Globals
+//
+static int EGTBMenCount = 0;
+void *egtb_cache = NULL;
+#define EGTB_CACHE_SIZE (8*1024*1024)
+
+
+void
+InitializeEGTB(void)
+/**
+
+Routine description:
+
+ [Re]Initialize the Nalimov EGTB system. Called during system
+ startup and when the user uses "set" to change the EGTB path.
+
+Parameters:
+
+ void (uses g_OPtionz.szEGTBPath)
+
+Return value:
+
+ void
+
+**/
+{
+ CHAR *szPath = g_Options.szEGTBPath;
+
+ if ((szPath != NULL) && strlen(szPath) > 0) {
+ // TB_CRC_CHECK = 1;
+ EGTBMenCount = IInitializeTb(szPath);
+ if (0 != EGTBMenCount)
+ {
+ Trace("Found %d-men endgame tablebases.\n\n", EGTBMenCount);
+ if (NULL != egtb_cache)
+ {
+ SystemFreeMemory(egtb_cache);
+ egtb_cache = NULL;
+ }
+ egtb_cache = SystemAllocateMemory(EGTB_CACHE_SIZE);
+ if (NULL != egtb_cache)
+ {
+ FTbSetCacheSize(egtb_cache, EGTB_CACHE_SIZE);
+ }
+ }
+ }
+}
+
+void
+CleanupEGTB(void)
+/**
+
+Routine description:
+
+ Cleanup the Nalimov EGTB system.
+
+Parameters:
+
+ void
+
+Return value:
+
+ void
+
+**/
+{
+ if (NULL != egtb_cache)
+ {
+ SystemFreeMemory(egtb_cache);
+ egtb_cache = NULL;
+ }
+}
+
+
+FLAG
+ProbeEGTB(SEARCHER_THREAD_CONTEXT *ctx,
+ SCORE *piScore)
+/**
+
+Routine description:
+
+ Search for a board position in the EGTB files on disk.
+
+Parameters:
+
+ SEARCHER_THREAD_CONTEXT *ctx,
+ SCORE *piScore
+
+Return value:
+
+ FLAG
+
+**/
+{
+ POSITION *pos = &(ctx->sPosition);
+ int pcCount[10];
+ int wSquares[C_PIECES*5+1], bSquares[C_PIECES*5+1];
+ int iTB;
+ ULONG uColor;
+ int invert;
+ int *wp, *bp;
+ int ep;
+ INDEX index;
+ int value;
+ FLAG fResult;
+ ULONG x;
+ int y;
+ COOR c;
+ PIECE p;
+ PfnCalcIndex fp;
+
+ //
+ // EGTB initialized?
+ //
+ ULONG wcount = (pos->uNonPawnCount[WHITE][0] +
+ pos->uPawnCount[WHITE]);
+ ULONG bcount = (pos->uNonPawnCount[BLACK][0] +
+ pos->uPawnCount[BLACK]);
+ if ((wcount + bcount > (ULONG)EGTBMenCount) ||
+ (wcount > 3) ||
+ (bcount > 3))
+ {
+ return(FALSE);
+ }
+ INC(ctx->sCounters.egtb.uProbes);
+ memset(pcCount, 0, sizeof(pcCount));
+
+ for (x = 0;
+ x < pos->uPawnCount[WHITE];
+ x++)
+ {
+ c = pos->cPawns[WHITE][x];
+ ASSERT (IS_ON_BOARD(c));
+ ASSERT(pos->rgSquare[c].pPiece && IS_PAWN(pos->rgSquare[c].pPiece));
+
+ c = TO64(c);
+ ASSERT((c >= 0) && (c <= 64));
+
+ y = pcCount[0];
+ ASSERT(y >= 0);
+ ASSERT(y < (C_PIECES * 5 + 1));
+ wSquares[y] = c;
+ pcCount[0]++;
+ }
+
+ for (x = 1;
+ x < pos->uNonPawnCount[WHITE][0];
+ x++)
+ {
+ c = pos->cNonPawns[WHITE][x];
+ ASSERT (IS_ON_BOARD(c));
+
+ p = pos->rgSquare[c].pPiece;
+ ASSERT(p && !IS_PAWN(p) && !IS_KING(p));
+
+ //
+ // convert: into:
+ // XXX_PAWN 0
+ // XXX_KNIGHT 1
+ // XXX_BISHOP 2
+ // XXX_ROOK 3
+ // XXX_QUEEN 4
+ //
+ p = ((p >> 1) & 0x7) - 1;
+ ASSERT(p > 0);
+ ASSERT(p < 5);
+
+ c = TO64(c);
+ ASSERT((c >= 0) && (c <= 64));
+
+ y = p * C_PIECES + pcCount[p];
+ ASSERT(y >= 0);
+ ASSERT(y < (C_PIECES * 5 + 1));
+ wSquares[y] = c;
+ pcCount[p]++;
+ }
+
+ for (x = 0;
+ x < pos->uPawnCount[BLACK];
+ x++)
+ {
+ c = pos->cPawns[BLACK][x];
+ ASSERT(IS_ON_BOARD(c));
+ ASSERT(pos->rgSquare[c].pPiece && IS_PAWN(pos->rgSquare[c].pPiece));
+
+ c = TO64(c);
+ ASSERT(c >= 0);
+ ASSERT(c <= 64);
+
+ y = pcCount[5];
+ ASSERT(y >= 0);
+ ASSERT(y < (C_PIECES * 5 + 1));
+ bSquares[y] = c;
+ pcCount[5]++;
+ }
+
+ for (x = 1;
+ x < pos->uNonPawnCount[BLACK][0];
+ x++)
+ {
+ c = pos->cNonPawns[BLACK][x];
+ ASSERT(IS_ON_BOARD(c));
+
+ p = pos->rgSquare[c].pPiece;
+ ASSERT(p && !IS_PAWN(p) && !IS_KING(p));
+
+ //
+ // convert: into:
+ // XXX_PAWN 0
+ // XXX_KNIGHT 1
+ // XXX_BISHOP 2
+ // XXX_ROOK 3
+ // XXX_QUEEN 4
+ //
+ p = ((p >> 1) & 0x7) - 1;
+ ASSERT(p > 0);
+ ASSERT(p < 5);
+
+ c = TO64(c);
+ ASSERT(c >= 0);
+ ASSERT(c <= 64);
+
+ y = p * C_PIECES + pcCount[5 + p];
+ ASSERT(y >= 0);
+ ASSERT(y < (C_PIECES * 5 + 1));
+ bSquares[y] = c;
+ pcCount[5 + p]++;
+ }
+
+ AcquireSpinLock(&g_uEgtbLock);
+ iTB = IDescFindFromCounters(pcCount);
+ if (iTB == 0)
+ {
+ fResult = FALSE;
+ goto end;
+ }
+
+ //
+ // Add the kings to the piece lists
+ //
+ ASSERT(pos->rgSquare[pos->cNonPawns[WHITE][0]].pPiece == WHITE_KING);
+ wSquares[C_PIECES * 5] = TO64(pos->cNonPawns[WHITE][0]);
+ ASSERT(wSquares[C_PIECES * 5] >= 0);
+ ASSERT(wSquares[C_PIECES * 5] <= 64);
+
+ ASSERT(pos->rgSquare[pos->cNonPawns[BLACK][0]].pPiece == BLACK_KING);
+ bSquares[C_PIECES * 5] = TO64(pos->cNonPawns[BLACK][0]);
+ ASSERT(bSquares[C_PIECES * 5] >= 0);
+ ASSERT(bSquares[C_PIECES * 5] <= 64);
+
+ if (iTB > 0)
+ {
+ uColor = (pos->uToMove == WHITE) ? 0 : 1;
+ invert = 0;
+ wp = wSquares;
+ bp = bSquares;
+ }
+ else
+ {
+ uColor = (pos->uToMove == WHITE) ? 1 : 0;
+ invert = 1;
+ wp = bSquares;
+ bp = wSquares;
+ iTB = -iTB;
+ }
+
+ if (!FRegisteredFun(iTB, uColor))
+ {
+ fResult = FALSE;
+ goto end;
+ }
+ ep = XX;
+ if (IS_ON_BOARD(pos->cEpSquare))
+ {
+ ASSERT((IS_ON_BOARD(pos->cEpSquare + 1) &&
+ IS_PAWN(pos->rgSquare[pos->cEpSquare + 1].pPiece)) ||
+ (IS_ON_BOARD(pos->cEpSquare - 1) &&
+ IS_PAWN(pos->rgSquare[pos->cEpSquare - 1].pPiece)));
+ ep = TO64(pos->cEpSquare);
+ }
+
+#if 0
+ DumpPosition(pos);
+ Trace("iTB = %d, uColor = %u, ep = %u, invert = %u\n",
+ iTB, uColor, ep, invert);
+ Trace("wp =\t\t\tbp =\n");
+ for(x = 0; x < 16; x++)
+ {
+ Trace("%u\t\t\t%u\n", wSquares[x], bSquares[x]);
+ }
+#endif
+ ASSERT(IS_VALID_COLOR(uColor));
+ fp = PfnIndCalcFun(iTB, uColor);
+ index = fp((squaret *)wp,
+ (squaret *)bp,
+ (squaret)ep,
+ invert);
+ value = L_TbtProbeTable(iTB, uColor, index);
+ if (value == bev_broken)
+ {
+ fResult = FALSE;
+ goto end;
+ }
+
+ if (value > 0)
+ {
+ *piScore = INFINITY + (2*(-bev_mi1+value)) - 1;
+ }
+ else if (value < 0)
+ {
+ *piScore = -INFINITY + (2*(bev_mi1+value));
+ }
+ else
+ {
+ *piScore = 0; // g_iDrawValue[pos->uToMove];
+ }
+ fResult = TRUE;
+
+ end:
+ ReleaseSpinLock(&g_uEgtbLock);
+#ifdef PERF_COUNTERS
+ if (fResult == TRUE)
+ {
+ INC(ctx->sCounters.egtb.uHits);
+ }
+#endif
+ return(fResult);
+}