#include "tools.h"
 
#include <stdlib.h>
 
#include <stdio.h>
 
#include <string.h>
 
#include <ctype.h>
 
#if defined(_WIN32)
 
#include <windows.h>
 
#endif
 
 
 
#ifdef INCLUDE_TABLEBASE_ACCESS
 
 
 
#define NEW
 
#define T41_INCLUDE
 
#define T42_INCLUDE
 
#define T33_INCLUDE
 
#define T_INDEX64
 
#define  XX  127
 
 
 
#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
 
 
 
typedef unsigned int square;
 
 
 
typedef int color;
 
 
 
#define  x_colorWhite    0
 
#define  x_colorBlack    1
 
#define  x_colorNeutral  2
 
 
 
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
 
 
 
/*
 
   Macro that fetches positions of pieces
 
 */
 
 
 
#define  C_PIECES  3    /* Maximum # of pieces of one color OTB */
 
 
 
#define  SqFindKing(psq)       (psq[C_PIECES*(x_pieceKing-1)])
 
#define  SqFindOne(psq, pi)    (psq[C_PIECES*(pi-1)])
 
#define  SqFindFirst(psq, pi)  (psq[C_PIECES*(pi-1)])
 
#define  SqFindSecond(psq, pi) (psq[C_PIECES*(pi-1)+1])
 
#define  SqFindThird(psq, pi)  (psq[C_PIECES*(pi-1)+2])
 
 
 
#define LockInit(p)
 
#define LockFree(p)
 
#define Lock(p)
 
#define Unlock(p)
 
#define lock_t volatile int
 
 
 
/*
 
   All defined, now include probing code
 
 */
 
 
 
/* -------------------------------------------------------------------- */
 
/*                                                                      */
 
/*              Probe chess endgame database ("tablebase")              */
 
/*                                                                      */
 
/*               Copyright (c) 1998--2001 Eugene Nalimov                */
 
/*                                                                      */
 
/* The code listed below should not be used in any product (software or */
 
/* hardware,  commercial or not,  and so on) without written permission */
 
/* from the author.                                                     */
 
/*                                                                      */
 
/* -------------------------------------------------------------------- */
 
 
 
#if defined (_WIN32) || defined(_WIN64)
 
#  include <windows.h>
 
#endif
 
 
 
#ifdef UNICODE
 
#define STRING_PTR LPCWSTR
 
#else
 
#define STRING_PTR LPCSTR
 
#endif
 
 
 
#include <string.h>
 
#include <stdlib.h>
 
#include <stdio.h>
 
#if !defined (DEBUG) && !defined(NDEBUG)
 
#  define   NDEBUG
 
#endif
 
#include <assert.h>
 
 
 
static  lock_t  lockLRU;
 
 
 
// Declarations
 
 
 
typedef unsigned    char BYTE;
 
typedef unsigned    long ULONG;
 
typedef signed      char tb_t;
 
 
 
#if !defined (COLOR_DECLARED)
 
typedef int color;
 
#  define   x_colorWhite    0
 
#  define   x_colorBlack    1
 
#  define   x_colorNeutral  2
 
#  define COLOR_DECLARED
 
#endif
 
 
 
#if !defined (PIECES_DECLARED)
 
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
 
#endif
 
 
 
#if !defined (SqFind2)
 
#  define   SqFind2(psq,pi1,sq1,pi2,sq2)    sq1=SqFindFirst(psq,pi1);sq2=SqFindFirst(psq,pi2);
 
#endif
 
 
 
// Machine and compiler-specific declarations
 
 
 
#if defined (_MSC_VER)
 
 
 
#  undef    TB_CDECL
 
#  define   TB_CDECL    __cdecl
 
#  define   TB_FASTCALL /* __fastcall */
 
#  if _MSC_VER >= 1200
 
#    define INLINE      __forceinline
 
#  endif
 
 
 
#else
 
 
 
#  define   TB_CDECL
 
#  define   TB_FASTCALL
 
 
 
#endif
 
 
 
#if !defined (INLINE)
 
#  define   INLINE  inline
 
#endif
 
 
 
// Printf formats
 
 
 
#if defined (T_INDEX64) && defined (_MSC_VER)
 
#   define HEX_INDEX_FORMAT "%016I64X"
 
#   define DEC_INDEX_FORMAT "%I64u"
 
#elif defined (T_INDEX64)
 
#   define HEX_INDEX_FORMAT "%016llX"
 
#   define DEC_INDEX_FORMAT "%llu"
 
#else
 
#   define HEX_INDEX_FORMAT "%08X"
 
#   define DEC_INDEX_FORMAT "%lu"
 
#endif
 
 
 
// Directory delimiter
 
 
 
#if defined (_WIN32) || defined(_WIN64)
 
#   define DELIMITER   "\\"
 
#elif defined (__MWERKS__)
 
#   define DELIMITER   ":"
 
#else
 
#   define DELIMITER   "/"
 
#endif
 
 
 
 
 
// Some constants from SJE program
 
 
 
#define pageL 256
 
 
 
/* tablebase byte entry semispan length */
 
 
 
#define tbbe_ssL ((pageL - 4) / 2)
 
 
 
/* tablebase signed byte entry values */
 
 
 
#define bev_broken  (tbbe_ssL + 1)  /* illegal or busted */
 
 
 
#define bev_mi1     tbbe_ssL        /* mate in 1 move */
 
#define bev_mimin   1               /* mate in 126 moves */
 
 
 
#define bev_draw    0               /* draw */
 
 
 
#define bev_limax   (-1)            /* mated in 125 moves */
 
#define bev_li0     (-tbbe_ssL)     /* mated in 0 moves */
 
 
 
#define bev_limaxx  (-tbbe_ssL - 1) /* mated in 126 moves */
 
#define bev_miminx  (-tbbe_ssL - 2) /* mate in 127 moves */
 
 
 
// Some constants for 16-bit tables
 
 
 
#define L_pageL 65536
 
 
 
/* tablebase short entry semispan length */
 
 
 
#define L_tbbe_ssL ((L_pageL - 4) / 2)
 
 
 
/* tablebase signed short entry values */
 
 
 
#define L_bev_broken  (L_tbbe_ssL + 1)      /* illegal or busted */
 
 
 
#define L_bev_mi1     L_tbbe_ssL            /* mate in 1 move */
 
#define L_bev_mimin   1                     /* mate in 32766 moves */
 
 
 
#define L_bev_draw    0                     /* draw */
 
 
 
#define L_bev_limax   (-1)                  /* mated in 32765 moves */
 
#define L_bev_li0     (-L_tbbe_ssL)         /* mated in 0 moves */
 
 
 
#define L_bev_limaxx    (-L_tbbe_ssL - 1)   /* mated in 32766 moves */
 
#define L_bev_miminx    (-L_tbbe_ssL - 2)   /* mate in 32767 moves */
 
 
 
// Convertion from 8-bit to 16-bit score
 
// UNDONE: Maybe implement via lookup table?
 
 
 
#define S_to_L(tbt)\
 
    (\
 
     (0 == tbt) ? 0:\
 
     (tbt > 0) ? (bev_broken != tbt ? tbt + 32640 : L_bev_broken):\
 
     (tbt >= bev_li0) ? tbt - 32640:\
 
     (bev_limaxx == tbt) ? -32640:\
 
     /*bev_miminx == tbt*/  32640\
 
    )
 
 
 
// Constants
 
 
 
#define i8  ((unsigned) 8)
 
#define i14 ((unsigned) 14)
 
#define i42 ((unsigned) 42)
 
#define i43 ((unsigned) 43)
 
#define i44 ((unsigned) 44)
 
#define i45 ((unsigned) 45)
 
#define i46 ((unsigned) 46)
 
#define i47 ((unsigned) 47)
 
#define i48 ((unsigned) 48)
 
#define i57 ((unsigned) 57)
 
#define i58 ((unsigned) 58)
 
#define i59 ((unsigned) 59)
 
#define i60 ((unsigned) 60)
 
#define i61 ((unsigned) 61)
 
#define i62 ((unsigned) 62)
 
#define i63 ((unsigned) 63)
 
#define i64 ((unsigned) 64)
 
 
 
#define x_row_1 0
 
#define x_row_2 1
 
#define x_row_3 2
 
#define x_row_4 3
 
#define x_row_5 4
 
#define x_row_6 5
 
#define x_row_7 6
 
#define x_row_8 7
 
 
 
#define x_column_a 0
 
#define x_column_b 1
 
#define x_column_c 2
 
#define x_column_d 3
 
#define x_column_e 4
 
#define x_column_f 5
 
#define x_column_g 6
 
#define x_column_h 7
 
 
 
/* reflection macros */
 
 
 
#define reflect_x(sq) ((sq) ^ 0x38)
 
#define reflect_y(sq) ((sq) ^ 0x07)
 
#define reflect_xy(sq) rgsqReflectXY[sq]
 
 
 
static const square rgsqReflectXY [] =
 
{
 
  0,  8, 16, 24, 32, 40, 48, 56,
 
  1,  9, 17, 25, 33, 41, 49, 57,
 
  2, 10, 18, 26, 34, 42, 50, 58,
 
  3, 11, 19, 27, 35, 43, 51, 59,
 
  4, 12, 20, 28, 36, 44, 52, 60,
 
  5, 13, 21, 29, 37, 45, 53, 61,
 
  6, 14, 22, 30, 38, 46, 54, 62,
 
  7, 15, 23, 31, 39, 47, 55, 63,
 
};
 
 
 
static const square rgsqReflectMaskY [] =
 
{
 
 0, 0, 0, 0, 7, 7, 7, 7,
 
 0, 0, 0, 0, 7, 7, 7, 7,
 
 0, 0, 0, 0, 7, 7, 7, 7,
 
 0, 0, 0, 0, 7, 7, 7, 7,
 
 0, 0, 0, 0, 7, 7, 7, 7,
 
 0, 0, 0, 0, 7, 7, 7, 7,
 
 0, 0, 0, 0, 7, 7, 7, 7,
 
 0, 0, 0, 0, 7, 7, 7, 7,
 
};
 
 
 
static const square rgsqReflectMaskYandX [] =
 
{
 
 0, 0, 0, 0, 7, 7, 7, 7,
 
 0, 0, 0, 0, 7, 7, 7, 7,
 
 0, 0, 0, 0, 7, 7, 7, 7,
 
 0, 0, 0, 0, 7, 7, 7, 7,
 
 0x38, 0x38, 0x38, 0x38, 0x38+7, 0x38+7, 0x38+7, 0x38+7,
 
 0x38, 0x38, 0x38, 0x38, 0x38+7, 0x38+7, 0x38+7, 0x38+7,
 
 0x38, 0x38, 0x38, 0x38, 0x38+7, 0x38+7, 0x38+7, 0x38+7,
 
 0x38, 0x38, 0x38, 0x38, 0x38+7, 0x38+7, 0x38+7, 0x38+7,
 
};
 
 
 
static const square rgsqReflectInvertMask[] = { 0, 0x38 };
 
 
 
/* useful macros */
 
 
 
#define TbRow(sq)               ((sq) >> 3)
 
#define TbColumn(sq)            ((sq) & 7)
 
 
 
#if defined (NEW)
 
#  define   PchExt(side) ((x_colorWhite == side) ? ".nbw" : ".nbb")
 
#else
 
#  define   PchExt(side) ((x_colorWhite == side) ? ".tbw" : ".tbb")
 
#endif
 
 
 
// Verbose levels
 
 
 
static bool     fPrint = false;     // Print some technical statistics
 
static bool     fVerbose = false;   // Print additional information
 
 
 
// Malloc that checks for out-of-memory condition
 
 
 
static size_t   cbAllocated;
 
static int      cOpenFilesAttempts;
 
static int      cOpenFilesSuceed;
 
 
 
static void* PvMalloc
 
    (
 
    size_t cb
 
    )
 
    {
 
    void    *pv;
 
 
 
    pv = malloc (cb);
 
    if (NULL == pv)
 
        {
 
        printf ("*** Cannot allocate %d bytes of memory\n", (int) cb);
 
        exit (1);
 
        }
 
    cbAllocated += cb;
 
    return pv;
 
    }
 
 
 
#if defined (NEW)   // New index schema ----------------------------------------
 
 
 
// 'Invalid' value have to be large, so index
 
// of invalid position will be very large, too.
 
 
 
#define INF 4000
 
 
 
// Enumeration: valid positions with 2 kings on board; white king restricted to
 
// a1-d1-d4 triangle; also, if it's at a1-d4 half-diagonal, then black king
 
// must be in a1-h1-h8 triangle// Enumeration: all valid positions with 2 kings on board when white king
 
// restricted to left half of the board// Useful macro and enumeration tables
 
 
 
#define IndTriKings(sqk1,sqk2)  ((unsigned) rgsTriKings[sqk1*64+sqk2])
 
#define IndHalfKings(sqk1,sqk2) ((unsigned) rgsHalfKings[sqk1*64+sqk2])
 
 
 
static const bool rgfTriangle[64] =
 
{
 
     true,  true,  true,  true,  false, false, false, false,
 
     false, true,  true,  true,  false, false, false, false,
 
     false, false, true,  true,  false, false, false, false,
 
     false, false, false, true,  false, false, false, false,
 
     false, false, false, false, false, false, false, false,
 
     false, false, false, false, false, false, false, false,
 
     false, false, false, false, false, false, false, false,
 
     false, false, false, false, false, false, false, false,
 
};
 
 
 
static const bool rgfNotDiagonal[64] =
 
{
 
     false, true,  true,  true,  true,  true,  true,  true,
 
     true,  false, true,  true,  true,  true,  true,  true,
 
     true,  true,  false, true,  true,  true,  true,  true,
 
     true,  true,  true,  false, true,  true,  true,  true,
 
     true,  true,  true,  true,  false, true,  true,  true,
 
     true,  true,  true,  true,  true,  false, true,  true,
 
     true,  true,  true,  true,  true,  true,  false, true,
 
     true,  true,  true,  true,  true,  true,  true,  false,
 
};
 
 
 
static const bool rgfInLargeTriangle[64] =
 
{
 
     true,  true,  true,  true,  true,  true,  true,  true,
 
     false, true,  true,  true,  true,  true,  true,  true,
 
     false, false, true,  true,  true,  true,  true,  true,
 
     false, false, false, true,  true,  true,  true,  true,
 
     false, false, false, false, true,  true,  true,  true,
 
     false, false, false, false, false, true,  true,  true,
 
     false, false, false, false, false, false, true,  true,
 
     false, false, false, false, false, false, false, true,
 
};
 
 
 
#define FInTriangle(sqwk,sqbk)  (rgfTriangle[sqwk] & (rgfNotDiagonal[sqwk]|rgfInLargeTriangle[sqbk]))
 
 
 
// Sort pieces
 
 
 
#define SORT(sq1,sq2)   if (sq1>sq2) { square sqTmp; sqTmp=sq1; sq1=sq2; sq2=sqTmp; }
 
 
 
// Exclude occupied squares
 
 
 
#define EXCLUDE1(sq,sq1)                         (sq-(sq>sq1))
 
#define EXCLUDE2(sq,sq1,sq2)                     (sq-((sq>sq1)+(sq>sq2)))
 
#define EXCLUDE3(sq,sq1,sq2,sq3)                 (sq-((sq>sq1)+(sq>sq2)+(sq>sq3)))
 
#define EXCLUDE4(sq,sq1,sq2,sq3,sq4)             (sq-((sq>sq1)+(sq>sq2)+(sq>sq3)+(sq>sq4)))
 
#define EXCLUDE5(sq,sq1,sq2,sq3,sq4,sq5)         (sq-((sq>sq1)+(sq>sq2)+(sq>sq3)+(sq>sq4)+(sq>sq5)))
 
#define EXCLUDE6(sq,sq1,sq2,sq3,sq4,sq5,sq6)     (sq-((sq>sq1)+(sq>sq2)+(sq>sq3)+(sq>sq4)+(sq>sq5)+(sq>sq6)))
 
#define EXCLUDE7(sq,sq1,sq2,sq3,sq4,sq5,sq6,sq7) (sq-((sq>sq1)+(sq>sq2)+(sq>sq3)+(sq>sq4)+(sq>sq5)+(sq>sq6)+(sq>sq7)))
 
 
 
#if !defined(SWAP)
 
#define SWAP(sq1, sq2)  {square sq_tmp = sq2; sq2 = sq1; sq1 = sq_tmp;}
 
#endif
 
 
 
// Calculate index - a lot of functions...
 
 
 
// Enumeration tables
 
 
 
static BYTE     *rgprgsqPiece[6];   // Enumeration for each piece (0 - black pawn)
 
                                    // For each position of the King, all legal squares
 
                                    // of the opposite piece enumerated
 
static BYTE     rgcLegal[6][64];    // # of enumerated positions for each piece and each
 
                                    // location of enemy king
 
 
 
// Enumerations - indexed by [piece] and [kings enumeration].
 
// In each table for each [piece] and [king enumeration] we store # of preceeding positions.
 
 
 
static ULONG    *rgprgulSinglePawnless[6];
 
static ULONG    *rgprgulPairPawnless[6][6];
 
#if defined (T41_INCLUDE) || defined (T42_INCLUDE)
 
  static ULONG  *rgprgulTriplePawnless[6][6][6];
 
#endif
 
static ULONG    *rgprgulSinglePawnPresent[6];
 
static ULONG    *rgprgulPairPawnPresent[6][6];
 
#if defined (T41_INCLUDE) || defined (T42_INCLUDE)
 
  static ULONG  *rgprgulTriplePawnPresent[6][6][6];
 
#endif
 
 
 
// Total # of enumerated positions
 
 
 
static ULONG    rgcSinglePawnPresent[6];
 
static ULONG    rgcSinglePawnless[6];
 
static ULONG    rgcPairPawnPresent[6][6];
 
static ULONG    rgcPairPawnless[6][6];
 
#if defined (T41_INCLUDE) || defined (T42_INCLUDE)
 
  static ULONG  rgcTriplePawnPresent[6][6][6];
 
  static ULONG  rgcTriplePawnless[6][6][6];
 
#endif
 
 
 
// Infinities. Have to be larger than any legal enumeration yet small enough
 
// so there will be no overflow when combining them with remaining pieces.
 
 
 
#define INF_SINGLE  (110000)
 
#define INF_PAIR    (6500000)
 
#define INF_TRIPLE  (500000000)
 
 
 
// Initialize squares and counters table for one piece.
 
// Piece can be x_pieceNone - that means 'pawn of the wrong color', e.g. KPK BTM.
 
 
 
static void VInitSquaresTable
 
    (
 
    piece   pi,
 
    BYTE    *prgsqPiece,
 
    BYTE    *prgcLegal
 
    )
 
    {
 
    int sqLo, sqHi;
 
 
 
    memset (prgsqPiece, -1, 64*64);
 
    sqLo = 0;
 
    sqHi = 64;
 
    if (pi <= x_piecePawn)
 
        {
 
        sqLo = 8;
 
        sqHi = 56;
 
        }
 
    for (int sqKing = 0; sqKing < 64; sqKing ++)
 
        {
 
        int iPiece;
 
 
 
        iPiece = 0;
 
        for (int sq = sqLo; sq < sqHi; sq ++)
 
            {
 
            if (sq == sqKing)
 
                continue;
 
            switch (pi)
 
                {
 
            case x_piecePawn:
 
                if (
 
                    0 != TbColumn (sq) && sqKing == sq+7 ||
 
                    7 != TbColumn (sq) && sqKing == sq+9
 
                   )
 
                   continue;
 
                break;
 
            case x_pieceKnight:
 
                if (
 
                    TbRow (sq) >= 2 && TbColumn (sq) >= 1 && sqKing == sq-17 ||
 
                    TbRow (sq) >= 2 && TbColumn (sq) <= 6 && sqKing == sq-15 ||
 
                    TbRow (sq) >= 1 && TbColumn (sq) >= 2 && sqKing == sq-10 ||
 
                    TbRow (sq) >= 1 && TbColumn (sq) <= 5 && sqKing == sq-6 ||
 
                    TbRow (sq) <= 6 && TbColumn (sq) >= 2 && sqKing == sq+6 ||
 
                    TbRow (sq) <= 6 && TbColumn (sq) <= 5 && sqKing == sq+10 ||
 
                    TbRow (sq) <= 5 && TbColumn (sq) >= 1 && sqKing == sq+15 ||
 
                    TbRow (sq) <= 5 && TbColumn (sq) <= 6 && sqKing == sq+17
 
                   )
 
                    continue;
 
                break;
 
            case x_pieceBishop:
 
                if (
 
                    0 != TbRow (sq) && 0 != TbColumn (sq) && sqKing == sq-9 ||
 
                    0 != TbRow (sq) && 7 != TbColumn (sq) && sqKing == sq-7 ||
 
                    7 != TbRow (sq) && 0 != TbColumn (sq) && sqKing == sq+7 ||
 
                    7 != TbRow (sq) && 7 != TbColumn (sq) && sqKing == sq+9
 
                   )
 
                    continue;
 
                break;
 
            case x_pieceRook:
 
                if (
 
                    0 != TbColumn (sq) && sqKing == sq-1 ||
 
                    7 != TbColumn (sq) && sqKing == sq+1 ||
 
                    0 != TbRow (sq) && sqKing == sq-8 ||
 
                    7 != TbRow (sq) && sqKing == sq+8
 
                   )
 
                    continue;
 
                break;
 
            case x_pieceQueen:
 
                if (
 
                    0 != TbColumn (sq) && sqKing == sq-1 ||
 
                    7 != TbColumn (sq) && sqKing == sq+1 ||
 
                    0 != TbRow (sq) && sqKing == sq-8 ||
 
                    7 != TbRow (sq) && sqKing == sq+8 ||
 
                    0 != TbRow (sq) && 0 != TbColumn (sq) && sqKing == sq-9 ||
 
                    0 != TbRow (sq) && 7 != TbColumn (sq) && sqKing == sq-7 ||
 
                    7 != TbRow (sq) && 0 != TbColumn (sq) && sqKing == sq+7 ||
 
                    7 != TbRow (sq) && 7 != TbColumn (sq) && sqKing == sq+9
 
                   )
 
                    continue;
 
                break;
 
                }
 
            prgsqPiece[sqKing*64+sq] = (BYTE) iPiece;
 
            iPiece ++;
 
            }
 
        prgcLegal[sqKing] = (BYTE) iPiece;
 
        }
 
    }
 
 
 
// Initialize enumeration table for single piece
 
 
 
static void VInitSingle
 
    (
 
    ULONG       *prgIndex,
 
    const short *prgsKings,
 
    const BYTE  *prgcLegal,
 
    const BYTE  *prgsqPiece,
 
    ULONG       *pcEnumeration
 
    )
 
    {
 
    ULONG iIndex;
 
 
 
    iIndex = 0;
 
    for (int sqKing1 = 0; sqKing1 < 64; sqKing1 ++)
 
        for (int sqKing2 = 0; sqKing2 < 64; sqKing2 ++)
 
            {
 
            if (INF != prgsKings[sqKing1*64+sqKing2])
 
                {
 
                prgIndex[prgsKings[sqKing1*64+sqKing2]] = iIndex;
 
                iIndex += prgcLegal[sqKing2] - ((BYTE) -1 != prgsqPiece[sqKing2*64+sqKing1]);
 
                }
 
            }
 
    *pcEnumeration = iIndex;
 
    }
 
 
 
// Initialize enumeration table for pair of pieces
 
 
 
static void VInitPair
 
    (
 
    ULONG       *prgIndex,
 
    const short *prgsKings,
 
    const BYTE  *prgcLegal1,
 
    const BYTE  *prgsqPiece1,
 
    const BYTE  *prgcLegal2,
 
    const BYTE  *prgsqPiece2,
 
    ULONG       *pcEnumeration
 
    )
 
    {
 
    ULONG iIndex;
 
    ULONG cPositions1, cPositions2;
 
 
 
    iIndex = 0;
 
    for (int sqKing1 = 0; sqKing1 < 64; sqKing1 ++)
 
        for (int sqKing2 = 0; sqKing2 < 64; sqKing2 ++)
 
            {
 
            if (INF != prgsKings[sqKing1*64+sqKing2])
 
                {
 
                prgIndex[prgsKings[sqKing1*64+sqKing2]] = iIndex;
 
                cPositions1 = prgcLegal1[sqKing2] - ((BYTE) -1 != prgsqPiece1[sqKing2*64+sqKing1]);
 
                if (prgcLegal1 == prgcLegal2)
 
                    iIndex += cPositions1*(cPositions1-1)/2;
 
                else
 
                    {
 
                    cPositions2 = prgcLegal2[sqKing2] - ((BYTE) -1 != prgsqPiece2[sqKing2*64+sqKing1]);
 
                    iIndex += cPositions1*cPositions2;
 
                    }
 
                }
 
            }
 
    *pcEnumeration = iIndex;
 
    }
 
 
 
#if defined (T41_INCLUDE) || defined (T42_INCLUDE)
 
 
 
// Initialize enumeration table for triple piece
 
 
 
static void VInitTriple
 
    (
 
    ULONG       *prgIndex,
 
    const short *prgsKings,
 
    const BYTE  *prgcLegal1,
 
    const BYTE  *prgsqPiece1,
 
    const BYTE  *prgcLegal2,
 
    const BYTE  *prgsqPiece2,
 
    const BYTE  *prgcLegal3,
 
    const BYTE  *prgsqPiece3,
 
    ULONG       *pcEnumeration
 
    )
 
    {
 
    ULONG iIndex;
 
    ULONG cPositions1, cPositions2, cPositions3;
 
 
 
    iIndex = 0;
 
    for (int sqKing1 = 0; sqKing1 < 64; sqKing1 ++)
 
        for (int sqKing2 = 0; sqKing2 < 64; sqKing2 ++)
 
            {
 
            if (INF != prgsKings[sqKing1*64+sqKing2])
 
                {
 
                prgIndex[prgsKings[sqKing1*64+sqKing2]] = iIndex;
 
                cPositions1 = prgcLegal1[sqKing2] - ((BYTE) -1 != prgsqPiece1[sqKing2*64+sqKing1]);
 
                if (prgcLegal1 == prgcLegal2 && prgcLegal2 == prgcLegal3)
 
                    iIndex += cPositions1*(cPositions1-1)*(cPositions1-2)/6;
 
                else if (prgcLegal1 == prgcLegal2)
 
                    {
 
                    cPositions3 = prgcLegal3[sqKing2] - ((BYTE) -1 != prgsqPiece3[sqKing2*64+sqKing1]);
 
                    iIndex += cPositions1*(cPositions1-1)/2*cPositions3;
 
                    }
 
                else if (prgcLegal2 == prgcLegal3)
 
                    {
 
                    cPositions2 = prgcLegal2[sqKing2] - ((BYTE) -1 != prgsqPiece2[sqKing2*64+sqKing1]);
 
                    iIndex += cPositions1*cPositions2*(cPositions2-1)/2;
 
                    }
 
                else
 
                    {
 
                    cPositions2 = prgcLegal2[sqKing2] - ((BYTE) -1 != prgsqPiece2[sqKing2*64+sqKing1]);
 
                    cPositions3 = prgcLegal3[sqKing2] - ((BYTE) -1 != prgsqPiece3[sqKing2*64+sqKing1]);
 
                    iIndex += cPositions1*cPositions2*cPositions3;
 
                    }
 
                }
 
            }
 
    *pcEnumeration = iIndex;
 
    }
 
 
 
#endif
 
 
 
// Initialize all Enumeration tables
 
 
 
static bool fEnumerationInitted = false;
 
 
 
static void VInitEnumerations (void)
 
    {
 
    piece   pi1;
 
    piece   pi2;
 
#if defined (T41_INCLUDE) || defined (T42_INCLUDE)
 
    piece   pi3;
 
#endif
 
 
 
    if (fEnumerationInitted)
 
        return;
 
    fEnumerationInitted = true;
 
    // Initialize square tables
 
    for (pi1 = x_pieceNone; pi1 <= x_pieceQueen; pi1 = (piece) (pi1 + 1))
 
        {
 
        rgprgsqPiece[pi1] = (BYTE *) PvMalloc (64*64);
 
        VInitSquaresTable (pi1, rgprgsqPiece[pi1], rgcLegal[pi1]);
 
        }
 
 
 
    for (pi1 = x_pieceNone; pi1 <= x_pieceQueen; pi1 = (piece) (pi1 + 1))
 
        {
 
        // Initialize enumeration tables for single piece
 
        rgprgulSinglePawnPresent[pi1] = (ULONG *) PvMalloc (1806*sizeof (ULONG));
 
        VInitSingle (rgprgulSinglePawnPresent[pi1], rgsHalfKings,
 
                     rgcLegal[pi1], rgprgsqPiece[pi1], &rgcSinglePawnPresent[pi1]);
 
        if (pi1 > x_piecePawn)
 
            {
 
            rgprgulSinglePawnless[pi1] = (ULONG *) PvMalloc (462*sizeof (ULONG));
 
            VInitSingle (rgprgulSinglePawnless[pi1], rgsTriKings,
 
                         rgcLegal[pi1], rgprgsqPiece[pi1], &rgcSinglePawnless[pi1]);
 
            }
 
        // Initialize enumeration tables for pair of pieces
 
        for (pi2 = (x_pieceNone == pi1 ? x_pieceNone : x_piecePawn); pi2 <= pi1; pi2 = (piece) (pi2 + 1))
 
            {
 
            rgprgulPairPawnPresent[pi1][pi2] = (ULONG *) PvMalloc (1806*sizeof (ULONG));
 
            VInitPair (rgprgulPairPawnPresent[pi1][pi2], rgsHalfKings,
 
                       rgcLegal[pi1], rgprgsqPiece[pi1], rgcLegal[pi2], rgprgsqPiece[pi2],
 
                       &rgcPairPawnPresent[pi1][pi2]);
 
            if (pi1 > x_piecePawn && pi2 > x_piecePawn)
 
                {
 
                rgprgulPairPawnless[pi1][pi2] = (ULONG *) PvMalloc (462*sizeof (ULONG));
 
                VInitPair (rgprgulPairPawnless[pi1][pi2], rgsTriKings,
 
                           rgcLegal[pi1], rgprgsqPiece[pi1], rgcLegal[pi2], rgprgsqPiece[pi2],
 
                           &rgcPairPawnless[pi1][pi2]);
 
                }
 
#if defined (T41_INCLUDE) || defined (T42_INCLUDE)
 
            // Initialize enumeration tables for three pieces
 
            for (pi3 = (x_pieceNone == pi1 ? x_pieceNone : x_piecePawn); pi3 <= pi2; pi3 = (piece) (pi3 + 1))
 
                {
 
                if (pi1 <= x_piecePawn || pi2 <= x_piecePawn || pi3 <= x_piecePawn)
 
                    {
 
                    rgprgulTriplePawnPresent[pi1][pi2][pi3] = (ULONG *) PvMalloc (1806*sizeof (ULONG));
 
                    VInitTriple (rgprgulTriplePawnPresent[pi1][pi2][pi3], rgsHalfKings,
 
                                 rgcLegal[pi1], rgprgsqPiece[pi1],
 
                                 rgcLegal[pi2], rgprgsqPiece[pi2],
 
                                 rgcLegal[pi3], rgprgsqPiece[pi3],
 
                                 &rgcTriplePawnPresent[pi1][pi2][pi3]);
 
                    }
 
                else
 
                    {
 
                    rgprgulTriplePawnless[pi1][pi2][pi3] = (ULONG *) PvMalloc (462*sizeof (ULONG));
 
                    VInitTriple (rgprgulTriplePawnless[pi1][pi2][pi3], rgsTriKings,
 
                        rgcLegal[pi1], rgprgsqPiece[pi1],
 
                        rgcLegal[pi2], rgprgsqPiece[pi2],
 
                        rgcLegal[pi3], rgprgsqPiece[pi3],
 
                        &rgcTriplePawnless[pi1][pi2][pi3]);
 
#if defined (T42_INCLUDE)
 
                    rgprgulTriplePawnPresent[pi1][pi2][pi3] = (ULONG *) PvMalloc (1806*sizeof (ULONG));
 
                    VInitTriple (rgprgulTriplePawnPresent[pi1][pi2][pi3], rgsHalfKings,
 
                                 rgcLegal[pi1], rgprgsqPiece[pi1],
 
                                 rgcLegal[pi2], rgprgsqPiece[pi2],
 
                                 rgcLegal[pi3], rgprgsqPiece[pi3],
 
                                 &rgcTriplePawnPresent[pi1][pi2][pi3]);
 
#endif
 
                    }
 
                }
 
#endif
 
            }
 
        }
 
 
 
    // All done!
 
    if (fPrint)
 
        {
 
        for (pi1 = x_pieceNone; pi1 <= x_pieceQueen; pi1 = (piece) (pi1 + 1))
 
            printf ("%c - %d enumerated positions\n", "pPNBRQ"[pi1], (int) rgcSinglePawnPresent[pi1]);
 
        for (pi1 = x_pieceNone; pi1 <= x_pieceQueen; pi1 = (piece) (pi1 + 1))
 
            {
 
            if (0 != rgcSinglePawnless[pi1])
 
                printf ("pawnless %c - %d enumerated positions\n", "pPNBRQ"[pi1], (int) rgcSinglePawnless[pi1]);
 
            }
 
        for (pi1 = x_pieceNone; pi1 <= x_pieceQueen; pi1 = (piece) (pi1 + 1))
 
            for (pi2 = x_pieceNone; pi2 <= pi1; pi2 = (piece) (pi2 + 1))
 
                {
 
                if (0 != rgcPairPawnPresent[pi1][pi2])
 
                    printf ("%c%c - %d enumerated positions\n", "pPNBRQ"[pi1], "pPNBRQ"[pi2],
 
                            (int) rgcPairPawnPresent[pi1][pi2]);
 
                }
 
        for (pi1 = x_pieceNone; pi1 <= x_pieceQueen; pi1 = (piece) (pi1 + 1))
 
            for (pi2 = x_pieceNone; pi2 <= pi1; pi2 = (piece) (pi2 + 1))
 
                {
 
                if (0 != rgcPairPawnless[pi1][pi2])
 
                    printf ("pawnless %c%c - %d enumerated positions\n", "pPNBRQ"[pi1], "pPNBRQ"[pi2],
 
                            (int) rgcPairPawnless[pi1][pi2]);
 
                }
 
#if defined (T41_INCLUDE) || defined (T42_INCLUDE)
 
        for (pi1 = x_pieceNone; pi1 <= x_pieceQueen; pi1 = (piece) (pi1 + 1))
 
            for (pi2 = x_pieceNone; pi2 <= pi1; pi2 = (piece) (pi2 + 1))
 
                for (pi3 = x_pieceNone; pi3 <= pi2; pi3 = (piece) (pi3 + 1))
 
                    {
 
                    if (0 != rgcTriplePawnPresent[pi1][pi2][pi3])
 
                        printf ("%c%c%c - %d enumerated positions\n",
 
                                "pPNBRQ"[pi1], "pPNBRQ"[pi2], "pPNBRQ"[pi3],
 
                                (int) rgcTriplePawnPresent[pi1][pi2][pi3]);
 
                    }
 
        for (pi1 = x_pieceNone; pi1 <= x_pieceQueen; pi1 = (piece) (pi1 + 1))
 
            for (pi2 = x_pieceNone; pi2 <= pi1; pi2 = (piece) (pi2 + 1))
 
                for (pi3 = x_pieceNone; pi3 <= pi2; pi3 = (piece) (pi3 + 1))
 
                    {
 
                    if (0 != rgcTriplePawnless[pi1][pi2][pi3])
 
                        printf ("pawnless %c%c%c - %d enumerated positions\n",
 
                                "pPNBRQ"[pi1], "pPNBRQ"[pi2], "pPNBRQ"[pi3],
 
                                (int) rgcTriplePawnless[pi1][pi2][pi3]);
 
                    }
 
#endif
 
        printf ("\nAllocated %dk\n\n", (int) ((cbAllocated + 1023)/1024));
 
        }
 
    }
 
 
 
// Return enumeration of 2 kings and single piece
 
 
 
template <int piw1, bool fPawns, bool fInvert> class TEnumerate1
 
    {
 
public:
 
    static INLINE unsigned TB_FASTCALL Index
 
        (
 
        square  sqwk,
 
        square  sqw1,
 
        square  sqbk
 
        )
 
        {
 
        unsigned ind;
 
        ULONG    ulKings;
 
 
 
        // For black pawn invert the board
 
        if (piw1 <= x_piecePawn && fInvert)
 
            {
 
            sqwk = reflect_x(sqwk);
 
            sqw1 = reflect_x(sqw1);
 
            sqbk = reflect_x(sqbk);
 
            }
 
        
 
        // Get enumerated square
 
        ind = rgprgsqPiece[piw1][sqbk*64+sqw1];
 
#if defined (ILLEGAL_POSSIBLE)
 
        if ((BYTE) -1 == ind)
 
            return INF_SINGLE;
 
#endif
 
        // Get enumerated position of both kings
 
        if (fPawns)
 
            ulKings = rgsHalfKings[sqwk*64+sqbk];   // 0..1805
 
        else
 
            ulKings = rgsTriKings[sqwk*64+sqbk];    // 0..461
 
#if defined (ILLEGAL_POSSIBLE)
 
        if (INF == ulKings)
 
            return INF_SINGLE;
 
#endif
 
        // Can we remove one extra square?
 
        if ((piw1>x_pieceKnight) || ((BYTE)-1 != rgprgsqPiece[piw1][sqbk*64+sqwk]))
 
            ind -= (sqw1 > sqwk);
 
        // Add enumerated square to the # of the preceeding positions
 
        return ind + (fPawns ? rgprgulSinglePawnPresent[piw1][ulKings] : rgprgulSinglePawnless[piw1][ulKings]);
 
        }
 
    };
 
 
 
// Return enumeration of 2 kings and 2 pieces
 
 
 
template <int piw1, int piw2, bool fPawns, bool fInvert> class TEnumerate2
 
    {
 
public:
 
    static INLINE unsigned TB_FASTCALL Index
 
        (
 
        square  sqwk,
 
        square  sqw1,
 
        square  sqw2,
 
        square  sqbk
 
        )
 
        {
 
        unsigned ind1, ind2, cInd2;
 
        ULONG    ulKings;
 
 
 
        // For black pawn invert the board
 
        if (piw2 <= x_piecePawn && fInvert)
 
            {
 
            sqwk = reflect_x(sqwk);
 
            sqw1 = reflect_x(sqw1);
 
            sqw2 = reflect_x(sqw2);
 
            sqbk = reflect_x(sqbk);
 
            }
 
        
 
        // Get enumerated squares for both pieces
 
        if (piw1 == piw2)
 
            SORT (sqw1, sqw2);
 
        ind1 = rgprgsqPiece[piw1][sqbk*64+sqw1];
 
        ind2 = rgprgsqPiece[piw2][sqbk*64+sqw2];
 
#if defined (ILLEGAL_POSSIBLE)
 
        if ((BYTE) -1 == ind1 || (BYTE) -1 == ind2)
 
            return INF_PAIR;
 
#endif
 
        // Get enumerated position of both kings
 
        if (fPawns)
 
            ulKings = rgsHalfKings[sqwk*64+sqbk];   // 0..1805
 
        else
 
            ulKings = rgsTriKings[sqwk*64+sqbk];    // 0..461
 
#if defined (ILLEGAL_POSSIBLE)
 
        if (INF == ulKings)
 
            return INF_PAIR;
 
#endif
 
        if (piw1 == piw2)
 
            {
 
            // Can we remove one extra square?
 
            if ((piw1>x_pieceKnight) || ((BYTE)-1 != rgprgsqPiece[piw1][sqbk*64+sqwk]))
 
                {
 
                ind1 -= (sqw1 > sqwk);
 
                ind2 -= (sqw2 > sqwk);
 
                }
 
            // Add enumerated squares to the # of the preceeding positions
 
            return  ind2*(ind2-1)/2 + ind1 +
 
                    (fPawns ? rgprgulPairPawnPresent[piw1][piw2][ulKings] : rgprgulPairPawnless[piw1][piw2][ulKings]);
 
            }
 
        else
 
            {
 
            // Can we remove WK square from 1st piece Enumeration?
 
            if ((piw1>x_pieceKnight) || ((BYTE)-1 != rgprgsqPiece[piw1][sqbk*64+sqwk]))
 
                ind1 -= (sqw1 > sqwk);
 
            // Get # of enumerated positions of 2nd piece
 
            cInd2 = rgcLegal[piw2][sqbk];
 
            // Can we remove WK square from 2nd piece Enumeration?
 
            if ((piw2>x_pieceKnight) || ((BYTE)-1 != rgprgsqPiece[piw2][sqbk*64+sqwk]))
 
                {
 
                cInd2 --;
 
                ind2 -= (sqw2 > sqwk);
 
                }
 
            // Add enumerated square to the # of the preceeding positions
 
            return cInd2*ind1 + ind2 + (fPawns ? rgprgulPairPawnPresent[piw1][piw2][ulKings] : rgprgulPairPawnless[piw1][piw2][ulKings]);
 
            }
 
        }
 
    };
 
 
 
#if defined (T41_INCLUDE) || defined (T42_INCLUDE)
 
 
 
// Return enumeration of 2 kings and 3 pieces
 
 
 
template <int piw1, int piw2, int piw3, bool fPawns, bool fInvert> class TEnumerate3
 
    {
 
public:
 
    static INLINE unsigned TB_FASTCALL Index
 
        (
 
        square  sqwk,
 
        square  sqw1,
 
        square  sqw2,
 
        square  sqw3,
 
        square  sqbk
 
        )
 
        {
 
        unsigned ind1, ind2, ind3, cInd1, cInd2, cInd3;
 
        ULONG    ulKings;
 
 
 
        // For black pawn invert the board
 
        if (piw3 <= x_piecePawn && fInvert)
 
            {
 
            sqwk = reflect_x(sqwk);
 
            sqw1 = reflect_x(sqw1);
 
            sqw2 = reflect_x(sqw2);
 
            sqw3 = reflect_x(sqw3);
 
            sqbk = reflect_x(sqbk);
 
            }
 
        
 
        // Get enumerated squares for all pieces
 
        if (piw1 == piw2 && piw1 == piw3)
 
            {
 
            SORT (sqw1, sqw2);
 
            SORT (sqw2, sqw3);
 
            SORT (sqw1, sqw2);
 
            }
 
        else if (piw1 == piw2)
 
            {
 
            SORT (sqw1, sqw2);
 
            }
 
        else if (piw2 == piw3)
 
            {
 
            SORT (sqw2, sqw3);
 
            }
 
        ind1 = rgprgsqPiece[piw1][sqbk*64+sqw1];
 
        ind2 = rgprgsqPiece[piw2][sqbk*64+sqw2];
 
        ind3 = rgprgsqPiece[piw3][sqbk*64+sqw3];
 
#if defined (ILLEGAL_POSSIBLE)
 
        if ((BYTE) -1 == ind1 || (BYTE) -1 == ind2 || (BYTE) -1 == ind3)
 
            return INF_TRIPLE;
 
#endif
 
        // Get enumerated position of both kings
 
        if (fPawns)
 
            ulKings = rgsHalfKings[sqwk*64+sqbk];   // 0..1805
 
        else
 
            ulKings = rgsTriKings[sqwk*64+sqbk];    // 0..461
 
#if defined (ILLEGAL_POSSIBLE)
 
        if (INF == ulKings)
 
            return INF_TRIPLE;
 
#endif
 
        if (piw1 == piw2 && piw2 == piw3)
 
            {
 
            // Can we remove one extra square?
 
            if ((piw1>x_pieceKnight) || ((BYTE)-1 != rgprgsqPiece[piw1][sqbk*64+sqwk]))
 
                {
 
                ind1 -= (sqw1 > sqwk);
 
                ind2 -= (sqw2 > sqwk);
 
                ind3 -= (sqw3 > sqwk);
 
                }
 
            // Add enumerated squares to the # of the preceeding positions
 
            return  ind3*(ind3-1)*(ind3-2)/6 + ind2*(ind2-1)/2 + ind1 +
 
                    (fPawns ? rgprgulTriplePawnPresent[piw1][piw2][piw3][ulKings] :
 
                              rgprgulTriplePawnless[piw1][piw2][piw3][ulKings]);
 
            }
 
        else if (piw1 == piw2)
 
            {
 
            // Can we remove one extra square?
 
            if ((piw1>x_pieceKnight) || ((BYTE)-1 != rgprgsqPiece[piw1][sqbk*64+sqwk]))
 
                {
 
                ind1 -= (sqw1 > sqwk);
 
                ind2 -= (sqw2 > sqwk);
 
                }
 
            // Get # of enumerated positions of 3rd piece
 
            cInd3 = rgcLegal[piw3][sqbk];
 
            // Can we remove WK square from 3rd piece Enumeration?
 
            if ((piw3>x_pieceKnight) || ((BYTE)-1 != rgprgsqPiece[piw3][sqbk*64+sqwk]))
 
                {
 
                cInd3 --;
 
                ind3 -= (sqw3 > sqwk);
 
                }
 
            // Add enumerated squares to the # of the preceeding positions
 
            return  (ind2*(ind2-1)/2 + ind1)*cInd3 + ind3 +
 
                    (fPawns ? rgprgulTriplePawnPresent[piw1][piw2][piw3][ulKings] :
 
                              rgprgulTriplePawnless[piw1][piw2][piw3][ulKings]);
 
            }
 
        else if (piw2 == piw3)
 
            {
 
            // Can we remove one extra square?
 
            if ((piw2>x_pieceKnight) || ((BYTE)-1 != rgprgsqPiece[piw2][sqbk*64+sqwk]))
 
                {
 
                ind2 -= (sqw2 > sqwk);
 
                ind3 -= (sqw3 > sqwk);
 
                }
 
            // Get # of enumerated positions of 1st piece
 
            cInd1 = rgcLegal[piw1][sqbk];
 
            // Can we remove WK square from 3rd piece Enumeration?
 
            if ((piw1>x_pieceKnight) || ((BYTE)-1 != rgprgsqPiece[piw1][sqbk*64+sqwk]))
 
                {
 
                cInd1 --;
 
                ind1 -= (sqw1 > sqwk);
 
                }
 
            // Add enumerated squares to the # of the preceeding positions
 
            return  (ind3*(ind3-1)/2 + ind2)*cInd1 + ind1 +
 
                    (fPawns ? rgprgulTriplePawnPresent[piw1][piw2][piw3][ulKings] :
 
                              rgprgulTriplePawnless[piw1][piw2][piw3][ulKings]);
 
            }
 
        else
 
            {
 
            // Can we remove WK square from 1st piece Enumeration?
 
            if ((piw1>x_pieceKnight) || ((BYTE)-1 != rgprgsqPiece[piw1][sqbk*64+sqwk]))
 
                ind1 -= (sqw1 > sqwk);
 
            // Get # of enumerated positions of 2nd piece
 
            cInd2 = rgcLegal[piw2][sqbk];
 
            // Can we remove WK square from 2nd piece Enumeration?
 
            if ((piw2>x_pieceKnight) || ((BYTE)-1 != rgprgsqPiece[piw2][sqbk*64+sqwk]))
 
                {
 
                cInd2 --;
 
                ind2 -= (sqw2 > sqwk);
 
                }
 
            // Get # of enumerated positions of 3rd piece
 
            cInd3 = rgcLegal[piw3][sqbk];
 
            // Can we remove WK square from 3rd piece Enumeration?
 
            if ((piw3>x_pieceKnight) || ((BYTE)-1 != rgprgsqPiece[piw3][sqbk*64+sqwk]))
 
                {
 
                cInd3 --;
 
                ind3 -= (sqw3 > sqwk);
 
                }
 
            // Add enumerated square to the # of the preceeding positions
 
            return  cInd3*(cInd2*ind1 + ind2) + ind3 +
 
                    (fPawns ? rgprgulTriplePawnPresent[piw1][piw2][piw3][ulKings] :
 
                              rgprgulTriplePawnless[piw1][piw2][piw3][ulKings]);
 
            }
 
        }
 
    };
 
 
 
#endif
 
 
 
// Enumerate en passant captures
 
 
 
static INLINE unsigned TB_FASTCALL IndEnPassant11W
 
    (
 
    square  sqw,
 
    square  sqb,
 
    square  sqEnP
 
    )
 
    {
 
    assert (sqb+8 == sqEnP);
 
    if (sqw+7 == sqEnP)
 
        // Capture to the left
 
        return  (sqw&7)-1;
 
    else
 
        {
 
        // Capture to the right
 
        assert (sqw+9 == sqEnP);
 
        return  (sqw&7)+7;
 
        }
 
    }
 
 
 
static INLINE unsigned TB_FASTCALL IndEnPassant11B
 
    (
 
    square  sqw,
 
    square  sqb,
 
    square  sqEnP
 
    )
 
    {
 
    assert (sqw-8 == sqEnP);
 
    if (sqb-9 == sqEnP)
 
        // Capture to the left
 
        return (sqb&7)-1;
 
    else
 
        {
 
        // Capture to the right
 
        assert (sqb-7 == sqEnP);
 
        return (sqb&7)+7;
 
        }
 
    }
 
 
 
static INLINE unsigned TB_FASTCALL IndEnPassant21W
 
    (
 
    square  sqw1,
 
    square  sqw2,
 
    square  sqb,
 
    square  sqEnP
 
    )
 
    {
 
    assert (sqb+8 == sqEnP);
 
    SORT (sqw1, sqw2);
 
    if (sqw1+7 == sqEnP && 0 != TbColumn(sqw1))
 
        // Capture to the left
 
        return (sqw1&7)-1+(EXCLUDE3(sqw2,sqb,sqEnP,sqEnP+8)-i8-1)*i14;
 
    else if (sqw1+9 == sqEnP && 7 != TbColumn(sqw1))
 
        // Capture to the right
 
        return (sqw1&7)+7+(EXCLUDE3(sqw2,sqb,sqEnP,sqEnP+8)-i8-1)*i14;
 
    else if (sqw2+7 == sqEnP && 0 != TbColumn(sqw2))
 
        // Capture to the left
 
        return (sqw2&7)-1+(EXCLUDE3(sqw1,sqb,sqEnP,sqEnP+8)-i8)*i14;
 
    else
 
        {
 
        // Capture to the right
 
        assert (sqw2+9 == sqEnP && 7 != TbColumn(sqw2));
 
        return (sqw2&7)+7+(EXCLUDE3(sqw1,sqb,sqEnP,sqEnP+8)-i8)*i14;
 
        }
 
    }
 
 
 
static INLINE unsigned TB_FASTCALL IndEnPassant21B
 
    (
 
    square  sqw1,
 
    square  sqw2,
 
    square  sqb,
 
    square  sqEnP
 
    )
 
    {
 
    assert (sqw1 < sqw2);   // Must be already sorted
 
    if (sqb-9 == sqEnP && 0 != TbColumn(sqb))
 
        // Capture to the left
 
        if (sqw1-8 == sqEnP)
 
            return (sqb&7)-1+(EXCLUDE3(sqw2,sqb,sqEnP,sqEnP-8)-i8-1)*i14;
 
        else
 
            {
 
            assert (sqw2-8 == sqEnP);
 
            return (sqb&7)-1+(EXCLUDE3(sqw1,sqb,sqEnP,sqEnP-8)-i8)*i14;
 
            }
 
    else
 
        {
 
        // Capture to the right
 
        assert (sqb-7 == sqEnP && 7 != TbColumn(sqb));
 
        if (sqw1-8 == sqEnP)
 
            return (sqb&7)+7+(EXCLUDE3(sqw2,sqb,sqEnP,sqEnP-8)-i8-1)*i14;
 
        else
 
            {
 
            assert (sqw2-8 == sqEnP);
 
            return (sqb&7)+7+(EXCLUDE3(sqw1,sqb,sqEnP,sqEnP-8)-i8)*i14;
 
            }
 
        }
 
    }
 
 
 
static INLINE unsigned TB_FASTCALL IndEnPassant12W
 
    (
 
    square  sqw,
 
    square  sqb1,
 
    square  sqb2,
 
    square  sqEnP
 
    )
 
{
 
    if(sqb2+8 == sqEnP)
 
        SWAP(sqb1, sqb2);
 
 
 
    assert(sqb1+8 == sqEnP);
 
 
 
    if (sqw+7 == sqEnP && 0 != TbColumn(sqw))
 
        // Capture to the left
 
        return TbColumn(sqw)-1+(EXCLUDE4(sqb2,sqb1,sqw,sqEnP,sqEnP+8)-i8)*i14;
 
 
 
    assert(sqw+9 == sqEnP && 7 != TbColumn(sqw));
 
 
 
    // Capture to the right
 
    return TbColumn(sqw)+7 + (EXCLUDE4(sqb2,sqb1,sqw,sqEnP,sqEnP+8)-i8)*i14;
 
}
 
 
 
static INLINE unsigned TB_FASTCALL IndEnPassant12B
 
    (
 
    square  sqw,
 
    square  sqb1,
 
    square  sqb2,
 
    square  sqEnP
 
    )
 
{
 
    assert(sqw-8 == sqEnP);
 
 
 
    SORT(sqb1, sqb2);
 
 
 
    if(sqb1-9 == sqEnP && 0 != TbColumn(sqb1))
 
        // Capture to the left
 
        return TbColumn(sqb1) - 1 + (sqb2-i8-4)*i14;
 
    else if(sqb1-7 == sqEnP && 7 != TbColumn(sqb1))
 
        // Capture to the right
 
        return TbColumn(sqb1) + 7 + (sqb2-i8-4)*i14;
 
    else if(sqb2-9 == sqEnP && 0 != TbColumn(sqb2))
 
        // Capture to the left
 
        return TbColumn(sqb2) - 1 + (EXCLUDE2(sqb1,sqEnP,sqEnP-8)-i8)*i14;
 
 
 
    // Capture to the right
 
    assert(sqb2-7 == sqEnP && 7 != TbColumn(sqb2));
 
    return TbColumn(sqb2) + 7 + (EXCLUDE2(sqb1,sqEnP,sqEnP-8)-i8)*i14;
 
}
 
 
 
static INLINE unsigned TB_FASTCALL IndEnPassant22W
 
    (
 
    square  sqw1,
 
    square  sqw2,
 
    square  sqb1,
 
    square  sqb2,
 
    square  sqEnP
 
    )
 
{
 
    square sqEmptyEnP = sqEnP + 8;
 
 
 
    if(sqb2+8== sqEnP)
 
       SWAP(sqb1, sqb2);
 
 
 
    assert(sqb1+8 == sqEnP);
 
 
 
    SORT(sqw1, sqw2);
 
 
 
    if (sqw1+7 == sqEnP && 0 != TbColumn(sqw1))
 
            // Capture to the left
 
        return TbColumn(sqw1)-1+
 
           (EXCLUDE2(sqw2,sqEnP,sqEmptyEnP)-i8-2)*i14+
 
           (EXCLUDE5(sqb2,sqb1,sqw1,sqw2,sqEnP,sqEmptyEnP)-i8)*(i14*i44);
 
    else if (sqw1+9 == sqEnP && 7 != TbColumn(sqw1))
 
            // Capture to the right
 
        return TbColumn(sqw1)+7+
 
           (EXCLUDE2(sqw2,sqEnP,sqEmptyEnP)-i8-2)*i14+
 
           (EXCLUDE5(sqb2,sqb1,sqw1,sqw2,sqEnP,sqEmptyEnP)-i8)*(i14*i44);
 
    else if (sqw2+7 == sqEnP && 0 != TbColumn(sqw2))
 
            // Capture to the left
 
        return TbColumn(sqw2)-1+
 
           (sqw1-i8)*i14+
 
           (EXCLUDE5(sqb2,sqb1,sqw1,sqw2,sqEnP,sqEmptyEnP)-i8)*(i14*i44);
 
 
 
    // Capture to the right
 
    assert(sqw2+9 == sqEnP && 7 != TbColumn(sqw2));
 
    return TbColumn(sqw2)+7+
 
           (sqw1-i8)*i14+
 
       (EXCLUDE5(sqb2,sqb1,sqw1,sqw2,sqEnP,sqEmptyEnP)-i8)*(i14*i44);
 
}
 
 
 
static INLINE unsigned TB_FASTCALL IndEnPassant22B
 
    (
 
    square  sqw1,
 
    square  sqw2,
 
    square  sqb1,
 
    square  sqb2,
 
    square  sqEnP
 
    )
 
{
 
    square sqEmptyEnP = sqEnP - 8;
 
 
 
    if(sqw2-8 == sqEnP)
 
       SWAP(sqw1, sqw2);
 
 
 
    assert(sqw1-8 == sqEnP);
 
 
 
    SORT(sqb1, sqb2);
 
 
 
    if (sqb1-9 == sqEnP && 0 != TbColumn(sqb1))
 
        // Capture to the left
 
        return TbColumn(sqb1)-1+
 
           (sqb2-i8-4)*i14+
 
           (EXCLUDE5(sqw2,sqw1,sqb1,sqb2,sqEnP,sqEmptyEnP)-i8)*(i14*i44);
 
    else if (sqb1-7 == sqEnP && 7 != TbColumn(sqb1))
 
        // Capture to the right
 
        return TbColumn(sqb1)+7+
 
           (sqb2-i8-4)*i14+
 
           (EXCLUDE5(sqw2,sqw1,sqb1,sqb2,sqEnP,sqEmptyEnP)-i8)*(i14*i44);
 
    else if (sqb2-9 == sqEnP && 0 != TbColumn(sqb2))
 
        // Capture to the left
 
        return TbColumn(sqb2)-1+
 
           (EXCLUDE2(sqb1,sqEnP,sqEmptyEnP)-i8)*i14+
 
           (EXCLUDE5(sqw2,sqw1,sqb1,sqb2,sqEnP,sqEmptyEnP)-i8)*(i14*i44);
 
 
 
    // Capture to the right
 
    assert(sqb2-7 == sqEnP && 7 != TbColumn(sqb2));
 
    return TbColumn(sqb2)+7+
 
           (EXCLUDE2(sqb1,sqEnP,sqEmptyEnP)-i8)*i14+
 
       (EXCLUDE5(sqw2,sqw1,sqb1,sqb2,sqEnP,sqEmptyEnP)-i8)*(i14*i44);
 
}
 
 
 
static INLINE unsigned TB_FASTCALL IndEnPassant31W
 
    (
 
    square  sqw1,
 
    square  sqw2,
 
    square  sqw3,
 
    square  sqb,
 
    square  sqEnP
 
    )
 
{
 
    square sqEmptyEnP = sqEnP + 8;
 
 
 
    assert(sqb + 8 == sqEnP);
 
 
 
    SORT (sqw1, sqw2);
 
    SORT (sqw2, sqw3);
 
    SORT (sqw1, sqw2);
 
 
 
    if (sqw1+7 == sqEnP && 0 != TbColumn(sqw1)) {
 
        // Capture to the left
 
        sqw3 = EXCLUDE2(sqw3,sqEnP,sqEmptyEnP)-i8-2;
 
        return TbColumn(sqw1)-1+
 
               (EXCLUDE2(sqw2,sqEnP,sqEmptyEnP)-i8-2)*i14+
 
               (sqw3*(sqw3-1)/2)*i14;
 
        }
 
    else if (sqw1+9 == sqEnP && 7 != TbColumn(sqw1)) {
 
        // Capture to the right
 
        sqw3 = EXCLUDE2(sqw3,sqEnP,sqEmptyEnP)-i8-2;
 
        return TbColumn(sqw1)+7+
 
               (EXCLUDE2(sqw2,sqEnP,sqEmptyEnP)-i8-2)*i14+
 
               (sqw3*(sqw3-1)/2)*i14;
 
    }
 
    else if (sqw2+7 == sqEnP && 0 != TbColumn(sqw2)) {
 
        // Capture to the left
 
        sqw3 = EXCLUDE2(sqw3,sqEnP,sqEmptyEnP)-i8-2;
 
        return TbColumn(sqw2)-1+
 
               (sqw1-i8)*i14+
 
               (sqw3*(sqw3-1)/2)*i14;
 
    }
 
    else if (sqw2+9 == sqEnP && 7 != TbColumn(sqw2)) {
 
        // Capture to the right
 
        sqw3 = EXCLUDE2(sqw3,sqEnP,sqEmptyEnP)-i8-2;
 
        return TbColumn(sqw2)+7+
 
               (sqw1-i8)*i14+
 
               (sqw3*(sqw3-1)/2)*i14;
 
    }
 
    else if (sqw3+7 == sqEnP && 0 != TbColumn(sqw3)) {
 
        // Capture to the left
 
        sqw2 = sqw2-i8;
 
        return TbColumn(sqw3)-1+
 
               (sqw1-i8)*i14+
 
               (sqw2*(sqw2-1)/2)*i14;
 
    }
 
    else {
 
        // Capture to the right
 
        sqw2 = sqw2-i8;
 
        return TbColumn(sqw3)+7+
 
               (sqw1-i8)*i14+
 
               (sqw2*(sqw2-1)/2)*i14;
 
    }
 
}
 
 
 
static INLINE unsigned TB_FASTCALL IndEnPassant31B
 
    (
 
    square  sqw1,
 
    square  sqw2,
 
    square  sqw3,
 
    square  sqb,
 
    square  sqEnP
 
    )
 
{
 
    square sqEmptyEnP = sqEnP - 8;
 
 
 
    if(sqw2 - 8 == sqEnP)
 
        SWAP(sqw1, sqw2);
 
    if(sqw3 - 8 == sqEnP)
 
        SWAP(sqw1, sqw3);
 
 
 
    assert(sqw1 - 8 == sqEnP);
 
 
 
    SORT(sqw2, sqw3);
 
 
 
    if(sqb - 9 == sqEnP && 0 != TbColumn(sqb)) {
 
        sqw3 = EXCLUDE4(sqw3,sqw1,sqb,sqEnP,sqEmptyEnP)-i8;
 
        return TbColumn(sqb)-1+
 
        (EXCLUDE4(sqw2,sqw1,sqb,sqEnP,sqEmptyEnP)-i8)*i14+
 
        (sqw3*(sqw3-1)/2)*i14;
 
    }
 
    else {
 
        assert(sqb - 7 == sqEnP && 7 != TbColumn(sqb));
 
        sqw3 = EXCLUDE4(sqw3,sqw1,sqb,sqEnP,sqEmptyEnP)-i8;
 
        return TbColumn(sqb)+7+
 
            (EXCLUDE4(sqw2,sqw1,sqb,sqEnP,sqEmptyEnP)-i8)*i14+
 
        (sqw3*(sqw3-1)/2)*i14;
 
    }
 
}
 
 
 
// Index calculation functions for different endgame classes
 
 
 
template <int piw1> class T21
 
    {
 
public:
 
    static INDEX TB_FASTCALL IndCalcW
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        square sqwk, sqw1, sqbk, sqMask;
 
 
 
        sqwk = SqFindKing (psqW);
 
        sqw1 = SqFindOne  (psqW, piw1);
 
        sqbk = SqFindKing (psqB);
 
 
 
        if (x_piecePawn == piw1)
 
            sqMask = rgsqReflectMaskY [sqwk] ^ rgsqReflectInvertMask [fInvert];
 
        else
 
            sqMask = rgsqReflectMaskYandX [sqwk];
 
        sqwk ^= sqMask;
 
        sqbk ^= sqMask;
 
        sqw1 ^= sqMask;
 
 
 
        if (x_piecePawn != piw1)
 
            {
 
            // No pawn
 
            if (! FInTriangle (sqwk, sqbk))
 
                {
 
                sqwk = reflect_xy(sqwk);
 
                sqbk = reflect_xy(sqbk);
 
                sqw1 = reflect_xy(sqw1);
 
                };
 
            }
 
        return TEnumerate1<piw1,x_piecePawn==piw1 ? true : false,false>::Index(sqwk,sqw1,sqbk);
 
        }
 
 
 
    static INDEX TB_FASTCALL IndCalcB
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        square sqwk, sqw1, sqbk, sqMask;
 
 
 
        sqwk = SqFindKing (psqW);
 
        sqw1 = SqFindOne  (psqW, piw1);
 
        sqbk = SqFindKing (psqB);
 
 
 
        if (x_piecePawn == piw1)
 
            sqMask = rgsqReflectMaskY [sqbk] ^ rgsqReflectInvertMask [fInvert];
 
        else
 
            sqMask = rgsqReflectMaskYandX [sqbk];
 
        sqwk ^= sqMask;
 
        sqbk ^= sqMask;
 
        sqw1 ^= sqMask;
 
 
 
        if (x_piecePawn == piw1)
 
            return TEnumerate1<x_pieceNone,true,true>::Index(sqbk,sqw1,sqwk);
 
        else
 
            {
 
            // No pawn
 
            if (! FInTriangle (sqbk, sqwk))
 
                {
 
                sqwk = reflect_xy(sqwk);
 
                sqbk = reflect_xy(sqbk);
 
                sqw1 = reflect_xy(sqw1);
 
                };
 
            return IndTriKings(sqbk,sqwk)*i62 + EXCLUDE2(sqw1,sqwk,sqbk);
 
            }
 
        }
 
    };
 
 
 
template <int piw1, int pib1> class T22
 
    {
 
public:
 
    static INDEX TB_FASTCALL IndCalcW
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        square sqwk, sqw1, sqbk, sqb1, sqMask;
 
 
 
        sqwk = SqFindKing (psqW);
 
        sqw1 = SqFindOne  (psqW, piw1);
 
        sqbk = SqFindKing (psqB);
 
        sqb1 = SqFindOne  (psqB, pib1);
 
 
 
        if (x_piecePawn == pib1)
 
            sqMask = rgsqReflectMaskY [sqwk] ^ rgsqReflectInvertMask [fInvert];
 
        else
 
            sqMask = rgsqReflectMaskYandX [sqwk];
 
        sqwk ^= sqMask;
 
        sqbk ^= sqMask;
 
        sqw1 ^= sqMask;
 
        sqb1 ^= sqMask;
 
 
 
        if (x_piecePawn == pib1)
 
            {
 
            // There are pawns on the board
 
            if (x_piecePawn == piw1)
 
                {
 
                // One white and one black pawn
 
                if (XX == sqEnP)
 
                    return  TEnumerate1<x_piecePawn,true,false>::Index(sqwk,sqw1,sqbk)*i47 + 
 
                            EXCLUDE1(sqb1,sqw1)-i8; // 47
 
                else
 
                    return  rgcSinglePawnPresent[x_piecePawn]*i47 +
 
                            IndHalfKings(sqwk,sqbk)*i14 +
 
                            IndEnPassant11W (sqw1, sqb1, sqEnP ^ sqMask);
 
                }
 
            else
 
                // Only black pawn
 
                return  TEnumerate1<piw1,true,false>::Index(sqwk,sqw1,sqbk)*i48 + sqb1-i8;
 
            }
 
        else
 
            {
 
            // No pawns at all
 
            if (!FInTriangle (sqwk, sqbk))
 
                {
 
                sqwk = reflect_xy(sqwk);
 
                sqbk = reflect_xy(sqbk);
 
                sqw1 = reflect_xy(sqw1);
 
                sqb1 = reflect_xy(sqb1);
 
                };
 
            return  TEnumerate1<piw1,false,false>::Index(sqwk,sqw1,sqbk)*i61 +
 
                    EXCLUDE3(sqb1,sqwk,sqbk,sqw1);  // 61
 
            }
 
        }
 
 
 
    static INDEX TB_FASTCALL IndCalcB
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        square sqwk, sqw1, sqbk, sqb1, sqMask;
 
 
 
        sqwk = SqFindKing (psqW);
 
        sqw1 = SqFindOne  (psqW, piw1);
 
        sqbk = SqFindKing (psqB);
 
        sqb1 = SqFindOne  (psqB, pib1);
 
 
 
        if (x_piecePawn == pib1)
 
            sqMask = rgsqReflectMaskY [sqbk] ^ rgsqReflectInvertMask [fInvert];
 
        else
 
            sqMask = rgsqReflectMaskYandX [sqbk];
 
        sqwk ^= sqMask;
 
        sqbk ^= sqMask;
 
        sqw1 ^= sqMask;
 
        sqb1 ^= sqMask;
 
 
 
        if (x_piecePawn == pib1)
 
            {
 
            // There are pawns on the board
 
            if (x_piecePawn == piw1)
 
                {
 
                // One white and one black pawn
 
                if (XX == sqEnP)
 
                    return  TEnumerate1<x_piecePawn,true,true>::Index(sqbk,sqb1,sqwk)*i47 + 
 
                            EXCLUDE1(sqw1,sqb1)-i8; // 47
 
                else
 
                    return  rgcSinglePawnPresent[x_piecePawn]*i47 +
 
                            IndHalfKings(sqbk,sqwk)*i14 +
 
                            IndEnPassant11B (sqw1, sqb1, sqEnP ^ sqMask);
 
                }
 
            }
 
        else
 
            {
 
            // No pawns at all
 
            if (!FInTriangle (sqbk, sqwk))
 
                {
 
                sqwk = reflect_xy(sqwk);
 
                sqbk = reflect_xy(sqbk);
 
                sqw1 = reflect_xy(sqw1);
 
                sqb1 = reflect_xy(sqb1);
 
                };
 
            }
 
        return  (x_piecePawn == pib1 ?  TEnumerate1<pib1,true,true>::Index(sqbk,sqb1,sqwk) :
 
                                        TEnumerate1<pib1,false,false>::Index(sqbk,sqb1,sqwk))*i61 +
 
                EXCLUDE3(sqw1,sqwk,sqbk,sqb1);  // 61
 
        }
 
    };
 
 
 
template <int piw1, int piw2> class T31
 
    {
 
public:
 
    static INDEX TB_FASTCALL IndCalcW
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        square sqwk, sqw1, sqw2, sqbk, sqMask;
 
 
 
        sqwk = SqFindKing (psqW);
 
        if (piw1 == piw2)
 
            {
 
            sqw1 = SqFindFirst  (psqW, piw1);
 
            sqw2 = SqFindSecond (psqW, piw2);
 
            }
 
        else
 
            {
 
            SqFind2 (psqW, piw1, sqw1, piw2, sqw2);
 
            }
 
        sqbk = SqFindKing (psqB);
 
 
 
        if (x_piecePawn == piw2)
 
            sqMask = rgsqReflectMaskY [sqwk] ^ rgsqReflectInvertMask [fInvert];
 
        else
 
            sqMask = rgsqReflectMaskYandX [sqwk];
 
        sqwk ^= sqMask;
 
        sqbk ^= sqMask;
 
        sqw1 ^= sqMask;
 
        sqw2 ^= sqMask;
 
 
 
        if (x_piecePawn != piw2)
 
            {
 
            // There are no pawns on the board
 
            if (!FInTriangle (sqwk, sqbk))
 
                {
 
                sqwk = reflect_xy(sqwk);
 
                sqw1 = reflect_xy(sqw1);
 
                sqw2 = reflect_xy(sqw2);
 
                sqbk = reflect_xy(sqbk);
 
                };
 
            }
 
        return TEnumerate2<piw1, piw2, x_piecePawn==piw2 ? true : false, false>::Index(sqwk, sqw1, sqw2, sqbk);
 
        }
 
 
 
    static INDEX TB_FASTCALL IndCalcB
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        square sqwk, sqw1, sqw2, sqbk, sqMask;
 
 
 
        sqwk = SqFindKing (psqW);
 
        if (piw1 == piw2)
 
            {
 
            sqw1 = SqFindFirst (psqW, piw1);
 
            sqw2 = SqFindSecond (psqW, piw2);
 
            }
 
        else
 
            {
 
            SqFind2 (psqW, piw1, sqw1, piw2, sqw2);
 
            }
 
        sqbk = SqFindKing (psqB);
 
 
 
        if (x_piecePawn == piw2)
 
            sqMask = rgsqReflectMaskY [sqbk] ^ rgsqReflectInvertMask [fInvert];
 
        else
 
            sqMask = rgsqReflectMaskYandX [sqbk];
 
        sqwk ^= sqMask;
 
        sqbk ^= sqMask;
 
        sqw1 ^= sqMask;
 
        sqw2 ^= sqMask;
 
 
 
        if (x_piecePawn == piw2)
 
            {
 
            // There are pawns on the board
 
            if (x_piecePawn == piw1)
 
                // Two white pawns
 
                return  TEnumerate2<x_pieceNone,x_pieceNone,true,true>::Index(sqbk,sqw1,sqw2,sqwk);
 
            else
 
                // Only one white pawn
 
                return  TEnumerate1<x_pieceNone,true,true>::Index(sqbk,sqw2,sqwk)*i61 +
 
                        EXCLUDE3(sqw1,sqwk,sqbk,sqw2);  // 61
 
            }
 
        else
 
            {
 
            // No pawns
 
            if (!FInTriangle (sqbk, sqwk))
 
                {
 
                sqwk = reflect_xy(sqwk);
 
                sqw1 = reflect_xy(sqw1);
 
                sqw2 = reflect_xy(sqw2);
 
                sqbk = reflect_xy(sqbk);
 
                };
 
            if (piw1 == piw2)
 
                {
 
                SORT (sqw1, sqw2);
 
                sqw2 = EXCLUDE2(sqw2,sqwk,sqbk);                    // 62
 
                return  IndTriKings(sqbk,sqwk)*(i62*i61/2) +
 
                        sqw2*(sqw2-1)/2+EXCLUDE2(sqw1,sqwk,sqbk);   // 62*61/2
 
                }
 
            else
 
                return  IndTriKings(sqbk,sqwk)*(i62*i61) +
 
                        EXCLUDE2(sqw1,sqwk,sqbk)*i61 +  // 62
 
                        EXCLUDE3(sqw2,sqwk,sqbk,sqw1);  // 61
 
            }
 
        }
 
    };
 
 
 
template <int piw1, int piw2, int pib1> class T32
 
    {
 
public:
 
    static INDEX TB_FASTCALL IndCalcW
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        square sqwk, sqw1, sqw2, sqbk, sqb1, sqMask;
 
 
 
        sqwk = SqFindKing (psqW);
 
        if (piw1 == piw2)
 
            {
 
            sqw1 = SqFindFirst  (psqW, piw1);
 
            sqw2 = SqFindSecond (psqW, piw2);
 
            }
 
        else
 
            {
 
            SqFind2 (psqW, piw1, sqw1, piw2, sqw2);
 
            }
 
        sqbk = SqFindKing (psqB);
 
        sqb1 = SqFindOne  (psqB, pib1);
 
 
 
        if (x_piecePawn == piw2 || x_piecePawn == pib1)
 
            sqMask = rgsqReflectMaskY [sqwk] ^ rgsqReflectInvertMask [fInvert];
 
        else
 
            sqMask = rgsqReflectMaskYandX [sqwk];
 
        sqwk ^= sqMask;
 
        sqbk ^= sqMask;
 
        sqw1 ^= sqMask;
 
        sqw2 ^= sqMask;
 
        sqb1 ^= sqMask;
 
 
 
        if (x_piecePawn == piw2 || x_piecePawn == pib1)
 
            {
 
            // There are pawns on the board
 
            if (x_piecePawn == pib1)
 
                {
 
                // Black pawn
 
                if (x_piecePawn == piw1 && x_piecePawn == piw2)
 
                    {
 
                    // All 3 pieces are pawns
 
                    if (XX == sqEnP)
 
                        return  TEnumerate2<x_piecePawn,x_piecePawn,true,false>::
 
                                    Index(sqwk,sqw1,sqw2,sqbk)*i46+
 
                                EXCLUDE2(sqb1,sqw1,sqw2)-i8;    // 46
 
                    else
 
                        // En passant capture
 
                        return  rgcPairPawnPresent[x_piecePawn][x_piecePawn]*i46 +
 
                                IndHalfKings(sqwk,sqbk)*(i14*i44) +
 
                                IndEnPassant21W (sqw1, sqw2, sqb1, sqEnP ^ sqMask);
 
                    }
 
                else if (x_piecePawn == piw2)
 
                    {
 
                    // One white pawn, one black pawn
 
                    if (XX == sqEnP)
 
                        return  TEnumerate2<piw1,x_piecePawn,true,false>::
 
                                    Index(sqwk,sqw1,sqw2,sqbk)*i47 +
 
                                EXCLUDE1(sqb1,sqw2)-i8; // 47
 
                    else
 
                        // En passant capture
 
                        return  rgcPairPawnPresent[piw1][x_piecePawn]*i47 +
 
                                TEnumerate1<piw1,true,false>::Index(sqwk,sqw1,sqbk)*i14 +
 
                                IndEnPassant11W (sqw2, sqb1, sqEnP ^ sqMask);
 
                    }
 
                else
 
                    // Only black pawn
 
                    return  TEnumerate2<piw1,piw2,true,false>::
 
                                Index(sqwk,sqw1,sqw2,sqbk)*i48 +
 
                            sqb1-i8;    // 48
 
                }
 
            }
 
        else
 
            {
 
            // No pawns
 
            if (!FInTriangle (sqwk, sqbk))
 
                {
 
                sqwk = reflect_xy(sqwk);
 
                sqw1 = reflect_xy(sqw1);
 
                sqw2 = reflect_xy(sqw2);
 
                sqbk = reflect_xy(sqbk);
 
                sqb1 = reflect_xy(sqb1);
 
                };
 
            }
 
        return  TEnumerate2<piw1,piw2,(x_piecePawn==piw2||x_piecePawn==pib1) ? true : false,false>::
 
                    Index(sqwk,sqw1,sqw2,sqbk)*i60 +
 
                EXCLUDE4(sqb1,sqwk,sqbk,sqw1,sqw2); // 60
 
        }
 
 
 
    static INDEX TB_FASTCALL IndCalcB
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        square sqwk, sqw1, sqw2, sqbk, sqb1, sqMask;
 
 
 
        sqwk = SqFindKing (psqW);
 
        if (piw1 == piw2)
 
            {
 
            sqw1 = SqFindFirst  (psqW, piw1);
 
            sqw2 = SqFindSecond (psqW, piw2);
 
            }
 
        else
 
            {
 
            SqFind2 (psqW, piw1, sqw1, piw2, sqw2);
 
            }
 
        sqbk = SqFindKing (psqB);
 
        sqb1 = SqFindOne  (psqB, pib1);
 
 
 
        if (x_piecePawn == piw2 || x_piecePawn == pib1)
 
            sqMask = rgsqReflectMaskY [sqbk] ^ rgsqReflectInvertMask [fInvert];
 
        else
 
            sqMask = rgsqReflectMaskYandX [sqbk];
 
        sqwk ^= sqMask;
 
        sqbk ^= sqMask;
 
        sqw1 ^= sqMask;
 
        sqw2 ^= sqMask;
 
        sqb1 ^= sqMask;
 
 
 
        if (x_piecePawn == piw2 || x_piecePawn == pib1)
 
            {
 
            // There are pawns on the board
 
            if (x_piecePawn == pib1)
 
                {
 
                // Black pawn
 
                if (x_piecePawn == piw1 && x_piecePawn == piw2)
 
                    {
 
                    // All 3 pieces are pawns
 
                    SORT (sqw1, sqw2);
 
                    if (XX == sqEnP)
 
                        {
 
                        sqw2 = EXCLUDE1(sqw2,sqb1)-i8;                  // 47
 
                        return  TEnumerate1<x_piecePawn,true,true>::
 
                                    Index(sqbk,sqb1,sqwk)*(i47*i46/2) +
 
                                sqw2*(sqw2-1)/2+EXCLUDE1(sqw1,sqb1)-i8; // 47*46/2
 
                        }
 
                    else
 
                        // En passant capture
 
                        return  rgcSinglePawnPresent[x_piecePawn]*(i47*i46/2) +
 
                                IndHalfKings(sqbk,sqwk)*(i44*i14) +
 
                                IndEnPassant21B (sqw1, sqw2, sqb1, sqEnP ^ sqMask);
 
                    }
 
                else if (x_piecePawn == piw2)
 
                    {
 
                    // One white pawn, one black pawn
 
                    if (XX == sqEnP)
 
                        return  TEnumerate1<x_piecePawn,true,true>::
 
                                    Index(sqbk,sqb1,sqwk)*(i60*i47) +
 
                                EXCLUDE4(sqw1,sqwk,sqbk,sqw2,sqb1)*i47 +    // 60
 
                                EXCLUDE1(sqw2,sqb1)-i8;                     // 47
 
                    else
 
                        {
 
                        // En passant capture
 
                        sqEnP ^= sqMask;
 
                        return  rgcSinglePawnPresent[x_piecePawn]*(i60*i47) +
 
                                IndHalfKings(sqbk,sqwk)*(i58*i14) +
 
                                EXCLUDE6(sqw1,sqwk,sqbk,sqw2,sqb1,sqEnP,sqEnP-8)*i14 +  // 58
 
                                IndEnPassant11B (sqw2, sqb1, sqEnP);
 
                        }
 
                    }
 
                else
 
                    {
 
                    // Only black pawn
 
                    if (piw1 == piw2)
 
                        {
 
                        // 2 identical white pieces
 
                        SORT (sqw1, sqw2);
 
                        sqw2 = EXCLUDE3(sqw2,sqwk,sqbk,sqb1);                       // 61
 
                        return  TEnumerate1<x_piecePawn,true,true>::
 
                                    Index(sqbk,sqb1,sqwk)*(i61*i60/2) +
 
                                sqw2*(sqw2-1)/2 + EXCLUDE3(sqw1,sqwk,sqbk,sqb1);    // 61*60/2
 
                        }
 
                    return  TEnumerate1<x_piecePawn,true,true>::
 
                                Index(sqbk,sqb1,sqwk)*(i61*i60) +
 
                            EXCLUDE3(sqw1,sqwk,sqbk,sqb1)*i60 + // 61
 
                            EXCLUDE4(sqw2,sqwk,sqbk,sqw1,sqb1); // 60
 
                    }
 
                }
 
            else
 
                {
 
                // No black pawn
 
                if (x_piecePawn == piw1)
 
                    {
 
                    // Only 2 white pawns
 
                    SORT (sqw1, sqw2);
 
                    sqw2 -= i8;
 
                    return  TEnumerate1<pib1,true,true>::
 
                                Index(sqbk,sqb1,sqwk)*(i48*47/2) +
 
                            sqw2*(sqw2-1)/2+sqw1-i8;            // 48*47/2
 
                    }
 
                else
 
                    // Only one white pawn
 
                    return  TEnumerate1<pib1,true,true>::
 
                                Index(sqbk,sqb1,sqwk)*(i60*i48) +
 
                            EXCLUDE4(sqw1,sqwk,sqbk,sqw2,sqb1)*i48 +    // 60
 
                            sqw2-i8;                                    // 48
 
                }
 
            }
 
        else
 
            {
 
            // No pawns
 
            if (!FInTriangle (sqbk, sqwk))
 
                {
 
                sqwk = reflect_xy(sqwk);
 
                sqw1 = reflect_xy(sqw1);
 
                sqw2 = reflect_xy(sqw2);
 
                sqbk = reflect_xy(sqbk);
 
                sqb1 = reflect_xy(sqb1);
 
                };
 
            if (piw1 == piw2)
 
                {
 
                // 2 identical white pieces
 
                SORT (sqw1, sqw2);
 
                sqw2 = EXCLUDE3(sqw2,sqwk,sqbk,sqb1);                   // 61
 
                return  TEnumerate1<pib1,false,false>::
 
                            Index(sqbk,sqb1,sqwk)*(i61*i60/2) +
 
                        sqw2*(sqw2-1)/2+EXCLUDE3(sqw1,sqwk,sqbk,sqb1);  // 61*60/2
 
                }
 
            else
 
                return  TEnumerate1<pib1,false,false>::
 
                            Index(sqbk,sqb1,sqwk)*(i61*i60) +
 
                        EXCLUDE3(sqw1,sqwk,sqbk,sqb1)*i60 + // 61
 
                        EXCLUDE4(sqw2,sqwk,sqbk,sqw1,sqb1); // 60
 
            }
 
        }
 
    };
 
 
 
#if defined (T41_INCLUDE)
 
 
 
template <int piw1, int piw2, int piw3> class T41
 
    {
 
public:
 
    static INDEX TB_FASTCALL IndCalcW
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        square sqwk, sqw1, sqw2, sqw3, sqbk, sqMask;
 
 
 
        sqwk = SqFindKing (psqW);
 
        sqw1 = SqFindFirst (psqW, piw1);
 
        if (piw1 == piw2 && piw2 == piw3)
 
            {
 
            sqw2 = SqFindSecond (psqW, piw2);
 
            sqw3 = SqFindThird (psqW, piw3);
 
            }
 
        else if (piw1 == piw2)
 
            {
 
            sqw2 = SqFindSecond (psqW, piw2);
 
            sqw3 = SqFindFirst (psqW, piw3);
 
            }
 
        else if (piw2 == piw3)
 
            {
 
            sqw2 = SqFindFirst (psqW, piw2);
 
            sqw3 = SqFindSecond (psqW, piw3);
 
            }
 
        else
 
            {
 
            sqw2 = SqFindFirst (psqW, piw2);
 
            sqw3 = SqFindFirst (psqW, piw3);
 
            }
 
        sqbk = SqFindKing (psqB);
 
 
 
        if (x_piecePawn == piw3)
 
            sqMask = rgsqReflectMaskY [sqwk] ^ rgsqReflectInvertMask [fInvert];
 
        else
 
            sqMask = rgsqReflectMaskYandX [sqwk];
 
        sqwk ^= sqMask;
 
        sqbk ^= sqMask;
 
        sqw1 ^= sqMask;
 
        sqw2 ^= sqMask;
 
        sqw3 ^= sqMask;
 
 
 
        if (x_piecePawn != piw3)
 
            {
 
            // No pawns
 
            if (!FInTriangle (sqwk, sqbk))
 
                {
 
                sqwk = reflect_xy(sqwk);
 
                sqw1 = reflect_xy(sqw1);
 
                sqw2 = reflect_xy(sqw2);
 
                sqw3 = reflect_xy(sqw3);
 
                sqbk = reflect_xy(sqbk);
 
                };
 
            }
 
        return  TEnumerate3<piw1,piw2,piw3,x_piecePawn == piw3,false>::Index(sqwk,sqw1,sqw2,sqw3,sqbk);
 
        }
 
 
 
    static INDEX TB_FASTCALL IndCalcB
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        square sqwk, sqw1, sqw2, sqw3, sqbk, sqMask;
 
 
 
        sqwk = SqFindKing (psqW);
 
        sqw1 = SqFindFirst (psqW, piw1);
 
        if (piw1 == piw2 && piw2 == piw3)
 
            {
 
            sqw2 = SqFindSecond (psqW, piw2);
 
            sqw3 = SqFindThird (psqW, piw3);
 
            }
 
        else if (piw1 == piw2)
 
            {
 
            sqw2 = SqFindSecond (psqW, piw2);
 
            sqw3 = SqFindFirst (psqW, piw3);
 
            }
 
        else if (piw2 == piw3)
 
            {
 
            sqw2 = SqFindFirst (psqW, piw2);
 
            sqw3 = SqFindSecond (psqW, piw3);
 
            }
 
        else
 
            {
 
            sqw2 = SqFindFirst (psqW, piw2);
 
            sqw3 = SqFindFirst (psqW, piw3);
 
            }
 
        sqbk = SqFindKing (psqB);
 
 
 
        if (x_piecePawn == piw3)
 
            sqMask = rgsqReflectMaskY [sqbk] ^ rgsqReflectInvertMask [fInvert];
 
        else
 
            sqMask = rgsqReflectMaskYandX [sqbk];
 
        sqwk ^= sqMask;
 
        sqbk ^= sqMask;
 
        sqw1 ^= sqMask;
 
        sqw2 ^= sqMask;
 
        sqw3 ^= sqMask;
 
 
 
        if (x_piecePawn == piw3)
 
            {
 
            // There are pawns on the board
 
            if (x_piecePawn == piw1)
 
                // 3 white pawns
 
                return  TEnumerate3<x_pieceNone,x_pieceNone,x_pieceNone,true,true>::
 
                            Index(sqbk,sqw1,sqw2,sqw3,sqwk);
 
            else if (x_piecePawn == piw2)
 
                // 2 white pawns
 
                return  TEnumerate2<x_pieceNone,x_pieceNone,true,true>::
 
                            Index(sqbk,sqw2,sqw3,sqwk)*i60 +
 
                        EXCLUDE4(sqw1,sqwk,sqbk,sqw2,sqw3); // 60
 
            else if (piw1 == piw2)
 
                {
 
                // 1 pawn, 2 pieces equal
 
                SORT (sqw1, sqw2);
 
                sqw2 = EXCLUDE3(sqw2,sqwk,sqbk,sqw3);                   // 61
 
                return  TEnumerate1<x_pieceNone,true,true>::
 
                            Index(sqbk,sqw3,sqwk)*(i61*i60/2) +
 
                        sqw2*(sqw2-1)/2+EXCLUDE3(sqw1,sqwk,sqbk,sqw3);  // 61*60/2
 
                }
 
            else
 
                // Only one white pawn
 
                return  TEnumerate1<x_pieceNone,true,true>::Index(sqbk,sqw3,sqwk)*i61*i60 +
 
                        EXCLUDE3(sqw1,sqwk,sqbk,sqw3)*i60 + // 61
 
                        EXCLUDE4(sqw2,sqwk,sqbk,sqw1,sqw3); // 60
 
            }
 
        else
 
            {
 
            // No pawns
 
            if (!FInTriangle (sqbk, sqwk))
 
                {
 
                sqwk = reflect_xy(sqwk);
 
                sqw1 = reflect_xy(sqw1);
 
                sqw2 = reflect_xy(sqw2);
 
                sqw3 = reflect_xy(sqw3);
 
                sqbk = reflect_xy(sqbk);
 
                };
 
            if (piw1 == piw2 && piw2 == piw3)
 
                {
 
                // All 3 pieces equal
 
                SORT (sqw1, sqw2);
 
                SORT (sqw2, sqw3);
 
                SORT (sqw1, sqw2);
 
                sqw3 = EXCLUDE2(sqw3,sqwk,sqbk);    // 62
 
                sqw2 = EXCLUDE2(sqw2,sqwk,sqbk);
 
                return  IndTriKings(sqbk,sqwk)*(i62*i61*i60/6) +
 
                        sqw3*(sqw3-1)*(sqw3-2)/6+
 
                        sqw2*(sqw2-1)/2+
 
                        EXCLUDE2(sqw1,sqwk,sqbk);   // 62*61*60/6
 
                }
 
            else if (piw1 == piw2)
 
                {
 
                // 2 major pieces equal
 
                SORT (sqw1, sqw2);
 
                sqw2 = EXCLUDE3(sqw2,sqwk,sqbk,sqw3);                           // 61
 
                return  IndTriKings(sqbk,sqwk)*(i61*i60/2*i62) +
 
                        (sqw2*(sqw2-1)/2+EXCLUDE3(sqw1,sqwk,sqbk,sqw3))*i62 +   // 61*60/2
 
                        EXCLUDE2(sqw3,sqwk,sqbk);                               // 62
 
                }
 
            else if (piw2 == piw3)
 
                {
 
                // 2 minor pieces equal
 
                SORT (sqw2, sqw3);
 
                sqw3 = EXCLUDE3(sqw3,sqwk,sqbk,sqw1);                   // 61
 
                return  IndTriKings(sqbk,sqwk)*(i62*i61*i60/2) +
 
                        EXCLUDE2(sqw1,sqwk,sqbk)*(i61*i60/2) +          // 62
 
                        sqw3*(sqw3-1)/2+EXCLUDE3(sqw2,sqwk,sqbk,sqw1);  // 61*60/2
 
                }
 
            else
 
                return  IndTriKings(sqbk,sqwk)*(i62*i61*i60) +
 
                        EXCLUDE2(sqw1,sqwk,sqbk)*(i61*i60) +    // 62
 
                        EXCLUDE3(sqw2,sqwk,sqbk,sqw1)*i60 +     // 61
 
                        EXCLUDE4(sqw3,sqwk,sqbk,sqw1,sqw2);     // 60
 
            }
 
        }
 
    };
 
 
 
#endif  // T41
 
 
 
#if defined (ILLEGAL_POSSIBLE)
 
 
 
#define CHECK_INF_SINGLE(ind)\
 
        if (INF_SINGLE == ind)\
 
            return (INDEX) -1;\
 
 
 
#define CHECK_INF_PAIR(ind)\
 
        if (INF_PAIR == ind)\
 
            return (INDEX) -1;\
 
 
 
#define CHECK_INF_TRIPLE(ind)\
 
        if (INF_TRIPLE == ind)\
 
            return (INDEX) -1;\
 
 
 
#else
 
 
 
#define CHECK_INF_SINGLE(ind)
 
#define CHECK_INF_PAIR(ind)
 
#define CHECK_INF_TRIPLE(ind)
 
 
 
#endif
 
 
 
#if defined (T33_INCLUDE)
 
 
 
template <int piw1, int piw2, int pib1, int pib2> class T33
 
{
 
public:
 
    static INDEX TB_FASTCALL IndCalcW
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
    {
 
        square   sqwk, sqw1, sqw2, sqbk, sqb1, sqb2, sqMask;
 
        unsigned uInd;
 
 
 
        sqwk = SqFindKing (psqW);
 
        if (piw1 == piw2) {
 
            sqw1 = SqFindFirst  (psqW, piw1);
 
            sqw2 = SqFindSecond (psqW, piw2);
 
            }
 
        else {
 
            SqFind2 (psqW, piw1, sqw1, piw2, sqw2);
 
            }
 
        sqbk = SqFindKing (psqB);
 
        if (pib1 == pib2) {
 
            sqb1 = SqFindFirst  (psqB, pib1);
 
            sqb2 = SqFindSecond (psqB, pib2);
 
            }
 
        else {
 
            SqFind2 (psqB, pib1, sqb1, pib2, sqb2);
 
            }
 
 
 
        if(x_piecePawn == piw2 || x_piecePawn == pib2)
 
            sqMask = rgsqReflectMaskY[sqwk] ^ rgsqReflectInvertMask[fInvert];
 
        else
 
            sqMask = rgsqReflectMaskYandX[sqwk];
 
 
 
        sqwk ^= sqMask;
 
        sqbk ^= sqMask;
 
        sqw1 ^= sqMask;
 
        sqw2 ^= sqMask;
 
        sqb1 ^= sqMask;
 
        sqb2 ^= sqMask;
 
 
 
        if(x_piecePawn == piw2 || x_piecePawn == pib2) {
 
            // There are pawns on the board
 
            if(XX == sqEnP) {
 
                // No En Passant possible
 
                uInd = TEnumerate2<piw1,piw2,true,false>::Index(sqwk,sqw1,sqw2,sqbk);
 
                CHECK_INF_PAIR(uInd);
 
                if(x_piecePawn == piw1) {
 
                    // all 4 pieces are pawns
 
                    SORT(sqb1, sqb2);
 
                    sqb2 = EXCLUDE2(sqb2,sqw1,sqw2) - i8;
 
                    return uInd*(INDEX)(i46*i45/2) +
 
                           sqb2*(sqb2-1)/2 + EXCLUDE2(sqb1,sqw1,sqw2) - i8;
 
                }
 
                else if(x_piecePawn == piw2) {
 
                    if(x_piecePawn == pib1) {
 
                        // 1 white, 2 black pawns
 
                        SORT(sqb1, sqb2);
 
                        sqb2 = EXCLUDE1(sqb2,sqw2) - i8;
 
                        return uInd*(INDEX)(i47*i46/2) +
 
                               sqb2*(sqb2-1)/2 + EXCLUDE1(sqb1,sqw2) - i8;
 
                    }
 
                    else if(x_piecePawn == pib2) {
 
                        // 1 white, 1 black pawn
 
                        return uInd*(INDEX)(i59*i47) +
 
                               (EXCLUDE1(sqb2,sqw2)-i8)*i59 +
 
                               EXCLUDE5(sqb1,sqb2,sqwk,sqw1,sqw2,sqbk);
 
                    }
 
                    else if(pib2 == pib1) {
 
                        // only 1 white pawn, two identical black pieces
 
                        SORT(sqb1, sqb2);
 
                        sqb2 = EXCLUDE4(sqb2,sqwk,sqw1,sqw2,sqbk);
 
                        return uInd*(INDEX)(i60*i59/2) +
 
                               sqb2*(sqb2-1)/2 +
 
                               EXCLUDE4(sqb1,sqwk,sqw1,sqw2,sqbk);
 
                    }
 
                    else {
 
                        // only 1 white pawn, two different black pieces
 
                        return uInd*(INDEX)(i60*i59) +
 
                               EXCLUDE4(sqb2,sqwk,sqw1,sqw2,sqbk)*i59 +
 
                               EXCLUDE5(sqb1,sqb2,sqwk,sqw1,sqw2,sqbk);
 
                    }
 
                }
 
                else if(x_piecePawn == pib1) {
 
                    // no white pawns, two black pawns
 
                    SORT(sqb1, sqb2);
 
                    sqb2 -= i8;
 
                    return uInd*(INDEX)(i48*i47/2) +
 
                           sqb2*(sqb2-1)/2 + sqb1 - i8;
 
                }
 
                else {
 
                    // no white pawns, 1 black pawn
 
                    return uInd*(INDEX)(i48*i59) +
 
                           (sqb2 - i8)*i59 +
 
                           EXCLUDE5(sqb1,sqb2,sqwk,sqw1,sqw2,sqbk);
 
                }
 
            }
 
            else {
 
                // En Passant possible
 
                sqEnP ^= sqMask;
 
                if(x_piecePawn == piw1) {
 
                    // all 4 pieces are pawns
 
                    uInd = rgcPairPawnPresent[x_piecePawn][x_piecePawn];
 
                    return uInd*(INDEX)(i46*i45/2) +
 
                           IndHalfKings(sqwk,sqbk)*(i14*i44*i43) +
 
                           IndEnPassant22W(sqw1, sqw2, sqb1, sqb2, sqEnP);
 
                }
 
                else {
 
                    assert(x_piecePawn == piw2);
 
 
 
                    uInd = TEnumerate1<piw1, true, false>::
 
                           Index(sqwk,sqw1,sqbk);
 
                    CHECK_INF_SINGLE(uInd);
 
 
 
                    if(x_piecePawn == pib1) {
 
                        // 1 white pawn, 2 black pawns
 
                        return rgcPairPawnPresent[piw1][x_piecePawn]*((INDEX)(i47*i46/2)) +
 
                               (uInd*(i14*i44) +
 
                                IndEnPassant12W(sqw2, sqb1, sqb2, sqEnP));
 
                    }
 
                    else {
 
                        // 1 white pawn, 1 black pawn
 
                        assert(x_piecePawn == pib2);
 
                        return rgcPairPawnPresent[piw1][x_piecePawn]*((INDEX)(i47*i59))+
 
                               (uInd*(i14*i57) +
 
                                 EXCLUDE7(sqb1,sqb2,sqwk,sqw1,sqw2,sqbk,sqEnP,sqEnP+8)*i14+
 
                                 IndEnPassant11W(sqw2,sqb2,sqEnP));
 
                    }
 
                }
 
            }
 
        }
 
        else {
 
            // no pawns at all
 
            if (!FInTriangle (sqwk, sqbk)) {
 
                sqwk = reflect_xy(sqwk);
 
                sqw1 = reflect_xy(sqw1);
 
                sqw2 = reflect_xy(sqw2);
 
                sqbk = reflect_xy(sqbk);
 
                sqb1 = reflect_xy(sqb1);
 
                sqb2 = reflect_xy(sqb2);
 
                }
 
 
 
            uInd = TEnumerate2<piw1,piw2,false,false>::Index(sqwk,sqw1,sqw2,sqbk);
 
            CHECK_INF_PAIR(uInd);
 
            if (pib1 == pib2) {
 
                SORT (sqb1, sqb2);
 
                sqb2 = EXCLUDE4(sqb2,sqwk,sqbk,sqw1,sqw2);
 
                return  uInd*(i60*i59/2) +
 
                        sqb2*(sqb2-1)/2+
 
                        EXCLUDE4(sqb1,sqwk,sqbk,sqw1,sqw2);
 
                }
 
            else {
 
                // Divide by 2 to avoid overflow on the 32-bit systems, later
 
                // add to itself to produce the correct result. Only the final
 
                // addition have to be done using 64-bit arithmetic.
 
                uInd *= (i60*i59/2);
 
                return  ((INDEX) uInd) +
 
                          (INDEX) (uInd +
 
                            EXCLUDE4(sqb1,sqwk,sqbk,sqw1,sqw2)*i59 +
 
                            EXCLUDE5(sqb2,sqwk,sqbk,sqw1,sqw2,sqb1));
 
                }
 
            }
 
    }
 
 
 
    static INDEX TB_FASTCALL IndCalcB
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
    {
 
        square   sqwk, sqw1, sqw2, sqbk, sqb1, sqb2, sqMask;
 
        unsigned uInd;
 
 
 
        sqwk = SqFindKing (psqW);
 
        if (piw1 == piw2) {
 
            sqw1 = SqFindFirst  (psqW, piw1);
 
            sqw2 = SqFindSecond (psqW, piw2);
 
            }
 
        else {
 
            SqFind2 (psqW, piw1, sqw1, piw2, sqw2);
 
            }
 
        sqbk = SqFindKing (psqB);
 
        if (pib1 == pib2) {
 
            sqb1 = SqFindFirst  (psqB, pib1);
 
            sqb2 = SqFindSecond (psqB, pib2);
 
            }
 
        else {
 
            SqFind2 (psqB, pib1, sqb1, pib2, sqb2);
 
            }
 
 
 
        if(piw2 == x_piecePawn || pib2 == x_piecePawn)
 
            sqMask = rgsqReflectMaskY[sqbk] ^ rgsqReflectInvertMask[fInvert];
 
        else
 
            sqMask = rgsqReflectMaskYandX[sqbk];
 
 
 
        sqwk ^= sqMask;
 
        sqw1 ^= sqMask;
 
        sqw2 ^= sqMask;
 
        sqbk ^= sqMask;
 
        sqb1 ^= sqMask;
 
        sqb2 ^= sqMask;
 
 
 
        if(x_piecePawn == piw2 || x_piecePawn == pib2) {
 
            // There are pawns on the board
 
            if(XX == sqEnP) {
 
                // No En Passant possible
 
                uInd = TEnumerate2<pib1,pib2,true,true>::Index(sqbk,sqb1,sqb2,sqwk);
 
                CHECK_INF_PAIR(uInd);
 
                if(x_piecePawn == piw1) {
 
                    // all 4 pieces are pawns
 
                    SORT(sqw1, sqw2);
 
                    sqw2 = EXCLUDE2(sqw2,sqb1,sqb2) - i8;
 
                    return uInd*(INDEX)(i46*i45/2) +
 
                           sqw2*(sqw2-1)/2 + EXCLUDE2(sqw1,sqb1,sqw2) - i8;
 
                }
 
                else if(x_piecePawn == piw2) {
 
                    if(x_piecePawn == pib1) {
 
                        // 1 white, 2 black pawns
 
                        return uInd*(INDEX)(i46*i59) +
 
                               (EXCLUDE2(sqw2,sqb1,sqb2)-i8)*i59 +
 
                               EXCLUDE5(sqw1,sqw2,sqb1,sqb2,sqwk,sqbk);
 
                    }
 
                    else if(x_piecePawn == pib2) {
 
                        // 1 white, 1 black pawn
 
                        return uInd*(INDEX)(i47*i59) +
 
                               (EXCLUDE1(sqw2,sqb2)-i8)*i59 +
 
                               EXCLUDE5(sqw1,sqw2,sqb1,sqb2,sqwk,sqbk);
 
                    }
 
                    else {
 
                        // only 1 white pawn
 
                        return uInd*(INDEX)(i48*i59) +
 
                               (sqw2 - i8)*i59 +
 
                               EXCLUDE5(sqw1,sqw2,sqb1,sqb2,sqwk,sqbk);
 
                    }
 
                }
 
                else if(piw1 == piw2) {
 
                    // no white pawns, two identical white pieces
 
                    SORT(sqw1, sqw2);
 
                    sqw2 = EXCLUDE4(sqw2,sqb1,sqb2,sqwk,sqbk);
 
                    return uInd*(INDEX)(i60*i59/2) +
 
                           sqw2*(sqw2-1)/2 +
 
                           EXCLUDE4(sqw1,sqb1,sqb2,sqwk,sqbk);
 
                }
 
                else {
 
                    // no white pawns, two different white pieces
 
                    return uInd*(INDEX)(i60*i59) +
 
                           EXCLUDE4(sqw2,sqb1,sqb2,sqwk,sqbk)*i59 +
 
                           EXCLUDE5(sqw1,sqw2,sqb1,sqb2,sqwk,sqbk);
 
                }
 
            }
 
            else {
 
                // En Passant possible
 
                sqEnP ^= sqMask;
 
                if(x_piecePawn == piw1) {
 
                    // all 4 pieces are pawns
 
                    uInd = rgcPairPawnPresent[x_piecePawn][x_piecePawn];
 
                    return uInd*(INDEX)(i46*i45/2) +
 
                           IndHalfKings(sqbk,sqwk)*(i14*i44*i43) +
 
                           IndEnPassant22B(sqw1, sqw2, sqb1, sqb2, sqEnP);
 
                }
 
                else if(x_piecePawn == pib1) {
 
                    // 1 white, 2 black pawns
 
                    assert(x_piecePawn == piw2);
 
                    uInd = rgcPairPawnPresent[x_piecePawn][x_piecePawn];
 
                    return uInd*(INDEX)(i46*i59) +
 
                           IndHalfKings(sqbk,sqwk)*(i14*i44*i57) +
 
                           EXCLUDE7(sqw1,sqw2,sqb1,sqb2,sqbk,sqwk,sqEnP,sqEnP-8)*(i44*i14)+
 
                           IndEnPassant12B(sqw2, sqb1, sqb2, sqEnP);
 
                }
 
                else {
 
                    // 1 white, 1 black pawn
 
                    assert(x_piecePawn == piw2 && x_piecePawn == pib2);
 
                    uInd = TEnumerate1<pib1, true, true>::
 
                           Index(sqbk,sqb1,sqwk);
 
                    CHECK_INF_SINGLE(uInd);
 
                    return rgcPairPawnPresent[pib1][x_piecePawn]*((INDEX)(i47*i59)) +
 
                           (uInd*(i14*i57) +
 
                            EXCLUDE7(sqw1,sqw2,sqb1,sqb2,sqwk,sqbk,sqEnP,sqEnP-8)*i14 +
 
                            IndEnPassant11B(sqw2,sqb2,sqEnP));
 
                }
 
            }
 
        }
 
        else {
 
            // no pawns at all
 
            if (!FInTriangle (sqbk, sqwk)) {
 
            sqwk = reflect_xy(sqwk);
 
            sqw1 = reflect_xy(sqw1);
 
            sqw2 = reflect_xy(sqw2);
 
            sqbk = reflect_xy(sqbk);
 
            sqb1 = reflect_xy(sqb1);
 
            sqb2 = reflect_xy(sqb2);
 
            }
 
            uInd = TEnumerate2<pib1,pib2,false,false>::Index(sqbk,sqb1,sqb2,sqwk);
 
            CHECK_INF_PAIR(uInd);
 
            if (piw1 == piw2) {
 
            SORT (sqw1, sqw2);
 
                sqw2 = EXCLUDE4(sqw2,sqbk,sqwk,sqb1,sqb2);
 
                return  uInd*(i60*i59/2) +
 
                    sqw2*(sqw2-1)/2+
 
                        EXCLUDE4(sqw1,sqbk,sqwk,sqb1,sqb2);
 
            }
 
            else {
 
            // Divide by 2 to avoid overflow on the 32-bit systems, later
 
            // add to itself to produce the correct result. Only the final
 
                // addition have to be done using 64-bit arithmetic.
 
                uInd *= (i60*i59/2);
 
                return  ((INDEX) uInd) +
 
                         (INDEX) (uInd +
 
                          EXCLUDE4(sqw1,sqbk,sqwk,sqb1,sqb2)*i59 +
 
                           EXCLUDE5(sqw2,sqbk,sqwk,sqb1,sqb2,sqw1));
 
            }
 
        }
 
    }
 
 
 
    // IndCalcBF should replace IndCalcB for symmetric endgames
 
 
 
    static INDEX TB_FASTCALL IndCalcBF
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int fInvert
 
        )
 
    {
 
            return IndCalcW(psqB, psqW, sqEnP, !fInvert);
 
    }
 
};
 
 
 
#endif  // T33
 
 
 
#if defined (T42_INCLUDE)
 
 
 
// TODO: Add code for the TBs with pawns
 
 
 
template <int piw1, int piw2, int piw3, int pib1> class T42
 
    {
 
public:
 
    static INDEX TB_FASTCALL IndCalcW
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        unsigned uInd;
 
        square sqwk, sqw1, sqw2, sqw3, sqbk, sqb1, sqMask;
 
 
 
        sqwk = SqFindKing (psqW);
 
        sqw1 = SqFindFirst (psqW, piw1);
 
        if (piw1 == piw2 && piw2 == piw3)
 
            {
 
            sqw2 = SqFindSecond (psqW, piw2);
 
            sqw3 = SqFindThird (psqW, piw3);
 
            }
 
        else if (piw1 == piw2)
 
            {
 
            sqw2 = SqFindSecond (psqW, piw2);
 
            sqw3 = SqFindFirst (psqW, piw3);
 
            }
 
        else if (piw2 == piw3)
 
            {
 
            sqw2 = SqFindFirst (psqW, piw2);
 
            sqw3 = SqFindSecond (psqW, piw3);
 
            }
 
        else
 
            {
 
            sqw2 = SqFindFirst (psqW, piw2);
 
            sqw3 = SqFindFirst (psqW, piw3);
 
            }
 
        sqbk = SqFindKing (psqB);
 
        sqb1 = SqFindOne  (psqB, pib1);
 
 
 
        if (x_piecePawn == piw3 || x_piecePawn == pib1)
 
            sqMask = rgsqReflectMaskY [sqwk] ^ rgsqReflectInvertMask [fInvert];
 
        else
 
            sqMask = rgsqReflectMaskYandX [sqwk];
 
        sqwk ^= sqMask;
 
        sqbk ^= sqMask;
 
        sqw1 ^= sqMask;
 
        sqw2 ^= sqMask;
 
        sqw3 ^= sqMask;
 
        sqb1 ^= sqMask;
 
 
 
        if (x_piecePawn == piw3 || x_piecePawn == pib1)
 
            {
 
            // There are pawns on the board
 
            if (x_piecePawn == pib1)
 
                {
 
                // Black pawn
 
                if (x_piecePawn == piw1)
 
                    {
 
                    // All 4 pieces are pawns
 
                    if (XX == sqEnP)
 
                        {
 
                        uInd = TEnumerate3<x_piecePawn,x_piecePawn,x_piecePawn,true,false>::
 
                                Index(sqwk,sqw1,sqw2,sqw3,sqbk);
 
                        CHECK_INF_TRIPLE(uInd);
 
                        return uInd*i45 + EXCLUDE3(sqb1,sqw1,sqw2,sqw3)-i8; // 45
 
                        }
 
                    else
 
                        {
 
                        // En passant capture
 
                        uInd = rgcTriplePawnPresent[x_piecePawn][x_piecePawn][x_piecePawn];
 
                        return  uInd*i45 +
 
                                IndHalfKings(sqwk,sqbk)*(i14*i44*i43/2) +
 
                                IndEnPassant31W (sqw1, sqw2, sqw3, sqb1, sqEnP ^ sqMask);
 
                        }
 
                    }
 
                else if (x_piecePawn == piw2)
 
                    {
 
                    // Two white pawns, one black pawn
 
                    if (XX == sqEnP)
 
                        {
 
                        uInd = TEnumerate3<piw1,x_piecePawn,x_piecePawn,true,false>::
 
                                Index(sqwk,sqw1,sqw2,sqw3,sqbk);
 
                        CHECK_INF_TRIPLE(uInd);
 
                        return uInd*(INDEX)i46 + (EXCLUDE2(sqb1,sqw2,sqw3)-i8);   // 46
 
                        }
 
                    else
 
                        {
 
                        // En passant capture
 
                        uInd = TEnumerate1<piw1,true,false>::Index(sqwk,sqw1,sqbk);
 
                        CHECK_INF_SINGLE(uInd);
 
                        return  rgcTriplePawnPresent[piw1][x_piecePawn][x_piecePawn]*(INDEX)i46 +
 
                                (uInd*(i14*i44) + IndEnPassant21W (sqw2, sqw3, sqb1, sqEnP ^ sqMask));
 
                        }
 
                    }
 
                else if (x_piecePawn == piw3)
 
                    {
 
                    // One white pawn, one black pawn
 
                    if (XX == sqEnP)
 
                        {
 
                        uInd = TEnumerate3<piw1,piw2,x_piecePawn,true,false>::
 
                                Index(sqwk,sqw1,sqw2,sqw3,sqbk);
 
                        CHECK_INF_TRIPLE(uInd);
 
                        return  uInd*((INDEX)i47) + (EXCLUDE1(sqb1,sqw3)-i8);    // 47
 
                        }
 
                    else
 
                        {
 
                        // En passant capture
 
                        uInd = TEnumerate2<piw1,piw2,true,false>::Index(sqwk,sqw1,sqw2,sqbk);
 
                        CHECK_INF_PAIR(uInd);
 
                        return  rgcTriplePawnPresent[piw1][piw2][x_piecePawn]*(INDEX)i47 +
 
                                (uInd*i14 + IndEnPassant11W (sqw3, sqb1, sqEnP ^ sqMask));
 
                        }
 
                    }
 
                else
 
                    {
 
                    // Only black pawn
 
                    uInd = TEnumerate3<piw1,piw2,piw3,true,false>::
 
                            Index(sqwk,sqw1,sqw2,sqw3,sqbk);
 
                    CHECK_INF_TRIPLE(uInd);
 
                    return  (uInd*3)*(INDEX)16 + (sqb1-i8); // 48
 
                    }
 
                }
 
            else
 
                {
 
                // No black pawn
 
                uInd = TEnumerate3<piw1,piw2,piw3,true,false>::
 
                    Index(sqwk,sqw1,sqw2,sqw3,sqbk);
 
                CHECK_INF_TRIPLE(uInd);
 
                return uInd*(INDEX)i59 + EXCLUDE5(sqb1,sqwk,sqbk,sqw1,sqw2,sqw3);    // 59
 
                }
 
            }
 
        else
 
            {
 
            // No pawns
 
            if (!FInTriangle (sqwk, sqbk))
 
                {
 
                sqwk = reflect_xy(sqwk);
 
                sqw1 = reflect_xy(sqw1);
 
                sqw2 = reflect_xy(sqw2);
 
                sqw3 = reflect_xy(sqw3);
 
                sqbk = reflect_xy(sqbk);
 
                sqb1 = reflect_xy(sqb1);
 
                };
 
            uInd = TEnumerate3<piw1,piw2,piw3,false,false>::Index(sqwk,sqw1,sqw2,sqw3,sqbk);
 
            CHECK_INF_TRIPLE(uInd);
 
            return uInd*(INDEX)i59 + EXCLUDE5(sqb1,sqwk,sqbk,sqw1,sqw2,sqw3);   // 59
 
            }
 
        }
 
 
 
    static INDEX TB_FASTCALL IndCalcB
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        unsigned uInd;
 
        square sqwk, sqw1, sqw2, sqw3, sqbk, sqb1, sqMask, sqTemp;
 
 
 
        sqwk = SqFindKing (psqW);
 
        sqw1 = SqFindFirst (psqW, piw1);
 
        if (piw1 == piw2 && piw2 == piw3)
 
            {
 
            sqw2 = SqFindSecond (psqW, piw2);
 
            sqw3 = SqFindThird (psqW, piw3);
 
            }
 
        else if (piw1 == piw2)
 
            {
 
            sqw2 = SqFindSecond (psqW, piw2);
 
            sqw3 = SqFindFirst (psqW, piw3);
 
            }
 
        else if (piw2 == piw3)
 
            {
 
            sqw2 = SqFindFirst (psqW, piw2);
 
            sqw3 = SqFindSecond (psqW, piw3);
 
            }
 
        else
 
            {
 
            sqw2 = SqFindFirst (psqW, piw2);
 
            sqw3 = SqFindFirst (psqW, piw3);
 
            }
 
        sqbk = SqFindKing (psqB);
 
        sqb1 = SqFindOne  (psqB, pib1);
 
 
 
        if (x_piecePawn == piw3 || x_piecePawn == pib1)
 
            sqMask = rgsqReflectMaskY [sqbk] ^ rgsqReflectInvertMask [fInvert];
 
        else
 
            sqMask = rgsqReflectMaskYandX [sqbk];
 
        sqwk ^= sqMask;
 
        sqbk ^= sqMask;
 
        sqw1 ^= sqMask;
 
        sqw2 ^= sqMask;
 
        sqw3 ^= sqMask;
 
        sqb1 ^= sqMask;
 
 
 
        if (x_piecePawn == piw3 || x_piecePawn == pib1)
 
            {
 
            // There are pawns on the board
 
            if (x_piecePawn == pib1)
 
                {
 
                // Black pawn
 
                if (x_piecePawn == piw1)
 
                    {
 
                    // All 4 pieces are pawns
 
                    SORT (sqw1, sqw2);
 
                    SORT (sqw2, sqw3);
 
                    SORT (sqw1, sqw2);
 
                    if (XX == sqEnP)
 
                        {
 
                        sqw3 = EXCLUDE1(sqw3,sqb1)-i8;                  // 47
 
                        sqw2 = EXCLUDE1(sqw2,sqb1)-i8;                  // 47
 
                        uInd = TEnumerate1<x_piecePawn,true,true>::Index(sqbk,sqb1,sqwk);
 
                        CHECK_INF_SINGLE(uInd);
 
                        return  uInd*(i47*i46*i45/6) +
 
                                sqw3*(sqw3-1)*(sqw3-2)/6 +
 
                                sqw2*(sqw2-1)/2 +
 
                                EXCLUDE1(sqw1,sqb1)-i8; // 47*46*45/6
 
                        }
 
                    else
 
                        // En passant capture
 
                        return  rgcSinglePawnPresent[x_piecePawn]*(i47*i46*i45/6) +
 
                                IndHalfKings(sqbk,sqwk)*(i44*i43/2*i14) +
 
                                IndEnPassant31B (sqw1, sqw2, sqw3, sqb1, sqEnP ^ sqMask);
 
                    }
 
                else if (x_piecePawn == piw2)
 
                    {
 
                    // Two white pawns, one black pawn
 
                    SORT (sqw2, sqw3);
 
                    if (XX == sqEnP)
 
                        {
 
                        sqTemp = EXCLUDE1(sqw3,sqb1)-i8;                    // 47
 
                        uInd = TEnumerate1<x_piecePawn,true,true>::
 
                                    Index(sqbk,sqb1,sqwk);
 
                        CHECK_INF_SINGLE(uInd);
 
                        return (uInd*(i59*i47)*(INDEX)(i46/2)) +
 
                                (EXCLUDE5(sqw1,sqwk,sqbk,sqw2,sqw3,sqb1)*(i47*i46/2) +  // 59
 
                                 sqTemp*(sqTemp-1)/2 +
 
                                 EXCLUDE1(sqw2,sqb1)-i8);   // 47*46/2
 
                        }
 
                    else
 
                        {
 
                        // En passant capture
 
                        sqEnP ^= sqMask;
 
                        uInd = rgcSinglePawnPresent[x_piecePawn];
 
                        return (uInd*(i59*i47))*(INDEX)(i46/2) +
 
                                (IndHalfKings(sqbk,sqwk)*(i57*i44*i14) +
 
                                 EXCLUDE7(sqw1,sqwk,sqbk,sqw2,sqw3,sqb1,sqEnP,sqEnP-8)*(i44*i14) +  // 57
 
                                 IndEnPassant21B (sqw2, sqw3, sqb1, sqEnP));
 
                        }
 
                    }
 
                else if (x_piecePawn == piw3)
 
                    {
 
                    // One white pawn, one black pawn
 
                    if (piw1 == piw2)
 
                        {
 
                        // Two identical white pieces
 
                        SORT (sqw1, sqw2);
 
                        if (XX == sqEnP)
 
                            {
 
                            sqw2 = EXCLUDE4(sqw2,sqwk,sqbk,sqw3,sqb1);
 
                            sqw1 = EXCLUDE4(sqw1,sqwk,sqbk,sqw3,sqb1);
 
                            uInd = TEnumerate1<x_piecePawn,true,true>::Index(sqbk,sqb1,sqwk);
 
                            CHECK_INF_SINGLE(uInd);
 
                            return  (uInd*(i59*i47))*((INDEX)i60/2) +
 
                                    ((sqw2*(sqw2-1)/2+sqw1)*i47 +   // 60*59/2
 
                                     EXCLUDE1(sqw3,sqb1)-i8);           // 47
 
                            }
 
                        else
 
                            {
 
                            // En passant capture
 
                            sqEnP ^= sqMask;
 
                            sqw2 = EXCLUDE6(sqw2,sqwk,sqbk,sqw3,sqb1,sqEnP,sqEnP-8);
 
                            sqw1 = EXCLUDE6(sqw1,sqwk,sqbk,sqw3,sqb1,sqEnP,sqEnP-8);
 
                            uInd = rgcSinglePawnPresent[x_piecePawn];
 
                            return  (uInd*(i59*i47))*((INDEX)i60/2) +
 
                                    (IndHalfKings(sqbk,sqwk)*(i58*i57/2*i14) +
 
                                     (sqw2*(sqw2-1)/2+sqw1)*i14 + // 58*57/2
 
                                     IndEnPassant11B (sqw3, sqb1, sqEnP));
 
                            }
 
                        }
 
                    else
 
                        {
 
                        // Two different white pieces
 
                        if (XX == sqEnP)
 
                            {
 
                            uInd = TEnumerate1<x_piecePawn,true,true>::Index(sqbk,sqb1,sqwk);
 
                            CHECK_INF_SINGLE(uInd);
 
                            return  (uInd*(i59*i47))*((INDEX)i60) +
 
                                    (EXCLUDE4(sqw1,sqwk,sqbk,sqw3,sqb1)*i59*i47 +   // 60
 
                                     EXCLUDE5(sqw2,sqwk,sqbk,sqw1,sqw3,sqb1)*i47 +  // 59
 
                                     EXCLUDE1(sqw3,sqb1)-i8);                       // 47
 
                            }
 
                        else
 
                            {
 
                            // En passant capture
 
                            sqEnP ^= sqMask;
 
                            uInd = rgcSinglePawnPresent[x_piecePawn];
 
                            return  (uInd*(i59*i47))*((INDEX)i60) +
 
                                    (IndHalfKings(sqbk,sqwk)*(i58*i57*i14) +
 
                                     EXCLUDE6(sqw1,sqwk,sqbk,sqw3,sqb1,sqEnP,sqEnP-8)*(i57*i14) +   // 58
 
                                     EXCLUDE7(sqw2,sqwk,sqbk,sqw1,sqw3,sqb1,sqEnP,sqEnP-8)*i14 +        // 57
 
                                     IndEnPassant11B (sqw3, sqb1, sqEnP));
 
                            }
 
                        }
 
                    }
 
                else
 
                    {
 
                    // Only black pawn
 
                    uInd = TEnumerate1<x_piecePawn,true,true>::Index(sqbk,sqb1,sqwk);
 
                    CHECK_INF_SINGLE(uInd);
 
                    if (piw1 == piw3)
 
                        {
 
                        // 3 identical white pieces
 
                        SORT (sqw1, sqw2);
 
                        SORT (sqw2, sqw3);
 
                        SORT (sqw1, sqw2);
 
                        sqw1 = EXCLUDE3(sqw1,sqwk,sqbk,sqb1);                       // 61
 
                        sqw2 = EXCLUDE3(sqw2,sqwk,sqbk,sqb1);                       // 61
 
                        sqw3 = EXCLUDE3(sqw3,sqwk,sqbk,sqb1);                       // 61
 
                        return  uInd*(i61*i60*i59/6) +
 
                                sqw3*(sqw3-1)*(sqw3-2)/6 + sqw2*(sqw2-1)/2 + sqw1;  // 61*60*59/6
 
                        }
 
                    else if (piw1 == piw2)
 
                        {
 
                        // 2 identical major white pieces
 
                        SORT (sqw1, sqw2);
 
                        sqw3 = EXCLUDE5(sqw3,sqwk,sqbk,sqw1,sqw2,sqb1);
 
                        sqw1 = EXCLUDE3(sqw1,sqwk,sqbk,sqb1);               // 61
 
                        sqw2 = EXCLUDE3(sqw2,sqwk,sqbk,sqb1);               // 61
 
                        return  (uInd*(i61*i59))*(INDEX)(i60/2) +
 
                                ((sqw2*(sqw2-1)/2 + sqw1)*i59 +             // 61*60/2
 
                                 sqw3);                                     // 59
 
                        }
 
                    else if (piw2 == piw3)
 
                        {
 
                        // 2 identical minor white pieces
 
                        SORT (sqw2, sqw3);
 
                        sqw2 = EXCLUDE4(sqw2,sqwk,sqbk,sqw1,sqb1);              // 60
 
                        sqw3 = EXCLUDE4(sqw3,sqwk,sqbk,sqw1,sqb1);              // 60
 
                        return  (uInd*(i61*i59))*(INDEX)(i60/2) +
 
                                (EXCLUDE3(sqw1,sqwk,sqbk,sqb1)*(i60*i59/2) +    // 61
 
                                 sqw3*(sqw3-1)/2 + sqw2);                       // 60*59/2
 
                        }
 
                    else
 
                        {
 
                        // All 3 white pieces are different
 
                        return  (uInd*(i61*i59))*(INDEX)i60 +
 
                                (EXCLUDE3(sqw1,sqwk,sqbk,sqb1)*(i60*i59) +  // 61
 
                                 EXCLUDE4(sqw2,sqwk,sqbk,sqw1,sqb1)*i59 +   // 60
 
                                 EXCLUDE5(sqw3,sqwk,sqbk,sqw1,sqw2,sqb1));  // 59
 
                        }
 
                    }
 
                }
 
            else
 
                {
 
                // No black pawn
 
                uInd = TEnumerate1<pib1,true,true>::Index(sqbk,sqb1,sqwk);
 
                CHECK_INF_SINGLE(uInd);
 
                if (x_piecePawn == piw1)
 
                    {
 
                    // Only 3 white pawns
 
                    SORT (sqw1, sqw2);
 
                    SORT (sqw2, sqw3);
 
                    SORT (sqw1, sqw2);
 
                    sqw3 -= i8;
 
                    sqw2 -= i8;
 
                    return  uInd*(i48*47*i46/6) +
 
                            sqw3*(sqw3-1)*(sqw3-2)/6+sqw2*(sqw2-1)/2+sqw1-i8;           // 48*47*46/6
 
                    }
 
                else if (x_piecePawn == piw2)
 
                    {
 
                    // 2 white pawns, one non-pawn
 
                    SORT (sqw2, sqw3);
 
                    sqTemp = sqw3 - i8;
 
                    return  (uInd*(i59*47))*(INDEX)(i48/2) +
 
                            (EXCLUDE5(sqw1,sqwk,sqbk,sqb1,sqw2,sqw3)*(i48*i47/2) +
 
                             sqTemp*(sqTemp-1)/2+sqw2-i8);          // 48*47/2
 
                    }
 
                else if (piw1 == piw2)
 
                    {
 
                    // One white pawn, 2 identical white pieces
 
                    SORT (sqw1, sqw2);
 
                    sqw1 = EXCLUDE4(sqw1,sqwk,sqbk,sqb1,sqw3);
 
                    sqw2 = EXCLUDE4(sqw2,sqwk,sqbk,sqb1,sqw3);
 
                    return  (uInd*(i60*i59/2))*(INDEX)i48 +
 
                            ((sqw2*(sqw2-1)/2+sqw1)*i48 +   // 60*59/2
 
                             sqw3-i8);                      // 48
 
                    }
 
                else
 
                    {
 
                    // One white pawn, 2 different white pieces
 
                    return  (uInd*(i60*i59))*(INDEX)i48 +
 
                            (EXCLUDE4(sqw1,sqwk,sqbk,sqb1,sqw3)*(i59*i48) + // 60
 
                             EXCLUDE5(sqw2,sqwk,sqbk,sqb1,sqw1,sqw3)*i48 +  // 59
 
                             sqw3-i8);                                      // 48
 
                    }
 
                }
 
            }
 
        else
 
            {
 
            // No pawns
 
            if (!FInTriangle (sqbk, sqwk))
 
                {
 
                sqwk = reflect_xy(sqwk);
 
                sqw1 = reflect_xy(sqw1);
 
                sqw2 = reflect_xy(sqw2);
 
                sqw3 = reflect_xy(sqw3);
 
                sqbk = reflect_xy(sqbk);
 
                sqb1 = reflect_xy(sqb1);
 
                };
 
            uInd = TEnumerate1<pib1,false,false>::Index(sqbk,sqb1,sqwk);
 
            CHECK_INF_SINGLE(uInd);
 
            if (piw1 == piw2 && piw2 == piw3)
 
                {
 
                // All 3 pieces equal
 
                SORT (sqw1, sqw2);
 
                SORT (sqw2, sqw3);
 
                SORT (sqw1, sqw2);
 
                sqw3 = EXCLUDE3(sqw3,sqwk,sqbk,sqb1);   // 61
 
                sqw2 = EXCLUDE3(sqw2,sqwk,sqbk,sqb1);
 
                return  uInd*(i61*i60*i59/6) +
 
                        sqw3*(sqw3-1)*(sqw3-2)/6+
 
                        sqw2*(sqw2-1)/2+
 
                        EXCLUDE3(sqw1,sqwk,sqbk,sqb1);  // 61*60*59/6
 
                }
 
            else if (piw1 == piw2)
 
                {
 
                // 2 major pieces equal
 
                SORT (sqw1, sqw2);
 
                sqw2 = EXCLUDE4(sqw2,sqwk,sqbk,sqw3,sqb1);                          // 60
 
                return uInd*(i60*i59/2*i61) +
 
                        (sqw2*(sqw2-1)/2+EXCLUDE4(sqw1,sqwk,sqbk,sqw3,sqb1))*i61 +  // 60*59/2
 
                        EXCLUDE3(sqw3,sqwk,sqbk,sqb1);                              // 61
 
                }
 
            else if (piw2 == piw3)
 
                {
 
                // 2 minor pieces equal
 
                SORT (sqw2, sqw3);
 
                sqw3 = EXCLUDE4(sqw3,sqwk,sqbk,sqw1,sqb1);                  // 60
 
                return uInd*(i61*i60*i59/2) +
 
                        EXCLUDE3(sqw1,sqwk,sqbk,sqb1)*(i60*i59/2) +         // 62
 
                        sqw3*(sqw3-1)/2+EXCLUDE4(sqw2,sqwk,sqbk,sqw1,sqb1); // 60*59/2
 
                }
 
            else
 
                {
 
                uInd *= i61*i60*i59/2;
 
                return (INDEX) uInd + 
 
                       (INDEX) (uInd +
 
                                EXCLUDE3(sqw1,sqwk,sqbk,sqb1)*(i60*i59) +   // 61
 
                                EXCLUDE4(sqw2,sqwk,sqbk,sqw1,sqb1)*i59 +    // 60
 
                                EXCLUDE5(sqw3,sqwk,sqbk,sqw1,sqw2,sqb1));   // 59
 
                }
 
            }
 
        }
 
    };
 
 
 
#endif  // T42
 
 
 
#else   // Old SJE schema ------------------------------------------------------
 
 
 
/* scanning pattern: triangle encoding */
 
 
 
static const INDEX sptriv[] = 
 
    {
 
     0,  1,  2,  3, -1, -1, -1, -1,
 
    -1,  4,  5,  6, -1, -1, -1, -1,
 
    -1, -1,  7,  8, -1, -1, -1, -1,
 
    -1, -1, -1,  9, -1, -1, -1, -1,
 
    -1, -1, -1, -1, -1, -1, -1, -1,
 
    -1, -1, -1, -1, -1, -1, -1, -1,
 
    -1, -1, -1, -1, -1, -1, -1, -1,
 
    -1, -1, -1, -1, -1, -1, -1, -1,
 
    };
 
 
 
/* scanning pattern: queenside flank encoding */
 
 
 
static const INDEX spqsfv[] = 
 
    {
 
     0,  1,  2,  3, -1, -1, -1, -1,
 
     4,  5,  6,  7, -1, -1, -1, -1,
 
     8,  9, 10, 11, -1, -1, -1, -1,
 
    12, 13, 14, 15, -1, -1, -1, -1,
 
    16, 17, 18, 19, -1, -1, -1, -1,
 
    20, 21, 22, 23, -1, -1, -1, -1,
 
    24, 25, 26, 27, -1, -1, -1, -1,
 
    28, 29, 30, 31, -1, -1, -1, -1,
 
    };
 
 
 
/*--> CalcIndex3A: calculate index, mode 3A */
 
INLINE INDEX CalcIndex3A
 
    (
 
    square sq0,
 
    square sq1,
 
    square sq2
 
    )
 
    {
 
    INDEX index;
 
 
 
    if (TbRow(sq2) > x_row_4)
 
        {
 
        sq0 = reflect_x(sq0);
 
        sq1 = reflect_x(sq1);
 
        sq2 = reflect_x(sq2);
 
        };
 
 
 
    if (TbColumn(sq2) > x_column_d)
 
        {
 
        sq0 = reflect_y(sq0);
 
        sq1 = reflect_y(sq1);
 
        sq2 = reflect_y(sq2);
 
        };
 
 
 
    if (TbRow(sq2) > TbColumn(sq2))
 
        {
 
        sq0 = reflect_xy(sq0);
 
        sq1 = reflect_xy(sq1);
 
        sq2 = reflect_xy(sq2);
 
        };
 
 
 
    index =
 
        sq0 +
 
        sq1 * i64 +
 
        sptriv [sq2] * i64 * i64;
 
 
 
    return (index);
 
    }
 
 
 
/*--> CalcIndex3B: calculate index, mode 3B */
 
INLINE INDEX CalcIndex3B
 
    (
 
    square sq0,
 
    square sq1,
 
    square sq2
 
    )
 
    {
 
    INDEX index;
 
 
 
    if (TbColumn(sq1) > x_column_d)
 
        {
 
        sq0 = reflect_y(sq0);
 
        sq1 = reflect_y(sq1);
 
        sq2 = reflect_y(sq2);
 
        };
 
 
 
    index =
 
        sq0 +
 
        spqsfv [sq1] * i64 +
 
        sq2 * (i64 / 2) * i64;
 
 
 
    return (index);
 
    }
 
 
 
/*--> CalcIndex4A: calculate index, mode 4A */
 
INLINE INDEX CalcIndex4A
 
    (
 
    square sq0,
 
    square sq1,
 
    square sq2,
 
    square sq3
 
    )
 
    {
 
    INDEX index;
 
 
 
    if (TbRow(sq3) > x_row_4)
 
        {
 
        sq0 = reflect_x(sq0);
 
        sq1 = reflect_x(sq1);
 
        sq2 = reflect_x(sq2);
 
        sq3 = reflect_x(sq3);
 
        };
 
 
 
    if (TbColumn(sq3) > x_column_d)
 
        {
 
        sq0 = reflect_y(sq0);
 
        sq1 = reflect_y(sq1);
 
        sq2 = reflect_y(sq2);
 
        sq3 = reflect_y(sq3);
 
        };
 
 
 
    if (TbRow(sq3) > TbColumn(sq3))
 
        {
 
        sq0 = reflect_xy(sq0);
 
        sq1 = reflect_xy(sq1);
 
        sq2 = reflect_xy(sq2);
 
        sq3 = reflect_xy(sq3);
 
        };
 
 
 
    index =
 
        sq0 +
 
        sq1 * i64 +
 
        sq2 * i64 * i64 +
 
        sptriv [sq3] * i64 * i64 * i64;
 
 
 
    return (index);
 
    }
 
 
 
/*--> CalcIndex4B: calculate index, mode 4B */
 
INLINE INDEX CalcIndex4B
 
    (
 
    square sq0,
 
    square sq1,
 
    square sq2,
 
    square sq3
 
    )
 
    {
 
    INDEX index;
 
 
 
    if (TbColumn(sq3) > x_column_d)
 
        {
 
        sq0 = reflect_y(sq0);
 
        sq1 = reflect_y(sq1);
 
        sq2 = reflect_y(sq2);
 
        sq3 = reflect_y(sq3);
 
        };
 
 
 
    index =
 
        sq0 +
 
        sq1 * i64 +
 
        sq2 * i64 * i64 +
 
        spqsfv [sq3] * i64 * i64 * i64;
 
 
 
    return (index);
 
    }
 
 
 
/*--> CalcIndex4C: calculate index, mode 4C */
 
INLINE INDEX CalcIndex4C
 
    (
 
    square sq0,
 
    square sq1,
 
    square sq2,
 
    square sq3
 
    )
 
    {
 
    INDEX index;
 
 
 
    if (TbColumn(sq2) > x_column_d)
 
        {
 
        sq0 = reflect_y(sq0);
 
        sq1 = reflect_y(sq1);
 
        sq2 = reflect_y(sq2);
 
        sq3 = reflect_y(sq3);
 
        };
 
 
 
    index =
 
        sq0 +
 
        sq1 * i64 +
 
        spqsfv [sq2] * i64 * i64 +
 
        sq3 * (i64 / 2) * i64 * i64;
 
 
 
    return (index);
 
    }
 
 
 
/*--> CalcIndex5A: calculate index, mode 5A */
 
INLINE INDEX CalcIndex5A
 
    (
 
    square sq0,
 
    square sq1,
 
    square sq2,
 
    square sq3,
 
    square sq4
 
    )
 
    {
 
    INDEX index;
 
 
 
    if (TbRow(sq4) > x_row_4)
 
        {
 
        sq0 = reflect_x(sq0);
 
        sq1 = reflect_x(sq1);
 
        sq2 = reflect_x(sq2);
 
        sq3 = reflect_x(sq3);
 
        sq4 = reflect_x(sq4);
 
        };
 
 
 
    if (TbColumn(sq4) > x_column_d)
 
        {
 
        sq0 = reflect_y(sq0);
 
        sq1 = reflect_y(sq1);
 
        sq2 = reflect_y(sq2);
 
        sq3 = reflect_y(sq3);
 
        sq4 = reflect_y(sq4);
 
        };
 
 
 
    if (TbRow(sq4) > TbColumn(sq4))
 
        {
 
        sq0 = reflect_xy(sq0);
 
        sq1 = reflect_xy(sq1);
 
        sq2 = reflect_xy(sq2);
 
        sq3 = reflect_xy(sq3);
 
        sq4 = reflect_xy(sq4);
 
        };
 
 
 
    index =
 
        sq0 +
 
        sq1 * i64 +
 
        sq2 * i64 * i64 +
 
        sq3 * i64 * i64 * i64 +
 
        sptriv [sq4] * i64 * i64 * i64 * i64;
 
 
 
    return (index);
 
    }
 
 
 
/*--> CalcIndex5B: calculate index, mode 5B */
 
INLINE INDEX CalcIndex5B
 
    (
 
    square sq0,
 
    square sq1,
 
    square sq2,
 
    square sq3,
 
    square sq4
 
    )
 
    {
 
    INDEX index;
 
 
 
    if (TbColumn(sq4) > x_column_d)
 
        {
 
        sq0 = reflect_y(sq0);
 
        sq1 = reflect_y(sq1);
 
        sq2 = reflect_y(sq2);
 
        sq3 = reflect_y(sq3);
 
        sq4 = reflect_y(sq4);
 
        };
 
 
 
    index =
 
        sq0 +
 
        sq1 * i64 +
 
        sq2 * i64 * i64 +
 
        sq3 * i64 * i64 * i64 +
 
        spqsfv [sq4] * i64 * i64 * i64 * i64;
 
 
 
    return (index);
 
    }
 
 
 
/*--> CalcIndex5C: calculate index, mode 5C */
 
INLINE INDEX CalcIndex5C
 
    (
 
    square sq0,
 
    square sq1,
 
    square sq2,
 
    square sq3,
 
    square sq4
 
    )
 
    {
 
    INDEX index;
 
 
 
    if (TbColumn(sq3) > x_column_d)
 
        {
 
        sq0 = reflect_y(sq0);
 
        sq1 = reflect_y(sq1);
 
        sq2 = reflect_y(sq2);
 
        sq3 = reflect_y(sq3);
 
        sq4 = reflect_y(sq4);
 
        };
 
 
 
    index =
 
        sq0 +
 
        sq1 * i64 +
 
        sq2 * i64 * i64 +
 
        spqsfv [sq3] * i64 * i64 * i64 +
 
        sq4 * (i64 / 2) * i64 * i64 * i64;
 
 
 
    return (index);
 
    }
 
 
 
/*--> CalcIndex5D: calculate index, mode 5D */
 
INLINE INDEX CalcIndex5D
 
    (
 
    square sq0,
 
    square sq1,
 
    square sq2,
 
    square sq3,
 
    square sq4
 
    )
 
    {
 
    INDEX index;
 
 
 
    if (TbColumn(sq2) > x_column_d)
 
        {
 
        sq0 = reflect_y(sq0);
 
        sq1 = reflect_y(sq1);
 
        sq2 = reflect_y(sq2);
 
        sq3 = reflect_y(sq3);
 
        sq4 = reflect_y(sq4);
 
        };
 
 
 
    index =
 
        sq0 +
 
        sq1 * i64 +
 
        spqsfv [sq2] * i64 * i64 +
 
        sq3 * (i64 / 2) * i64 * i64 +
 
        sq4 * (i64 / 2) * i64 * i64 * i64;
 
 
 
    return (index);
 
    }
 
 
 
// Calculate index - a lot of functions...
 
 
 
#define IndCalcW    IndCalc
 
#define IndCalcB    IndCalc
 
 
 
template <int pi> class T21
 
    {
 
public:
 
    static INDEX TB_FASTCALL IndCalc
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        square sq0, sq1, sq2;
 
 
 
        sq0 = SqFindKing (psqW);
 
        sq1 = SqFindOne  (psqW, pi);
 
        sq2 = SqFindKing (psqB);
 
 
 
        if (x_piecePawn == pi)
 
            {
 
            if (fInvert)
 
                {
 
                sq0 = reflect_x (sq0);
 
                sq1 = reflect_x (sq1);
 
                sq2 = reflect_x (sq2);
 
                }
 
            return CalcIndex3B (sq0, sq1, sq2);
 
            }
 
        else
 
            return CalcIndex3A (sq0, sq1, sq2);
 
        }
 
    };
 
 
 
template <int pi1, int pi2> class T22
 
    {
 
public:
 
    static INDEX TB_FASTCALL IndCalc
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        square sq0, sq1, sq2, sq3;
 
 
 
        sq0 = SqFindKing (psqW);
 
        sq1 = SqFindOne  (psqW, pi1);
 
        sq2 = SqFindKing (psqB);
 
        sq3 = SqFindOne  (psqB, pi2);
 
 
 
        if (x_piecePawn == pi1 || x_piecePawn == pi2)
 
            {
 
            if (fInvert)
 
                {
 
                sq0 = reflect_x (sq0);
 
                sq1 = reflect_x (sq1);
 
                sq2 = reflect_x (sq2);
 
                sq3 = reflect_x (sq3);
 
                }
 
            return CalcIndex4B (sq0, sq1, sq2, sq3);
 
            }
 
        else
 
            return CalcIndex4A (sq0, sq1, sq2, sq3);
 
        }
 
    };
 
 
 
template <int pi1, int pi2> class T31
 
    {
 
public:
 
    static INDEX TB_FASTCALL IndCalc
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        square sq0, sq1, sq2, sq3;
 
 
 
        sq0 = SqFindKing (psqW);
 
        sq1 = SqFindFirst (psqW, pi1);
 
        if (pi1 == pi2)
 
            sq2 = SqFindSecond (psqW, pi2);
 
        else
 
            sq2 = SqFindFirst (psqW, pi2);
 
        sq3 = SqFindKing (psqB);
 
 
 
        if (x_piecePawn == pi1 || x_piecePawn == pi2)
 
            {
 
            if (fInvert)
 
                {
 
                sq0 = reflect_x (sq0);
 
                sq1 = reflect_x (sq1);
 
                sq2 = reflect_x (sq2);
 
                sq3 = reflect_x (sq3);
 
                }
 
            return CalcIndex4C (sq0, sq1, sq2, sq3);
 
            }
 
        else
 
            return CalcIndex4A (sq0, sq1, sq2, sq3);
 
        }
 
    };
 
 
 
template <int pi1, int pi2, int pi3> class T32
 
    {
 
public:
 
    static INDEX TB_FASTCALL IndCalc
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        square sq0, sq1, sq2, sq3, sq4;
 
 
 
        sq0 = SqFindKing (psqW);
 
        sq1 = SqFindFirst (psqW, pi1);
 
        if (pi1 == pi2)
 
            sq2 = SqFindSecond (psqW, pi2);
 
        else
 
            sq2 = SqFindFirst (psqW, pi2);
 
        sq3 = SqFindKing (psqB);
 
        sq4 = SqFindOne  (psqB, pi3);
 
 
 
        if (x_piecePawn == pi1 || x_piecePawn == pi2 || x_piecePawn == pi3)
 
            {
 
            if (fInvert)
 
                {
 
                sq0 = reflect_x (sq0);
 
                sq1 = reflect_x (sq1);
 
                sq2 = reflect_x (sq2);
 
                sq3 = reflect_x (sq3);
 
                sq4 = reflect_x (sq4);
 
                }
 
            if (x_piecePawn == pi3)
 
                return CalcIndex5B (sq0, sq1, sq2, sq3, sq4);
 
            else
 
                return CalcIndex5D (sq0, sq1, sq2, sq3, sq4);
 
            }
 
        else
 
            return CalcIndex5A (sq0, sq1, sq2, sq3, sq4);
 
        }
 
    };
 
 
 
#if defined (T41_INCLUDE)
 
 
 
template <int pi1, int pi2, int pi3> class T41
 
    {
 
public:
 
    static INDEX TB_FASTCALL IndCalc
 
        (
 
        square  *psqW,
 
        square  *psqB,
 
        square  sqEnP,
 
        int     fInvert
 
        )
 
        {
 
        square sq0, sq1, sq2, sq3, sq4;
 
 
 
        sq0 = SqFindKing (psqW);
 
        sq1 = SqFindFirst (psqW, pi1);
 
        sq2 = SqFindFirst (psqW, pi2);
 
        sq3 = SqFindFirst (psqW, pi3);
 
        sq4 = SqFindKing (psqB);
 
 
 
        if (x_piecePawn == pi1 || x_piecePawn == pi2 || x_piecePawn == pi3)
 
            {
 
            // There are pawns on the board
 
            if (fInvert)
 
                {
 
                sq0 = reflect_x (sq0);
 
                sq1 = reflect_x (sq1);
 
                sq2 = reflect_x (sq2);
 
                sq3 = reflect_x (sq3);
 
                sq4 = reflect_x (sq4);
 
                }
 
            return CalcIndex5C (sq0, sq1, sq2, sq3, sq4);
 
            }
 
        else    // No pawns
 
            return CalcIndex5A (sq0, sq1, sq2, sq3, sq4);
 
        }
 
    };
 
 
 
#endif
 
 
 
#endif  //----------------------------------------------------------------------
 
 
 
// All tablebases enumerated
 
 
 
#define tbid_kk      0
 
#define tbid_kpk     1
 
#define tbid_knk     2
 
#define tbid_kbk     3
 
#define tbid_krk     4
 
#define tbid_kqk     5
 
#define tbid_kpkp    6
 
#define tbid_knkp    7
 
#define tbid_knkn    8
 
#define tbid_kbkp    9
 
#define tbid_kbkn   10
 
#define tbid_kbkb   11
 
#define tbid_krkp   12
 
#define tbid_krkn   13
 
#define tbid_krkb   14
 
#define tbid_krkr   15
 
#define tbid_kqkp   16
 
#define tbid_kqkn   17
 
#define tbid_kqkb   18
 
#define tbid_kqkr   19
 
#define tbid_kqkq   20
 
#define tbid_kppk   21
 
#define tbid_knpk   22
 
#define tbid_knnk   23
 
#define tbid_kbpk   24
 
#define tbid_kbnk   25
 
#define tbid_kbbk   26
 
#define tbid_krpk   27
 
#define tbid_krnk   28
 
#define tbid_krbk   29
 
#define tbid_krrk   30
 
#define tbid_kqpk   31
 
#define tbid_kqnk   32
 
#define tbid_kqbk   33
 
#define tbid_kqrk   34
 
#define tbid_kqqk   35
 
#define tbid_kppkp  36
 
#define tbid_kppkn  37
 
#define tbid_kppkb  38
 
#define tbid_kppkr  39
 
#define tbid_kppkq  40
 
#define tbid_knpkp  41
 
#define tbid_knpkn  42
 
#define tbid_knpkb  43
 
#define tbid_knpkr  44
 
#define tbid_knpkq  45
 
#define tbid_knnkp  46
 
#define tbid_knnkn  47
 
#define tbid_knnkb  48
 
#define tbid_knnkr  49
 
#define tbid_knnkq  50
 
#define tbid_kbpkp  51
 
#define tbid_kbpkn  52
 
#define tbid_kbpkb  53
 
#define tbid_kbpkr  54
 
#define tbid_kbpkq  55
 
#define tbid_kbnkp  56
 
#define tbid_kbnkn  57
 
#define tbid_kbnkb  58
 
#define tbid_kbnkr  59
 
#define tbid_kbnkq  60
 
#define tbid_kbbkp  61
 
#define tbid_kbbkn  62
 
#define tbid_kbbkb  63
 
#define tbid_kbbkr  64
 
#define tbid_kbbkq  65
 
#define tbid_krpkp  66
 
#define tbid_krpkn  67
 
#define tbid_krpkb  68
 
#define tbid_krpkr  69
 
#define tbid_krpkq  70
 
#define tbid_krnkp  71
 
#define tbid_krnkn  72
 
#define tbid_krnkb  73
 
#define tbid_krnkr  74
 
#define tbid_krnkq  75
 
#define tbid_krbkp  76
 
#define tbid_krbkn  77
 
#define tbid_krbkb  78
 
#define tbid_krbkr  79
 
#define tbid_krbkq  80
 
#define tbid_krrkp  81
 
#define tbid_krrkn  82
 
#define tbid_krrkb  83
 
#define tbid_krrkr  84
 
#define tbid_krrkq  85
 
#define tbid_kqpkp  86
 
#define tbid_kqpkn  87
 
#define tbid_kqpkb  88
 
#define tbid_kqpkr  89
 
#define tbid_kqpkq  90
 
#define tbid_kqnkp  91
 
#define tbid_kqnkn  92
 
#define tbid_kqnkb  93
 
#define tbid_kqnkr  94
 
#define tbid_kqnkq  95
 
#define tbid_kqbkp  96
 
#define tbid_kqbkn  97
 
#define tbid_kqbkb  98
 
#define tbid_kqbkr  99
 
#define tbid_kqbkq 100
 
#define tbid_kqrkp 101
 
#define tbid_kqrkn 102
 
#define tbid_kqrkb 103
 
#define tbid_kqrkr 104
 
#define tbid_kqrkq 105
 
#define tbid_kqqkp 106
 
#define tbid_kqqkn 107
 
#define tbid_kqqkb 108
 
#define tbid_kqqkr 109
 
#define tbid_kqqkq 110
 
 
 
#if defined (T41_INCLUDE)
 
#  define tbid_kpppk    111
 
#  define tbid_knppk    112
 
#  define tbid_knnpk    113
 
#  define tbid_knnnk    114
 
#  define tbid_kbppk    115
 
#  define tbid_kbnpk    116
 
#  define tbid_kbnnk    117
 
#  define tbid_kbbpk    118
 
#  define tbid_kbbnk    119
 
#  define tbid_kbbbk    120
 
#  define tbid_krppk    121
 
#  define tbid_krnpk    122
 
#  define tbid_krnnk    123
 
#  define tbid_krbpk    124
 
#  define tbid_krbnk    125
 
#  define tbid_krbbk    126
 
#  define tbid_krrpk    127
 
#  define tbid_krrnk    128
 
#  define tbid_krrbk    129
 
#  define tbid_krrrk    130
 
#  define tbid_kqppk    131
 
#  define tbid_kqnpk    132
 
#  define tbid_kqnnk    133
 
#  define tbid_kqbpk    134
 
#  define tbid_kqbnk    135
 
#  define tbid_kqbbk    136
 
#  define tbid_kqrpk    137
 
#  define tbid_kqrnk    138
 
#  define tbid_kqrbk    139
 
#  define tbid_kqrrk    140
 
#  define tbid_kqqpk    141
 
#  define tbid_kqqnk    142
 
#  define tbid_kqqbk    143
 
#  define tbid_kqqrk    144
 
#  define tbid_kqqqk    145
 
#endif
 
 
 
#if defined (T33_INCLUDE)
 
#  if defined (T41_INCLUDE)
 
#    define BASE_33 145
 
#  else
 
#    define BASE_33 110
 
#  endif
 
#  define tbid_knnknn   (BASE_33 + 1)
 
#  define tbid_kbnknn   (BASE_33 + 2)
 
#  define tbid_kbbknn   (BASE_33 + 3)
 
#  define tbid_kbbkbn   (BASE_33 + 4)
 
#  define tbid_kbbkbb   (BASE_33 + 5)
 
#  define tbid_krnknn   (BASE_33 + 6)
 
#  define tbid_krnkbb   (BASE_33 + 7)
 
#  define tbid_krbknn   (BASE_33 + 8)
 
#  define tbid_krbkbb   (BASE_33 + 9)
 
#  define tbid_krrknn   (BASE_33 + 10)
 
#  define tbid_krrkbn   (BASE_33 + 11)
 
#  define tbid_krrkbb   (BASE_33 + 12)
 
#  define tbid_krrkrn   (BASE_33 + 13)
 
#  define tbid_krrkrb   (BASE_33 + 14)
 
#  define tbid_krrkrr   (BASE_33 + 15)
 
#  define tbid_kqnknn   (BASE_33 + 16)
 
#  define tbid_kqnkbb   (BASE_33 + 17)
 
#  define tbid_kqnkrr   (BASE_33 + 18)
 
#  define tbid_kqbknn   (BASE_33 + 19)
 
#  define tbid_kqbkbb   (BASE_33 + 20)
 
#  define tbid_kqbkrr   (BASE_33 + 21)
 
#  define tbid_kqrknn   (BASE_33 + 22)
 
#  define tbid_kqrkbb   (BASE_33 + 23)
 
#  define tbid_kqrkrr   (BASE_33 + 24)
 
#  define tbid_kqqknn   (BASE_33 + 25)
 
#  define tbid_kqqkbn   (BASE_33 + 26)
 
#  define tbid_kqqkbb   (BASE_33 + 27)
 
#  define tbid_kqqkrn   (BASE_33 + 28)
 
#  define tbid_kqqkrb   (BASE_33 + 29)
 
#  define tbid_kqqkrr   (BASE_33 + 30)
 
#  define tbid_kqqkqn   (BASE_33 + 31)
 
#  define tbid_kqqkqb   (BASE_33 + 32)
 
#  define tbid_kqqkqr   (BASE_33 + 33)
 
#  define tbid_kqqkqq   (BASE_33 + 34)
 
#  if defined (T_INDEX64)
 
#    define tbid_kbnkbn (BASE_33 + 35)
 
#    define tbid_krnkrn (BASE_33 + 36)
 
#    define tbid_krbkrb (BASE_33 + 37)
 
#    define tbid_kqnkqn (BASE_33 + 38)
 
#    define tbid_kqbkqb (BASE_33 + 39)
 
#    define tbid_kqrkqr (BASE_33 + 40)
 
#    define tbid_krnkbn (BASE_33 + 41)
 
#    define tbid_krbkbn (BASE_33 + 42)
 
#    define tbid_krbkrn (BASE_33 + 43)
 
#    define tbid_kqnkbn (BASE_33 + 44)
 
#    define tbid_kqnkrn (BASE_33 + 45)
 
#    define tbid_kqnkrb (BASE_33 + 46)
 
#    define tbid_kqbkbn (BASE_33 + 47)
 
#    define tbid_kqbkrn (BASE_33 + 48)
 
#    define tbid_kqbkrb (BASE_33 + 49)
 
#    define tbid_kqbkqn (BASE_33 + 50)
 
#    define tbid_kqrkbn (BASE_33 + 51)
 
#    define tbid_kqrkrn (BASE_33 + 52)
 
#    define tbid_kqrkrb (BASE_33 + 53)
 
#    define tbid_kqrkqn (BASE_33 + 54)
 
#    define tbid_kqrkqb (BASE_33 + 55)
 
#    define tbid_kppkpp (BASE_33 + 56)
 
#    define tbid_knpkpp (BASE_33 + 57)
 
#    define tbid_knpknp (BASE_33 + 58)
 
#    define tbid_knnkpp (BASE_33 + 59)
 
#    define tbid_knnknp (BASE_33 + 60)
 
#    define tbid_kbpkpp (BASE_33 + 61)
 
#    define tbid_kbpknp (BASE_33 + 62)
 
#    define tbid_kbpknn (BASE_33 + 63)
 
#    define tbid_kbpkbp (BASE_33 + 64)
 
#    define tbid_kbnkpp (BASE_33 + 65)
 
#    define tbid_kbnknp (BASE_33 + 66)
 
#    define tbid_kbnkbp (BASE_33 + 67)
 
#    define tbid_kbbkpp (BASE_33 + 68)
 
#    define tbid_kbbknp (BASE_33 + 69)
 
#    define tbid_kbbkbp (BASE_33 + 70)
 
#    define tbid_krpkpp (BASE_33 + 71)
 
#    define tbid_krpknp (BASE_33 + 72)
 
#    define tbid_krpknn (BASE_33 + 73)
 
#    define tbid_krpkbp (BASE_33 + 74)
 
#    define tbid_krpkbn (BASE_33 + 75)
 
#    define tbid_krpkbb (BASE_33 + 76)
 
#    define tbid_krpkrp (BASE_33 + 77)
 
#    define tbid_krnkpp (BASE_33 + 78)
 
#    define tbid_krnknp (BASE_33 + 79)
 
#    define tbid_krnkbp (BASE_33 + 80)
 
#    define tbid_krnkrp (BASE_33 + 81)
 
#    define tbid_krbkpp (BASE_33 + 82)
 
#    define tbid_krbknp (BASE_33 + 83)
 
#    define tbid_krbkbp (BASE_33 + 84)
 
#    define tbid_krbkrp (BASE_33 + 85)
 
#    define tbid_krrkpp (BASE_33 + 86)
 
#    define tbid_krrknp (BASE_33 + 87)
 
#    define tbid_krrkbp (BASE_33 + 88)
 
#    define tbid_krrkrp (BASE_33 + 89)
 
#    define tbid_kqpkpp (BASE_33 + 90)
 
#    define tbid_kqpknp (BASE_33 + 91)
 
#    define tbid_kqpknn (BASE_33 + 92)
 
#    define tbid_kqpkbp (BASE_33 + 93)
 
#    define tbid_kqpkbn (BASE_33 + 94)
 
#    define tbid_kqpkbb (BASE_33 + 95)
 
#    define tbid_kqpkrp (BASE_33 + 96)
 
#    define tbid_kqpkrn (BASE_33 + 97)
 
#    define tbid_kqpkrb (BASE_33 + 98)
 
#    define tbid_kqpkrr (BASE_33 + 99)
 
#    define tbid_kqpkqp (BASE_33 + 100)
 
#    define tbid_kqnkpp (BASE_33 + 101)
 
#    define tbid_kqnknp (BASE_33 + 102)
 
#    define tbid_kqnkbp (BASE_33 + 103)
 
#    define tbid_kqnkrp (BASE_33 + 104)
 
#    define tbid_kqnkqp (BASE_33 + 105)
 
#    define tbid_kqbkpp (BASE_33 + 106)
 
#    define tbid_kqbknp (BASE_33 + 107)
 
#    define tbid_kqbkbp (BASE_33 + 108)
 
#    define tbid_kqbkrp (BASE_33 + 109)
 
#    define tbid_kqbkqp (BASE_33 + 110)
 
#    define tbid_kqrkpp (BASE_33 + 111)
 
#    define tbid_kqrknp (BASE_33 + 112)
 
#    define tbid_kqrkbp (BASE_33 + 113)
 
#    define tbid_kqrkrp (BASE_33 + 114)
 
#    define tbid_kqrkqp (BASE_33 + 115)
 
#    define tbid_kqqkpp (BASE_33 + 116)
 
#    define tbid_kqqknp (BASE_33 + 117)
 
#    define tbid_kqqkbp (BASE_33 + 118)
 
#    define tbid_kqqkrp (BASE_33 + 119)
 
#    define tbid_kqqkqp (BASE_33 + 120)
 
#    define C33 (tbid_kqqkqp - BASE_33)
 
#  else
 
#    define C33 (tbid_kqqkqq - BASE_33)
 
#  endif
 
#else
 
#  define C33   0
 
#endif
 
 
 
#if defined (T41_INCLUDE)
 
#  define BASE_42   (145 + C33)
 
#else
 
#  define BASE_42   (110 + C33)
 
#endif
 
 
 
#if defined (T42_INCLUDE)
 
#  define tbid_knnnkn   (BASE_42 + 1)
 
#  define tbid_kbnnkn   (BASE_42 + 2)
 
#  define tbid_kbbnkn   (BASE_42 + 3)
 
#  define tbid_kbbbkn   (BASE_42 + 4)
 
#  define tbid_krnnkn   (BASE_42 + 5)
 
#  define tbid_krbbkn   (BASE_42 + 6)
 
#  define tbid_krrnkn   (BASE_42 + 7)
 
#  define tbid_krrbkn   (BASE_42 + 8)
 
#  define tbid_krrrkn   (BASE_42 + 9)
 
#  define tbid_kqnnkn   (BASE_42 + 10)
 
#  define tbid_kqbbkn   (BASE_42 + 11)
 
#  define tbid_kqrrkn   (BASE_42 + 12)
 
#  define tbid_kqqnkn   (BASE_42 + 13)
 
#  define tbid_kqqbkn   (BASE_42 + 14)
 
#  define tbid_kqqrkn   (BASE_42 + 15)
 
#  define tbid_kqqqkn   (BASE_42 + 16)
 
#  define tbid_knnnkb   (BASE_42 + 17)
 
#  define tbid_kbnnkb   (BASE_42 + 18)
 
#  define tbid_kbbnkb   (BASE_42 + 19)
 
#  define tbid_kbbbkb   (BASE_42 + 20)
 
#  define tbid_krnnkb   (BASE_42 + 21)
 
#  define tbid_krbbkb   (BASE_42 + 22)
 
#  define tbid_krrnkb   (BASE_42 + 23)
 
#  define tbid_krrbkb   (BASE_42 + 24)
 
#  define tbid_krrrkb   (BASE_42 + 25)
 
#  define tbid_kqnnkb   (BASE_42 + 26)
 
#  define tbid_kqbbkb   (BASE_42 + 27)
 
#  define tbid_kqrrkb   (BASE_42 + 28)
 
#  define tbid_kqqnkb   (BASE_42 + 29)
 
#  define tbid_kqqbkb   (BASE_42 + 30)
 
#  define tbid_kqqrkb   (BASE_42 + 31)
 
#  define tbid_kqqqkb   (BASE_42 + 32)
 
#  define tbid_knnnkr   (BASE_42 + 33)
 
#  define tbid_kbnnkr   (BASE_42 + 34)
 
#  define tbid_kbbnkr   (BASE_42 + 35)
 
#  define tbid_kbbbkr   (BASE_42 + 36)
 
#  define tbid_krnnkr   (BASE_42 + 37)
 
#  define tbid_krbbkr   (BASE_42 + 38)
 
#  define tbid_krrnkr   (BASE_42 + 39)
 
#  define tbid_krrbkr   (BASE_42 + 40)
 
#  define tbid_krrrkr   (BASE_42 + 41)
 
#  define tbid_kqnnkr   (BASE_42 + 42)
 
#  define tbid_kqbbkr   (BASE_42 + 43)
 
#  define tbid_kqrrkr   (BASE_42 + 44)
 
#  define tbid_kqqnkr   (BASE_42 + 45)
 
#  define tbid_kqqbkr   (BASE_42 + 46)
 
#  define tbid_kqqrkr   (BASE_42 + 47)
 
#  define tbid_kqqqkr   (BASE_42 + 48)
 
#  define tbid_knnnkq   (BASE_42 + 49)
 
#  define tbid_kbnnkq   (BASE_42 + 50)
 
#  define tbid_kbbnkq   (BASE_42 + 51)
 
#  define tbid_kbbbkq   (BASE_42 + 52)
 
#  define tbid_krnnkq   (BASE_42 + 53)
 
#  define tbid_krbbkq   (BASE_42 + 54)
 
#  define tbid_krrnkq   (BASE_42 + 55)
 
#  define tbid_krrbkq   (BASE_42 + 56)
 
#  define tbid_krrrkq   (BASE_42 + 57)
 
#  define tbid_kqnnkq   (BASE_42 + 58)
 
#  define tbid_kqbbkq   (BASE_42 + 59)
 
#  define tbid_kqrrkq   (BASE_42 + 60)
 
#  define tbid_kqqnkq   (BASE_42 + 61)
 
#  define tbid_kqqbkq   (BASE_42 + 62)
 
#  define tbid_kqqrkq   (BASE_42 + 63)
 
#  define tbid_kqqqkq   (BASE_42 + 64)
 
#  if defined (T_INDEX64)
 
#    define tbid_krbnkn (BASE_42 + 65)
 
#    define tbid_kqbnkn (BASE_42 + 66)
 
#    define tbid_kqrnkn (BASE_42 + 67)
 
#    define tbid_kqrbkn (BASE_42 + 68)
 
#    define tbid_krbnkb (BASE_42 + 69)
 
#    define tbid_kqbnkb (BASE_42 + 70)
 
#    define tbid_kqrnkb (BASE_42 + 71)
 
#    define tbid_kqrbkb (BASE_42 + 72)
 
#    define tbid_krbnkr (BASE_42 + 73)
 
#    define tbid_kqbnkr (BASE_42 + 74)
 
#    define tbid_kqrnkr (BASE_42 + 75)
 
#    define tbid_kqrbkr (BASE_42 + 76)
 
#    define tbid_krbnkq (BASE_42 + 77)
 
#    define tbid_kqbnkq (BASE_42 + 78)
 
#    define tbid_kqrnkq (BASE_42 + 79)
 
#    define tbid_kqrbkq (BASE_42 + 80)
 
 
 
#    define tbid_kpppkp (BASE_42 + 81)
 
#    define tbid_knppkp (BASE_42 + 82)
 
#    define tbid_knnpkp (BASE_42 + 83)
 
#    define tbid_knnnkp (BASE_42 + 84)
 
#    define tbid_kbppkp (BASE_42 + 85)
 
#    define tbid_kbnpkp (BASE_42 + 86)
 
#    define tbid_kbnnkp (BASE_42 + 87)
 
#    define tbid_kbbpkp (BASE_42 + 88)
 
#    define tbid_kbbnkp (BASE_42 + 89)
 
#    define tbid_kbbbkp (BASE_42 + 90)
 
#    define tbid_krppkp (BASE_42 + 91)
 
#    define tbid_krnpkp (BASE_42 + 92)
 
#    define tbid_krnnkp (BASE_42 + 93)
 
#    define tbid_krbpkp (BASE_42 + 94)
 
#    define tbid_krbnkp (BASE_42 + 95)
 
#    define tbid_krbbkp (BASE_42 + 96)
 
#    define tbid_krrpkp (BASE_42 + 97)
 
#    define tbid_krrnkp (BASE_42 + 98)
 
#    define tbid_krrbkp (BASE_42 + 99)
 
#    define tbid_krrrkp (BASE_42 + 100)
 
#    define tbid_kqppkp (BASE_42 + 101)
 
#    define tbid_kqnpkp (BASE_42 + 102)
 
#    define tbid_kqnnkp (BASE_42 + 103)
 
#    define tbid_kqbpkp (BASE_42 + 104)
 
#    define tbid_kqbnkp (BASE_42 + 105)
 
#    define tbid_kqbbkp (BASE_42 + 106)
 
#    define tbid_kqrpkp (BASE_42 + 107)
 
#    define tbid_kqrnkp (BASE_42 + 108)
 
#    define tbid_kqrbkp (BASE_42 + 109)
 
#    define tbid_kqrrkp (BASE_42 + 110)
 
#    define tbid_kqqpkp (BASE_42 + 111)
 
#    define tbid_kqqnkp (BASE_42 + 112)
 
#    define tbid_kqqbkp (BASE_42 + 113)
 
#    define tbid_kqqrkp (BASE_42 + 114)
 
#    define tbid_kqqqkp (BASE_42 + 115)
 
#    define tbid_kpppkn (BASE_42 + 116)
 
#    define tbid_knppkn (BASE_42 + 117)
 
#    define tbid_knnpkn (BASE_42 + 118)
 
#    define tbid_kbppkn (BASE_42 + 119)
 
#    define tbid_kbnpkn (BASE_42 + 120)
 
#    define tbid_kbbpkn (BASE_42 + 121)
 
#    define tbid_krppkn (BASE_42 + 122)
 
#    define tbid_krnpkn (BASE_42 + 123)
 
#    define tbid_krbpkn (BASE_42 + 124)
 
#    define tbid_krrpkn (BASE_42 + 125)
 
#    define tbid_kqppkn (BASE_42 + 126)
 
#    define tbid_kqnpkn (BASE_42 + 127)
 
#    define tbid_kqbpkn (BASE_42 + 128)
 
#    define tbid_kqrpkn (BASE_42 + 129)
 
#    define tbid_kqqpkn (BASE_42 + 130)
 
#    define tbid_kpppkb (BASE_42 + 131)
 
#    define tbid_knppkb (BASE_42 + 132)
 
#    define tbid_knnpkb (BASE_42 + 133)
 
#    define tbid_kbppkb (BASE_42 + 134)
 
#    define tbid_kbnpkb (BASE_42 + 135)
 
#    define tbid_kbbpkb (BASE_42 + 136)
 
#    define tbid_krppkb (BASE_42 + 137)
 
#    define tbid_krnpkb (BASE_42 + 138)
 
#    define tbid_krbpkb (BASE_42 + 139)
 
#    define tbid_krrpkb (BASE_42 + 140)
 
#    define tbid_kqppkb (BASE_42 + 141)
 
#    define tbid_kqnpkb (BASE_42 + 142)
 
#    define tbid_kqbpkb (BASE_42 + 143)
 
#    define tbid_kqrpkb (BASE_42 + 144)
 
#    define tbid_kqqpkb (BASE_42 + 145)
 
#    define tbid_kpppkr (BASE_42 + 146)
 
#    define tbid_knppkr (BASE_42 + 147)
 
#    define tbid_knnpkr (BASE_42 + 148)
 
#    define tbid_kbppkr (BASE_42 + 149)
 
#    define tbid_kbnpkr (BASE_42 + 150)
 
#    define tbid_kbbpkr (BASE_42 + 151)
 
#    define tbid_krppkr (BASE_42 + 152)
 
#    define tbid_krnpkr (BASE_42 + 153)
 
#    define tbid_krbpkr (BASE_42 + 154)
 
#    define tbid_krrpkr (BASE_42 + 155)
 
#    define tbid_kqppkr (BASE_42 + 156)
 
#    define tbid_kqnpkr (BASE_42 + 157)
 
#    define tbid_kqbpkr (BASE_42 + 158)
 
#    define tbid_kqrpkr (BASE_42 + 159)
 
#    define tbid_kqqpkr (BASE_42 + 160)
 
#    define tbid_kpppkq (BASE_42 + 161)
 
#    define tbid_knppkq (BASE_42 + 162)
 
#    define tbid_knnpkq (BASE_42 + 163)
 
#    define tbid_kbppkq (BASE_42 + 164)
 
#    define tbid_kbnpkq (BASE_42 + 165)
 
#    define tbid_kbbpkq (BASE_42 + 166)
 
#    define tbid_krppkq (BASE_42 + 167)
 
#    define tbid_krnpkq (BASE_42 + 168)
 
#    define tbid_krbpkq (BASE_42 + 169)
 
#    define tbid_krrpkq (BASE_42 + 170)
 
#    define tbid_kqppkq (BASE_42 + 171)
 
#    define tbid_kqnpkq (BASE_42 + 172)
 
#    define tbid_kqbpkq (BASE_42 + 173)
 
#    define tbid_kqrpkq (BASE_42 + 174)
 
#    define tbid_kqqpkq (BASE_42 + 175)
 
 
 
#    define C42 175
 
#  else
 
#    define C42 64
 
#  endif
 
#endif
 
 
 
#if defined (T42_INCLUDE)
 
#  define cTb   (BASE_42 + C42 + 1)
 
#else
 
#  define cTb   (BASE_42 + 1)
 
#endif
 
 
 
// Compression
 
 
 
#include "tbdecode.h"
 
 
 
#if !defined (CPUS)
 
#  define   CPUS    1
 
#endif
 
 
 
#if (CPUS > 1)
 
  static    lock_t  lockDecode;
 
#endif
 
/*extern "C" int TB_CRC_CHECK = 0; */
 
int TB_CRC_CHECK = 0;
 
static int cCompressed = 0;
 
static decode_block *rgpdbDecodeBlocks[CPUS];
 
 
 
// Information about tablebases
 
 
 
#define MAX_EXTENTS                 18  /* Maximum # of 2Gb file extents */
 
 
 
#if defined (T33_INCLUDE) || defined (T42_INCLUDE)
 
#  define   MAX_TOTAL_PIECES        6   /* Maximum # of pieces on the board */
 
#else
 
#  define   MAX_TOTAL_PIECES        5   /* Maximum # of pieces on the board */
 
#endif
 
#define MAX_NON_KINGS           (MAX_TOTAL_PIECES - 2)
 
 
 
#if !defined (TB_DIRECTORY_SIZE)
 
#  define   TB_DIRECTORY_SIZE       32  /* # of cache buckets */
 
#endif
 
 
 
#if !defined (PFNCALCINDEX_DECLARED)
 
typedef INDEX (TB_FASTCALL * PfnCalcIndex) (square *psqW, square *psqB,
 
                                         square sqEnP, int fInverse);
 
#  define   PFNCALCINDEX_DECLARED
 
#endif
 
 
 
struct CTbCache;
 
 
 
typedef struct      // Hungarian: tbcb
 
    {
 
#if (CPUS > 1)
 
    lock_t                       m_lock;            // Lock on this cache bucket list
 
#endif
 
    volatile CTbCache * volatile m_ptbcFirst;   // Cached file chunks in LRU order
 
    }
 
    CTbCacheBucket;
 
 
 
typedef struct      // Hungarian: tbd
 
    {
 
    int             m_iTbId;
 
    unsigned int    m_fSymmetric:1;
 
    unsigned int    m_f16bit:1;
 
    unsigned int    m_fSplit:1;
 
    PfnCalcIndex    m_rgpfnCalcIndex[2];
 
    char            m_rgchName[MAX_TOTAL_PIECES+1];
 
    INDEX           m_rgcbLength[2];
 
    char            *m_rgpchFileName[2][MAX_EXTENTS];
 
#if (CPUS > 1)
 
    lock_t          m_rglockFiles[2];
 
#endif
 
    FILE            *m_rgfpFiles[2][MAX_EXTENTS];
 
    decode_info     *m_rgpdiDecodeInfo[2][MAX_EXTENTS];
 
    CTbCacheBucket  *m_prgtbcbBuckets[2];   // Cached file chunks in LRU order
 
    BYTE            *m_rgpbRead[2];
 
    }
 
    CTbDesc;
 
 
 
#if defined (T_INDEX64) && defined (_MSC_VER)
 
#  define   TB(name, fSym, f16bit, fSplit, funW, funB, cbW, cbB)\
 
                    { tbid_##name, fSym, f16bit, fSplit, { funW, funB }, #name, { cbW##ULL, cbB##ULL } },
 
#elif defined (T_INDEX64)
 
#  define   TB(name, fSym, f16bit, fSplit, funW, funB, cbW, cbB)\
 
                    { tbid_##name, fSym, f16bit, fSplit, { funW, funB }, #name, { cbW##llu, cbB##llu } },
 
#else
 
#  define   TB(name, fSym, f16bit, fSplit, funW, funB, cbW, cbB)\
 
                    { tbid_##name, fSym, f16bit, fSplit, { funW, funB }, #name, { cbW##u, cbB##u } },
 
#endif
 
 
 
#define P   x_piecePawn
 
#define N   x_pieceKnight
 
#define B   x_pieceBishop
 
#define R   x_pieceRook
 
#define Q   x_pieceQueen
 
 
 
CTbDesc rgtbdDesc[cTb] =
 
    {
 
    TB (kk, true, false, false, NULL, NULL, 0, 0)
 
 
 
    TB (kpk, false, false, false, (T21<P>::IndCalcW), (T21<P>::IndCalcB), 81664, 84012)
 
    TB (knk, false, false, false, (T21<N>::IndCalcW), (T21<N>::IndCalcB), 26282, 28644)
 
    TB (kbk, false, false, false, (T21<B>::IndCalcW), (T21<B>::IndCalcB), 27243, 28644)
 
    TB (krk, false, false, false, (T21<R>::IndCalcW), (T21<R>::IndCalcB), 27030, 28644)
 
    TB (kqk, false, false, false, (T21<Q>::IndCalcW), (T21<Q>::IndCalcB), 25629, 28644)
 
 
 
    TB (kpkp, false, false, false, (T22<P, P>::IndCalcW), (T22<P, P>::IndCalcB), 3863492, 3863492)
 
    TB (knkp, false, false, false, (T22<N, P>::IndCalcW), (T22<N, P>::IndCalcB), 4931904, 4981504)
 
    TB (knkn, true,  false, false, (T22<N, N>::IndCalcW), (T22<N, N>::IndCalcB), 1603202, 1603202)
 
    TB (kbkp, false, false, false, (T22<B, P>::IndCalcW), (T22<B, P>::IndCalcB), 5112000, 4981504)
 
    TB (kbkn, false, false, false, (T22<B, N>::IndCalcW), (T22<B, N>::IndCalcB), 1661823, 1603202)
 
    TB (kbkb, true,  false, false, (T22<B, B>::IndCalcW), (T22<B, B>::IndCalcB), 1661823, 1661823)
 
    TB (krkp, false, false, false, (T22<R, P>::IndCalcW), (T22<R, P>::IndCalcB), 5072736, 4981504)
 
    TB (krkn, false, false, false, (T22<R, N>::IndCalcW), (T22<R, N>::IndCalcB), 1649196, 1603202)
 
    TB (krkb, false, false, false, (T22<R, B>::IndCalcW), (T22<R, B>::IndCalcB), 1649196, 1661823)
 
    TB (krkr, true,  false, false, (T22<R, R>::IndCalcW), (T22<R, R>::IndCalcB), 1649196, 1649196)
 
    TB (kqkp, false, false, false, (T22<Q, P>::IndCalcW), (T22<Q, P>::IndCalcB), 4810080, 4981504)
 
    TB (kqkn, false, false, false, (T22<Q, N>::IndCalcW), (T22<Q, N>::IndCalcB), 1563735, 1603202)
 
    TB (kqkb, false, false, false, (T22<Q, B>::IndCalcW), (T22<Q, B>::IndCalcB), 1563735, 1661823)
 
    TB (kqkr, false, false, false, (T22<Q, R>::IndCalcW), (T22<Q, R>::IndCalcB), 1563735, 1649196)
 
    TB (kqkq, true,  false, false, (T22<Q, Q>::IndCalcW), (T22<Q, Q>::IndCalcB), 1563735, 1563735)
 
    TB (kppk, false, false, false, (T31<P, P>::IndCalcW), (T31<P, P>::IndCalcB), 1806671, 1912372)
 
    TB (knpk, false, false, false, (T31<N, P>::IndCalcW), (T31<N, P>::IndCalcB), 4648581, 5124732)
 
    TB (knnk, false, false, false, (T31<N, N>::IndCalcW), (T31<N, N>::IndCalcB),  735304,  873642)
 
    TB (kbpk, false, false, false, (T31<B, P>::IndCalcW), (T31<B, P>::IndCalcB), 4817128, 5124732)
 
    TB (kbnk, false, false, false, (T31<B, N>::IndCalcW), (T31<B, N>::IndCalcB), 1550620, 1747284)
 
    TB (kbbk, false, false, false, (T31<B, B>::IndCalcW), (T31<B, B>::IndCalcB),  789885,  873642)
 
    TB (krpk, false, false, false, (T31<R, P>::IndCalcW), (T31<R, P>::IndCalcB), 4779530, 5124732)
 
    TB (krnk, false, false, false, (T31<R, N>::IndCalcW), (T31<R, N>::IndCalcB), 1538479, 1747284)
 
    TB (krbk, false, false, false, (T31<R, B>::IndCalcW), (T31<R, B>::IndCalcB), 1594560, 1747284)
 
    TB (krrk, false, false, false, (T31<R, R>::IndCalcW), (T31<R, R>::IndCalcB),  777300,  873642)
 
    TB (kqpk, false, false, false, (T31<Q, P>::IndCalcW), (T31<Q, P>::IndCalcB), 4533490, 5124732)
 
    TB (kqnk, false, false, false, (T31<Q, N>::IndCalcW), (T31<Q, N>::IndCalcB), 1459616, 1747284)
 
    TB (kqbk, false, false, false, (T31<Q, B>::IndCalcW), (T31<Q, B>::IndCalcB), 1512507, 1747284)
 
    TB (kqrk, false, false, false, (T31<Q, R>::IndCalcW), (T31<Q, R>::IndCalcB), 1500276, 1747284)
 
    TB (kqqk, false, false, false, (T31<Q, Q>::IndCalcW), (T31<Q, Q>::IndCalcB),  698739,  873642)
 
 
 
#if !defined (KPPKP_16BIT)
 
    TB (kppkp, false, false, false, (T32<P, P, P>::IndCalcW), (T32<P, P, P>::IndCalcB),  84219361,  89391280)
 
#else
 
    TB (kppkp, false, true,  false, (T32<P, P, P>::IndCalcW), (T32<P, P, P>::IndCalcB),  84219361,  89391280)
 
#endif
 
    TB (kppkn, false, false, false, (T32<P, P, N>::IndCalcW), (T32<P, P, N>::IndCalcB), 108400260, 115899744)
 
    TB (kppkb, false, false, false, (T32<P, P, B>::IndCalcW), (T32<P, P, B>::IndCalcB), 108400260, 120132000)
 
    TB (kppkr, false, false, false, (T32<P, P, R>::IndCalcW), (T32<P, P, R>::IndCalcB), 108400260, 119209296)
 
    TB (kppkq, false, false, false, (T32<P, P, Q>::IndCalcW), (T32<P, P, Q>::IndCalcB), 108400260, 113036880)
 
    TB (knpkp, false, false, false, (T32<N, P, P>::IndCalcW), (T32<N, P, P>::IndCalcB), 219921779, 231758952)
 
    TB (knpkn, false, false, false, (T32<N, P, N>::IndCalcW), (T32<N, P, N>::IndCalcB), 278914860, 295914240)
 
    TB (knpkb, false, false, false, (T32<N, P, B>::IndCalcW), (T32<N, P, B>::IndCalcB), 278914860, 306720000)
 
    TB (knpkr, false, false, false, (T32<N, P, R>::IndCalcW), (T32<N, P, R>::IndCalcB), 278914860, 304369920)
 
    TB (knpkq, false, false, false, (T32<N, P, Q>::IndCalcW), (T32<N, P, Q>::IndCalcB), 278914860, 288610560)
 
    TB (knnkp, false, false, false, (T32<N, N, P>::IndCalcW), (T32<N, N, P>::IndCalcB), 137991648, 149445120)
 
    TB (knnkn, false, false, false, (T32<N, N, N>::IndCalcW), (T32<N, N, N>::IndCalcB),  44118240,  48096060)
 
    TB (knnkb, false, false, false, (T32<N, N, B>::IndCalcW), (T32<N, N, B>::IndCalcB),  44118240,  49854690)
 
    TB (knnkr, false, false, false, (T32<N, N, R>::IndCalcW), (T32<N, N, R>::IndCalcB),  44118240,  49475880)
 
    TB (knnkq, false, false, false, (T32<N, N, Q>::IndCalcW), (T32<N, N, Q>::IndCalcB),  44118240,  46912050)
 
    TB (kbpkp, false, false, false, (T32<B, P, P>::IndCalcW), (T32<B, P, P>::IndCalcB), 227896016, 231758952)
 
    TB (kbpkn, false, false, false, (T32<B, P, N>::IndCalcW), (T32<B, P, N>::IndCalcB), 289027680, 295914240)
 
    TB (kbpkb, false, false, false, (T32<B, P, B>::IndCalcW), (T32<B, P, B>::IndCalcB), 289027680, 306720000)
 
    TB (kbpkr, false, false, false, (T32<B, P, R>::IndCalcW), (T32<B, P, R>::IndCalcB), 289027680, 304369920)
 
    TB (kbpkq, false, false, false, (T32<B, P, Q>::IndCalcW), (T32<B, P, Q>::IndCalcB), 289027680, 288610560)
 
    TB (kbnkp, false, false, false, (T32<B, N, P>::IndCalcW), (T32<B, N, P>::IndCalcB), 290989584, 298890240)
 
    TB (kbnkn, false, false, false, (T32<B, N, N>::IndCalcW), (T32<B, N, N>::IndCalcB),  93037200,  96192120)
 
    TB (kbnkb, false, false, false, (T32<B, N, B>::IndCalcW), (T32<B, N, B>::IndCalcB),  93037200,  99709380)
 
    TB (kbnkr, false, false, false, (T32<B, N, R>::IndCalcW), (T32<B, N, R>::IndCalcB),  93037200,  98951760)
 
    TB (kbnkq, false, false, false, (T32<B, N, Q>::IndCalcW), (T32<B, N, Q>::IndCalcB),  93037200,  93824100)
 
    TB (kbbkp, false, false, false, (T32<B, B, P>::IndCalcW), (T32<B, B, P>::IndCalcB), 148223520, 149445120)
 
    TB (kbbkn, false, false, false, (T32<B, B, N>::IndCalcW), (T32<B, B, N>::IndCalcB),  47393100,  48096060)
 
    TB (kbbkb, false, false, false, (T32<B, B, B>::IndCalcW), (T32<B, B, B>::IndCalcB),  47393100,  49854690)
 
    TB (kbbkr, false, false, false, (T32<B, B, R>::IndCalcW), (T32<B, B, R>::IndCalcB),  47393100,  49475880)
 
    TB (kbbkq, false, false, false, (T32<B, B, Q>::IndCalcW), (T32<B, B, Q>::IndCalcB),  47393100,  46912050)
 
    TB (krpkp, false, false, false, (T32<R, P, P>::IndCalcW), (T32<R, P, P>::IndCalcB), 226121876, 231758952)
 
    TB (krpkn, false, false, false, (T32<R, P, N>::IndCalcW), (T32<R, P, N>::IndCalcB), 286777440, 295914240)
 
    TB (krpkb, false, false, false, (T32<R, P, B>::IndCalcW), (T32<R, P, B>::IndCalcB), 286777440, 306720000)
 
    TB (krpkr, false, false, false, (T32<R, P, R>::IndCalcW), (T32<R, P, R>::IndCalcB), 286777440, 304369920)
 
    TB (krpkq, false, false, false, (T32<R, P, Q>::IndCalcW), (T32<R, P, Q>::IndCalcB), 286777440, 288610560)
 
    TB (krnkp, false, false, false, (T32<R, N, P>::IndCalcW), (T32<R, N, P>::IndCalcB), 288692928, 298890240)
 
    TB (krnkn, false, false, false, (T32<R, N, N>::IndCalcW), (T32<R, N, N>::IndCalcB),  92308740,  96192120)
 
    TB (krnkb, false, false, false, (T32<R, N, B>::IndCalcW), (T32<R, N, B>::IndCalcB),  92308740,  99709380)
 
    TB (krnkr, false, false, false, (T32<R, N, R>::IndCalcW), (T32<R, N, R>::IndCalcB),  92308740,  98951760)
 
    TB (krnkq, false, false, false, (T32<R, N, Q>::IndCalcW), (T32<R, N, Q>::IndCalcB),  92308740,  93824100)
 
    TB (krbkp, false, false, false, (T32<R, B, P>::IndCalcW), (T32<R, B, P>::IndCalcB), 299203200, 298890240)
 
    TB (krbkn, false, false, false, (T32<R, B, N>::IndCalcW), (T32<R, B, N>::IndCalcB),  95673600,  96192120)
 
    TB (krbkb, false, false, false, (T32<R, B, B>::IndCalcW), (T32<R, B, B>::IndCalcB),  95673600,  99709380)
 
    TB (krbkr, false, false, false, (T32<R, B, R>::IndCalcW), (T32<R, B, R>::IndCalcB),  95673600,  98951760)
 
    TB (krbkq, false, false, false, (T32<R, B, Q>::IndCalcW), (T32<R, B, Q>::IndCalcB),  95673600,  93824100)
 
    TB (krrkp, false, false, false, (T32<R, R, P>::IndCalcW), (T32<R, R, P>::IndCalcB), 145901232, 149445120)
 
    TB (krrkn, false, false, false, (T32<R, R, N>::IndCalcW), (T32<R, R, N>::IndCalcB),  46658340,  48096060)
 
    TB (krrkb, false, false, false, (T32<R, R, B>::IndCalcW), (T32<R, R, B>::IndCalcB),  46658340,  49854690)
 
    TB (krrkr, false, false, false, (T32<R, R, R>::IndCalcW), (T32<R, R, R>::IndCalcB),  46658340,  49475880)
 
    TB (krrkq, false, false, false, (T32<R, R, Q>::IndCalcW), (T32<R, R, Q>::IndCalcB),  46658340,  46912050)
 
    TB (kqpkp, false, false, false, (T32<Q, P, P>::IndCalcW), (T32<Q, P, P>::IndCalcB), 214481388, 231758952)
 
    TB (kqpkn, false, false, false, (T32<Q, P, N>::IndCalcW), (T32<Q, P, N>::IndCalcB), 272015040, 295914240)
 
    TB (kqpkb, false, false, false, (T32<Q, P, B>::IndCalcW), (T32<Q, P, B>::IndCalcB), 272015040, 306720000)
 
    TB (kqpkr, false, false, false, (T32<Q, P, R>::IndCalcW), (T32<Q, P, R>::IndCalcB), 272015040, 304369920)
 
    TB (kqpkq, false, false, false, (T32<Q, P, Q>::IndCalcW), (T32<Q, P, Q>::IndCalcB), 272015040, 288610560)
 
    TB (kqnkp, false, false, false, (T32<Q, N, P>::IndCalcW), (T32<Q, N, P>::IndCalcB), 273904512, 298890240)
 
    TB (kqnkn, false, false, false, (T32<Q, N, N>::IndCalcW), (T32<Q, N, N>::IndCalcB),  87576960,  96192120)
 
    TB (kqnkb, false, false, false, (T32<Q, N, B>::IndCalcW), (T32<Q, N, B>::IndCalcB),  87576960,  99709380)
 
    TB (kqnkr, false, false, false, (T32<Q, N, R>::IndCalcW), (T32<Q, N, R>::IndCalcB),  87576960,  98951760)
 
    TB (kqnkq, false, false, false, (T32<Q, N, Q>::IndCalcW), (T32<Q, N, Q>::IndCalcB),  87576960,  93824100)
 
    TB (kqbkp, false, false, false, (T32<Q, B, P>::IndCalcW), (T32<Q, B, P>::IndCalcB), 283818240, 298890240)
 
    TB (kqbkn, false, false, false, (T32<Q, B, N>::IndCalcW), (T32<Q, B, N>::IndCalcB),  90750420,  96192120)
 
    TB (kqbkb, false, false, false, (T32<Q, B, B>::IndCalcW), (T32<Q, B, B>::IndCalcB),  90750420,  99709380)
 
    TB (kqbkr, false, false, false, (T32<Q, B, R>::IndCalcW), (T32<Q, B, R>::IndCalcB),  90750420,  98951760)
 
    TB (kqbkq, false, false, false, (T32<Q, B, Q>::IndCalcW), (T32<Q, B, Q>::IndCalcB),  90750420,  93824100)
 
    TB (kqrkp, false, false, false, (T32<Q, R, P>::IndCalcW), (T32<Q, R, P>::IndCalcB), 281568240, 298890240)
 
    TB (kqrkn, false, false, false, (T32<Q, R, N>::IndCalcW), (T32<Q, R, N>::IndCalcB),  90038460,  96192120)
 
    TB (kqrkb, false, false, false, (T32<Q, R, B>::IndCalcW), (T32<Q, R, B>::IndCalcB),  90038460,  99709380)
 
    TB (kqrkr, false, false, false, (T32<Q, R, R>::IndCalcW), (T32<Q, R, R>::IndCalcB),  90038460,  98951760)
 
    TB (kqrkq, false, false, false, (T32<Q, R, Q>::IndCalcW), (T32<Q, R, Q>::IndCalcB),  90038460,  93824100)
 
    TB (kqqkp, false, false, false, (T32<Q, Q, P>::IndCalcW), (T32<Q, Q, P>::IndCalcB), 131170128, 149445120)
 
    TB (kqqkn, false, false, false, (T32<Q, Q, N>::IndCalcW), (T32<Q, Q, N>::IndCalcB),  41944320,  48096060)
 
    TB (kqqkb, false, false, false, (T32<Q, Q, B>::IndCalcW), (T32<Q, Q, B>::IndCalcB),  41944320,  49854690)
 
    TB (kqqkr, false, false, false, (T32<Q, Q, R>::IndCalcW), (T32<Q, Q, R>::IndCalcB),  41944320,  49475880)
 
    TB (kqqkq, false, false, false, (T32<Q, Q, Q>::IndCalcW), (T32<Q, Q, Q>::IndCalcB),  41944320,  46912050)
 
 
 
#if defined (T41_INCLUDE)
 
    TB (kpppk, false, false, false, (T41<P, P, P>::IndCalcW), (T41<P, P, P>::IndCalcB),  26061704,  28388716)
 
    TB (knppk, false, false, false, (T41<N, P, P>::IndCalcW), (T41<N, P, P>::IndCalcB), 102898651, 114742320)
 
    TB (knnpk, false, false, false, (T41<N, N, P>::IndCalcW), (T41<N, N, P>::IndCalcB), 130135501, 153741960)
 
    TB (knnnk, false, false, false, (T41<N, N, N>::IndCalcW), (T41<N, N, N>::IndCalcB),  13486227,  17472840)
 
    TB (kbppk, false, false, false, (T41<B, P, P>::IndCalcW), (T41<B, P, P>::IndCalcB), 106602156, 114742320)
 
    TB (kbnpk, false, false, false, (T41<B, N, P>::IndCalcW), (T41<B, N, P>::IndCalcB), 274352939, 307483920)
 
    TB (kbnnk, false, false, false, (T41<B, N, N>::IndCalcW), (T41<B, N, N>::IndCalcB),  43406294, 52418520)
 
    TB (kbbpk, false, false, false, (T41<B, B, P>::IndCalcW), (T41<B, B, P>::IndCalcB), 139715040, 153741960)
 
    TB (kbbnk, false, false, false, (T41<B, B, N>::IndCalcW), (T41<B, B, N>::IndCalcB),  44983618,  52418520)
 
    TB (kbbbk, false, false, false, (T41<B, B, B>::IndCalcW), (T41<B, B, B>::IndCalcB),  15010230,  17472840)
 
    TB (krppk, false, false, false, (T41<R, P, P>::IndCalcW), (T41<R, P, P>::IndCalcB), 105758666, 114742320)
 
    TB (krnpk, false, false, false, (T41<R, N, P>::IndCalcW), (T41<R, N, P>::IndCalcB), 272153675, 307483920)
 
    TB (krnnk, false, false, false, (T41<R, N, N>::IndCalcW), (T41<R, N, N>::IndCalcB),  43056198,  52418520)
 
    TB (krbpk, false, false, false, (T41<R, B, P>::IndCalcW), (T41<R, B, P>::IndCalcB), 281991360, 307483920)
 
    TB (krbnk, false, false, false, (T41<R, B, N>::IndCalcW), (T41<R, B, N>::IndCalcB),  90787358, 104837040)
 
    TB (krbbk, false, false, false, (T41<R, B, B>::IndCalcW), (T41<R, B, B>::IndCalcB),  46242089,  52418520)
 
    TB (krrpk, false, false, false, (T41<R, R, P>::IndCalcW), (T41<R, R, P>::IndCalcB), 137491197, 153741960)
 
    TB (krrnk, false, false, false, (T41<R, R, N>::IndCalcW), (T41<R, R, N>::IndCalcB),  44265261,  52418520)
 
    TB (krrbk, false, false, false, (T41<R, R, B>::IndCalcW), (T41<R, R, B>::IndCalcB),  45873720,  52418520)
 
    TB (krrrk, false, false, false, (T41<R, R, R>::IndCalcW), (T41<R, R, R>::IndCalcB),  14644690,  17472840)
 
    TB (kqppk, false, false, false, (T41<Q, P, P>::IndCalcW), (T41<Q, P, P>::IndCalcB), 100347220, 114742320)
 
    TB (kqnpk, false, false, false, (T41<Q, N, P>::IndCalcW), (T41<Q, N, P>::IndCalcB), 258294639, 307483920)
 
    TB (kqnnk, false, false, false, (T41<Q, N, N>::IndCalcW), (T41<Q, N, N>::IndCalcB),  40873646,  52418520)
 
    TB (kqbpk, false, false, false, (T41<Q, B, P>::IndCalcW), (T41<Q, B, P>::IndCalcB), 267576632, 307483920)
 
    TB (kqbnk, false, false, false, (T41<Q, B, N>::IndCalcW), (T41<Q, B, N>::IndCalcB),  86166717, 104837040)
 
    TB (kqbbk, false, false, false, (T41<Q, B, B>::IndCalcW), (T41<Q, B, B>::IndCalcB),  43879679,  52418520)
 
    TB (kqrpk, false, false, false, (T41<Q, R, P>::IndCalcW), (T41<Q, R, P>::IndCalcB), 265421907, 307483920)
 
    TB (kqrnk, false, false, false, (T41<Q, R, N>::IndCalcW), (T41<Q, R, N>::IndCalcB),  85470603, 104837040)
 
    TB (kqrbk, false, false, false, (T41<Q, R, B>::IndCalcW), (T41<Q, R, B>::IndCalcB),  88557959, 104837040)
 
    TB (kqrrk, false, false, false, (T41<Q, R, R>::IndCalcW), (T41<Q, R, R>::IndCalcB),  43157690,  52418520)
 
    TB (kqqpk, false, false, false, (T41<Q, Q, P>::IndCalcW), (T41<Q, Q, P>::IndCalcB), 123688859, 153741960)
 
    TB (kqqnk, false, false, false, (T41<Q, Q, N>::IndCalcW), (T41<Q, Q, N>::IndCalcB),  39840787,  52418520)
 
    TB (kqqbk, false, false, false, (T41<Q, Q, B>::IndCalcW), (T41<Q, Q, B>::IndCalcB),  41270973,  52418520)
 
    TB (kqqrk, false, false, false, (T41<Q, Q, R>::IndCalcW), (T41<Q, Q, R>::IndCalcB),  40916820,  52418520)
 
    TB (kqqqk, false, false, false, (T41<Q, Q, Q>::IndCalcW), (T41<Q, Q, Q>::IndCalcB),  12479974,  17472840)
 
#endif
 
 
 
#if defined (T33_INCLUDE)
 
    TB (knnknn, true,  false, false, (T33<N, N, N, N>::IndCalcW), (T33<N, N, N, N>::IndCalcB),  1301488080,  1301488080)
 
    TB (kbnknn, false, false, false, (T33<B, N, N, N>::IndCalcW), (T33<B, N, N, N>::IndCalcB),  2744597400,  2602976160)
 
    TB (kbbknn, false, false, false, (T33<B, B, N, N>::IndCalcW), (T33<B, B, N, N>::IndCalcB),  1398096450,  1301488080)
 
    TB (kbbkbn, false, false, false, (T33<B, B, B, N>::IndCalcW), (T33<B, B, B, N>::IndCalcB),  2796192900,  2744597400)
 
    TB (kbbkbb, true,  false, false, (T33<B, B, B, B>::IndCalcW), (T33<B, B, B, B>::IndCalcB),  1398096450,  1398096450)
 
    TB (krnknn, false, true,  false, (T33<R, N, N, N>::IndCalcW), (T33<R, N, N, N>::IndCalcB),  2723107830,  2602976160)
 
    TB (krnkbb, false, true,  false, (T33<R, N, B, B>::IndCalcW), (T33<R, N, B, B>::IndCalcB),  2723107830,  2796192900)
 
    TB (krbknn, false, true,  false, (T33<R, B, N, N>::IndCalcW), (T33<R, B, N, N>::IndCalcB),  2822371200,  2602976160)
 
    TB (krbkbb, false, false, false, (T33<R, B, B, B>::IndCalcW), (T33<R, B, B, B>::IndCalcB),  2822371200,  2796192900)
 
    TB (krrknn, false, false, false, (T33<R, R, N, N>::IndCalcW), (T33<R, R, N, N>::IndCalcB),  1376421030,  1301488080)
 
    TB (krrkbn, false, false, false, (T33<R, R, B, N>::IndCalcW), (T33<R, R, B, N>::IndCalcB),  2752842060,  2744597400)
 
    TB (krrkbb, false, false, false, (T33<R, R, B, B>::IndCalcW), (T33<R, R, B, B>::IndCalcB),  1376421030,  1398096450)
 
    TB (krrkrn, false, false, false, (T33<R, R, R, N>::IndCalcW), (T33<R, R, R, N>::IndCalcB),  2752842060,  2723107830)
 
    TB (krrkrb, false, false, false, (T33<R, R, R, B>::IndCalcW), (T33<R, R, R, B>::IndCalcB),  2752842060,  2822371200)
 
    TB (krrkrr, true,  false, false, (T33<R, R, R, R>::IndCalcW), (T33<R, R, R, R>::IndCalcB),  1376421030,  1376421030)
 
    TB (kqnknn, false, false, false, (T33<Q, N, N, N>::IndCalcW), (T33<Q, N, N, N>::IndCalcB),  2583520320,  2602976160)
 
    TB (kqnkbb, false, false, false, (T33<Q, N, B, B>::IndCalcW), (T33<Q, N, B, B>::IndCalcB),  2583520320,  2796192900)
 
    TB (kqnkrr, false, true,  false, (T33<Q, N, R, R>::IndCalcW), (T33<Q, N, R, R>::IndCalcB),  2583520320,  2752842060)
 
    TB (kqbknn, false, false, false, (T33<Q, B, N, N>::IndCalcW), (T33<Q, B, N, N>::IndCalcB),  2677137390,  2602976160)
 
    TB (kqbkbb, false, false, false, (T33<Q, B, B, B>::IndCalcW), (T33<Q, B, B, B>::IndCalcB),  2677137390,  2796192900)
 
    TB (kqbkrr, false, false, false, (T33<Q, B, R, R>::IndCalcW), (T33<Q, B, R, R>::IndCalcB),  2677137390,  2752842060)
 
    TB (kqrknn, false, false, false, (T33<Q, R, N, N>::IndCalcW), (T33<Q, R, N, N>::IndCalcB),  2656134570,  2602976160)
 
    TB (kqrkbb, false, false, false, (T33<Q, R, B, B>::IndCalcW), (T33<Q, R, B, B>::IndCalcB),  2656134570,  2796192900)
 
    TB (kqrkrr, false, false, false, (T33<Q, R, R, R>::IndCalcW), (T33<Q, R, R, R>::IndCalcB),  2656134570,  2752842060)
 
    TB (kqqknn, false, false, false, (T33<Q, Q, N, N>::IndCalcW), (T33<Q, Q, N, N>::IndCalcB),  1237357440,  1301488080)
 
    TB (kqqkbn, false, false, false, (T33<Q, Q, B, N>::IndCalcW), (T33<Q, Q, B, N>::IndCalcB),  2474714880,  2744597400)
 
    TB (kqqkbb, false, false, false, (T33<Q, Q, B, B>::IndCalcW), (T33<Q, Q, B, B>::IndCalcB),  1237357440,  1398096450)
 
    TB (kqqkrn, false, false, false, (T33<Q, Q, R, N>::IndCalcW), (T33<Q, Q, R, N>::IndCalcB),  2474714880,  2723107830)
 
    TB (kqqkrb, false, false, false, (T33<Q, Q, R, B>::IndCalcW), (T33<Q, Q, R, B>::IndCalcB),  2474714880,  2822371200)
 
    TB (kqqkrr, false, false, false, (T33<Q, Q, R, R>::IndCalcW), (T33<Q, Q, R, R>::IndCalcB),  1237357440,  1376421030)
 
    TB (kqqkqn, false, false, false, (T33<Q, Q, Q, N>::IndCalcW), (T33<Q, Q, Q, N>::IndCalcB),  2474714880,  2583520320)
 
    TB (kqqkqb, false, false, false, (T33<Q, Q, Q, B>::IndCalcW), (T33<Q, Q, Q, B>::IndCalcB),  2474714880,  2677137390)
 
    TB (kqqkqr, false, false, false, (T33<Q, Q, Q, R>::IndCalcW), (T33<Q, Q, Q, R>::IndCalcB),  2474714880,  2656134570)
 
    TB (kqqkqq, true,  false, false, (T33<Q, Q, Q, Q>::IndCalcW), (T33<Q, Q, Q, Q>::IndCalcB),  1237357440,  1237357440)
 
#if defined (T_INDEX64)
 
    TB (kbnkbn, true,  false, false, (T33<B, N, B, N>::IndCalcW), (T33<B, N, B, N>::IndCalcB),  5489194800,  5489194800)
 
    TB (krnkrn, true,  false, false, (T33<R, N, R, N>::IndCalcW), (T33<R, N, R, N>::IndCalcB),  5446215660,  5446215660)
 
    TB (krbkrb, true,  false, false, (T33<R, B, R, B>::IndCalcW), (T33<R, B, R, B>::IndCalcB),  5644742400,  5644742400)
 
    TB (kqnkqn, true,  false, false, (T33<Q, N, Q, N>::IndCalcW), (T33<Q, N, Q, N>::IndCalcB),  5167040640,  5167040640)
 
    TB (kqbkqb, true,  false, false, (T33<Q, B, Q, B>::IndCalcW), (T33<Q, B, Q, B>::IndCalcB),  5354274780,  5354274780)
 
    TB (kqrkqr, true,  false, false, (T33<Q, R, Q, R>::IndCalcW), (T33<Q, R, Q, R>::IndCalcB),  5312269140,  5312269140)
 
    TB (krnkbn, false, true,  true,  (T33<R, N, B, N>::IndCalcW), (T33<R, N, B, N>::IndCalcB),  5446215660,  5489194800)
 
    TB (krbkbn, false, false, true,  (T33<R, B, B, N>::IndCalcW), (T33<R, B, B, N>::IndCalcB),  5644742400,  5489194800)
 
    TB (krbkrn, false, false, false, (T33<R, B, R, N>::IndCalcW), (T33<R, B, R, N>::IndCalcB),  5644742400,  5446215660)
 
    TB (kqnkbn, false, false, false, (T33<Q, N, B, N>::IndCalcW), (T33<Q, N, B, N>::IndCalcB),  5167040640,  5489194800)
 
    TB (kqnkrn, false, false, true,  (T33<Q, N, R, N>::IndCalcW), (T33<Q, N, R, N>::IndCalcB),  5167040640,  5446215660)
 
    TB (kqnkrb, false, false, true,  (T33<Q, N, R, B>::IndCalcW), (T33<Q, N, R, B>::IndCalcB),  5167040640,  5644742400)
 
    TB (kqbkbn, false, false, false, (T33<Q, B, B, N>::IndCalcW), (T33<Q, B, B, N>::IndCalcB),  5354274780,  5489194800)
 
    TB (kqbkrn, false, false, true,  (T33<Q, B, R, N>::IndCalcW), (T33<Q, B, R, N>::IndCalcB),  5354274780,  5446215660)
 
    TB (kqbkrb, false, false, true,  (T33<Q, B, R, B>::IndCalcW), (T33<Q, B, R, B>::IndCalcB),  5354274780,  5644742400)
 
    TB (kqbkqn, false, false, false, (T33<Q, B, Q, N>::IndCalcW), (T33<Q, B, Q, N>::IndCalcB),  5354274780,  5167040640)
 
    TB (kqrkbn, false, false, false, (T33<Q, R, B, N>::IndCalcW), (T33<Q, R, B, N>::IndCalcB),  5312269140,  5489194800)
 
    TB (kqrkrn, false, false, false, (T33<Q, R, R, N>::IndCalcW), (T33<Q, R, R, N>::IndCalcB),  5312269140,  5446215660)
 
    TB (kqrkrb, false, false, false, (T33<Q, R, R, B>::IndCalcW), (T33<Q, R, R, B>::IndCalcB),  5312269140,  5644742400)
 
    TB (kqrkqn, false, false, false, (T33<Q, R, Q, N>::IndCalcW), (T33<Q, R, Q, N>::IndCalcB),  5312269140,  5167040640)
 
    TB (kqrkqb, false, false, false, (T33<Q, R, Q, B>::IndCalcW), (T33<Q, R, Q, B>::IndCalcB),  5312269140,  5354274780)
 
 
 
    TB (kppkpp, true,  true,  false, (T33<P, P, P, P>::IndCalcW), (T33<P, P, P, P>::IndCalcBF),  1917741812,  1917741812)
 
    TB (knpkpp, false, true,  true,  (T33<N, P, P, P>::IndCalcW), (T33<N, P, P, P>::IndCalcB),   5088408829,  4966717366)
 
    TB (knpknp, true,  false, true,  (T33<N, P, N, P>::IndCalcW), (T33<N, P, N, P>::IndCalcBF), 12972508017, 12972508017)
 
    TB (knnkpp, false, true,  false, (T33<N, N, P, P>::IndCalcW), (T33<N, N, P, P>::IndCalcB),   3242803728,  3197807670)
 
    TB (knnknp, false, true,  true,  (T33<N, N, N, P>::IndCalcW), (T33<N, N, N, P>::IndCalcB),   8141507232,  8227988370)
 
    TB (kbpkpp, false, true,  true,  (T33<B, P, P, P>::IndCalcW), (T33<B, P, P, P>::IndCalcB),   5272919368,  4966717366)
 
    TB (kbpknp, false, true,  true,  (T33<B, P, N, P>::IndCalcW), (T33<B, P, N, P>::IndCalcB),  13442882944, 12972508017)
 
    TB (kbpknn, false, true,  true,  (T33<B, P, N, N>::IndCalcW), (T33<B, P, N, N>::IndCalcB),   8526316560,  8141507232)
 
    TB (kbpkbp, true,  false, true,  (T33<B, P, B, P>::IndCalcW), (T33<B, P, B, P>::IndCalcBF), 13442882944, 13442882944)
 
    TB (kbnkpp, false, true,  true,  (T33<B, N, P, P>::IndCalcW), (T33<B, N, P, P>::IndCalcB),   6838255224,  6395615340)
 
    TB (kbnknp, false, true,  true,  (T33<B, N, N, P>::IndCalcW), (T33<B, N, N, P>::IndCalcB),  17168385456, 16455976740)
 
    TB (kbnkbp, false, false, true,  (T33<B, N, B, P>::IndCalcW), (T33<B, N, B, P>::IndCalcB),  17168385456, 17052633120)
 
    TB (kbbkpp, false, false, false, (T33<B, B, P, P>::IndCalcW), (T33<B, B, P, P>::IndCalcB),   3483252720,  3197807670)
 
    TB (kbbknp, false, true,  true,  (T33<B, B, N, P>::IndCalcW), (T33<B, B, N, P>::IndCalcB),   8745187680,  8227988370)
 
    TB (kbbkbp, false, false, true,  (T33<B, B, B, P>::IndCalcW), (T33<B, B, B, P>::IndCalcB),   8745187680,  8526316560)
 
    TB (krpkpp, false, true,  true,  (T33<R, P, P, P>::IndCalcW), (T33<R, P, P, P>::IndCalcB),   5231873656,  4966717366)
 
    TB (krpknp, false, true,  true,  (T33<R, P, N, P>::IndCalcW), (T33<R, P, N, P>::IndCalcB),  13338233184, 12972508017)
 
    TB (krpknn, false, true,  true,  (T33<R, P, N, N>::IndCalcW), (T33<R, P, N, N>::IndCalcB),   8459934480,  8141507232)
 
    TB (krpkbp, false, true,  true,  (T33<R, P, B, P>::IndCalcW), (T33<R, P, B, P>::IndCalcB),  13338233184, 13442882944)
 
    TB (krpkbn, false, true,  true,  (T33<R, P, B, N>::IndCalcW), (T33<R, P, B, N>::IndCalcB),  16919868960, 17168385456)
 
    TB (krpkbb, false, true,  true,  (T33<R, P, B, B>::IndCalcW), (T33<R, P, B, B>::IndCalcB),   8459934480,  8745187680)
 
    TB (krpkrp, true,  false, true,  (T33<R, P, R, P>::IndCalcW), (T33<R, P, R, P>::IndCalcBF), 13338233184, 13338233184)
 
    TB (krnkpp, false, true,  true,  (T33<R, N, P, P>::IndCalcW), (T33<R, N, P, P>::IndCalcB),   6784283808,  6395615340)
 
    TB (krnknp, false, true,  true,  (T33<R, N, N, P>::IndCalcW), (T33<R, N, N, P>::IndCalcB),  17032882752, 16455976740)
 
    TB (krnkbp, false, true,  true,  (T33<R, N, B, P>::IndCalcW), (T33<R, N, B, P>::IndCalcB),  17032882752, 17052633120)
 
    TB (krnkrp, false, false, true,  (T33<R, N, R, P>::IndCalcW), (T33<R, N, R, P>::IndCalcB),  17032882752, 16919868906)
 
    TB (krbkpp, false, true,  true,  (T33<R, B, P, P>::IndCalcW), (T33<R, B, P, P>::IndCalcB),   7031275200,  6395615340)
 
    TB (krbknp, false, true,  true,  (T33<R, B, N, P>::IndCalcW), (T33<R, B, N, P>::IndCalcB),  17652988800, 16455976740)
 
    TB (krbkbp, false, false, true,  (T33<R, B, B, P>::IndCalcW), (T33<R, B, B, P>::IndCalcB),  17652988800, 17052633120)
 
    TB (krbkrp, false, false, true,  (T33<R, B, R, P>::IndCalcW), (T33<R, B, R, P>::IndCalcB),  17652988800, 16919868906)
 
    TB (krrkpp, false, true,  false, (T33<R, R, P, P>::IndCalcW), (T33<R, R, P, P>::IndCalcB),   3428678952,  3197807670)
 
    TB (krrknp, false, true,  true,  (T33<R, R, N, P>::IndCalcW), (T33<R, R, N, P>::IndCalcB),   8608504032,  8227988370)
 
    TB (krrkbp, false, false, true,  (T33<R, R, B, P>::IndCalcW), (T33<R, R, B, P>::IndCalcB),   8608504032,  8526316560)
 
    TB (krrkrp, false, false, true,  (T33<R, R, R, P>::IndCalcW), (T33<R, R, R, P>::IndCalcB),   8608504032,  8459934426)
 
    TB (kqpkpp, false, true,  true,  (T33<Q, P, P, P>::IndCalcW), (T33<Q, P, P, P>::IndCalcB),   4962533664,  4966717366)
 
    TB (kqpknp, false, false, true,  (T33<Q, P, N, P>::IndCalcW), (T33<Q, P, N, P>::IndCalcB),  12651597608, 12972508017)
 
    TB (kqpknn, false, false, true,  (T33<Q, P, N, N>::IndCalcW), (T33<Q, P, N, N>::IndCalcB),   8024443680,  8141507232)
 
    TB (kqpkbp, false, false, true,  (T33<Q, P, B, P>::IndCalcW), (T33<Q, P, B, P>::IndCalcB),  12651597608, 13442882944)
 
    TB (kqpkbn, false, false, true,  (T33<Q, P, B, N>::IndCalcW), (T33<Q, P, B, N>::IndCalcB),  16048887360, 17168385456)
 
    TB (kqpkbb, false, false, true,  (T33<Q, P, B, B>::IndCalcW), (T33<Q, P, B, B>::IndCalcB),   8024443680,  8745187680)
 
    TB (kqpkrp, false, false, true,  (T33<Q, P, R, P>::IndCalcW), (T33<Q, P, R, P>::IndCalcB),  12651597608, 13338233184)
 
    TB (kqpkrn, false, false, true,  (T33<Q, P, R, N>::IndCalcW), (T33<Q, P, R, N>::IndCalcB),  16048887360, 17032882752)
 
    TB (kqpkrb, false, true,  true,  (T33<Q, P, R, B>::IndCalcW), (T33<Q, P, R, B>::IndCalcB),  16048887360, 17652988800)
 
    TB (kqpkrr, false, true,  true,  (T33<Q, P, R, R>::IndCalcW), (T33<Q, P, R, R>::IndCalcB),   8024443680,  8608504032)
 
    TB (kqpkqp, true,  true,  true,  (T33<Q, P, Q, P>::IndCalcW), (T33<Q, P, Q, P>::IndCalcBF), 12651597608, 12651597608)
 
    TB (kqnkpp, false, true,  true,  (T33<Q, N, P, P>::IndCalcW), (T33<Q, N, P, P>::IndCalcB),   6436756032,  6395615340)
 
    TB (kqnknp, false, false, true,  (T33<Q, N, N, P>::IndCalcW), (T33<Q, N, N, P>::IndCalcB),  16160366208, 16455976740)
 
    TB (kqnkbp, false, false, true,  (T33<Q, N, B, P>::IndCalcW), (T33<Q, N, B, P>::IndCalcB),  16160366208, 17052633120)
 
    TB (kqnkrp, false, false, true,  (T33<Q, N, R, P>::IndCalcW), (T33<Q, N, R, P>::IndCalcB),  16160366208, 16919868906)
 
    TB (kqnkqp, false, true,  true,  (T33<Q, N, Q, P>::IndCalcW), (T33<Q, N, Q, P>::IndCalcB),  16160366208, 16048887306)
 
    TB (kqbkpp, false, false, true,  (T33<Q, B, P, P>::IndCalcW), (T33<Q, B, P, P>::IndCalcB),   6669728640,  6395615340)
 
    TB (kqbknp, false, false, true,  (T33<Q, B, N, P>::IndCalcW), (T33<Q, B, N, P>::IndCalcB),  16745276160, 16455976740)
 
    TB (kqbkbp, false, false, true,  (T33<Q, B, B, P>::IndCalcW), (T33<Q, B, B, P>::IndCalcB),  16745276160, 17052633120)
 
    TB (kqbkrp, false, false, true,  (T33<Q, B, R, P>::IndCalcW), (T33<Q, B, R, P>::IndCalcB),  16745276160, 16919868906)
 
    TB (kqbkqp, false, true,  true,  (T33<Q, B, Q, P>::IndCalcW), (T33<Q, B, Q, P>::IndCalcB),  16745276160, 16048887306)
 
    TB (kqrkpp, false, false, true,  (T33<Q, R, P, P>::IndCalcW), (T33<Q, R, P, P>::IndCalcB),   6616853640,  6395615340)
 
    TB (kqrknp, false, false, true,  (T33<Q, R, N, P>::IndCalcW), (T33<Q, R, N, P>::IndCalcB),  16612871664, 16455976740)
 
    TB (kqrkbp, false, false, true,  (T33<Q, R, B, P>::IndCalcW), (T33<Q, R, B, P>::IndCalcB),  16612871664, 17052633120)
 
    TB (kqrkrp, false, false, true,  (T33<Q, R, R, P>::IndCalcW), (T33<Q, R, R, P>::IndCalcB),  16612871664, 16919868906)
 
    TB (kqrkqp, false, true,  true,  (T33<Q, R, Q, P>::IndCalcW), (T33<Q, R, Q, P>::IndCalcB),  16612871664, 16048887306)
 
    TB (kqqkpp, false, false, false, (T33<Q, Q, P, P>::IndCalcW), (T33<Q, Q, P, P>::IndCalcB),   3082498008,  3197807670)
 
    TB (kqqknp, false, false, true,  (T33<Q, Q, N, P>::IndCalcW), (T33<Q, Q, N, P>::IndCalcB),   7739363232,  8227988370)
 
    TB (kqqkbp, false, false, true,  (T33<Q, Q, B, P>::IndCalcW), (T33<Q, Q, B, P>::IndCalcB),   7739363232,  8526316560)
 
    TB (kqqkrp, false, false, true,  (T33<Q, Q, R, P>::IndCalcW), (T33<Q, Q, R, P>::IndCalcB),   7739363232,  8459934426)
 
    TB (kqqkqp, false, false, true,  (T33<Q, Q, Q, P>::IndCalcW), (T33<Q, Q, Q, P>::IndCalcB),   7739363232,  8024443626)
 
#endif  // T_INDEX64
 
#endif  // T33_INCLUDE
 
 
 
#if defined (T42_INCLUDE)
 
    TB (knnnkn, false, false, false, (T42<N, N, N, N>::IndCalcW), (T42<N, N, N, N>::IndCalcB),  795687393,  945889180)
 
    TB (kbnnkn, false, false, false, (T42<B, N, N, N>::IndCalcW), (T42<B, N, N, N>::IndCalcB), 2560971346, 2837667540)
 
    TB (kbbnkn, false, false, false, (T42<B, B, N, N>::IndCalcW), (T42<B, B, N, N>::IndCalcB), 2654033462, 2837667540)
 
    TB (kbbbkn, false, false, false, (T42<B, B, B, N>::IndCalcW), (T42<B, B, B, N>::IndCalcB),  885603570,  945889180)
 
    TB (krnnkn, false, false, false, (T42<R, N, N, N>::IndCalcW), (T42<R, N, N, N>::IndCalcB), 2540315682, 2837667540)
 
    TB (krbbkn, false, false, false, (T42<R, B, B, N>::IndCalcW), (T42<R, B, B, N>::IndCalcB), 2728283251, 2837667540)
 
    TB (krrnkn, false, false, false, (T42<R, R, N, N>::IndCalcW), (T42<R, R, N, N>::IndCalcB), 2611650399, 2837667540)
 
    TB (krrbkn, false, false, false, (T42<R, R, B, N>::IndCalcW), (T42<R, R, B, N>::IndCalcB), 2706549480, 2837667540)
 
    TB (krrrkn, false, false, false, (T42<R, R, R, N>::IndCalcW), (T42<R, R, R, N>::IndCalcB),  864592254,  945889180)
 
    TB (kqnnkn, false, false, false, (T42<Q, N, N, N>::IndCalcW), (T42<Q, N, N, N>::IndCalcB), 2411545114, 2837667540)
 
    TB (kqbbkn, false, false, false, (T42<Q, B, B, N>::IndCalcW), (T42<Q, B, B, N>::IndCalcB), 2588901061, 2837667540)
 
    TB (kqrrkn, false, false, false, (T42<Q, R, R, N>::IndCalcW), (T42<Q, R, R, N>::IndCalcB), 2547484064, 2837667540)
 
    TB (kqqnkn, false, false, false, (T42<Q, Q, N, N>::IndCalcW), (T42<Q, Q, N, N>::IndCalcB), 2350606433, 2837667540)
 
    TB (kqqbkn, false, false, false, (T42<Q, Q, B, N>::IndCalcW), (T42<Q, Q, B, N>::IndCalcB), 2434987407, 2837667540)
 
    TB (kqqrkn, false, false, false, (T42<Q, Q, R, N>::IndCalcW), (T42<Q, Q, R, N>::IndCalcB), 2415271436, 2837667540)
 
    TB (kqqqkn, false, false, false, (T42<Q, Q, Q, N>::IndCalcW), (T42<Q, Q, Q, N>::IndCalcB),  736854363,  945889180)
 
    TB (knnnkb, false, false, false, (T42<N, N, N, B>::IndCalcW), (T42<N, N, N, B>::IndCalcB),  795687393,  980475570)
 
    TB (kbnnkb, false, false, false, (T42<B, N, N, B>::IndCalcW), (T42<B, N, N, B>::IndCalcB), 2560971346, 2941426710)
 
    TB (kbbnkb, false, false, false, (T42<B, B, N, B>::IndCalcW), (T42<B, B, N, B>::IndCalcB), 2654033462, 2941426710)
 
    TB (kbbbkb, false, false, false, (T42<B, B, B, B>::IndCalcW), (T42<B, B, B, B>::IndCalcB),  885603570,  980475570)
 
    TB (krnnkb, false, false, false, (T42<R, N, N, B>::IndCalcW), (T42<R, N, N, B>::IndCalcB), 2540315682, 2941426710)
 
    TB (krbbkb, false, false, false, (T42<R, B, B, B>::IndCalcW), (T42<R, B, B, B>::IndCalcB), 2728283251, 2941426710)
 
    TB (krrnkb, false, false, false, (T42<R, R, N, B>::IndCalcW), (T42<R, R, N, B>::IndCalcB), 2611650399, 2941426710)
 
    TB (krrbkb, false, false, false, (T42<R, R, B, B>::IndCalcW), (T42<R, R, B, B>::IndCalcB), 2706549480, 2941426710)
 
    TB (krrrkb, false, false, false, (T42<R, R, R, B>::IndCalcW), (T42<R, R, R, B>::IndCalcB),  864592254,  980475570)
 
    TB (kqnnkb, false, false, false, (T42<Q, N, N, B>::IndCalcW), (T42<Q, N, N, B>::IndCalcB), 2411545114, 2941426710)
 
    TB (kqbbkb, false, false, false, (T42<Q, B, B, B>::IndCalcW), (T42<Q, B, B, B>::IndCalcB), 2588901061, 2941426710)
 
    TB (kqrrkb, false, false, false, (T42<Q, R, R, B>::IndCalcW), (T42<Q, R, R, B>::IndCalcB), 2547484064, 2941426710)
 
    TB (kqqnkb, false, false, false, (T42<Q, Q, N, B>::IndCalcW), (T42<Q, Q, N, B>::IndCalcB), 2350606433, 2941426710)
 
    TB (kqqbkb, false, false, false, (T42<Q, Q, B, B>::IndCalcW), (T42<Q, Q, B, B>::IndCalcB), 2434987407, 2941426710)
 
    TB (kqqrkb, false, false, false, (T42<Q, Q, R, B>::IndCalcW), (T42<Q, Q, R, B>::IndCalcB), 2415271436, 2941426710)
 
    TB (kqqqkb, false, false, false, (T42<Q, Q, Q, B>::IndCalcW), (T42<Q, Q, Q, B>::IndCalcB),  736854363,  980475570)
 
    TB (knnnkr, false, false, false, (T42<N, N, N, R>::IndCalcW), (T42<N, N, N, R>::IndCalcB),  795687393,  973025640)
 
    TB (kbnnkr, false, false, false, (T42<B, N, N, R>::IndCalcW), (T42<B, N, N, R>::IndCalcB), 2560971346, 2919076920)
 
    TB (kbbnkr, false, false, false, (T42<B, B, N, R>::IndCalcW), (T42<B, B, N, R>::IndCalcB), 2654033462, 2919076920)
 
    TB (kbbbkr, false, false, false, (T42<B, B, B, R>::IndCalcW), (T42<B, B, B, R>::IndCalcB),  885603570,  973025640)
 
    TB (krnnkr, false, false, false, (T42<R, N, N, R>::IndCalcW), (T42<R, N, N, R>::IndCalcB), 2540315682, 2919076920)
 
    TB (krbbkr, false, false, false, (T42<R, B, B, R>::IndCalcW), (T42<R, B, B, R>::IndCalcB), 2728283251, 2919076920)
 
    TB (krrnkr, false, false, false, (T42<R, R, N, R>::IndCalcW), (T42<R, R, N, R>::IndCalcB), 2611650399, 2919076920)
 
    TB (krrbkr, false, false, false, (T42<R, R, B, R>::IndCalcW), (T42<R, R, B, R>::IndCalcB), 2706549480, 2919076920)
 
    TB (krrrkr, false, false, false, (T42<R, R, R, R>::IndCalcW), (T42<R, R, R, R>::IndCalcB),  864592254,  973025640)
 
    TB (kqnnkr, false, false, false, (T42<Q, N, N, R>::IndCalcW), (T42<Q, N, N, R>::IndCalcB), 2411545114, 2919076920)
 
    TB (kqbbkr, false, false, false, (T42<Q, B, B, R>::IndCalcW), (T42<Q, B, B, R>::IndCalcB), 2588901061, 2919076920)
 
    TB (kqrrkr, false, false, false, (T42<Q, R, R, R>::IndCalcW), (T42<Q, R, R, R>::IndCalcB), 2547484064, 2919076920)
 
    TB (kqqnkr, false, false, false, (T42<Q, Q, N, R>::IndCalcW), (T42<Q, Q, N, R>::IndCalcB), 2350606433, 2919076920)
 
    TB (kqqbkr, false, false, false, (T42<Q, Q, B, R>::IndCalcW), (T42<Q, Q, B, R>::IndCalcB), 2434987407, 2919076920)
 
    TB (kqqrkr, false, false, false, (T42<Q, Q, R, R>::IndCalcW), (T42<Q, Q, R, R>::IndCalcB), 2415271436, 2919076920)
 
    TB (kqqqkr, false, false, false, (T42<Q, Q, Q, R>::IndCalcW), (T42<Q, Q, Q, R>::IndCalcB),  736854363,  973025640)
 
    TB (knnnkq, false, false, false, (T42<N, N, N, Q>::IndCalcW), (T42<N, N, N, Q>::IndCalcB),  795687393,  922603650)
 
    TB (kbnnkq, false, false, false, (T42<B, N, N, Q>::IndCalcW), (T42<B, N, N, Q>::IndCalcB), 2560971346, 2767810950)
 
    TB (kbbnkq, false, false, false, (T42<B, B, N, Q>::IndCalcW), (T42<B, B, N, Q>::IndCalcB), 2654033462, 2767810950)
 
    TB (kbbbkq, false, false, false, (T42<B, B, B, Q>::IndCalcW), (T42<B, B, B, Q>::IndCalcB),  885603570,  922603650)
 
    TB (krnnkq, false, false, false, (T42<R, N, N, Q>::IndCalcW), (T42<R, N, N, Q>::IndCalcB), 2540315682, 2767810950)
 
    TB (krbbkq, false, false, false, (T42<R, B, B, Q>::IndCalcW), (T42<R, B, B, Q>::IndCalcB), 2728283251, 2767810950)
 
    TB (krrnkq, false, false, false, (T42<R, R, N, Q>::IndCalcW), (T42<R, R, N, Q>::IndCalcB), 2611650399, 2767810950)
 
    TB (krrbkq, false, false, false, (T42<R, R, B, Q>::IndCalcW), (T42<R, R, B, Q>::IndCalcB), 2706549480, 2767810950)
 
    TB (krrrkq, false, false, false, (T42<R, R, R, Q>::IndCalcW), (T42<R, R, R, Q>::IndCalcB),  864592254,  922603650)
 
    TB (kqnnkq, false, false, false, (T42<Q, N, N, Q>::IndCalcW), (T42<Q, N, N, Q>::IndCalcB), 2411545114, 2767810950)
 
    TB (kqbbkq, false, false, false, (T42<Q, B, B, Q>::IndCalcW), (T42<Q, B, B, Q>::IndCalcB), 2588901061, 2767810950)
 
    TB (kqrrkq, false, false, false, (T42<Q, R, R, Q>::IndCalcW), (T42<Q, R, R, Q>::IndCalcB), 2547484064, 2767810950)
 
    TB (kqqnkq, false, false, false, (T42<Q, Q, N, Q>::IndCalcW), (T42<Q, Q, N, Q>::IndCalcB), 2350606433, 2767810950)
 
    TB (kqqbkq, false, false, false, (T42<Q, Q, B, Q>::IndCalcW), (T42<Q, Q, B, Q>::IndCalcB), 2434987407, 2767810950)
 
    TB (kqqrkq, false, false, false, (T42<Q, Q, R, Q>::IndCalcW), (T42<Q, Q, R, Q>::IndCalcB), 2415271436, 2767810950)
 
    TB (kqqqkq, false, false, false, (T42<Q, Q, Q, Q>::IndCalcW), (T42<Q, Q, Q, Q>::IndCalcB),  736854363,  922603650)
 
#if defined (T_INDEX64)
 
    TB (krbnkn, false, false, false, (T42<R, B, N, N>::IndCalcW), (T42<R, B, N, N>::IndCalcB), 5356454122, 5675335080)
 
    TB (kqbnkn, false, false, false, (T42<Q, B, N, N>::IndCalcW), (T42<Q, B, N, N>::IndCalcB), 5083836303, 5675335080)
 
    TB (kqrnkn, false, false, false, (T42<Q, R, N, N>::IndCalcW), (T42<Q, R, N, N>::IndCalcB), 5042765577, 5675335080)
 
    TB (kqrbkn, false, false, false, (T42<Q, R, B, N>::IndCalcW), (T42<Q, R, B, N>::IndCalcB), 5224919581, 5675335080)
 
    TB (krbnkb, false, false, false, (T42<R, B, N, B>::IndCalcW), (T42<R, B, N, B>::IndCalcB), 5356454122, 5882853420)
 
    TB (kqbnkb, false, false, false, (T42<Q, B, N, B>::IndCalcW), (T42<Q, B, N, B>::IndCalcB), 5083836303, 5882853420)
 
    TB (kqrnkb, false, false, false, (T42<Q, R, N, B>::IndCalcW), (T42<Q, R, N, B>::IndCalcB), 5042765577, 5882853420)
 
    TB (kqrbkb, false, false, false, (T42<Q, R, B, B>::IndCalcW), (T42<Q, R, B, B>::IndCalcB), 5224919581, 5882853420)
 
    TB (krbnkr, false, false, false, (T42<R, B, N, R>::IndCalcW), (T42<R, B, N, R>::IndCalcB), 5356454122, 5838153840)
 
    TB (kqbnkr, false, false, false, (T42<Q, B, N, R>::IndCalcW), (T42<Q, B, N, R>::IndCalcB), 5083836303, 5838153840)
 
    TB (kqrnkr, false, false, false, (T42<Q, R, N, R>::IndCalcW), (T42<Q, R, N, R>::IndCalcB), 5042765577, 5838153840)
 
    TB (kqrbkr, false, false, false, (T42<Q, R, B, R>::IndCalcW), (T42<Q, R, B, R>::IndCalcB), 5224919581, 5838153840)
 
    TB (krbnkq, false, false, false, (T42<R, B, N, Q>::IndCalcW), (T42<R, B, N, Q>::IndCalcB), 5356454122, 5535621900)
 
    TB (kqbnkq, false, false, true,  (T42<Q, B, N, Q>::IndCalcW), (T42<Q, B, N, Q>::IndCalcB), 5083836303, 5535621900)
 
    TB (kqrnkq, false, false, false, (T42<Q, R, N, Q>::IndCalcW), (T42<Q, R, N, Q>::IndCalcB), 5042765577, 5535621900)
 
    TB (kqrbkq, false, false, false, (T42<Q, R, B, Q>::IndCalcW), (T42<Q, R, B, Q>::IndCalcB), 5224919581, 5535621900)
 
 
 
    TB (kpppkp, false, true,  false, (T42<P, P, P, P>::IndCalcW), (T42<P, P, P, P>::IndCalcB),  1196695343,  1348100424)
 
    TB (knppkp, false, true,  true,  (T42<N, P, P, P>::IndCalcW), (T42<N, P, P, P>::IndCalcB),  4796630713,  5271860528)
 
    TB (knnpkp, false, false, true,  (T42<N, N, P, P>::IndCalcW), (T42<N, N, P, P>::IndCalcB),  6156616111,  6835422612)
 
    TB (knnnkp, false, false, false, (T42<N, N, N, P>::IndCalcW), (T42<N, N, N, P>::IndCalcB),  2531022144,  2939087360)
 
    TB (kbppkp, false, true,  true,  (T42<B, P, P, P>::IndCalcW), (T42<B, P, P, P>::IndCalcB),  4969303175,  5271860528)
 
    TB (kbnpkp, false, true,  true,  (T42<B, N, P, P>::IndCalcW), (T42<B, N, P, P>::IndCalcB), 12979462304, 13670845224)
 
    TB (kbnnkp, false, false, true,  (T42<B, N, N, P>::IndCalcW), (T42<B, N, N, P>::IndCalcB),  8146120416,  8817262080)
 
    TB (kbbpkp, false, true,  true,  (T42<B, B, P, P>::IndCalcW), (T42<B, B, P, P>::IndCalcB),  6609838740,  6835422612)
 
    TB (kbbnkp, false, false, true,  (T42<B, B, N, P>::IndCalcW), (T42<B, B, N, P>::IndCalcB),  8441899104,  8817262080)
 
    TB (kbbbkp, false, false, false, (T42<B, B, B, P>::IndCalcW), (T42<B, B, B, P>::IndCalcB),  2816801280,  2939087360)
 
    TB (krppkp, false, true,  true,  (T42<R, P, P, P>::IndCalcW), (T42<R, P, P, P>::IndCalcB),  4929998839,  5271860528)
 
    TB (krnpkp, false, true,  true,  (T42<R, N, P, P>::IndCalcW), (T42<R, N, P, P>::IndCalcB), 12875424829, 13670845224)
 
    TB (krnnkp, false, false, true,  (T42<R, N, N, P>::IndCalcW), (T42<R, N, N, P>::IndCalcB),  8079921360,  8817262080)
 
    TB (krbpkp, false, true,  true,  (T42<R, B, P, P>::IndCalcW), (T42<R, B, P, P>::IndCalcB), 13340861520, 13670845224)
 
    TB (krbnkp, false, false, true,  (T42<R, B, N, P>::IndCalcW), (T42<R, B, N, P>::IndCalcB), 17036639904, 17634524160)
 
    TB (krbbkp, false, false, true,  (T42<R, B, B, P>::IndCalcW), (T42<R, B, B, P>::IndCalcB),  8677177872,  8817262080)
 
    TB (krrpkp, false, true,  true,  (T42<R, R, P, P>::IndCalcW), (T42<R, R, P, P>::IndCalcB),  6504899238,  6835422612)
 
    TB (krrnkp, false, false, true,  (T42<R, R, N, P>::IndCalcW), (T42<R, R, N, P>::IndCalcB),  8306047872,  8817262080)
 
    TB (krrbkp, false, false, true,  (T42<R, R, B, P>::IndCalcW), (T42<R, R, B, P>::IndCalcB),  8607504960,  8817262080)
 
    TB (krrrkp, false, false, false, (T42<R, R, R, P>::IndCalcW), (T42<R, R, R, P>::IndCalcB),  2749283520,  2939087360)
 
    TB (kqppkp, false, true,  true,  (T42<Q, P, P, P>::IndCalcW), (T42<Q, P, P, P>::IndCalcB),  4677701571,  5271860528)
 
    TB (kqnpkp, false, true,  true,  (T42<Q, N, P, P>::IndCalcW), (T42<Q, N, P, P>::IndCalcB), 12219736849, 13670845224)
 
    TB (kqnnkp, false, false, true,  (T42<Q, N, N, P>::IndCalcW), (T42<Q, N, N, P>::IndCalcB),  7670559696,  8817262080)
 
    TB (kqbpkp, false, true,  true,  (T42<Q, B, P, P>::IndCalcW), (T42<Q, B, P, P>::IndCalcB), 12658882024, 13670845224)
 
    TB (kqbnkp, false, false, true,  (T42<Q, B, N, P>::IndCalcW), (T42<Q, B, N, P>::IndCalcB), 16170070752, 17634524160)
 
    TB (kqbbkp, false, false, true,  (T42<Q, B, B, P>::IndCalcW), (T42<Q, B, B, P>::IndCalcB),  8234170512,  8817262080)
 
    TB (kqrpkp, false, false, true,  (T42<Q, R, P, P>::IndCalcW), (T42<Q, R, P, P>::IndCalcB), 12557225406, 13670845224)
 
    TB (kqrnkp, false, false, true,  (T42<Q, R, N, P>::IndCalcW), (T42<Q, R, N, P>::IndCalcB), 16038464256, 17634524160)
 
    TB (kqrbkp, false, false, true,  (T42<Q, R, B, P>::IndCalcW), (T42<Q, R, B, P>::IndCalcB), 16617170832, 17634524160)
 
    TB (kqrrkp, false, false, true,  (T42<Q, R, R, P>::IndCalcW), (T42<Q, R, R, P>::IndCalcB),  8101097520,  8817262080)
 
    TB (kqqpkp, false, false, true,  (T42<Q, Q, P, P>::IndCalcW), (T42<Q, Q, P, P>::IndCalcB),  5851888362,  6835422612)
 
    TB (kqqnkp, false, false, true,  (T42<Q, Q, N, P>::IndCalcW), (T42<Q, Q, N, P>::IndCalcB),  7476276864,  8817262080)
 
    TB (kqqbkp, false, false, true,  (T42<Q, Q, B, P>::IndCalcW), (T42<Q, Q, B, P>::IndCalcB),  7744392000,  8817262080)
 
    TB (kqqrkp, false, false, true,  (T42<Q, Q, R, P>::IndCalcW), (T42<Q, Q, R, P>::IndCalcB),  7680886080,  8817262080)
 
    TB (kqqqkp, false, false, false, (T42<Q, Q, Q, P>::IndCalcW), (T42<Q, Q, Q, P>::IndCalcB),  2343300048,  2939087360)
 
    TB (kpppkn, false, false, false, (T42<P, P, P, N>::IndCalcW), (T42<P, P, P, N>::IndCalcB),  1537640536,  1777129408)
 
    TB (knppkn, false, false, true,  (T42<N, P, P, N>::IndCalcW), (T42<N, P, P, N>::IndCalcB),  6071020409,  6838084896)
 
    TB (knnpkn, false, false, true,  (T42<N, N, P, N>::IndCalcW), (T42<N, N, P, N>::IndCalcB),  7677994559,  8729470080)
 
    TB (kbppkn, false, false, true,  (T42<B, P, P, N>::IndCalcW), (T42<B, P, P, N>::IndCalcB),  6289527204,  6838084896)
 
    TB (kbnpkn, false, false, true,  (T42<B, N, P, N>::IndCalcW), (T42<B, N, P, N>::IndCalcB), 16186823401, 17458940160)
 
    TB (kbbpkn, false, false, true,  (T42<B, B, P, N>::IndCalcW), (T42<B, B, P, N>::IndCalcB),  8243187360,  8729470080)
 
    TB (krppkn, false, false, true,  (T42<R, P, P, N>::IndCalcW), (T42<R, P, P, N>::IndCalcB),  6239761412,  6838084896)
 
    TB (krnpkn, false, false, true,  (T42<R, N, P, N>::IndCalcW), (T42<R, N, P, N>::IndCalcB), 16057066825, 17458940160)
 
    TB (krbpkn, false, false, true,  (T42<R, B, P, N>::IndCalcW), (T42<R, B, P, N>::IndCalcB), 16637490240, 17458940160)
 
    TB (krrpkn, false, false, true,  (T42<R, R, P, N>::IndCalcW), (T42<R, R, P, N>::IndCalcB),  8112305064,  8729470080)
 
    TB (kqppkn, false, false, true,  (T42<Q, P, P, N>::IndCalcW), (T42<Q, P, P, N>::IndCalcB),  5920486098,  6838084896)
 
    TB (kqnpkn, false, false, true,  (T42<Q, N, P, N>::IndCalcW), (T42<Q, N, P, N>::IndCalcB), 15239383701, 17458940160)
 
    TB (kqbpkn, false, false, true,  (T42<Q, B, P, N>::IndCalcW), (T42<Q, B, P, N>::IndCalcB), 15787021288, 17458940160)
 
    TB (kqrpkn, false, false, true,  (T42<Q, R, P, N>::IndCalcW), (T42<Q, R, P, N>::IndCalcB), 15660230819, 17458940160)
 
    TB (kqqpkn, false, false, true,  (T42<Q, Q, P, N>::IndCalcW), (T42<Q, Q, P, N>::IndCalcB),  7297961576,  8729470080)
 
    TB (kpppkb, false, false, false, (T42<P, P, P, B>::IndCalcW), (T42<P, P, P, B>::IndCalcB),  1537640536,  1842024000)
 
    TB (knppkb, false, false, true,  (T42<N, P, P, B>::IndCalcW), (T42<N, P, P, B>::IndCalcB),  6071020409,  7087788000)
 
    TB (knnpkb, false, false, true,  (T42<N, N, P, B>::IndCalcW), (T42<N, N, P, B>::IndCalcB),  7677994559,  9048240000)
 
    TB (kbppkb, false, false, true,  (T42<B, P, P, B>::IndCalcW), (T42<B, P, P, B>::IndCalcB),  6289527204,  7087788000)
 
    TB (kbnpkb, false, false, true,  (T42<B, N, P, B>::IndCalcW), (T42<B, N, P, B>::IndCalcB), 16186823401, 18096480000)
 
    TB (kbbpkb, false, false, true,  (T42<B, B, P, B>::IndCalcW), (T42<B, B, P, B>::IndCalcB),  8243187360,  9048240000)
 
    TB (krppkb, false, false, true,  (T42<R, P, P, B>::IndCalcW), (T42<R, P, P, B>::IndCalcB),  6239761412,  7087788000)
 
    TB (krnpkb, false, false, true,  (T42<R, N, P, B>::IndCalcW), (T42<R, N, P, B>::IndCalcB), 16057066825, 18096480000)
 
    TB (krbpkb, false, false, true,  (T42<R, B, P, B>::IndCalcW), (T42<R, B, P, B>::IndCalcB), 16637490240, 18096480000)
 
    TB (krrpkb, false, false, true,  (T42<R, R, P, B>::IndCalcW), (T42<R, R, P, B>::IndCalcB),  8112305064,  9048240000)
 
    TB (kqppkb, false, false, true,  (T42<Q, P, P, B>::IndCalcW), (T42<Q, P, P, B>::IndCalcB),  5920486098,  7087788000)
 
    TB (kqnpkb, false, false, true,  (T42<Q, N, P, B>::IndCalcW), (T42<Q, N, P, B>::IndCalcB), 15239383701, 18096480000)
 
    TB (kqbpkb, false, false, true,  (T42<Q, B, P, B>::IndCalcW), (T42<Q, B, P, B>::IndCalcB), 15787021288, 18096480000)
 
    TB (kqrpkb, false, false, true,  (T42<Q, R, P, B>::IndCalcW), (T42<Q, R, P, B>::IndCalcB), 15660230819, 18096480000)
 
    TB (kqqpkb, false, false, true,  (T42<Q, Q, P, B>::IndCalcW), (T42<Q, Q, P, B>::IndCalcB),  7297961576,  9048240000)
 
    TB (kpppkr, false, false, false, (T42<P, P, P, R>::IndCalcW), (T42<P, P, P, R>::IndCalcB),  1537640536,  1827875872)
 
    TB (knppkr, false, false, true,  (T42<N, P, P, R>::IndCalcW), (T42<N, P, P, R>::IndCalcB),  6071020409,  7033481568)
 
    TB (knnpkr, false, false, true,  (T42<N, N, P, R>::IndCalcW), (T42<N, N, P, R>::IndCalcB),  7677994559,  8978912640)
 
    TB (kbppkr, false, true,  true,  (T42<B, P, P, R>::IndCalcW), (T42<B, P, P, R>::IndCalcB),  6289527204,  7033481568)
 
    TB (kbnpkr, false, true,  true,  (T42<B, N, P, R>::IndCalcW), (T42<B, N, P, R>::IndCalcB), 16186823401, 17957825280)
 
    TB (kbbpkr, false, true,  true,  (T42<B, B, P, R>::IndCalcW), (T42<B, B, P, R>::IndCalcB),  8243187360,  8978912640)
 
    TB (krppkr, false, false, true,  (T42<R, P, P, R>::IndCalcW), (T42<R, P, P, R>::IndCalcB),  6239761412,  7033481568)
 
    TB (krnpkr, false, false, true,  (T42<R, N, P, R>::IndCalcW), (T42<R, N, P, R>::IndCalcB), 16057066825, 17957825280)
 
    TB (krbpkr, false, false, true,  (T42<R, B, P, R>::IndCalcW), (T42<R, B, P, R>::IndCalcB), 16637490240, 17957825280)
 
    TB (krrpkr, false, false, true,  (T42<R, R, P, R>::IndCalcW), (T42<R, R, P, R>::IndCalcB),  8112305064,  8978912640)
 
    TB (kqppkr, false, false, true,  (T42<Q, P, P, R>::IndCalcW), (T42<Q, P, P, R>::IndCalcB),  5920486098,  7033481568)
 
    TB (kqnpkr, false, false, true,  (T42<Q, N, P, R>::IndCalcW), (T42<Q, N, P, R>::IndCalcB), 15239383701, 17957825280)
 
    TB (kqbpkr, false, false, true,  (T42<Q, B, P, R>::IndCalcW), (T42<Q, B, P, R>::IndCalcB), 15787021288, 17957825280)
 
    TB (kqrpkr, false, false, true,  (T42<Q, R, P, R>::IndCalcW), (T42<Q, R, P, R>::IndCalcB), 15660230819, 17957825280)
 
    TB (kqqpkr, false, false, true,  (T42<Q, Q, P, R>::IndCalcW), (T42<Q, Q, P, R>::IndCalcB),  7297961576,  8978912640)
 
    TB (kpppkq, false, true,  false, (T42<P, P, P, Q>::IndCalcW), (T42<P, P, P, Q>::IndCalcB),  1537640536,  1733232160)
 
    TB (knppkq, false, true,  true,  (T42<N, P, P, Q>::IndCalcW), (T42<N, P, P, Q>::IndCalcB),  6071020409,  6669309024)
 
    TB (knnpkq, false, false, true,  (T42<N, N, P, Q>::IndCalcW), (T42<N, N, P, Q>::IndCalcB),  7677994559,  8514011520)
 
    TB (kbppkq, false, true,  true,  (T42<B, P, P, Q>::IndCalcW), (T42<B, P, P, Q>::IndCalcB),  6289527204,  6669309024)
 
    TB (kbnpkq, false, true,  true,  (T42<B, N, P, Q>::IndCalcW), (T42<B, N, P, Q>::IndCalcB), 16186823401, 17028023040)
 
    TB (kbbpkq, false, true,  true,  (T42<B, B, P, Q>::IndCalcW), (T42<B, B, P, Q>::IndCalcB),  8243187360,  8514011520)
 
    TB (krppkq, false, true,  true,  (T42<R, P, P, Q>::IndCalcW), (T42<R, P, P, Q>::IndCalcB),  6239761412,  6669309024)
 
    TB (krnpkq, false, true,  true,  (T42<R, N, P, Q>::IndCalcW), (T42<R, N, P, Q>::IndCalcB), 16057066825, 17028023040)
 
    TB (krbpkq, false, true,  true,  (T42<R, B, P, Q>::IndCalcW), (T42<R, B, P, Q>::IndCalcB), 16637490240, 17028023040)
 
    TB (krrpkq, false, true,  true,  (T42<R, R, P, Q>::IndCalcW), (T42<R, R, P, Q>::IndCalcB),  8112305064,  8514011520)
 
    TB (kqppkq, false, true,  true,  (T42<Q, P, P, Q>::IndCalcW), (T42<Q, P, P, Q>::IndCalcB),  5920486098,  6669309024)
 
    TB (kqnpkq, false, true,  true,  (T42<Q, N, P, Q>::IndCalcW), (T42<Q, N, P, Q>::IndCalcB), 15239383701, 17028023040)
 
    TB (kqbpkq, false, true,  true,  (T42<Q, B, P, Q>::IndCalcW), (T42<Q, B, P, Q>::IndCalcB), 15787021288, 17028023040)
 
    TB (kqrpkq, false, true,  true,  (T42<Q, R, P, Q>::IndCalcW), (T42<Q, R, P, Q>::IndCalcB), 15660230819, 17028023040)
 
    TB (kqqpkq, false, false, true,  (T42<Q, Q, P, Q>::IndCalcW), (T42<Q, Q, P, Q>::IndCalcB),  7297961576,  8514011520)
 
 
 
#endif
 
#endif
 
    };
 
 
 
#undef  P
 
#undef  N
 
#undef  B
 
#undef  R
 
#undef  Q
 
 
 
//  Helper structure
 
//  Used to classify on-board position
 
 
 
union CUTbReference     // Hungarian: utbr
 
    {
 
    int             m_iDesc;            // Negative if have to inverse
 
    int             m_cPieces;
 
    CUTbReference   *m_utbReference;
 
    };
 
 
 
//  Root of the search tree
 
 
 
static CUTbReference rgutbReference [MAX_NON_KINGS + 2];
 
 
 
// Convert TB name (e.g. KQKR) into set of counters
 
 
 
static const char *PchSetHalfCounters
 
    (
 
    int         *piCounters,
 
    const char  *pch
 
    )
 
    {
 
    memset (piCounters, 0, 5 * sizeof (int));
 
    while ('\0' != *pch && 'k' != *pch)
 
        {
 
        piece pi;
 
 
 
        pi = x_piecePawn;   // To make compiler happy
 
        switch (*pch)
 
            {
 
        case 'p':
 
            pi = x_piecePawn;
 
            break;
 
        case 'n':
 
            pi = x_pieceKnight;
 
            break;
 
        case 'b':
 
            pi = x_pieceBishop;
 
            break;
 
        case 'r':
 
            pi = x_pieceRook;
 
            break;
 
        case 'q':
 
            pi = x_pieceQueen;
 
            break;
 
        default:
 
            assert (0);
 
            }
 
        piCounters [pi-1] ++;
 
        pch ++;
 
        }
 
        return pch;
 
    };
 
 
 
static void VSetCounters
 
    (
 
    int         *piCounters,
 
    const char  *pch
 
    )
 
    {
 
    assert ('k' == *pch);
 
    pch = PchSetHalfCounters (piCounters, pch+1);
 
    assert ('k' == *pch);
 
    pch = PchSetHalfCounters (piCounters+5, pch+1);
 
    assert ('\0' == *pch);
 
    }
 
 
 
//  Following functions return TB index
 
//  They differ by input arguments
 
 
 
extern "C" int IDescFindFromCounters
 
    (
 
    int *piCount
 
    )
 
    {
 
    CUTbReference *putbr = rgutbReference;
 
 
 
    if (piCount[0] > putbr->m_cPieces)
 
        goto not_found;
 
    putbr = putbr[1 + piCount[0]].m_utbReference;
 
    if (piCount[1] > putbr->m_cPieces)
 
        goto not_found;
 
    putbr = putbr[1 + piCount[1]].m_utbReference;
 
    if (piCount[2] > putbr->m_cPieces)
 
        goto not_found;
 
    putbr = putbr[1 + piCount[2]].m_utbReference;
 
    if (piCount[3] > putbr->m_cPieces)
 
        goto not_found;
 
    putbr = putbr[1 + piCount[3]].m_utbReference;
 
    if (piCount[4] > putbr->m_cPieces)
 
        goto not_found;
 
    putbr = putbr[1 + piCount[4]].m_utbReference;
 
    if (piCount[5] > putbr->m_cPieces)
 
        goto not_found;
 
    putbr = putbr[1 + piCount[5]].m_utbReference;
 
    if (piCount[6] > putbr->m_cPieces)
 
        goto not_found;
 
    putbr = putbr[1 + piCount[6]].m_utbReference;
 
    if (piCount[7] > putbr->m_cPieces)
 
        goto not_found;
 
    putbr = putbr[1 + piCount[7]].m_utbReference;
 
    if (piCount[8] > putbr->m_cPieces)
 
        goto not_found;
 
    putbr = putbr[1 + piCount[8]].m_utbReference;
 
    if (piCount[9] <= putbr->m_cPieces)
 
        return putbr[1 + piCount[9]].m_iDesc;
 
not_found:
 
    return 0;
 
    }
 
 
 
int IDescFind
 
    (
 
    square  *p_piW, // IN | Pointer to array of white pieces (king excluded)
 
    square  *p_piB, // IN | Pointer to array of black pieces (king excluded)
 
    int     cWhite, // IN | Counter of white pieces (king excluded)
 
    int     cBlack  // IN | Counter of black pieces (king excluded)
 
    )
 
    {
 
    int rgiCount[10];
 
 
 
    // Set pieces counters
 
    rgiCount[0] =
 
    rgiCount[1] =
 
    rgiCount[2] =
 
    rgiCount[3] =
 
    rgiCount[4] =
 
    rgiCount[5] =
 
    rgiCount[6] =
 
    rgiCount[7] =
 
    rgiCount[8] =
 
    rgiCount[9] = 0;
 
    while (cWhite)
 
        {
 
        rgiCount[(*p_piW)-1] ++;
 
        p_piW ++;
 
        cWhite --;
 
        }
 
    while (cBlack)
 
        {
 
        rgiCount[5-1+(*p_piB)] ++;
 
        p_piB ++;
 
        cBlack --;
 
        }
 
    return IDescFindFromCounters (rgiCount);
 
    }
 
 
 
int IDescFindByName
 
    (
 
    char    *pchName
 
    )
 
    {
 
    int rgiCount[10];
 
 
 
    VSetCounters (rgiCount, pchName);
 
    return IDescFindFromCounters (rgiCount);
 
    }
 
 
 
//-----------------------------------------------------------------------------
 
//
 
//  Function used during initialization
 
 
 
//  Set of functions to create search table
 
 
 
static CUTbReference *PutbrCreateSubtable
 
    (
 
    int cPieces,    //  IN | # of pieces ramaining on board
 
    int iDepth      //  IN | Recursion depth (# of piece classes left)
 
    )
 
    {
 
    CUTbReference *putbr;
 
 
 
    putbr = (CUTbReference *) PvMalloc ((cPieces + 2) * sizeof (CUTbReference));
 
    putbr[0].m_cPieces = cPieces;
 
    if (0 == iDepth)
 
        {
 
        for (int i = 0; i <= cPieces; i ++)
 
            putbr[i+1].m_iDesc = 0;
 
        }
 
    else
 
        {
 
        for (int i = 0; i <= cPieces; i ++)
 
            putbr[i+1].m_utbReference = PutbrCreateSubtable (cPieces-i, iDepth-1);
 
        }
 
    return putbr;
 
    }
 
 
 
static bool fTbTableCreated = false;
 
 
 
static void VCreateEmptyTbTable (void)
 
    {
 
    if (fTbTableCreated)
 
        return;
 
    fTbTableCreated = true;
 
    rgutbReference[0].m_cPieces = MAX_NON_KINGS;
 
    for (int i = 0; i <= MAX_NON_KINGS; i ++)
 
        rgutbReference[i+1].m_utbReference = PutbrCreateSubtable (MAX_NON_KINGS - i, 8);
 
    }
 
 
 
// Insert TB (e.g. KQKR) into search table
 
 
 
static bool FRegisterHalf
 
    (
 
    int     iTb,
 
    int     *piCount
 
    )
 
    {
 
    CUTbReference   *putbr;
 
 
 
    putbr = rgutbReference;
 
    for (int i = 0; i < 9; i ++)
 
        {
 
        if (piCount[i] > putbr->m_cPieces)
 
            return false;
 
        putbr = putbr[1 + piCount[i]].m_utbReference;
 
        }
 
    if (piCount[9] > putbr->m_cPieces)
 
        return false;
 
    putbr[1 + piCount[9]].m_iDesc = iTb;
 
    return true;
 
    }
 
 
 
// Insert TB (both, e.g. KQKR and KRKQ) into search table
 
 
 
static bool FRegisterTb
 
    (
 
    CTbDesc *ptbDesc
 
    )
 
    {
 
    int     rgiCount[10];
 
    bool    fInserted;
 
 
 
    VSetCounters (rgiCount, ptbDesc->m_rgchName);
 
    fInserted = FRegisterHalf (ptbDesc->m_iTbId, rgiCount);
 
    if (fInserted)
 
        {
 
        if (ptbDesc->m_fSymmetric)
 
            return true;
 
        for (int i = 0; i < 5; i ++)
 
            {
 
            int iTemp;
 
 
 
            iTemp = rgiCount[i];
 
            rgiCount[i] = rgiCount[i+5];
 
            rgiCount[i+5] = iTemp;
 
            }
 
        fInserted = FRegisterHalf (-ptbDesc->m_iTbId, rgiCount);
 
        assert (fInserted);
 
        }
 
    return fInserted;
 
    }
 
 
 
// File mapping - Win32 code only
 
 
 
#if defined (_WIN32) || defined(_WIN64)
 
 
 
static BYTE * PbMapFileForRead
 
    (
 
    char    *szName,
 
    HANDLE  *phFile,
 
    HANDLE  *phFileMapping
 
    )
 
    {
 
    HANDLE  hFile;
 
    HANDLE  hFileMapping;
 
    LPVOID  lpFileBase;
 
 
 
    hFile = CreateFile ((STRING_PTR) (szName), GENERIC_READ, FILE_SHARE_READ,
 
                        NULL, OPEN_EXISTING,
 
                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
 
    if (INVALID_HANDLE_VALUE == hFile)
 
        {
 
        printf("*** Couldn't open file %s with CreateFile()\n", szName);
 
        exit (1);
 
        }
 
    hFileMapping = CreateFileMapping (hFile, NULL, PAGE_READONLY, 0, 0, NULL);
 
    if (0 == hFileMapping)
 
        {
 
        CloseHandle (hFile);
 
        printf ("*** Couldn't open file %s mapping with CreateFileMapping()\n", szName);
 
        exit (1);
 
        }
 
    lpFileBase = MapViewOfFile (hFileMapping, FILE_MAP_READ, 0, 0, 0);
 
    if (0 == lpFileBase)
 
        {
 
        CloseHandle (hFileMapping);
 
        CloseHandle (hFile);
 
        printf ("*** Couldn't map view of file %s with MapViewOfFile()\n", szName);
 
        exit (1);
 
        }
 
    if (NULL != phFile)
 
        *phFile = hFile;
 
    if (NULL != phFileMapping)
 
        *phFileMapping = hFileMapping;
 
    return (BYTE*) lpFileBase;
 
    }
 
 
 
static void VUnmapFile
 
    (
 
    BYTE    *pbFileBase,
 
    HANDLE  hFile,
 
    HANDLE  hFileMapping
 
    )
 
    {
 
    BOOL fFailed;
 
 
 
    fFailed = (0 == UnmapViewOfFile (pbFileBase)) |
 
              (0 == CloseHandle (hFileMapping)) |
 
              (0 == CloseHandle (hFile));
 
    if (fFailed) 
 
        {
 
        printf ("*** Couldn't unmap file\n");
 
        exit (1);
 
        }
 
    }
 
 
 
#endif
 
 
 
//-----------------------------------------------------------------------------
 
//
 
//  TB caching
 
 
 
#if !defined (TB_CB_CACHE_CHUNK)
 
#define TB_CB_CACHE_CHUNK           8192 /* Must be power of 2 */
 
#define LOG2_TB_CB_CACHE_CHUNK      13
 
#endif
 
 
 
#define TB_CHUNK(index)             ((index) >> LOG2_TB_CB_CACHE_CHUNK)
 
#define TB_OFFSET(index)            ((index) % TB_CB_CACHE_CHUNK)
 
#define TB_DIRECTORY_ENTRY(chunk)   ((chunk) % TB_DIRECTORY_SIZE)
 
 
 
#define WIDE_TB_CHUNK(index)        ((index) >> (LOG2_TB_CB_CACHE_CHUNK-1))
 
#define WIDE_TB_OFFSET(index)       ((index) % (TB_CB_CACHE_CHUNK/2))*2
 
 
 
struct CTbCache         //Hungarian: tbc
 
    {
 
    int volatile                m_iTb;
 
    color volatile              m_color;
 
    unsigned volatile           m_indChunk;
 
    volatile CTbCache *volatile m_ptbcNext;     // Next element in double-linked general LRU list
 
    volatile CTbCache *volatile m_ptbcPrev;     // Previous element in double-linked general LRU list
 
    volatile CTbCache *volatile m_ptbcTbNext;   // Next element in double-linked cache bucket LRU list
 
    volatile CTbCache *volatile m_ptbcTbPrev;   // Previous element in double-linked cache bucket LRU list
 
    BYTE                        *m_pbData;
 
    };
 
 
 
static CTbCache *ptbcTbCache;   // Cache memory
 
static ULONG    ctbcTbCache;    // Cache size (in entries)
 
 
 
static volatile CTbCache * volatile ptbcHead;       // Head of that list
 
static volatile CTbCache * volatile ptbcTail;       // Last element in that list
 
static volatile CTbCache * volatile ptbcFree;       // First free cache header
 
 
 
static INLINE void VTbCloseFile
 
    (
 
    int     iTb,
 
    color   side
 
    )
 
    {
 
    for (int iExtent = 0; iExtent < MAX_EXTENTS; iExtent ++) {
 
        if (NULL != rgtbdDesc[iTb].m_rgfpFiles[side][iExtent])
 
            {
 
            Lock (rgtbdDesc[iTb].m_rglockFiles[side]);
 
            if (NULL != rgtbdDesc[iTb].m_rgfpFiles[side][iExtent])
 
                {
 
                fclose (rgtbdDesc[iTb].m_rgfpFiles[side][iExtent]);
 
                rgtbdDesc[iTb].m_rgfpFiles[side][iExtent] = NULL;
 
                }
 
            Unlock (rgtbdDesc[iTb].m_rglockFiles[side]);
 
            }
 
        }
 
    }
 
 
 
extern "C" void VTbCloseFiles (void)
 
    {
 
    // Initialized?
 
    if (0 == ctbcTbCache)
 
        return;
 
 
 
    // Walk through TB cache and close all opened files
 
    for (int iTb = 1; iTb < cTb; iTb ++)
 
        {
 
        VTbCloseFile (iTb, x_colorWhite);
 
        VTbCloseFile (iTb, x_colorBlack);
 
        }
 
    }
 
 
 
void VTbClearCache (void)
 
    {
 
    CTbCacheBucket  *prgtbcbBuckets;
 
    CTbCache *ptbc;
 
    BYTE *pb;
 
    ULONG i;
 
 
 
    // Initialized?
 
    if (0 == ctbcTbCache)
 
        return;
 
    VTbCloseFiles();
 
    
 
    // Initialize all lists
 
    pb = (BYTE *) & ptbcTbCache [ctbcTbCache];
 
    for (i = 0, ptbc = ptbcTbCache; i < ctbcTbCache; i ++, ptbc ++)
 
        {
 
        ptbc->m_pbData = pb + i*(TB_CB_CACHE_CHUNK+32+4);
 
        ptbc->m_ptbcTbPrev =
 
        ptbc->m_ptbcTbNext =
 
        ptbc->m_ptbcPrev = NULL;
 
        ptbc->m_ptbcNext = (ptbc + 1);
 
        }
 
    ptbc[-1].m_ptbcNext = NULL;
 
 
 
    // Clear references from TBs
 
    for (int iTb = 1; iTb < cTb; iTb ++)
 
        {
 
        for (color sd=x_colorWhite; sd <= x_colorBlack; sd ++)
 
            {
 
            prgtbcbBuckets = rgtbdDesc[iTb].m_prgtbcbBuckets[sd];
 
            if (NULL != prgtbcbBuckets)
 
                {
 
#if (CPUS > 1)
 
                for (i = 0; i < TB_DIRECTORY_SIZE; i ++)
 
                    LockFree (prgtbcbBuckets[i].m_lock);
 
#endif
 
                memset (prgtbcbBuckets, 0, TB_DIRECTORY_SIZE * sizeof (CTbCacheBucket));
 
#if (CPUS > 1)
 
                for (i = 0; i < TB_DIRECTORY_SIZE; i ++)
 
                    LockInit (prgtbcbBuckets[i].m_lock);
 
#endif
 
                }
 
            }
 
        }
 
 
 
    // Set globals
 
    ptbcHead = ptbcTail = NULL;
 
    ptbcFree = ptbcTbCache;
 
    }
 
 
 
extern "C" int FTbSetCacheSize
 
    (
 
    void    *pv,
 
    ULONG   cbSize
 
    )
 
    {
 
    VTbCloseFiles();
 
    ctbcTbCache = 0;
 
    ptbcHead = NULL;
 
    if (cbSize < sizeof (CTbCache))
 
        return false;
 
    ptbcTbCache = (CTbCache*) pv;
 
    ctbcTbCache = cbSize / (sizeof (CTbCache) + TB_CB_CACHE_CHUNK+32+4);
 
    VTbClearCache();
 
    return true;
 
    }
 
 
 
// Table registered
 
 
 
INLINE int FRegisteredExtent
 
    (
 
    int     iTb,
 
    color   side,
 
    int     iExtent
 
    )
 
    {
 
    if (rgtbdDesc[iTb].m_fSymmetric)
 
        side = x_colorWhite;
 
    return (NULL != rgtbdDesc[iTb].m_rgpchFileName[side][iExtent]);
 
    }
 
 
 
INLINE int FRegistered
 
    (
 
    int     iTb,
 
    color   side
 
    )
 
    {
 
    int iExtent, cExtents;
 
    INDEX cBytes;
 
 
 
    if (rgtbdDesc[iTb].m_fSplit)
 
        {
 
        cBytes = rgtbdDesc[iTb].m_rgcbLength[side];
 
        if (rgtbdDesc[iTb].m_f16bit)
 
            cBytes *= 2;
 
        cExtents = (int) (cBytes >> 31) + 1;
 
        }
 
    else
 
        cExtents = 1;
 
    for (iExtent = 0; iExtent < cExtents; iExtent ++)
 
        {
 
        if (FRegisteredExtent (iTb, side, iExtent))
 
            return true;
 
        }
 
    return false;
 
    }
 
 
 
extern "C" int FRegisteredFun
 
    (
 
    int     iTb,
 
    color   side
 
    )
 
    {
 
    return FRegistered (iTb, side);
 
    }
 
 
 
// Return function that calculates the necessary index:
 
 
 
#define PfnIndCalc(iTb, side)   (rgtbdDesc[iTb].m_rgpfnCalcIndex[side])
 
extern "C" PfnCalcIndex PfnIndCalcFun
 
    (
 
    int     iTb,
 
    color   side
 
    )
 
    {
 
    return PfnIndCalc (iTb, side);
 
    }
 
 
 
// Read whole file into memory
 
 
 
extern "C" int FReadTableToMemory
 
    (
 
    int     iTb,    // IN | Tablebase
 
    color   side,   // IN | Side to move
 
    BYTE    *pb     // IN | Either buffer or NULL
 
    )
 
    {
 
    char    *pszName;
 
    INDEX   cb;
 
    FILE    *fp;
 
 
 
    if (rgtbdDesc[iTb].m_fSymmetric)
 
        side = x_colorWhite;
 
    if (!FRegistered (iTb, side))
 
        return false;
 
    if (rgtbdDesc[iTb].m_fSplit)
 
        return false;
 
    for (int iExtent = 0; iExtent < MAX_EXTENTS; iExtent ++)
 
        {
 
        if (NULL != rgtbdDesc[iTb].m_rgpdiDecodeInfo[side][iExtent])
 
            return false;
 
        }
 
    if (NULL != rgtbdDesc[iTb].m_rgpbRead[side])
 
        return true;
 
    pszName = rgtbdDesc[iTb].m_rgpchFileName[side][0];
 
    fp = fopen (pszName, "rb");
 
    if (NULL == fp)
 
        return false;
 
 
 
    // Find database size
 
#if defined (NEW)
 
    cb = rgtbdDesc[iTb].m_rgcbLength[side];
 
    if (0 == cb)
 
        {
 
#endif
 
        if (0 != fseek (fp, 0L, SEEK_END))
 
            {
 
            printf ("*** Seek in %s failed\n", pszName);
 
            exit (1);
 
            }
 
        cb = ftell (fp);
 
        if (-1 == (int) cb)
 
            {
 
            printf ("*** Cannot find length of %s\n", pszName);
 
            exit (1);
 
            }
 
        if (0 != fseek (fp, 0L, SEEK_SET))
 
            {
 
            printf ("*** Seek in %s failed\n", pszName);
 
            exit (1);
 
            }
 
#if defined (NEW)
 
        }
 
#if defined (T33_INCLUDE) || defined (KPPKP_16BIT)
 
    else if (rgtbdDesc[iTb].m_f16bit)
 
        {
 
        if ((size_t) cb != cb)   // Overflow
 
            {
 
            printf ("*** %s too big to read into memory\n", pszName);
 
            exit (1);
 
            }
 
        }
 
#endif
 
#endif
 
    
 
    // If buffer not specified, allocate memory for it
 
    if (NULL == pb)
 
        pb = (BYTE*) PvMalloc ((size_t) cb); // Pierre-Marie Baty -- added type cast
 
 
 
    // Read file into memory
 
    if (cb != (INDEX) fread (pb, 1, (size_t) cb, fp)) // Pierre-Marie Baty -- added type cast
 
        {
 
        printf ("*** Read from %s failed\n", pszName);
 
        exit (1);
 
        }
 
    fclose (fp);
 
 
 
    // All done
 
    rgtbdDesc[iTb].m_rgpbRead[side] = pb;
 
    return true;
 
    }
 
 
 
#if defined (_WIN32) || defined(_WIN64)
 
 
 
// Map whole file into memory
 
 
 
extern "C" int FMapTableToMemory
 
    (
 
    int     iTb,    // IN | Tablebase
 
    color   side    // IN | Side to move
 
    )
 
    {
 
    char *pszName;
 
 
 
    if (rgtbdDesc[iTb].m_fSymmetric)
 
        side = x_colorWhite;
 
    if (!FRegistered (iTb, side))
 
        return false;
 
    if (rgtbdDesc[iTb].m_fSplit)
 
        return false;
 
    for (int iExtent = 0; iExtent < MAX_EXTENTS; iExtent ++)
 
        {
 
        if (NULL != rgtbdDesc[iTb].m_rgpdiDecodeInfo[side][iExtent])
 
            return false;
 
        }
 
    pszName = rgtbdDesc[iTb].m_rgpchFileName[side][0];
 
    if (NULL == rgtbdDesc[iTb].m_rgpbRead[side])
 
        {
 
        rgtbdDesc[iTb].m_rgpbRead[side] = PbMapFileForRead (pszName, NULL, NULL);
 
        if (fVerbose)
 
            printf ("%s mapped\n", pszName);
 
        }
 
    return true;
 
    }
 
 
 
// Map whole file into memory
 
 
 
int FMapTableToMemory
 
    (
 
    int     iTb,            // IN  | Tablebase
 
    color   side,           // IN  | Side to move
 
    HANDLE  *phFile,        // OUT | File handle will be written here
 
    HANDLE  *phFileMapping  // OUT | File mapping handle will be written here
 
    )
 
    {
 
    char *pszName;
 
 
 
    if (rgtbdDesc[iTb].m_fSymmetric)
 
        side = x_colorWhite;
 
    if (!FRegistered (iTb, side))
 
        return false;
 
    if (rgtbdDesc[iTb].m_fSplit)
 
        return false;
 
    pszName = rgtbdDesc[iTb].m_rgpchFileName[side][0];
 
    if (NULL == rgtbdDesc[iTb].m_rgpbRead[side])
 
        {
 
        rgtbdDesc[iTb].m_rgpbRead[side] = PbMapFileForRead (pszName, phFile, phFileMapping);
 
        if (fVerbose)
 
            printf ("%s mapped\n", pszName);
 
        }
 
    return true;
 
    }
 
 
 
// Unmap whole file from memory
 
 
 
int FUnMapTableFromMemory
 
    (
 
    int     iTb,            // IN | Tablebase
 
    color   side,           // IN | Side to move
 
    HANDLE  hFile,          // IN | File handle will be written here
 
    HANDLE  hFileMapping    // IN | File mapping handle will be written here
 
    )
 
    {
 
    char *pszName;
 
 
 
    if (rgtbdDesc[iTb].m_fSymmetric)
 
        side = x_colorWhite;
 
    if (!FRegistered (iTb, side))
 
        return false;
 
    if (rgtbdDesc[iTb].m_fSplit)
 
        return false;
 
    pszName = rgtbdDesc[iTb].m_rgpchFileName[side][0];
 
    if (NULL != rgtbdDesc[iTb].m_rgpbRead[side])
 
        {
 
        VUnmapFile (rgtbdDesc[iTb].m_rgpbRead[side], hFile, hFileMapping);
 
        rgtbdDesc[iTb].m_rgpbRead[side] = NULL;
 
        if (fVerbose)
 
            printf ("%s unmapped\n", pszName);
 
        }
 
    return true;
 
    }
 
 
 
#endif
 
 
 
// Probe TB - lower level (not exportable) function
 
 
 
static int TB_FASTCALL TbtProbeTable
 
    (
 
    int      iTb,
 
    color    side,
 
    unsigned indChunk,
 
    unsigned indInChunk
 
    )
 
    {
 
    CTbDesc *ptbd;
 
    int iDirectory, iExtent, iPhysicalChunk;
 
    volatile CTbCache * ptbc;
 
    volatile CTbCache * ptbcTbFirst;
 
    const char *pszFileName;
 
 
 
    ptbd = & rgtbdDesc[iTb];
 
    iDirectory = TB_DIRECTORY_ENTRY (indChunk);
 
 
 
    // Head of the cache bucket LRU list
 
    Lock (ptbd->m_prgtbcbBuckets[side][iDirectory].m_lock);
 
    ptbcTbFirst = ptbd->m_prgtbcbBuckets[side][iDirectory].m_ptbcFirst;
 
 
 
    // First, search entry in the cache
 
    for (ptbc = ptbcTbFirst; NULL != ptbc; ptbc = ptbc->m_ptbcTbNext)
 
        {
 
        if (indChunk == ptbc->m_indChunk)
 
            {
 
            // Found - move cache entry to the head of the general LRU list
 
            Lock (lockLRU);
 
            if (ptbc != ptbcHead)
 
                {
 
                // Remove it from its current position
 
                ptbc->m_ptbcPrev->m_ptbcNext = ptbc->m_ptbcNext;
 
                if (NULL == ptbc->m_ptbcNext)
 
                    ptbcTail = ptbc->m_ptbcPrev;
 
                else
 
                    ptbc->m_ptbcNext->m_ptbcPrev = ptbc->m_ptbcPrev;
 
                // Insert it at the head
 
                ptbc->m_ptbcPrev = NULL;
 
                ptbc->m_ptbcNext = ptbcHead;
 
                ptbcHead->m_ptbcPrev = ptbc;
 
                ptbcHead = ptbc;
 
                }
 
            Unlock (lockLRU);
 
            // Move cache entry to the head of the cache bucket LRU list
 
            if (ptbc != ptbcTbFirst)
 
                {
 
                // Remove it from list
 
                ptbc->m_ptbcTbPrev->m_ptbcTbNext = ptbc->m_ptbcTbNext;
 
                if (NULL != ptbc->m_ptbcTbNext)
 
                    ptbc->m_ptbcTbNext->m_ptbcTbPrev = ptbc->m_ptbcTbPrev;
 
                // Insert it at head
 
                ptbc->m_ptbcTbPrev = NULL;
 
                ptbc->m_ptbcTbNext = ptbcTbFirst;
 
                ptbcTbFirst->m_ptbcTbPrev = ptbc;
 
                ptbd->m_prgtbcbBuckets[side][iDirectory].m_ptbcFirst = ptbc;
 
                }
 
            int tb;
 
 
 
            tb = (tb_t) (ptbc->m_pbData[(ULONG)indInChunk]);
 
            Unlock (ptbd->m_prgtbcbBuckets[side][iDirectory].m_lock);
 
            return tb;
 
            }
 
        }
 
    // Not in the cache - have to read it from disk.
 
    // I decided to write simple code - so sometimes it's possible that
 
    // 2 threads will simultaneously read exactly the same chunk into 2
 
    // different cache entries. In that case, all subsequent cache probes
 
    // will hit the first cache entry, so the second one will 'drift' to
 
    // the end of general LRU list and will be reused.
 
 
 
    // Unlock cache bucket, so other threads can continue execution
 
    Unlock (ptbd->m_prgtbcbBuckets[side][iDirectory].m_lock);
 
    // First, find cache entry we can use
 
    Lock (lockLRU);
 
    // Get it either from a free list, or reuse last element of the LRU list
 
    if (NULL != ptbcFree)
 
        {
 
        ptbc = ptbcFree;
 
        ptbcFree = ptbc->m_ptbcNext;
 
        Unlock (lockLRU);
 
        }
 
    else
 
        {
 
        unsigned iTailDirectory;
 
        int      iTailTb;
 
        color    colorTail;
 
 
 
        assert (NULL != ptbcTail);
 
#if (CPUS > 1)
 
        // "Optimistic" model - assuming that there is low content
 
        // (not hundreds of threads)
 
        for (;;)
 
            {
 
            ptbc = ptbcTail;
 
            iTailTb = ptbc->m_iTb;
 
            iTailDirectory = TB_DIRECTORY_ENTRY (ptbc->m_indChunk);
 
            colorTail = ptbc->m_color;
 
            // To avoid deadlocks, have to first acquire cache buckets lock,
 
            // and only then general LRU lock. So, free general LRU lock and
 
            // acquire 2 locks in a proper order.
 
            Unlock (lockLRU);
 
            Lock (rgtbdDesc[iTailTb].m_prgtbcbBuckets[colorTail][iTailDirectory].m_lock);
 
            Lock (lockLRU);
 
            // Have structures been modified while we re-acquired locks? 
 
            // (to be more precise, it's Ok, if structures were modified,
 
            // but cache entry again become the last element of the list,
 
            // and TB, color, and cache bucket did not changed, so we locked
 
            // proper locks).
 
            if (ptbc == ptbcTail && ptbc->m_iTb == iTailTb &&
 
                ptbc->m_color == colorTail &&
 
                TB_DIRECTORY_ENTRY (ptbc->m_indChunk) == iTailDirectory)
 
                break;
 
            // Sorry - try once again...
 
            Unlock (rgtbdDesc[iTailTb].m_prgtbcbBuckets[colorTail][iTailDirectory].m_lock);
 
            }
 
#else
 
        ptbc = ptbcTail;
 
        iTailTb = ptbc->m_iTb;
 
        iTailDirectory = TB_DIRECTORY_ENTRY (ptbc->m_indChunk);
 
        colorTail = ptbc->m_color;
 
#endif
 
 
 
        // Remove cache entry from the general LRU list
 
        ptbcTail = ptbc->m_ptbcPrev;
 
        if (NULL == ptbcTail)
 
            ptbcHead = NULL;
 
        else
 
            ptbcTail->m_ptbcNext = NULL;
 
        Unlock (lockLRU);
 
        
 
        // Remove it from cache bucket list
 
        if (NULL != ptbc->m_ptbcTbNext)
 
            ptbc->m_ptbcTbNext->m_ptbcTbPrev = ptbc->m_ptbcTbPrev;
 
        if (NULL == ptbc->m_ptbcTbPrev)
 
            rgtbdDesc[iTailTb].m_prgtbcbBuckets[colorTail][iTailDirectory].m_ptbcFirst = ptbc->m_ptbcTbNext;
 
        else
 
            ptbc->m_ptbcTbPrev->m_ptbcTbNext = ptbc->m_ptbcTbNext;
 
        Unlock (rgtbdDesc[iTailTb].m_prgtbcbBuckets[colorTail][iTailDirectory].m_lock);
 
        }
 
 
 
    // Ok, now we have "orphan" cache entry - it's excluded from all lists,
 
    // so other threads will never touch it.
 
    ptbc->m_iTb = iTb;
 
    ptbc->m_color = side;
 
    ptbc->m_indChunk = indChunk;
 
 
 
    // Now read it from the disk
 
    FILE    *fp;
 
    size_t  cb;
 
 
 
    // First, check: is necessary file opened?
 
    // As files are not thread-safe, lock file
 
    Lock (ptbd->m_rglockFiles[side]);
 
    if (ptbd->m_fSplit)
 
        {
 
        iExtent = indChunk >> (31 - LOG2_TB_CB_CACHE_CHUNK);
 
        iPhysicalChunk = indChunk - (iExtent << (31 - LOG2_TB_CB_CACHE_CHUNK));
 
        }
 
    else
 
        {
 
        iExtent = 0;
 
        iPhysicalChunk = indChunk;
 
        }
 
    fp = ptbd->m_rgfpFiles[side][iExtent];
 
    if (NULL == fp)
 
        {
 
        // Not - try to open it
 
        pszFileName = ptbd->m_rgpchFileName[side][iExtent];
 
        if (NULL != pszFileName)
 
            {
 
            fp = fopen (pszFileName, "rb");
 
            if (NULL == fp)
 
                {
 
                // Failed. Close all the opened files and retry
 
                Unlock (ptbd->m_rglockFiles[side]);
 
                VTbCloseFiles ();
 
                Lock (ptbd->m_rglockFiles[side]);
 
                // Theoretically, it's possible that other threads opened a lot of
 
                // files in the interval between VTbCloseFiles() and Lock(). If
 
                // so, we'll fail - I don't like to have one more global lock
 
                // especially for file open, at least not in first version.
 
                // Problem can happen only on systems with small limit of
 
                // simultaneously open files and high number of threads - unlikely
 
                // combination.
 
                fp = ptbd->m_rgfpFiles[side][iExtent];
 
                if (NULL == fp)
 
                    {
 
                    fp = fopen (pszFileName, "rb");
 
                    if (NULL == fp)
 
                        {
 
#if defined (STOP_ON_ERROR)
 
                        printf ("*** Unable to open file %s\n", pszFileName);
 
                        fflush (stdout);
 
                        exit(1);
 
#endif
 
                        goto ERROR_LABEL;
 
                        }
 
                    }
 
                }
 
            ptbd->m_rgfpFiles[side][iExtent] = fp;
 
            }
 
        else
 
            goto ERROR_LABEL;
 
        }
 
 
 
    // File opened. Now seek and read necessary chunk
 
    if (NULL == ptbd->m_rgpdiDecodeInfo[side][iExtent])
 
        {
 
        long lPos;
 
        int  iResult;
 
 
 
        lPos = (long) (iPhysicalChunk*TB_CB_CACHE_CHUNK);
 
#if defined (T33_INCLUDE) || defined (T42_INCLUDE)
 
        if (lPos < 0)
 
            {
 
            iResult = fseek (fp, 0L, SEEK_SET);
 
            if (iResult)
 
                {
 
#if defined (STOP_ON_ERROR)
 
                printf ("*** Unable to seek file %s offset %08X\n",
 
                        pszFileName, 0);
 
                fflush (stdout);
 
                exit(1);
 
#endif
 
                goto ERROR_LABEL;
 
                }
 
            do
 
                {
 
                iResult = fseek (fp, 0x40000000, SEEK_CUR);
 
                if (iResult)
 
                    {
 
#if defined (STOP_ON_ERROR)
 
                    printf ("*** Unable to seek file %s offset %08X\n",
 
                            pszFileName, 0x40000000);
 
                    fflush (stdout);
 
                    exit(1);
 
#endif
 
                    goto ERROR_LABEL;
 
                    }
 
                lPos -= 0x40000000;
 
                } while (lPos < 0);
 
            iResult = fseek (fp, lPos, SEEK_CUR);
 
            }
 
        else
 
#endif
 
            iResult = fseek (fp, lPos, SEEK_SET);
 
        // Read uncompressed file
 
        if (iResult)
 
            {
 
#if defined (STOP_ON_ERROR)
 
            printf ("*** Unable to seek file %s offset %08X\n",
 
                    pszFileName, lPos);
 
            fflush (stdout);
 
            exit(1);
 
#endif
 
            goto ERROR_LABEL;
 
            }
 
        cb = fread (ptbc->m_pbData, 1, TB_CB_CACHE_CHUNK, fp);
 
        if (cb != TB_CB_CACHE_CHUNK)
 
            {
 
            // Could not read TB_CB_CACHE_CHUNK - check for error
 
            if (ferror (fp) || ((size_t) -1 == cb))
 
                {
 
#if defined (STOP_ON_ERROR)
 
                printf ("*** Read error, file %s\n", pszFileName);
 
                fflush (stdout);
 
                exit(1);
 
#endif
 
                goto ERROR_LABEL;
 
                }
 
            }
 
        Unlock (ptbd->m_rglockFiles[side]);
 
        }
 
    else
 
        {
 
        // Read compressed file
 
        int fWasError;
 
        decode_block    *block;
 
        decode_info     *info = ptbd->m_rgpdiDecodeInfo[side][iExtent];
 
 
 
#if (CPUS > 1)
 
        // Find free decode block
 
        decode_block    **pBlock;
 
 
 
        Lock (lockDecode);
 
        pBlock = rgpdbDecodeBlocks;
 
        while (NULL == *pBlock)
 
            pBlock ++;
 
        block = *pBlock;
 
        *pBlock = NULL;
 
        Unlock (lockDecode);
 
#else
 
        block = rgpdbDecodeBlocks[0];
 
#endif
 
 
 
        // Initialize decode block and read chunk
 
        fWasError = 0 != comp_init_block (block, TB_CB_CACHE_CHUNK, ptbc->m_pbData) ||
 
                    0 != comp_read_block (block, info, fp, iPhysicalChunk);
 
        
 
        // Release lock on file, so other threads can proceed with that file
 
        Unlock (ptbd->m_rglockFiles[side]);
 
 
 
        // Decompress chunk
 
        if (!fWasError)
 
            fWasError |= (0 != comp_decode_and_check_crc (block, info, block->orig.size, TB_CRC_CHECK));
 
 
 
        // Release block
 
#if (CPUS > 1)
 
        Lock (lockDecode);
 
        *pBlock = block;
 
        Unlock (lockDecode);
 
#endif
 
 
 
        // Read Ok?
 
        if (fWasError)
 
            {
 
#if defined (STOP_ON_ERROR)
 
            printf ("*** Decompression error, file %s\n", pszFileName);
 
            fflush (stdout);
 
            exit(1);
 
#endif
 
            goto ERROR_LABEL_2;
 
            }
 
        }
 
 
 
    // Read - now acquire locks and insert cache entry in both lists
 
    Lock (ptbd->m_prgtbcbBuckets[side][iDirectory].m_lock);
 
    Lock (lockLRU);
 
 
 
    // Insert cache entry into general LRU list
 
    ptbc->m_ptbcPrev = NULL;
 
    ptbc->m_ptbcNext = ptbcHead;
 
    if (NULL == ptbcHead)
 
        ptbcTail = ptbc;
 
    else
 
        ptbcHead->m_ptbcPrev = ptbc;
 
    ptbcHead = ptbc;
 
 
 
    // Insert cache entry into cache bucket LRU list
 
    ptbc->m_ptbcTbPrev = NULL;
 
    ptbc->m_ptbcTbNext = ptbd->m_prgtbcbBuckets[side][iDirectory].m_ptbcFirst;
 
    if (NULL != ptbc->m_ptbcTbNext)
 
        ptbc->m_ptbcTbNext->m_ptbcTbPrev = ptbc;
 
    ptbd->m_prgtbcbBuckets[side][iDirectory].m_ptbcFirst = ptbc;
 
 
 
    // All done
 
    int tb;
 
 
 
    tb = (tb_t) (ptbc->m_pbData[indInChunk]);
 
    // Release locks
 
    Unlock (ptbd->m_prgtbcbBuckets[side][iDirectory].m_lock);
 
    Unlock (lockLRU);
 
    return tb;
 
 
 
    // I/O error. Here I don't want to halt the program, because that can
 
    // happen in the middle of the important game. Just return failure.
 
ERROR_LABEL:
 
    Unlock (ptbd->m_rglockFiles[side]);
 
ERROR_LABEL_2:
 
    Lock (lockLRU);
 
    ptbd->m_rgpchFileName[side][iExtent] = NULL;
 
    ptbc->m_ptbcNext = ptbcFree;
 
    ptbcFree = ptbc;
 
    Unlock (lockLRU);
 
    return L_bev_broken;
 
    }
 
 
 
// Probe TB - upper level function
 
 
 
static int  TB_FASTCALL TbtProbeTable
 
    (
 
    int     iTb,
 
    color   side,
 
    INDEX   indOffset
 
    )
 
    {
 
    CTbDesc *ptbd;
 
 
 
    assert (iTb > 0 && iTb < cTb);
 
    ptbd = & rgtbdDesc[iTb];
 
    if (ptbd->m_fSymmetric)
 
        side = x_colorWhite;
 
 
 
    // It's better for offset be smaller than TB size
 
    assert (!FRegistered (iTb, side) || indOffset < ptbd->m_rgcbLength[side]);
 
 
 
    // Entire file read/mapped to memory?
 
    if (NULL != ptbd->m_rgpbRead[side])
 
        return (tb_t) ptbd->m_rgpbRead[side][indOffset];
 
 
 
    // Cache initialized? TB registered?
 
    if (0 == ctbcTbCache || NULL == ptbd->m_prgtbcbBuckets[side])
 
        return bev_broken;
 
 
 
#if defined (T33_INCLUDE) || defined (KPPKP_16BIT)
 
    if (ptbd->m_f16bit)
 
        return bev_broken;
 
#endif
 
 
 
    int tb;
 
 
 
    tb = TbtProbeTable (iTb, side,(unsigned) TB_CHUNK (indOffset), (unsigned) TB_OFFSET (indOffset));
 
    return (L_bev_broken == tb) ? bev_broken : (tb_t) tb;
 
    }
 
 
 
// 16-bit version (recommended)
 
 
 
#define FOutOfBound(iTb, side, indOffset)\
 
        (tbid_kppkp == iTb && x_colorBlack == side &&\
 
         (indOffset == 0x0362BC7C || indOffset == 0x0362DE44 || indOffset == 0x03637648 ||\
 
          indOffset == 0x03639810 || indOffset == 0x038D4F29 || indOffset == 0x040A2CAB ||\
 
          indOffset == 0x043C778C))
 
 
 
extern "C" int TB_FASTCALL L_TbtProbeTable
 
    (
 
    int     iTb,
 
    color   side,
 
    INDEX   indOffset
 
    )
 
    {
 
    int tbtScore;
 
    CTbDesc *ptbd;
 
 
 
    assert (iTb > 0 && iTb < cTb);
 
    ptbd = & rgtbdDesc[iTb];
 
    if (ptbd->m_fSymmetric)
 
        side = x_colorWhite;
 
 
 
    // Entire file read/mapped to memory?
 
    if (NULL != ptbd->m_rgpbRead[side])
 
        {
 
#if defined (KPPKP_16BIT)
 
        if (!ptbd->m_f16bit)
 
            {
 
            tbtScore = (tb_t) ptbd->m_rgpbRead[side][indOffset];
 
            return S_to_L (tbtScore);
 
            }
 
        else
 
            return (((int) (((signed char) ptbd->m_rgpbRead[side][indOffset*2+1]))) << 8) +
 
                    ptbd->m_rgpbRead[side][indOffset*2];
 
#elif defined (T33_INCLUDE)
 
        if (!ptbd->m_f16bit)
 
            {
 
            if (FOutOfBound (iTb, side, indOffset))
 
                return -32639;
 
            else
 
                {
 
                tbtScore = (tb_t) ptbd->m_rgpbRead[side][indOffset];
 
                return S_to_L (tbtScore);
 
                }
 
            }
 
        else
 
            return (((int) (((signed char) ptbd->m_rgpbRead[side][indOffset*2+1]))) << 8) +
 
                    ptbd->m_rgpbRead[side][indOffset*2];
 
#else
 
        if (FOutOfBound (iTb, side, indOffset))
 
            return -32639;
 
        else
 
            {
 
            tbtScore = (tb_t) ptbd->m_rgpbRead[side][indOffset];
 
            return S_to_L (tbtScore);
 
            }
 
#endif
 
        }
 
 
 
    // Cache initialized? TB registered?
 
    if (0 == ctbcTbCache || NULL == ptbd->m_prgtbcbBuckets[side])
 
        return L_bev_broken;
 
 
 
#if defined (T33_INCLUDE) || defined (T42_INCLUDE)
 
    if (ptbd->m_f16bit)
 
        {
 
        // Inefficient, but very simple, code
 
        int iLo;
 
        int iHi;
 
        
 
        iLo = TbtProbeTable (iTb, side, (unsigned) WIDE_TB_CHUNK (indOffset), (unsigned) WIDE_TB_OFFSET (indOffset));
 
        iHi = TbtProbeTable (iTb, side, (unsigned) WIDE_TB_CHUNK (indOffset), (unsigned) WIDE_TB_OFFSET (indOffset)+1);
 
        tbtScore = (L_bev_broken == iLo || L_bev_broken == iHi) ? L_bev_broken : ((iHi << 8) + (iLo & 0xFF));
 
        }
 
    else
 
        {
 
#if !defined (KPPKP_16BIT)
 
        if (FOutOfBound (iTb, side, indOffset))
 
            return -32639;
 
#endif
 
        tbtScore = TbtProbeTable (iTb, side, (unsigned) TB_CHUNK (indOffset), (unsigned) TB_OFFSET (indOffset));
 
        tbtScore = L_bev_broken == tbtScore ? L_bev_broken : S_to_L (tbtScore);
 
        }
 
#elif !defined (KPPKP_16BIT)
 
    if (FOutOfBound (iTb, side, indOffset))
 
        return -32639;
 
    tbtScore = TbtProbeTable (iTb, side, (unsigned) TB_CHUNK (indOffset), (unsigned) TB_OFFSET (indOffset));
 
    tbtScore = L_bev_broken == tbtScore ? L_bev_broken : S_to_L (tbtScore);
 
#else
 
    if (tbid_kppkp != iTb)
 
        {
 
        // All tables but kppkp are 8-bit tables
 
        tbtScore = TbtProbeTable (iTb, side, (unsigned) TB_CHUNK (indOffset), (unsigned) TB_OFFSET (indOffset));
 
        tbtScore = L_bev_broken == tbtScore ? L_bev_broken : S_to_L (tbtScore);
 
        }
 
    else
 
        {
 
        // Special handling of kppkp - it's 16-bit table
 
        // Inefficient, but very simple, code
 
        int iLo;
 
        int iHi;
 
        
 
        iLo = TbtProbeTable (iTb, side, (unsigned) WIDE_TB_CHUNK (indOffset), (unsigned) WIDE_TB_OFFSET (indOffset));
 
        iHi = TbtProbeTable (iTb, side, (unsigned) WIDE_TB_CHUNK (indOffset), (unsigned) WIDE_TB_OFFSET (indOffset)+1);
 
        tbtScore = (L_bev_broken == iLo || L_bev_broken == iHi) ? L_bev_broken : ((iHi << 8) + (iLo & 0xFF));
 
        }
 
#endif
 
    return tbtScore;
 
    }
 
 
 
//-----------------------------------------------------------------------------
 
//
 
//  Global initialization
 
 
 
// TODO: Check size of split tables, too
 
 
 
static void VCheckSize
 
    (
 
    int     iTb,
 
    color   side,
 
    int     iExtent,
 
    INDEX   cb,
 
    char    *rgchTbName
 
    )
 
    {
 
#if defined (NEW)
 
    INDEX   cbOk1, cbOk2;
 
 
 
    if (0 == rgtbdDesc[iTb].m_rgcbLength[side])
 
        return;
 
 
 
    cbOk1 = rgtbdDesc[iTb].m_rgcbLength[side];
 
    cbOk2 = cbOk1;
 
#if defined (T_INDEX64)
 
    if (rgtbdDesc[iTb].m_fSplit)
 
        {
 
        cbOk1 = (1uLL << (rgtbdDesc[iTb].m_f16bit ? 30 : 31)); // Pierre-Marie Baty -- added type cast
 
        cbOk2 = cbOk2 % (1uLL << (rgtbdDesc[iTb].m_f16bit ? 30 : 31)); // Pierre-Marie Baty -- added type cast
 
        }
 
#endif
 
 
 
    if (cb != cbOk1 && cb != cbOk2)
 
        {
 
        printf ("*** %s corrupted "
 
                DEC_INDEX_FORMAT " " DEC_INDEX_FORMAT " " DEC_INDEX_FORMAT "\n", // Pierre-Marie Baty -- added spaces
 
                rgchTbName, cbOk1, cbOk2, cb);
 
        exit (1);
 
        }
 
#endif
 
    }
 
 
 
 
 
#if defined (_WIN32) || defined (_WIN64)
 
int     iDrivesMap;
 
BOOL    rgfAccessed[26];
 
BOOL    rgfNotReady[26];
 
#endif
 
 
 
static int FCheckExtentExistance
 
    (
 
    char    *pszPath,
 
    int     iTb,
 
    color   side,
 
    int     iExtent
 
    )
 
    {
 
    FILE            *fp;
 
    char            *pchCopy;
 
    const char      *pchExt = PchExt (side);
 
    char            rgchTbName[1024];
 
    char            rgchExtent[4];
 
    CTbCacheBucket  *prgtbcbBuckets;
 
    INDEX           cb;
 
    decode_info     *comp_info = NULL;
 
//  int             fWasError;
 
//  decode_block    *block;
 
//  BYTE            rgbBuffer[TB_CB_CACHE_CHUNK+32+4];
 
 
 
    if (FRegisteredExtent (iTb, side, iExtent) || NULL != rgtbdDesc[iTb].m_rgpbRead[side])
 
        return true;
 
 
 
#if defined (_WIN32) || defined (_WIN64)
 
    // Do not repeatedely probe device that is not ready
 
    // (i.e. unmapped disk or CD-ROM that does not contain the disk).
 
    if (NULL != pszPath && 0 != pszPath[0] && ':' == pszPath[1])
 
        {
 
        int  iDrive;
 
        char szRoot[5];
 
        WIN32_FIND_DATA fd;
 
        HANDLE hResult;
 
 
 
        iDrive = tolower(pszPath[0]) - 'a';
 
        if (iDrive >= 0 && iDrive < 26)
 
            {
 
            if (rgfNotReady[iDrive])
 
                return false;
 
            if (!rgfAccessed[iDrive])
 
                {
 
                if (iDrivesMap && 0 == (iDrivesMap & (1 << iDrive)))
 
                    return false;
 
                szRoot[0] = pszPath[0];
 
                szRoot[1] = pszPath[1];
 
                szRoot[2] = '\\';
 
                szRoot[3] = '*';
 
                szRoot[4] = 0;
 
                hResult = FindFirstFile ((STRING_PTR) (szRoot), &fd);
 
                if (INVALID_HANDLE_VALUE == hResult)
 
                    {
 
                    if (ERROR_NOT_READY == GetLastError())
 
                        {
 
                        rgfNotReady[iDrive] = true;
 
                        return false;
 
                        }
 
                    }
 
                else
 
                    FindClose (hResult);
 
                rgfAccessed[iDrive] = true;
 
                }
 
            }
 
        }
 
#endif
 
 
 
    strcpy (rgchTbName, pszPath);
 
    if (0 != pszPath[0] && DELIMITER[0] != pszPath[strlen(pszPath)-1])
 
        strcat (rgchTbName, DELIMITER);
 
    strcat (rgchTbName, rgtbdDesc[iTb].m_rgchName);
 
    if (rgtbdDesc[iTb].m_fSplit)
 
        {
 
        rgchExtent[0] = '.';
 
        if (iExtent >= 10)
 
            rgchExtent[1] = (char) (iExtent + 'a' - 10);
 
        else
 
            rgchExtent[1] = (char) (iExtent + '0');
 
        rgchExtent[2] = '\0';
 
        strcat (rgchTbName, rgchExtent);
 
        }
 
    strcat (rgchTbName, pchExt);
 
    cOpenFilesAttempts ++;
 
    fp = fopen (rgchTbName, "rb");
 
    //printf (">>> Opening %s\n", rgchTbName);
 
    cOpenFilesSuceed += (NULL != fp);
 
#if !defined (NEW) && !defined (_WIN32) && !defined(_WIN64)
 
    // For case-sensitive systems, have to try once more
 
    if (NULL == fp)
 
        {
 
        for (int i = strchr(rgchTbName,'.')-rgchTbName-1; i>=0 && isalpha(rgchTbName[i]); i--)
 
            rgchTbName[i] = toupper (rgchTbName[i]);
 
        cOpenFilesAttempts ++;
 
        fp = fopen (rgchTbName, "rb");
 
        //printf (">>> Opening %s\n", rgchTbName);
 
        cOpenFilesSuceed += (NULL != fp);
 
        }
 
#endif
 
    if (NULL != fp)
 
        {
 
        // Found uncompressed table
 
        if (rgtbdDesc[iTb].m_f16bit ||
 
            ((int)(cb = rgtbdDesc[iTb].m_rgcbLength[side])) < 0 ||
 
            cb != (unsigned) cb)
 
            {
 
            // Do not check the length for too large files
 
            cb = rgtbdDesc[iTb].m_rgcbLength[side];
 
            }
 
        else
 
            {
 
            if (0 != fseek (fp, 0L, SEEK_END))
 
                {
 
                printf ("*** Seek in %s failed\n", rgchTbName);
 
                exit (1);
 
                }
 
            cb = (INDEX) ftell (fp);
 
            VCheckSize (iTb, side, iExtent, cb, rgchTbName);
 
            }
 
        }
 
    else
 
        {
 
        // Check for compressed table.
 
        // First, check for kxykz.nb?.emd
 
        strcat (rgchTbName, ".emd");
 
        cOpenFilesAttempts ++;
 
        fp = fopen (rgchTbName, "rb");
 
        //printf (">>> Opening %s\n", rgchTbName);
 
        cOpenFilesSuceed += (NULL != fp);
 
        if ((NULL == fp) && !rgtbdDesc[iTb].m_fSplit)
 
            {
 
            // Check for kxykz_nb?.emd
 
            rgchTbName [strlen(rgchTbName)-8] = '_';
 
            cOpenFilesAttempts ++;
 
            fp = fopen (rgchTbName, "rb");
 
            //printf (">>> Opening %s\n", rgchTbName);
 
            cOpenFilesSuceed += (NULL != fp);
 
            }
 
        if ((NULL == fp) && !rgtbdDesc[iTb].m_fSplit)
 
            {
 
            // Check for kxykz_nb?_emd
 
            rgchTbName [strlen(rgchTbName)-4] = '_';
 
            cOpenFilesAttempts ++;
 
            fp = fopen (rgchTbName, "rb");
 
            //printf (">>> Opening %s\n", rgchTbName);
 
            cOpenFilesSuceed += (NULL != fp);
 
            }
 
#if defined (T41_INCLUDE)
 
        if ((NULL == fp) && (iTb <= tbid_kqqqk))
 
#else
 
        if ((NULL == fp) && (iTb <= tbid_kqqkq))
 
#endif
 
            {
 
            // Check for kxykznb?.emd (8+3 format)
 
            int cch;
 
            
 
            rgchTbName [strlen(rgchTbName)-4] = '.';
 
            cch = strlen (rgchTbName);
 
            memmove (rgchTbName+cch-8, rgchTbName+cch-7, 8);
 
            cOpenFilesAttempts ++;
 
            fp = fopen (rgchTbName, "rb");
 
            //printf (">>> Opening %s\n", rgchTbName);
 
            cOpenFilesSuceed += (NULL != fp);
 
            }
 
        if (NULL == fp)
 
            return false;
 
        cCompressed ++;
 
        int iResult = comp_open_file (&comp_info, fp, TB_CRC_CHECK);
 
        if (0 != iResult)
 
            {
 
            printf ("*** Unable to read %s - ", rgchTbName);
 
            switch (iResult & 0xFF)
 
                {
 
            case COMP_ERR_READ:
 
                printf ("read error\n");
 
                break;
 
            case COMP_ERR_NOMEM:
 
                printf ("out of memory\n");
 
                break;
 
            case COMP_ERR_BROKEN:
 
                printf ("file broken\n");
 
                break;
 
            default:
 
                printf ("error %d\n", iResult);
 
                break;
 
                }
 
            exit (1);
 
            }
 
        if (comp_info->block_size != TB_CB_CACHE_CHUNK)
 
            {
 
            printf ("*** %s: Unsupported block size %d\n", rgchTbName, comp_info->block_size);
 
            exit (1);
 
            }
 
        if (rgtbdDesc[iTb].m_f16bit)
 
            {
 
            cb = ((INDEX)comp_info->block_size/2)*(comp_info->n_blk-1) +
 
                  (INDEX)comp_info->last_block_size/2;
 
            VCheckSize (iTb, side, iExtent, cb, rgchTbName);
 
            }
 
        else
 
            {
 
            cb = ((INDEX)comp_info->block_size)*(comp_info->n_blk-1) +
 
                 (INDEX)comp_info->last_block_size;
 
            VCheckSize (iTb, side, iExtent, cb, rgchTbName);
 
            }
 
 
 
#if 0
 
        block = rgpdbDecodeBlocks[0];
 
        if (NULL == block)
 
            {
 
            int iResult = comp_alloc_block (&rgpdbDecodeBlocks[0], TB_CB_CACHE_CHUNK);
 
            if (0 != iResult)
 
                {
 
                printf ("*** Cannot allocate decode block: error code %d\n", iResult);
 
                exit (1);
 
                }
 
            block = rgpdbDecodeBlocks[0];
 
            }
 
        // Initialize decode block and read chunk
 
        fWasError = 0 != comp_init_block (block, TB_CB_CACHE_CHUNK, rgbBuffer) ||
 
                    0 != comp_read_block (block, comp_info, fp, TB_CHUNK (cb-1)) ||
 
                    0 != comp_decode_and_check_crc (block, comp_info, block->orig.size, TB_CRC_CHECK);
 
        if (fWasError)
 
            {
 
            printf ("*** Sanity check on %s failed\n", rgchTbName);
 
            exit (1);
 
            }
 
#endif
 
        }
 
 
 
    fclose (fp);
 
    if (FRegisterTb (& (rgtbdDesc[iTb])))
 
        {
 
        pchCopy = (char*) PvMalloc (strlen(rgchTbName)+1);
 
        strcpy (pchCopy, rgchTbName);
 
        free (rgtbdDesc[iTb].m_rgpchFileName[side][iExtent]);
 
        rgtbdDesc[iTb].m_rgpchFileName[side][iExtent] = pchCopy;
 
        if (NULL == rgtbdDesc[iTb].m_prgtbcbBuckets[side])
 
            {
 
            prgtbcbBuckets = (CTbCacheBucket*) PvMalloc (TB_DIRECTORY_SIZE*sizeof(CTbCacheBucket));
 
            memset (prgtbcbBuckets, 0, TB_DIRECTORY_SIZE*sizeof(CTbCacheBucket));
 
#if (CPUS > 1)
 
            for (int i = 0; i < TB_DIRECTORY_SIZE; i ++)
 
                LockInit (prgtbcbBuckets[i].m_lock);
 
#endif
 
            rgtbdDesc[iTb].m_prgtbcbBuckets[side] = prgtbcbBuckets;
 
            if (fVerbose)
 
                printf ("%s registered\n", pchCopy);
 
            }
 
        else
 
            {
 
            if (fVerbose)
 
                printf ("%s found\n", pchCopy);
 
            }
 
        rgtbdDesc[iTb].m_rgpdiDecodeInfo[side][iExtent] = comp_info;
 
        return true;
 
        }
 
    else
 
        {
 
        printf ("*** Unable to register %s\n", rgchTbName);
 
        exit (1);
 
        }
 
    return false;
 
    }
 
 
 
int FCheckExistance
 
    (
 
    char    *pszPath,
 
    int     iTb,
 
    color   side
 
    )
 
    {
 
    int  fFound;
 
    int  cExtents;
 
    INDEX cBytes;
 
 
 
    if (rgtbdDesc[iTb].m_fSplit)
 
        {
 
        cBytes = rgtbdDesc[iTb].m_rgcbLength[side];
 
        if (rgtbdDesc[iTb].m_f16bit)
 
            cBytes *= 2;
 
        cExtents = (int) (cBytes >> 31) + 1;
 
        }
 
    else
 
        cExtents = 1;
 
    fFound = false;
 
    for (int iExtent = 0; iExtent < cExtents; iExtent++)
 
        {
 
        if (!FCheckExtentExistance (pszPath, iTb, side, iExtent))
 
            break;
 
        fFound = true;
 
        }
 
    return fFound;
 
    }
 
 
 
extern "C" int IInitializeTb
 
    (
 
    char *pszPath
 
    )
 
    {
 
    char    szTemp[1024];
 
    color   sd;
 
    int     iTb, iMaxTb, iExtent, i;
 
    CTbCacheBucket  *prgtbcbBuckets;
 
 
 
#if defined (_WIN32) || defined (_WIN64)
 
    // For Windows, get bit map of ready devices
 
    iDrivesMap = GetLogicalDrives();
 
    memset (rgfAccessed, 0, sizeof(rgfAccessed));
 
    memset (rgfNotReady, 0, sizeof(rgfNotReady));
 
#endif
 
 
 
    cOpenFilesAttempts = cOpenFilesSuceed = 0;
 
    cbAllocated = cbEGTBCompBytes = 0;
 
    // If there are open files, close those
 
    VTbCloseFiles ();
 
#if (CPUS > 1)
 
    // Init all locks
 
    LockInit (lockLRU);
 
    LockInit (lockDecode);
 
    for (iTb = 1; iTb < cTb; iTb ++)
 
        {
 
        LockInit (rgtbdDesc[iTb].m_rglockFiles[x_colorWhite]);
 
        LockInit (rgtbdDesc[iTb].m_rglockFiles[x_colorBlack]);
 
        }
 
#endif
 
#if defined (NEW)
 
    // Create enumeration tables
 
    VInitEnumerations ();
 
#endif
 
    // Create empty TB search table
 
    VCreateEmptyTbTable ();
 
    // Free memory from TB table
 
    for (iTb = 1; iTb < cTb; iTb ++)
 
        {
 
        for (sd = x_colorWhite; sd <= x_colorBlack; sd = (color) (sd + 1))
 
            {
 
            if (NULL != rgtbdDesc[iTb].m_prgtbcbBuckets[sd] &&
 
                NULL == rgtbdDesc[iTb].m_rgpbRead[sd])
 
                {
 
                prgtbcbBuckets = rgtbdDesc[iTb].m_prgtbcbBuckets[sd];
 
#if (CPUS > 1)
 
                for (i = 0; i < TB_DIRECTORY_SIZE; i ++)
 
                    LockFree (prgtbcbBuckets[i].m_lock);
 
#endif
 
                free (prgtbcbBuckets);
 
                rgtbdDesc[iTb].m_prgtbcbBuckets[sd] = NULL;
 
                }
 
            for (iExtent = 0; iExtent < MAX_EXTENTS; iExtent ++)
 
                {
 
                if (NULL != rgtbdDesc[iTb].m_rgpchFileName[sd][iExtent])
 
                    {
 
                    free (rgtbdDesc[iTb].m_rgpchFileName[sd][iExtent]);
 
                    rgtbdDesc[iTb].m_rgpchFileName[sd][iExtent] = NULL;
 
                    }
 
                if (NULL != rgtbdDesc[iTb].m_rgpdiDecodeInfo[sd][iExtent])
 
                    {
 
                    free (rgtbdDesc[iTb].m_rgpdiDecodeInfo[sd][iExtent]);
 
                    rgtbdDesc[iTb].m_rgpdiDecodeInfo[sd][iExtent] = NULL;
 
                    }
 
                }
 
            }
 
        }
 
    // Free compressed blocks
 
    for (i = 0; i < CPUS; i ++)
 
        {
 
        if (NULL != rgpdbDecodeBlocks[i])
 
            {
 
            free (rgpdbDecodeBlocks[i]);
 
            rgpdbDecodeBlocks[i] = NULL;
 
            }
 
        }
 
 
 
    if(pszPath == NULL)
 
        return 0;
 
 
 
    // Search for existing TBs
 
    iMaxTb = 0;
 
    for (;;)
 
        {
 
        for (i = 0; pszPath[i] != '\0' && pszPath[i] != ',' && pszPath[i] != ';'
 
#if !defined (_WIN32) && !defined (__MWERKS__) && !defined(_WIN64)
 
             && pszPath[i] != ':'
 
#endif
 
             ; i ++)
 
            {
 
            szTemp[i] = pszPath[i];
 
            }
 
        szTemp[i] = '\0';
 
        for (iTb = 1; iTb < cTb; iTb ++)
 
            {
 
            if (FCheckExistance (szTemp, iTb, x_colorWhite))
 
                {
 
                if (iTb > iMaxTb)
 
                    iMaxTb = iTb;
 
                }
 
        if (! rgtbdDesc[iTb].m_fSymmetric && FCheckExistance (szTemp, iTb, x_colorBlack))
 
                {
 
                if (iTb > iMaxTb)
 
                    iMaxTb = iTb;
 
                }
 
            }
 
        pszPath += i;
 
        if ('\0' == *pszPath)
 
            break;
 
        pszPath ++;
 
        }
 
    
 
    // If there were compressed files, have to allocate buffer(s)
 
    if (0 != cCompressed)
 
        {
 
        for (i = 0; i < CPUS; i ++)
 
            {
 
            if (NULL == rgpdbDecodeBlocks[i])
 
                {
 
                int iResult = comp_alloc_block (&rgpdbDecodeBlocks[i], TB_CB_CACHE_CHUNK);
 
                if (0 != iResult)
 
                    {
 
                    printf ("*** Cannot allocate decode block: error code %d\n", iResult);
 
                    exit (1);
 
                    }
 
                }
 
            }
 
        if (fVerbose)
 
            printf ("Allocated %dKb for decompression tables, indices, and buffers.\n",
 
                    (cbEGTBCompBytes+1023)/1024);
 
        }
 
 
 
    if (fVerbose)
 
        printf ("Tried to open %d files. Opened %d files.\n",
 
                cOpenFilesAttempts, cOpenFilesSuceed);
 
    // All done!
 
#if defined T33_INCLUDE
 
    if (iMaxTb >= tbid_knnknn)
 
        return 6;
 
#elif defined (T42_INCLUDE)
 
    if (iMaxTb >= tbid_knnnkn)
 
        return 6;
 
#endif
 
    if (iMaxTb >= tbid_kppkp)
 
        return 5;
 
    if (iMaxTb >= tbid_kpkp)
 
        return 4;
 
    if (iMaxTb >= tbid_kpk)
 
        return 3;
 
    return 0;
 
    }
 
 
 
#endif