/*
 
This Software is distributed with the following X11 License,
 
sometimes also known as MIT license.
 
 
 
Copyright (c) 2010 Miguel A. Ballicora
 
 
 
 Permission is hereby granted, free of charge, to any person
 
 obtaining a copy of this software and associated documentation
 
 files (the "Software"), to deal in the Software without
 
 restriction, including without limitation the rights to use,
 
 copy, modify, merge, publish, distribute, sublicense, and/or sell
 
 copies of the Software, and to permit persons to whom the
 
 Software is furnished to do so, subject to the following
 
 conditions:
 
 
 
 The above copyright notice and this permission notice shall be
 
 included in all copies or substantial portions of the Software.
 
 
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 
 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 
 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 
 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 
 OTHER DEALINGS IN THE SOFTWARE.
 
*/
 
 
 
 
 
/* NBBOTF will remove the internal bitbase on the fly */
 
#ifdef NBBOTF
 
        #ifdef WDL_PROBE
 
                #undef WDL_PROBE
 
        #endif
 
#else
 
        #define WDL_PROBE
 
#endif
 
 
 
/*-- Intended to be modified to make public --> Supporting functions the TB generator ---------------------*/
 
 
 
#ifdef GTB_SHARE
 
#define SHARED_forbuilding
 
#endif
 
 
 
/*---------------------------------------------------------------------------------------------------------*/
 
#include <stdlib.h>
 
#include <stdio.h>
 
#include <string.h>
 
 
 
#include "gtb-probe.h"
 
 
 
#if defined(SHARED_forbuilding)
 
        #include "gtb-prob2.h"
 
#else
 
        #define mySHARED static
 
        typedef unsigned char                   SQ_CONTENT;
 
        typedef unsigned int                    SQUARE;
 
#endif
 
 
 
#include "sysport.h"
 
#include "gtb-att.h"
 
#include "gtb-types.h"
 
 
 
/*---------------------------------------------------------------------------------------------------------*/
 
/*#include "posit_t.h"*/
 
 
 
#define MAX_LISTSIZE 17
 
#if 0
 
typedef unsigned                sq_t;
 
typedef unsigned char   pc_t;
 
typedef uint32_t                mv_t;
 
#endif
 
 
 
struct posit {
 
        sq_t                    ws[MAX_LISTSIZE];
 
        sq_t                    bs[MAX_LISTSIZE];
 
        pc_t                    wp[MAX_LISTSIZE];
 
        pc_t                    bp[MAX_LISTSIZE];
 
        sq_t                    ep;
 
        unsigned int    stm;
 
        unsigned int    cas;
 
};
 
typedef struct  posit posit_t;
 
 
 
#if 0
 
typedef long int                tbkey_t;
 
#endif
 
 
 
/*---------------------------------------------------------------------------------------------------------*/
 
/*#include "bool_t.h"*/
 
 
 
#if !defined(H_BOOL)
 
typedef int                                             bool_t;
 
#endif
 
 
 
#if !defined(TRUE)
 
#define TRUE ((bool_t)1)
 
#endif
 
 
 
#if !defined(FALSE)
 
#define FALSE ((bool_t)0)
 
#endif
 
 
 
/*--------- private if external building code is not present ----------------------------------------------*/
 
 
 
#if !defined(SHARED_forbuilding)
 
 
 
#define MAX_EGKEYS 145
 
#define SLOTSIZE 1
 
#define NOINDEX ((index_t)(-1))
 
 
 
#if 0
 
typedef unsigned short int      dtm_t;
 
typedef size_t                          index_t;
 
/*typedef int                           index_t;*/
 
#endif
 
 
 
enum Loading_status {
 
                                STATUS_ABSENT           = 0,
 
                                STATUS_STATICRAM        = 1,
 
                                STATUS_MALLOC           = 2,
 
                                STATUS_FILE             = 3,
 
                                STATUS_REJECT           = 4
 
};
 
 
 
struct endgamekey {
 
        int             id;
 
        const char *str;
 
        index_t         maxindex;
 
        index_t         slice_n;
 
        void            (*itopc) (index_t, SQUARE *, SQUARE *);
 
        bool_t          (*pctoi) (const SQUARE *, const SQUARE *, index_t *);
 
        dtm_t *         egt_w;
 
        dtm_t *         egt_b;
 
        FILE *          fd;
 
        int             status;
 
        int                     pathn;
 
};
 
#endif
 
 
 
/*----------------------------------------------------------------------------------------------------------*/
 
 
 
/* array for better moves */
 
#ifdef GTB_SHARE
 
mySHARED int            bettarr [2] [8] [8];
 
#endif
 
 
 
/*------------ ENUMS ----------------------------------------------------------*/
 
 
 
enum Mask_values {
 
                                        RESMASK  = tb_RESMASK,
 
                                        INFOMASK = tb_INFOMASK,
 
                                        PLYSHIFT = tb_PLYSHIFT
 
};
 
 
 
enum Info_values {
 
                                        iDRAW    = tb_DRAW,
 
                                        iWMATE   = tb_WMATE,
 
                                        iBMATE   = tb_BMATE,
 
                                        iFORBID  = tb_FORBID,
 
 
 
                                        iDRAWt   = tb_DRAW  |4,
 
                                        iWMATEt  = tb_WMATE |4,
 
                                        iBMATEt  = tb_BMATE |4,
 
                                        iUNKNOWN = tb_UNKNOWN,
 
 
 
                                        iUNKNBIT = (1<<2)
 
};
 
 
 
/*-------------------------- inherited from a previous maindef.h -----------*/
 
 
 
#define WHITES (1u<<6)
 
#define BLACKS (1u<<7)
 
 
 
#define NOPIECE 0u
 
#define PAWN    1u
 
#define KNIGHT  2u
 
#define BISHOP  3u
 
#define ROOK    4u
 
#define QUEEN   5u
 
#define KING    6u
 
 
 
#define WH 0
 
#define BL 1
 
#define Opp(x) ((x)^1)
 
#define wK (KING   | WHITES)
 
 
 
/*-------------------
 
       SQUARES
 
  -------------------*/
 
 
 
/* from 1-63 different squares posibles   */
 
 
 
/*squares*/
 
enum SQUARES {
 
        A1,B1,C1,D1,E1,F1,G1,H1,
 
        A2,B2,C2,D2,E2,F2,G2,H2,
 
        A3,B3,C3,D3,E3,F3,G3,H3,
 
        A4,B4,C4,D4,E4,F4,G4,H4,
 
        A5,B5,C5,D5,E5,F5,G5,H5,
 
        A6,B6,C6,D6,E6,F6,G6,H6,
 
        A7,B7,C7,D7,E7,F7,G7,H7,
 
        A8,B8,C8,D8,E8,F8,G8,H8,
 
        NOSQUARE,
 
        ERRSQUARE = 128
 
};
 
 
 
/*------------------- end of inherited from a previous maindef.h -----------*/
 
 
 
#if !defined(NDEBUG)
 
#define NDEBUG
 
#endif
 
#ifdef DEBUG
 
#undef NDEBUG
 
#endif
 
#include "assert.h"
 
 
 
/*------------------- general DEFINES--------------------------- -----------*/
 
 
 
#define gtbNOSIDE       ((unsigned)-1)
 
#define gtbNOINDEX      ((index_t)-1)
 
 
 
/*************************************************\
 
|
 
|                               COMPRESSION SCHEMES
 
|
 
\*************************************************/
 
 
 
#include "gtb-dec.h"
 
 
 
static const char *const Extension[] = {
 
                                                         ".gtb.cp0"
 
                                                        ,".gtb.cp1"
 
                                                        ,".gtb.cp2"
 
                                                        ,".gtb.cp3"
 
                                                        ,".gtb.cp4"
 
                                                        ,".gtb.cp5"
 
                                                        ,".gtb.cp6"
 
                                                        ,".gtb.cp7"
 
                                                        ,".gtb.cp8"
 
                                                        ,".gtb.cp9"
 
};
 
 
 
/*************************************************\
 
|
 
|                                       MOVES
 
|
 
\*************************************************/
 
 
 
enum move_kind {
 
                NORMAL_MOVE = 0,
 
                CASTLE_MOVE,
 
                PASSNT_MOVE,
 
                PROMOT_MOVE
 
};
 
 
 
enum move_content {
 
                NOMOVE = 0
 
};
 
 
 
#define MV_TYPE(mv)   ( (BYTE)       ((mv) >>6 & 3 )      )
 
#define MV_TO(mv)     ( (SQUARE)     ((mv) >>8 & 63)      )
 
#define MV_PT(mv)     ( (SQ_CONTENT) ((mv) >>(3+16) &7  ) )
 
#define MV_TK(mv)     ( (SQ_CONTENT) ((mv) >>(6+16) &7  ) )
 
#define MV_FROM(mv)   ( (SQUARE)     ((mv)     & 63)      )
 
 
 
/*
 
|   move,type,color,piece,from,to,taken,promoted
 
*------------------------------------------------------------------*/
 
 
 
#define MV_BUILD(mv,ty,co,pc,fr,to,tk,pm) (                        \
 
    (mv)    =  (fr)     | (to)<< 8      | (ty)<<  6     | (co)<<8  \
 
            |  (pc)<<16 | (pm)<< (3+16) | (tk)<< (6+16)            \
 
)
 
 
 
#define MV_ADD_TOTK(mv,to,tk) (          \
 
     mv     |= (uint32_t)(to) << 8       \
 
            |  (uint32_t)(tk) << (6+16)  \
 
)
 
 
 
#define map88(x)    (   (x) + ((x)&070)        )
 
#define unmap88(x)  ( ( (x) + ((x)& 07) ) >> 1 )
 
 
 
/*************************************************\
 
|
 
|                               STATIC VARIABLES
 
|
 
\*************************************************/
 
 
 
static int GTB_scheme = 4;
 
 
 
/*************************************************\
 
|
 
|       needed for
 
|       PRE LOAD CACHE AND DEPENDENT FUNCTIONS
 
|
 
\*************************************************/
 
 
 
#define EGTB_MAXBLOCKSIZE 65536
 
 
 
static int GTB_MAXOPEN = 4;
 
 
 
static bool_t                   Uncompressed = TRUE;
 
static unsigned int             zipinfo_init (void);
 
static void                     zipinfo_done (void);
 
 
 
enum Flip_flags {
 
                WE_FLAG = 1, NS_FLAG = 2,  NW_SE_FLAG = 4
 
}; /* used in flipt */
 
 
 
struct filesopen {
 
                int n;
 
                tbkey_t *key;
 
};
 
 
 
/* STATIC GLOBALS */
 
 
 
static struct filesopen fd = {0, NULL};
 
 
 
static bool_t                   TB_INITIALIZED = FALSE;
 
static bool_t                   DTM_CACHE_INITIALIZED = FALSE;
 
 
 
static int                              WDL_FRACTION = 64;
 
static int                              WDL_FRACTION_MAX = 128;
 
 
 
static size_t                   DTM_cache_size = 0;
 
static size_t                   WDL_cache_size = 0;
 
 
 
static unsigned int             TB_AVAILABILITY = 0;
 
 
 
/* LOCKS */
 
static mythread_mutex_t Egtb_lock;
 
 
 
 
 
/****************************************************************************\
 
 *
 
 *
 
 *                      DEBUGGING or PRINTING ZONE
 
 *
 
 *
 
 ****************************************************************************/
 
 
 
#if 0
 
#define FOLLOW_EGTB
 
#ifndef DEBUG
 
#define DEBUG
 
#endif
 
#endif
 
 
 
#define validsq(x) ((x) >= A1 && (x) <= H8)
 
 
 
#if defined(DEBUG)
 
static void     print_pos (const sq_t *ws, const sq_t *bs, const pc_t *wp, const pc_t *bp);
 
#endif
 
 
 
#if defined(DEBUG) || defined(FOLLOW_EGTB)
 
static void     output_state (unsigned stm, const SQUARE *wSQ, const SQUARE *bSQ,
 
                                                                const SQ_CONTENT *wPC, const SQ_CONTENT *bPC);
 
static const char *Square_str[64] = {
 
        "a1","b1","c1","d1","e1","f1","g1","h1",
 
        "a2","b2","c2","d2","e2","f2","g2","h2",
 
        "a3","b3","c3","d3","e3","f3","g3","h3",
 
        "a4","b4","c4","d4","e4","f4","g4","h4",
 
        "a5","b5","c5","d5","e5","f5","g5","h5",
 
        "a6","b6","c6","d6","e6","f6","g6","h6",
 
        "a7","b7","c7","d7","e7","f7","g7","h7",
 
        "a8","b8","c8","d8","e8","f8","g8","h8"
 
};
 
static const char *P_str[] = {
 
        "--", "P", "N", "B", "R", "Q", "K"
 
};
 
#endif
 
 
 
#ifdef FOLLOW_EGTB
 
        #define STAB
 
        #define STABCONDITION 1 /*(stm == BL && whiteSQ[0]==H1 && whiteSQ[1]==D1 && whiteSQ[2]==D3 && blackSQ[0]==C2 )*/
 
        static bool_t GLOB_REPORT = TRUE;
 
#endif
 
 
 
#if defined(FOLLOW_EGTB)
 
static const char *Info_str[8] = {
 
        " Draw", " Wmate", " Bmate", "Illegal",
 
        "~Draw", "~Wmate", "~Bmate", "Unknown"
 
};
 
#endif
 
 
 
static void             list_index (void);
 
static void     fatal_error(void) {
 
}
 
 
 
#ifdef STAB
 
        #define FOLLOW_LU(x,y)  {if (GLOB_REPORT) printf ("************** %s: %lu\n", (x), (long unsigned)(y));}
 
#else
 
        #define FOLLOW_LU(x,y)
 
#endif
 
 
 
#ifdef STAB
 
        #define FOLLOW_LULU(x,y,z)  {if (GLOB_REPORT) printf ("************** %s: %lu, %lu\n", (x), (long unsigned)(y), (long unsigned)(z));}
 
#else
 
        #define FOLLOW_LULU(x,y,z)
 
#endif
 
 
 
#ifdef STAB
 
        #define FOLLOW_label(x) {if (GLOB_REPORT) printf ("************** %s\n", (x));}
 
#else
 
        #define FOLLOW_label(x)
 
#endif
 
 
 
#ifdef STAB
 
        #define FOLLOW_DTM(msg,dtm)  {if (GLOB_REPORT) printf ("************** %s: %lu, info:%s, plies:%lu \n"\
 
        , (msg), (long unsigned)(dtm), (Info_str[(dtm)&INFOMASK]), (long unsigned)((dtm)>>PLYSHIFT)\
 
        );}
 
#else
 
        #define FOLLOW_DTM(msg,dtm)
 
#endif
 
 
 
 
 
/*--------------------------------*\
 
|
 
|
 
|               INDEXING FUNCTIONS
 
|
 
|
 
*---------------------------------*/
 
 
 
#define IDX_set_empty(x) {x=0;x--;}
 
#define IDX_is_empty(x) (0==(1+(x)))
 
 
 
#define NO_KKINDEX NOINDEX
 
#define MAX_KKINDEX 462
 
#define MAX_PPINDEX 576
 
#define MAX_PpINDEX (24 * 48)
 
/*1128*/
 
#define MAX_AAINDEX ((63-62) + (62 * (127-62)/2) - 1 + 1)
 
#define MAX_AAAINDEX (64*21*31)
 
#define MAX_PP48_INDEX (1128)
 
/* (24*23*22/6) + 24 * (24*23/2) */
 
#define MAX_PPP48_INDEX 8648
 
 
 
/* VARIABLES */
 
 
 
static index_t                  kkidx [64] [64];
 
static index_t                  ppidx [24] [48];
 
static index_t                  pp48_idx[48][48];
 
static index_t                  ppp48_idx[48][48][48];
 
 
 
static sq_t                             wksq [MAX_KKINDEX];
 
static sq_t                             bksq [MAX_KKINDEX];
 
static sq_t                             pp48_sq_x[MAX_PP48_INDEX];
 
static sq_t                             pp48_sq_y[MAX_PP48_INDEX];
 
 
 
static index_t                  pp_hi24 [MAX_PPINDEX]; /* was unsigned int */
 
static index_t                  pp_lo48 [MAX_PPINDEX];
 
static unsigned int     flipt [64] [64];
 
static index_t                  aaidx [64] [64]; /* was unsigned int */
 
static unsigned char    aabase [MAX_AAINDEX];
 
 
 
static uint8_t                  ppp48_sq_x[MAX_PPP48_INDEX];
 
static uint8_t                  ppp48_sq_y[MAX_PPP48_INDEX];
 
static uint8_t                  ppp48_sq_z[MAX_PPP48_INDEX];
 
 
 
/* FUNCTIONS */
 
 
 
static void     init_indexing (int verbosity);
 
static void     norm_kkindex (SQUARE x, SQUARE y, /*@out@*/ SQUARE *pi, /*@out@*/ SQUARE *pj);
 
static void     pp_putanchorfirst (SQUARE a, SQUARE b, /*@out@*/ SQUARE *out_anchor, /*@out@*/ SQUARE *out_loosen);
 
 
 
static index_t  wsq_to_pidx24 (SQUARE pawn);
 
static index_t  wsq_to_pidx48 (SQUARE pawn);
 
static SQUARE   pidx24_to_wsq (index_t a);
 
static SQUARE   pidx48_to_wsq (index_t a);
 
 
 
static SQUARE   flipWE                  (SQUARE x) { return x ^  07;}
 
static SQUARE   flipNS                  (SQUARE x) { return x ^ 070;}
 
static SQUARE   flipNW_SE               (SQUARE x) { return ((x&7)<<3) | (x>>3);}
 
static SQUARE   getcol                  (SQUARE x) { return x &  7;}
 
static SQUARE   getrow                  (SQUARE x) { return x >> 3;}
 
static bool_t   in_queenside    (sq_t x)   { return 0 == (x & (1<<2));}
 
 
 
/* 1:0 */
 
static void     kxk_indextopc   (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
/* 2:0 */
 
static void     kabk_indextopc  (index_t i, SQUARE *pw, SQUARE *pb);
 
static void     kakb_indextopc  (index_t i, SQUARE *pw, SQUARE *pb);
 
static void             kaak_indextopc  (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
/* 2:1 */
 
static void     kabkc_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
static void             kaakb_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
/* 3:0 */
 
static void     kabck_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
static void             kaabk_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
static void             kaaak_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
static void             kabbk_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
/* one pawn */
 
static void     kpk_indextopc   (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
/* 1:1 one pawn */
 
static void     kakp_indextopc  (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
/* 2:0 one pawn */
 
static void     kapk_indextopc  (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
/* 2:0 two pawns */
 
static void     kppk_indextopc  (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
/*  2:1 one pawn */
 
static void             kapkb_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
static void             kabkp_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
static void             kaakp_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
/*  2:1 + 3:0 two pawns */
 
static void             kppka_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
static void             kappk_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
static void             kapkp_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
/*  3:0 one pawn */
 
static void             kabpk_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
static void             kaapk_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
/*  three pawns */
 
static void             kpppk_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
static void             kppkp_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
/* 1:1 two pawns */
 
static void     kpkp_indextopc  (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
/* corresponding pc to index */
 
static bool_t   kxk_pctoindex   (const SQUARE *pw, const SQUARE *pb, /*@out@*/ index_t *out);
 
static bool_t   kabk_pctoindex  (const SQUARE *pw, const SQUARE *pb, /*@out@*/ index_t *out);
 
static bool_t   kakb_pctoindex  (const SQUARE *pw, const SQUARE *pb, /*@out@*/ index_t *out);
 
static bool_t   kpk_pctoindex   (const SQUARE *pw, const SQUARE *pb, /*@out@*/ index_t *out);
 
static bool_t   kakp_pctoindex  (const SQUARE *pw, const SQUARE *pb, /*@out@*/ index_t *out);
 
static bool_t   kapk_pctoindex  (const SQUARE *pw, const SQUARE *pb, /*@out@*/ index_t *out);
 
static bool_t   kppk_pctoindex  (const SQUARE *pw, const SQUARE *pb, /*@out@*/ index_t *out);
 
static bool_t   kaak_pctoindex  (const SQUARE *pw, const SQUARE *pb, /*@out@*/ index_t *out);
 
static bool_t   kabkc_pctoindex (const SQUARE *pw, const SQUARE *pb, /*@out@*/ index_t *out);
 
 
 
static bool_t   kaakb_pctoindex (const SQUARE *pw, const SQUARE *pb, /*@out@*/ index_t *out);/**/
 
 
 
static bool_t   kabck_pctoindex (const SQUARE *pw, const SQUARE *pb, /*@out@*/ index_t *out);
 
static bool_t   kaabk_pctoindex (const SQUARE *pw, const SQUARE *pb, /*@out@*/ index_t *out);/**/
 
static bool_t   kaaak_pctoindex (const SQUARE *pw, const SQUARE *pb, /*@out@*/ index_t *out);
 
static bool_t   kabbk_pctoindex (const SQUARE *pw, const SQUARE *pb, /*@out@*/ index_t *out);/**/
 
static bool_t   kapkb_pctoindex (const SQUARE *pw, const SQUARE *pb, /*@out@*/ index_t *out);
 
static bool_t   kabkp_pctoindex (const SQUARE *pw, const SQUARE *pb, /*@out@*/ index_t *out);
 
static bool_t   kaakp_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, /*@out@*/ index_t *out);
 
static bool_t   kppka_pctoindex (const SQUARE *pw, const SQUARE *pb, index_t *out);
 
static bool_t   kappk_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, /*@out@*/ index_t *out);
 
static bool_t   kapkp_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, /*@out@*/ index_t *out);
 
static bool_t   kabpk_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, /*@out@*/ index_t *out);
 
static bool_t   kaapk_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, /*@out@*/ index_t *out);
 
static bool_t   kppkp_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, /*@out@*/ index_t *out);
 
static bool_t   kpppk_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, /*@out@*/ index_t *out);
 
static bool_t   kpkp_pctoindex  (const SQUARE *pw,     const SQUARE *pb, /*@out@*/ index_t *out);
 
 
 
/* testing functions */
 
static bool_t   test_kppk  (void);
 
static bool_t   test_kaakb (void);
 
static bool_t   test_kaabk (void);
 
static bool_t   test_kaaak (void);
 
static bool_t   test_kabbk (void);
 
static bool_t   test_kapkb (void);
 
static bool_t   test_kabkp (void);
 
static bool_t   test_kppka (void);
 
static bool_t   test_kappk (void);
 
static bool_t   test_kapkp (void);
 
static bool_t   test_kabpk (void);
 
static bool_t   test_kaapk (void);
 
static bool_t   test_kaakp (void);
 
static bool_t   test_kppkp (void);
 
static bool_t   test_kpppk (void);
 
 
 
static unsigned flip_type (SQUARE x, SQUARE y);
 
static index_t  init_kkidx (void);
 
static index_t  init_ppidx (void);
 
static void     init_flipt (void);
 
static index_t  init_aaidx (void);
 
static index_t  init_aaa   (void);
 
static index_t  init_pp48_idx (void);
 
static index_t  init_ppp48_idx (void);
 
 
 
enum TB_INDEXES
 
         {       MAX_KXK        = MAX_KKINDEX*64
 
                ,MAX_kabk       = MAX_KKINDEX*64*64
 
                ,MAX_kakb       = MAX_KKINDEX*64*64
 
                ,MAX_kpk        = 24*64*64
 
                ,MAX_kakp       = 24*64*64*64
 
                ,MAX_kapk       = 24*64*64*64
 
                ,MAX_kppk       = MAX_PPINDEX*64*64
 
                ,MAX_kpkp       = MAX_PpINDEX*64*64
 
                ,MAX_kaak       = MAX_KKINDEX*MAX_AAINDEX
 
                ,MAX_kabkc      = MAX_KKINDEX*64*64*64
 
                ,MAX_kabck      = MAX_KKINDEX*64*64*64
 
                ,MAX_kaakb      = MAX_KKINDEX*MAX_AAINDEX*64
 
                ,MAX_kaabk      = MAX_KKINDEX*MAX_AAINDEX*64
 
                ,MAX_kabbk  = MAX_KKINDEX*MAX_AAINDEX*64
 
                ,MAX_kaaak      = MAX_KKINDEX*MAX_AAAINDEX
 
                ,MAX_kapkb  = 24*64*64*64*64
 
                ,MAX_kabkp  = 24*64*64*64*64
 
                ,MAX_kabpk  = 24*64*64*64*64
 
                ,MAX_kppka  = MAX_kppk*64
 
                ,MAX_kappk  = MAX_kppk*64
 
                ,MAX_kapkp  = MAX_kpkp*64
 
                ,MAX_kaapk  = 24*MAX_AAINDEX*64*64
 
                ,MAX_kaakp  = 24*MAX_AAINDEX*64*64
 
                ,MAX_kppkp  = 24*MAX_PP48_INDEX*64*64
 
                ,MAX_kpppk  = MAX_PPP48_INDEX*64*64
 
};
 
 
 
#if defined(SHARED_forbuilding)
 
extern index_t
 
biggest_memory_needed (void) {
 
    return MAX_kabkc;
 
}
 
#endif
 
 
 
/*--------------------------------*\
 
|
 
|
 
|               CACHE PROTOTYPES
 
|
 
|
 
*---------------------------------*/
 
 
 
#if !defined(SHARED_forbuilding)
 
mySHARED bool_t         get_dtm (tbkey_t key, unsigned side, index_t idx, dtm_t *out, bool_t probe_hard);
 
#endif
 
 
 
static bool_t           get_dtm_from_cache (tbkey_t key, unsigned side, index_t idx, dtm_t *out);
 
 
 
 
 
/*--------------------------------*\
 
|
 
|
 
|                       INIT
 
|
 
|
 
*---------------------------------*/
 
 
 
static bool_t   fd_init (struct filesopen *pfd);
 
static void             fd_done (struct filesopen *pfd);
 
 
 
static void             RAM_egtbfree (void);
 
 
 
/*--------------------------------------------------------------------------*/
 
#if !defined(SHARED_forbuilding)
 
mySHARED void                   egtb_freemem (int i);
 
#endif
 
 
 
mySHARED struct endgamekey egkey[] = {
 
 
 
{0, "kqk",  MAX_KXK,  1, kxk_indextopc,  kxk_pctoindex,  NULL ,  NULL   ,NULL ,0, 0 },
 
{1, "krk",  MAX_KXK,  1, kxk_indextopc,  kxk_pctoindex,  NULL ,  NULL   ,NULL ,0, 0 },
 
{2, "kbk",  MAX_KXK,  1, kxk_indextopc,  kxk_pctoindex,  NULL ,  NULL   ,NULL ,0, 0 },
 
{3, "knk",  MAX_KXK,  1, kxk_indextopc,  kxk_pctoindex,  NULL ,  NULL   ,NULL ,0, 0 },
 
{4, "kpk",  MAX_kpk,  24,kpk_indextopc,  kpk_pctoindex,  NULL ,  NULL   ,NULL ,0, 0 },
 
        /* 4 pieces */
 
{5, "kqkq", MAX_kakb, 1, kakb_indextopc, kakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{6, "kqkr", MAX_kakb, 1, kakb_indextopc, kakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{7, "kqkb", MAX_kakb, 1, kakb_indextopc, kakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{8, "kqkn", MAX_kakb, 1, kakb_indextopc, kakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
 
 
{9, "krkr", MAX_kakb, 1, kakb_indextopc, kakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{10,"krkb", MAX_kakb, 1, kakb_indextopc, kakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{11,"krkn", MAX_kakb, 1, kakb_indextopc, kakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
 
 
{12,"kbkb", MAX_kakb, 1, kakb_indextopc, kakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{13,"kbkn", MAX_kakb, 1, kakb_indextopc, kakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
 
 
{14,"knkn", MAX_kakb, 1, kakb_indextopc, kakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
        /**/
 
{15,"kqqk", MAX_kaak, 1, kaak_indextopc, kaak_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{16,"kqrk", MAX_kabk, 1, kabk_indextopc, kabk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{17,"kqbk", MAX_kabk, 1, kabk_indextopc, kabk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{18,"kqnk", MAX_kabk, 1, kabk_indextopc, kabk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
 
 
{19,"krrk", MAX_kaak, 1, kaak_indextopc, kaak_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{20,"krbk", MAX_kabk, 1, kabk_indextopc, kabk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{21,"krnk", MAX_kabk, 1, kabk_indextopc, kabk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
 
 
{22,"kbbk", MAX_kaak, 1, kaak_indextopc, kaak_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{23,"kbnk", MAX_kabk, 1, kabk_indextopc, kabk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
 
 
{24,"knnk", MAX_kaak, 1, kaak_indextopc, kaak_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
        /**/
 
        /**/
 
{25,"kqkp", MAX_kakp, 24,kakp_indextopc, kakp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{26,"krkp", MAX_kakp, 24,kakp_indextopc, kakp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{27,"kbkp", MAX_kakp, 24,kakp_indextopc, kakp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{28,"knkp", MAX_kakp, 24,kakp_indextopc, kakp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
        /**/
 
{29,"kqpk", MAX_kapk, 24,kapk_indextopc, kapk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{30,"krpk", MAX_kapk, 24,kapk_indextopc, kapk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{31,"kbpk", MAX_kapk, 24,kapk_indextopc, kapk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{32,"knpk", MAX_kapk, 24,kapk_indextopc, kapk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
        /**/
 
{33,"kppk", MAX_kppk, MAX_PPINDEX ,kppk_indextopc, kppk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
        /**/
 
{34,"kpkp", MAX_kpkp, MAX_PpINDEX ,kpkp_indextopc, kpkp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
        /**/
 
        /**/
 
        /* 5 pieces */
 
{ 35,"kqqqk", MAX_kaaak, 1, kaaak_indextopc, kaaak_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 36,"kqqrk", MAX_kaabk, 1, kaabk_indextopc, kaabk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 37,"kqqbk", MAX_kaabk, 1, kaabk_indextopc, kaabk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 38,"kqqnk", MAX_kaabk, 1, kaabk_indextopc, kaabk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 39,"kqrrk", MAX_kabbk, 1, kabbk_indextopc, kabbk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 40,"kqrbk", MAX_kabck, 1, kabck_indextopc, kabck_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 41,"kqrnk", MAX_kabck, 1, kabck_indextopc, kabck_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 42,"kqbbk", MAX_kabbk, 1, kabbk_indextopc, kabbk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 43,"kqbnk", MAX_kabck, 1, kabck_indextopc, kabck_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 44,"kqnnk", MAX_kabbk, 1, kabbk_indextopc, kabbk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 45,"krrrk", MAX_kaaak, 1, kaaak_indextopc, kaaak_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 46,"krrbk", MAX_kaabk, 1, kaabk_indextopc, kaabk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 47,"krrnk", MAX_kaabk, 1, kaabk_indextopc, kaabk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 48,"krbbk", MAX_kabbk, 1, kabbk_indextopc, kabbk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 49,"krbnk", MAX_kabck, 1, kabck_indextopc, kabck_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 50,"krnnk", MAX_kabbk, 1, kabbk_indextopc, kabbk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 51,"kbbbk", MAX_kaaak, 1, kaaak_indextopc, kaaak_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 52,"kbbnk", MAX_kaabk, 1, kaabk_indextopc, kaabk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 53,"kbnnk", MAX_kabbk, 1, kabbk_indextopc, kabbk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 54,"knnnk", MAX_kaaak, 1, kaaak_indextopc, kaaak_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 55,"kqqkq", MAX_kaakb, 1, kaakb_indextopc, kaakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 56,"kqqkr", MAX_kaakb, 1, kaakb_indextopc, kaakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 57,"kqqkb", MAX_kaakb, 1, kaakb_indextopc, kaakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 58,"kqqkn", MAX_kaakb, 1, kaakb_indextopc, kaakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 59,"kqrkq", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 60,"kqrkr", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 61,"kqrkb", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 62,"kqrkn", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 63,"kqbkq", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 64,"kqbkr", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 65,"kqbkb", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 66,"kqbkn", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 67,"kqnkq", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 68,"kqnkr", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 69,"kqnkb", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 70,"kqnkn", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 71,"krrkq", MAX_kaakb, 1, kaakb_indextopc, kaakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 72,"krrkr", MAX_kaakb, 1, kaakb_indextopc, kaakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 73,"krrkb", MAX_kaakb, 1, kaakb_indextopc, kaakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 74,"krrkn", MAX_kaakb, 1, kaakb_indextopc, kaakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 75,"krbkq", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 76,"krbkr", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 77,"krbkb", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 78,"krbkn", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 79,"krnkq", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 80,"krnkr", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 81,"krnkb", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 82,"krnkn", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 83,"kbbkq", MAX_kaakb, 1, kaakb_indextopc, kaakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 84,"kbbkr", MAX_kaakb, 1, kaakb_indextopc, kaakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 85,"kbbkb", MAX_kaakb, 1, kaakb_indextopc, kaakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 86,"kbbkn", MAX_kaakb, 1, kaakb_indextopc, kaakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 87,"kbnkq", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 88,"kbnkr", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 89,"kbnkb", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 90,"kbnkn", MAX_kabkc, 1, kabkc_indextopc, kabkc_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 91,"knnkq", MAX_kaakb, 1, kaakb_indextopc, kaakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 92,"knnkr", MAX_kaakb, 1, kaakb_indextopc, kaakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 93,"knnkb", MAX_kaakb, 1, kaakb_indextopc, kaakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 94,"knnkn", MAX_kaakb, 1, kaakb_indextopc, kaakb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
 
 
{ 95,"kqqpk", MAX_kaapk, 24, kaapk_indextopc, kaapk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 96,"kqrpk", MAX_kabpk, 24, kabpk_indextopc, kabpk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 97,"kqbpk", MAX_kabpk, 24, kabpk_indextopc, kabpk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 98,"kqnpk", MAX_kabpk, 24, kabpk_indextopc, kabpk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{ 99,"krrpk", MAX_kaapk, 24, kaapk_indextopc, kaapk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{100,"krbpk", MAX_kabpk, 24, kabpk_indextopc, kabpk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{101,"krnpk", MAX_kabpk, 24, kabpk_indextopc, kabpk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{102,"kbbpk", MAX_kaapk, 24, kaapk_indextopc, kaapk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{103,"kbnpk", MAX_kabpk, 24, kabpk_indextopc, kabpk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{104,"knnpk", MAX_kaapk, 24, kaapk_indextopc, kaapk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
 
 
{105,"kqppk", MAX_kappk, MAX_PPINDEX, kappk_indextopc, kappk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{106,"krppk", MAX_kappk, MAX_PPINDEX, kappk_indextopc, kappk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{107,"kbppk", MAX_kappk, MAX_PPINDEX, kappk_indextopc, kappk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{108,"knppk", MAX_kappk, MAX_PPINDEX, kappk_indextopc, kappk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
 
 
{109,"kqpkq", MAX_kapkb, 24, kapkb_indextopc, kapkb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{110,"kqpkr", MAX_kapkb, 24, kapkb_indextopc, kapkb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{111,"kqpkb", MAX_kapkb, 24, kapkb_indextopc, kapkb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{112,"kqpkn", MAX_kapkb, 24, kapkb_indextopc, kapkb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{113,"krpkq", MAX_kapkb, 24, kapkb_indextopc, kapkb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{114,"krpkr", MAX_kapkb, 24, kapkb_indextopc, kapkb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{115,"krpkb", MAX_kapkb, 24, kapkb_indextopc, kapkb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{116,"krpkn", MAX_kapkb, 24, kapkb_indextopc, kapkb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{117,"kbpkq", MAX_kapkb, 24, kapkb_indextopc, kapkb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{118,"kbpkr", MAX_kapkb, 24, kapkb_indextopc, kapkb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{119,"kbpkb", MAX_kapkb, 24, kapkb_indextopc, kapkb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{120,"kbpkn", MAX_kapkb, 24, kapkb_indextopc, kapkb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{121,"knpkq", MAX_kapkb, 24, kapkb_indextopc, kapkb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{122,"knpkr", MAX_kapkb, 24, kapkb_indextopc, kapkb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{123,"knpkb", MAX_kapkb, 24, kapkb_indextopc, kapkb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{124,"knpkn", MAX_kapkb, 24, kapkb_indextopc, kapkb_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
 
 
{125,"kppkq", MAX_kppka, MAX_PPINDEX, kppka_indextopc, kppka_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{126,"kppkr", MAX_kppka, MAX_PPINDEX, kppka_indextopc, kppka_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{127,"kppkb", MAX_kppka, MAX_PPINDEX, kppka_indextopc, kppka_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{128,"kppkn", MAX_kppka, MAX_PPINDEX, kppka_indextopc, kppka_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
 
 
{129,"kqqkp", MAX_kaakp, 24, kaakp_indextopc, kaakp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{130,"kqrkp", MAX_kabkp, 24, kabkp_indextopc, kabkp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{131,"kqbkp", MAX_kabkp, 24, kabkp_indextopc, kabkp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{132,"kqnkp", MAX_kabkp, 24, kabkp_indextopc, kabkp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{133,"krrkp", MAX_kaakp, 24, kaakp_indextopc, kaakp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{134,"krbkp", MAX_kabkp, 24, kabkp_indextopc, kabkp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{135,"krnkp", MAX_kabkp, 24, kabkp_indextopc, kabkp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{136,"kbbkp", MAX_kaakp, 24, kaakp_indextopc, kaakp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{137,"kbnkp", MAX_kabkp, 24, kabkp_indextopc, kabkp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{138,"knnkp", MAX_kaakp, 24, kaakp_indextopc, kaakp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
 
 
{139,"kqpkp", MAX_kapkp, MAX_PpINDEX, kapkp_indextopc, kapkp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{140,"krpkp", MAX_kapkp, MAX_PpINDEX, kapkp_indextopc, kapkp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{141,"kbpkp", MAX_kapkp, MAX_PpINDEX, kapkp_indextopc, kapkp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{142,"knpkp", MAX_kapkp, MAX_PpINDEX, kapkp_indextopc, kapkp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
 
 
{143,"kppkp", MAX_kppkp, 24*MAX_PP48_INDEX, kppkp_indextopc, kppkp_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
{144,"kpppk", MAX_kpppk, MAX_PPP48_INDEX, kpppk_indextopc, kpppk_pctoindex, NULL ,  NULL   ,NULL ,0, 0 },
 
 
 
{MAX_EGKEYS, NULL,  0,        1, NULL,           NULL,           NULL,   NULL   ,NULL ,0 ,0}
 
 
 
};
 
 
 
#define EGKEY_HASH_SIZE 512
 
static tbkey_t egkey_hash[EGKEY_HASH_SIZE];
 
 
 
static size_t
 
str_hash_func_1 (const char * str)
 
{
 
        size_t h = 5381;
 
        int c;
 
        while ((c = *str++))
 
                h = h * 31 + c;
 
        return h;
 
}
 
 
 
static size_t
 
str_hash_func_2 (const char * str)
 
{
 
        size_t h = 0;
 
        int c;
 
        while ((c = *str++))
 
                h = h * 65599 + c;
 
        return 2 * h + 1;
 
}
 
 
 
static void
 
init_egkey_hash (void)
 
{
 
        size_t h1, h2;
 
        int i;
 
 
 
        for (i = 0; i < EGKEY_HASH_SIZE; i++)
 
                egkey_hash[i] = -1;
 
 
 
        for (i = 0; i < MAX_EGKEYS; i++) {
 
                h1 = str_hash_func_1 (egkey[i].str) & (EGKEY_HASH_SIZE - 1);
 
                h2 = str_hash_func_2 (egkey[i].str);
 
                while (egkey_hash[h1] >= 0)
 
                        h1 = (h1 + h2) & (EGKEY_HASH_SIZE - 1);
 
                egkey_hash[h1] = egkey[i].id;
 
        }
 
}
 
 
 
 
 
static int eg_was_open[MAX_EGKEYS];
 
 
 
static uint64_t Bytes_read = 0;
 
 
 
/****************************************************************************\
 
|
 
|
 
|                                               PATH MANAGEMENT ZONE
 
|
 
|
 
\****************************************************************************/
 
 
 
#define MAXPATHLEN tb_MAXPATHLEN
 
#define MAX_GTBPATHS 10
 
 
 
static int                      Gtbpath_end_index = 0;
 
static const char **    Gtbpath = NULL;
 
 
 
/*---------------- EXTERNAL PATH MANAGEMENT --------------------------------*/
 
 
 
extern const char *tbpaths_getmain (void) {     return Gtbpath[0];}
 
 
 
extern const char **
 
tbpaths_init(void)
 
{
 
        const char **newps;
 
        newps 
= (const char **) malloc (sizeof (char *)); 
        if (newps != NULL) {
 
                newps[0] = NULL;
 
        }
 
        return newps;
 
}
 
 
 
static const char **
 
tbpaths_add_single(const char **ps, const char *newpath)
 
{
 
        size_t counter;
 
        const char **newps;
 
        size_t i, psize;
 
        char *ppath;
 
 
 
        if (NULL == ps)
 
                return NULL;
 
 
 
        ppath 
= (char *) malloc (psize 
* sizeof (char)); 
        if (NULL == ppath)
 
                return ps; /* failed to incorporate a new path */
 
        for (i = 0; i < psize; i++) ppath[i] = newpath[i];
 
 
 
        for (counter = 0; ps[counter] != NULL; counter++)
 
                ;
 
 
 
        /* cast to deal with const poisoning */
 
        newps 
= (const char **) realloc ((char **)ps
, sizeof(char *) * (counter
+2)); 
        if (newps != NULL) {
 
                newps [counter] = ppath;
 
                newps [counter+1] = NULL;
 
        }
 
        return newps;
 
}
 
 
 
 
 
extern const char **
 
tbpaths_add(const char **ps, const char *newpath)
 
{
 
        size_t i, psize;
 
        char *mpath;
 
 
 
        if (NULL == ps)
 
                return NULL;
 
 
 
        mpath 
= (char *) malloc (psize 
* sizeof (char)); 
        if (NULL == mpath) {
 
                return ps; /* failed to incorporate a new path */
 
        }
 
        for (i = 0; i < psize; i++) mpath[i] = newpath[i];
 
 
 
        for (i = 0; i < psize; i++) {
 
                if(';' == mpath[i])
 
                        mpath[i] = '\0';
 
        }
 
 
 
        for (i = 0;;) {
 
                while (i < psize && mpath[i] == '\0') i++;
 
                if (i >= psize) break;
 
                ps = tbpaths_add_single (ps, &mpath[i]);
 
                while (i < psize && mpath[i] != '\0') i++;
 
        }
 
 
 
        return ps;
 
}
 
 
 
 
 
extern const char **
 
tbpaths_done(const char **ps)
 
{
 
        int counter;
 
        void *q;
 
 
 
        if (ps != NULL) {
 
                for (counter = 0; ps[counter] != NULL; counter++) {
 
                        /* cast to deal with const poisoning */
 
                        void *p = (void *) ps[counter];
 
                }
 
                /* cast to deal with const poisoning */
 
                q = (void *) ps;
 
        }
 
        return NULL;
 
}
 
 
 
/*---------------- PATH INITIALIZATION ROUTINES ----------------------------*/
 
 
 
static void path_system_reset(void) {Gtbpath_end_index = 0;}
 
 
 
static bool_t
 
path_system_init (const char **path)
 
{
 
        size_t i;
 
        size_t sz;
 
        const char *x;
 
        bool_t ok = TRUE;
 
        path_system_reset();
 
 
 
        if (path == NULL) {
 
                return FALSE;
 
        }
 
 
 
        /* calculate needed size for Gtbpath */
 
        i = 0;
 
        do {
 
                x = path[i++];
 
        } while (x != NULL);
 
        sz = i; /* sz includes the NULL */
 
 
 
 
 
        Gtbpath 
= (const char **) malloc (sz 
* sizeof(char *)); 
 
 
        if (Gtbpath) {
 
 
 
                ok = TRUE;
 
                /* point to the same strings provided */
 
                Gtbpath_end_index = 0;
 
                for (i = 0; i < sz; i++) {
 
                        Gtbpath[i] = path[i];
 
                        Gtbpath_end_index++;
 
                }
 
 
 
        } else {
 
                ok = FALSE;
 
        }
 
        return ok;
 
 
 
}
 
 
 
static void
 
path_system_done (void)
 
{
 
        /* before we free Gtbpath, we have to deal with the
 
        "const poisoning" and cast it. free() does not accept
 
        const pointers */
 
        char ** p = (char **) Gtbpath;
 
        /* clean up */
 
        if (p != NULL)
 
        return;
 
}
 
 
 
 
 
/****************************************************************************\
 
 *
 
 *
 
 *                                              General Initialization Zone
 
 *
 
 *
 
 ****************************************************************************/
 
 
 
 
 
#ifdef WDL_PROBE
 
static size_t           wdl_cache_init (size_t cache_mem);
 
static void             wdl_cache_flush (void);
 
 
 
static void                     wdl_cache_reset_counters (void);
 
static void                     wdl_cache_done (void);
 
 
 
static bool_t           get_WDL_from_cache (tbkey_t key, unsigned side, index_t idx, unsigned int *out);
 
static bool_t           wdl_preload_cache (tbkey_t key, unsigned side, index_t idx);
 
#endif
 
 
 
#ifdef GTB_SHARE
 
static void     init_bettarr (void);
 
#endif
 
 
 
static void     eg_was_open_reset(void)
 
{
 
        int i;
 
        for (i = 0; i < MAX_EGKEYS; i++) {
 
                eg_was_open[i] = 0;
 
        }
 
}
 
 
 
static long unsigned int eg_was_open_count(void)
 
{
 
        long int i, x;
 
        for (i = 0, x = 0; i < MAX_EGKEYS; i++) {
 
                x += eg_was_open[i];
 
        }
 
        return (long unsigned) x;
 
}
 
 
 
 
 
enum  Sizes {INISIZE = 4096};
 
static char ini_str[INISIZE];
 
static void sjoin_s
(char *s
, size_t size
, const char *tail
, size_t max
) {strncat_s
(s
, size
, tail
, max 
- strlen(s
) - 1);} // Pierre-Marie Baty -- safer version  
 
 
char *
 
tb_init (int verbosity, int decoding_sch, const char **paths)
 
{
 
        unsigned int zi;
 
        int paths_ok;
 
        char *ret_str;
 
        char localstr[256];
 
 
 
 
 
        init_egkey_hash ();
 
 
 
        if (verbosity) {
 
                ini_str[0] = '\0';
 
                ret_str = ini_str;
 
        } else {
 
                ret_str = NULL;
 
        }
 
 
 
        paths_ok = path_system_init (paths);
 
 
 
        if (paths_ok && verbosity) {
 
                int g;
 
                sjoin_s(ini_str,sizeof(ini_str),"\nGTB PATHS\n",INISIZE); // Pierre-Marie Baty -- using a more secure version of this function
 
                for (g = 0; Gtbpath[g] != NULL; g++) {
 
                        const char *p = Gtbpath[g];
 
                        if (0 == g) {
 
                                sprintf_s (localstr, sizeof(localstr),"  main: %s\n", p); // Pierre-Marie Baty -- using sprintf_s() instead of sprintf
 
                        } else {
 
                                sprintf_s (localstr, sizeof(localstr),"    #%d: %s\n", g, p); // Pierre-Marie Baty -- using sprintf_s() instead of sprintf
 
                        }
 
         sjoin_s(ini_str,sizeof(ini_str),localstr,INISIZE); // Pierre-Marie Baty -- using a more secure version of this function
 
                }
 
        }
 
 
 
        if (!paths_ok && verbosity) {
 
                sjoin_s (ini_str,sizeof(ini_str),"\nGTB PATHS not initialized\n",INISIZE); // Pierre-Marie Baty -- using a more secure version of this function
 
        }
 
 
 
        if (!reach_was_initialized())
 
                reach_init();
 
 
 
        attack_maps_init (); /* external initialization */
 
 
 
        init_indexing(0 /* no verbosity */);
 
 
 
        #ifdef GTB_SHARE
 
        init_bettarr();
 
        #endif
 
 
 
        if (!fd_init (&fd) && verbosity) {
 
                sjoin_s (ini_str,sizeof(ini_str),"  File Open Memory initialization = **FAILED**\n",INISIZE); // Pierre-Marie Baty -- using a more secure version of this function
 
                return ret_str;
 
        }
 
 
 
        GTB_scheme = decoding_sch;
 
        Uncompressed = GTB_scheme == 0;
 
 
 
        if (GTB_scheme == 0) {
 
                Uncompressed = TRUE;
 
        }
 
 
 
        set_decoding_scheme(GTB_scheme);
 
 
 
        if (verbosity) {
 
                sjoin_s (ini_str,sizeof(ini_str),"\nGTB initialization\n",INISIZE); // Pierre-Marie Baty -- using a more secure version of this function
 
      sprintf_s (localstr, sizeof (localstr), "  Compression  Scheme = %d\n", GTB_scheme); // Pierre-Marie Baty -- using sprintf_s() instead of sprintf
 
                sjoin_s (ini_str,sizeof(ini_str),localstr,INISIZE); // Pierre-Marie Baty -- using a more secure version of this function
 
        }
 
 
 
        zi = zipinfo_init();
 
 
 
        TB_AVAILABILITY = zi;
 
 
 
        if (verbosity) {
 
                if (0 == zi) {
 
                        sjoin_s (ini_str,sizeof(ini_str),"  Compression Indexes = **FAILED**\n",INISIZE); // Pierre-Marie Baty -- using a more secure version of this function
 
                } else {
 
                        int n, bit;
 
 
 
                        n = 3; bit = 1;
 
                        if (zi&(1u<<bit))
 
            sprintf_s (localstr, sizeof (localstr), "  Compression Indexes (%d-pc) = PASSED\n",n); // Pierre-Marie Baty -- using sprintf_s() instead of sprintf
 
                        else
 
            sprintf_s (localstr, sizeof (localstr), "  Compression Indexes (%d-pc) = **FAILED**\n",n); // Pierre-Marie Baty -- using sprintf_s() instead of sprintf
 
                        sjoin_s (ini_str,sizeof(ini_str),localstr,INISIZE); // Pierre-Marie Baty -- using a more secure version of this function
 
 
 
                        n = 4; bit = 3;
 
                        if (zi&(1u<<bit))
 
            sprintf_s (localstr, sizeof (localstr), "  Compression Indexes (%d-pc) = PASSED\n",n); // Pierre-Marie Baty -- using sprintf_s() instead of sprintf
 
                        else
 
            sprintf_s (localstr, sizeof (localstr), "  Compression Indexes (%d-pc) = **FAILED**\n",n); // Pierre-Marie Baty -- using sprintf_s() instead of sprintf
 
                        sjoin_s (ini_str,sizeof(ini_str),localstr,INISIZE); // Pierre-Marie Baty -- using a more secure version of this function
 
 
 
                        n = 5; bit = 5;
 
                        if (zi&(1u<<bit))
 
            sprintf_s (localstr, sizeof (localstr), "  Compression Indexes (%d-pc) = PASSED\n",n); // Pierre-Marie Baty -- using sprintf_s() instead of sprintf
 
                        else
 
                                sprintf_s (localstr, sizeof(localstr),"  Compression Indexes (%d-pc) = **FAILED**\n",n); // Pierre-Marie Baty -- using sprintf_s() instead of sprintf
 
                        sjoin_s (ini_str,sizeof(ini_str),localstr,INISIZE); // Pierre-Marie Baty -- using a more secure version of this function
 
                }
 
                sjoin_s (ini_str,sizeof(ini_str),"\n",INISIZE); // Pierre-Marie Baty -- using a more secure version of this function
 
        }
 
 
 
        eg_was_open_reset();
 
        Bytes_read = 0;
 
 
 
        mythread_mutex_init (&Egtb_lock);
 
 
 
        TB_INITIALIZED = TRUE;
 
 
 
        return ret_str;
 
}
 
 
 
extern unsigned int
 
tb_availability(void)
 
{
 
        return TB_AVAILABILITY;
 
}
 
 
 
extern bool_t
 
tb_is_initialized (void)
 
{
 
        return TB_INITIALIZED;
 
}
 
 
 
extern void
 
tb_done (void)
 
{
 
        fd_done (&fd);
 
        RAM_egtbfree();
 
        zipinfo_done();
 
        path_system_done();
 
        mythread_mutex_destroy (&Egtb_lock);
 
        TB_INITIALIZED = FALSE;
 
 
 
        /*
 
                HERE, I should be free() the ini_str, but in
 
                the current implementation, it is static
 
                rather than dynamic.
 
        */
 
        return;
 
}
 
 
 
char *
 
tb_restart(int verbosity, int decoding_sch, const char **paths)
 
{
 
        if (tb_is_initialized()) {
 
                tb_done();
 
        }
 
        return tb_init(verbosity, decoding_sch, paths);
 
}
 
 
 
/* whenever the program exits should release this memory */
 
static void
 
RAM_egtbfree (void)
 
{
 
        int i;
 
        for (i = 0; egkey[i].str != NULL; i++) {
 
                egtb_freemem (i);
 
        }
 
}
 
 
 
/*--------------------------------------------------------------------------*/
 
 
 
#ifdef GTB_SHARE
 
static void
 
init_bettarr (void)
 
{
 
/*
 
                iDRAW  = 0, iWMATE  = 1, iBMATE  = 2, iFORBID  = 3,
 
                iDRAWt = 4, iWMATEt = 5, iBMATEt = 6, iUNKNOWN = 7
 
 */
 
 
 
        int temp[] = {
 
        /*White*/
 
        /*iDRAW   vs*/
 
                1, 2, 1, 1,     2, 2, 2, 2,
 
        /*iWMATE  vs*/
 
                1, 3, 1, 1,     1, 1, 1, 1,
 
        /*iBMATE  vs*/
 
                2, 2, 4, 1,     2, 2, 2, 2,
 
        /*iFORBID vs*/
 
                2, 2, 2, 2,     2, 2, 2, 2,
 
 
 
        /*iDRAWt  vs*/
 
                1, 2, 1, 1,     2, 2, 1, 2,
 
        /*iWMATEt vs*/
 
                1, 2, 1, 1,     1, 3, 1, 1,
 
        /*iBMATEt vs*/
 
                1, 2, 1, 1,     2, 2, 4, 2,
 
        /*iUNKNOWN  */
 
                1, 2, 1, 1,     1, 2, 1, 2,
 
 
 
        /*Black*/
 
        /*iDRAW   vs*/
 
                1, 1, 2, 1,     2, 2, 2, 2,
 
        /*iWMATE  vs*/
 
                2, 4, 2, 1,     2, 2, 2, 2,
 
        /*iBMATE  vs*/
 
                1, 1, 3, 1,     1, 1, 1, 1,
 
        /*iFORBID vs*/
 
                2, 2, 2, 2,     2, 2, 2, 2,
 
 
 
        /*iDRAWt  vs*/
 
                1, 1, 2, 1,     2, 1, 2, 2,
 
        /*iWMATEt vs*/
 
                1, 1, 2, 1,     2, 4, 2, 2,
 
        /*iBMATEt vs*/
 
                1, 1, 2, 1,     1, 1, 3, 1,
 
        /*iUNKNOWN  */
 
                1, 1, 2, 1,     1, 1, 2, 2
 
        };
 
 
 
        int i, j, k, z;
 
 
 
        /* reset */
 
        z = 0;
 
        for (i = 0; i < 2; i++)
 
                for (j = 0; j < 8; j++)
 
                        for (k = 0; k < 8; k++)
 
                                bettarr [i][j][k] = temp[z++];
 
 
 
        return;
 
}
 
#endif
 
 
 
/*
 
|
 
|       Own File Descriptors
 
|
 
\*---------------------------------------------------------------------------*/
 
 
 
static bool_t
 
fd_init (struct filesopen *pfd)
 
{
 
        tbkey_t *p;
 
    int i, allowed;
 
 
 
        pfd->n = 0;
 
 
 
        allowed = mysys_fopen_max() - 5 /*stdin,stdout,sterr,stdlog,book*/;
 
        if (allowed < 4)
 
                GTB_MAXOPEN = 4;
 
        if (allowed > 32)
 
                GTB_MAXOPEN = 32;
 
 
 
        p 
=     (tbkey_t 
*) malloc(sizeof(tbkey_t
)*(size_t)GTB_MAXOPEN
); 
 
 
        if (p != NULL) {
 
                for (i = 0; i < GTB_MAXOPEN; i++) {
 
                        p[i] = -1;
 
                }
 
                pfd->key = p;
 
                return TRUE;
 
        } else {
 
                return FALSE;
 
        }
 
}
 
 
 
static void
 
fd_done (struct filesopen *pfd)
 
{
 
    int i;
 
        tbkey_t closingkey;
 
        FILE *finp;
 
 
 
 
 
        for (i = 0; i < pfd->n; i++) {
 
                closingkey = pfd->key[i];
 
                finp = egkey [closingkey].fd;
 
                egkey[closingkey].fd = NULL;
 
                pfd->key[i] = -1;
 
        }
 
        pfd->n = 0;
 
}
 
 
 
/****************************************************************************\
 
|
 
|
 
|                                                               PROBE ZONE
 
|
 
|
 
\****************************************************************************/
 
 
 
#if !defined(SHARED_forbuilding)
 
 
 
/* shared with building routines */
 
mySHARED void                   list_sq_copy    (const SQUARE *a, SQUARE *b);
 
mySHARED void                   list_pc_copy    (const SQ_CONTENT *a, SQ_CONTENT *b);
 
mySHARED dtm_t                  inv_dtm                 (dtm_t x);
 
mySHARED bool_t                 egtb_get_id     (SQ_CONTENT *w, SQ_CONTENT *b, tbkey_t *id);
 
mySHARED void                   list_sq_flipNS  (SQUARE *s);
 
mySHARED dtm_t                  adjust_up               (dtm_t dist);
 
mySHARED dtm_t                  bestx                   (unsigned stm, dtm_t a, dtm_t b);
 
mySHARED void                   sortlists               (SQUARE *ws, SQ_CONTENT *wp);
 
 
 
mySHARED /*@NULL@*/     FILE * fd_openit(tbkey_t key);
 
 
 
mySHARED dtm_t                  dtm_unpack      (unsigned stm, unsigned char packed);
 
mySHARED void                   unpackdist      (dtm_t d, unsigned int *res, unsigned int *ply);
 
mySHARED dtm_t                  packdist        (unsigned int inf, unsigned int ply);
 
 
 
mySHARED bool_t                 fread_entry_packed      (FILE *dest, unsigned side, dtm_t *px);
 
mySHARED bool_t                 fpark_entry_packed  (FILE *finp, unsigned side, index_t max, index_t idx);
 
#endif
 
 
 
/* use only with probe */
 
static bool_t                   egtb_get_dtm    (tbkey_t k, unsigned stm, const SQUARE *wS, const SQUARE *bS, bool_t probe_hard, dtm_t *dtm);
 
static void                             removepiece (SQUARE *ys, SQ_CONTENT *yp, int j);
 
static bool_t                   egtb_filepeek (tbkey_t key, unsigned side, index_t idx, dtm_t *out_dtm);
 
 
 
 
 
/*prototype*/
 
#ifdef WDL_PROBE
 
static bool_t
 
tb_probe_wdl
 
                        (unsigned stm,
 
                         const SQUARE *inp_wSQ,
 
                         const SQUARE *inp_bSQ,
 
                         const SQ_CONTENT *inp_wPC,
 
                         const SQ_CONTENT *inp_bPC,
 
                         bool_t probingtype,
 
                         /*@out@*/ unsigned *res);
 
#endif
 
 
 
static bool_t
 
tb_probe_       (unsigned stm,
 
                         SQUARE epsq,
 
                         const SQUARE *inp_wSQ,
 
                         const SQUARE *inp_bSQ,
 
                         const SQ_CONTENT *inp_wPC,
 
                         const SQ_CONTENT *inp_bPC,
 
                         bool_t probingtype,
 
                         /*@out@*/ unsigned *res,
 
                         /*@out@*/ unsigned *ply);
 
 
 
 
 
extern bool_t
 
tb_probe_soft
 
                        (unsigned stm,
 
                         SQUARE epsq,
 
                         unsigned castles,
 
                         const SQUARE *inp_wSQ,
 
                         const SQUARE *inp_bSQ,
 
                         const SQ_CONTENT *inp_wPC,
 
                         const SQ_CONTENT *inp_bPC,
 
                         /*@out@*/ unsigned *res,
 
                         /*@out@*/ unsigned *ply)
 
{
 
        if (castles != 0)
 
                return FALSE;
 
        return tb_probe_ (stm, epsq, inp_wSQ, inp_bSQ, inp_wPC, inp_bPC, FALSE, res, ply);
 
}
 
 
 
extern bool_t
 
tb_probe_hard
 
                        (unsigned stm,
 
                         SQUARE epsq,
 
                         unsigned castles,
 
                         const SQUARE *inp_wSQ,
 
                         const SQUARE *inp_bSQ,
 
                         const SQ_CONTENT *inp_wPC,
 
                         const SQ_CONTENT *inp_bPC,
 
                         /*@out@*/ unsigned *res,
 
                         /*@out@*/ unsigned *ply)
 
{
 
        if (castles != 0)
 
                return FALSE;
 
        return tb_probe_ (stm, epsq, inp_wSQ, inp_bSQ, inp_wPC, inp_bPC, TRUE, res, ply);
 
}
 
 
 
extern bool_t
 
tb_probe_WDL_soft
 
                        (unsigned stm,
 
                         SQUARE epsq,
 
                         unsigned castles,
 
                         const SQUARE *inp_wSQ,
 
                         const SQUARE *inp_bSQ,
 
                         const SQ_CONTENT *inp_wPC,
 
                         const SQ_CONTENT *inp_bPC,
 
                         /*@out@*/ unsigned *res)
 
{
 
        unsigned ply_n;
 
        unsigned *ply = &ply_n;
 
        if (castles != 0)
 
                return FALSE;
 
        if (epsq != NOSQUARE)
 
                return tb_probe_ (stm, epsq, inp_wSQ, inp_bSQ, inp_wPC, inp_bPC, FALSE, res, ply);
 
 
 
        /* probe bitbase like, assuming no en passant */
 
        #ifdef WDL_PROBE
 
        return tb_probe_wdl    (stm, inp_wSQ, inp_bSQ, inp_wPC, inp_bPC, FALSE, res);
 
        #else
 
        return tb_probe_ (stm, epsq, inp_wSQ, inp_bSQ, inp_wPC, inp_bPC, FALSE, res, ply);
 
        #endif
 
}
 
 
 
extern bool_t
 
tb_probe_WDL_hard
 
                        (unsigned stm,
 
                         SQUARE epsq,
 
                         unsigned castles,
 
                         const SQUARE *inp_wSQ,
 
                         const SQUARE *inp_bSQ,
 
                         const SQ_CONTENT *inp_wPC,
 
                         const SQ_CONTENT *inp_bPC,
 
                         /*@out@*/ unsigned *res)
 
{
 
        unsigned ply_n;
 
        unsigned *ply = &ply_n;
 
        if (castles != 0)
 
                return FALSE;
 
        if (epsq != NOSQUARE)
 
                return tb_probe_ (stm, epsq, inp_wSQ, inp_bSQ, inp_wPC, inp_bPC, TRUE, res, ply);
 
 
 
        /* probe bitbase like, assuming no en passant */
 
        #ifdef WDL_PROBE
 
        return tb_probe_wdl    (stm, inp_wSQ, inp_bSQ, inp_wPC, inp_bPC, TRUE, res);
 
        #else
 
        return tb_probe_ (stm, epsq, inp_wSQ, inp_bSQ, inp_wPC, inp_bPC, TRUE, res, ply);
 
        #endif
 
}
 
 
 
 
 
static bool_t
 
tb_probe_       (unsigned stm,
 
                         SQUARE epsq,
 
                         const SQUARE *inp_wSQ,
 
                         const SQUARE *inp_bSQ,
 
                         const SQ_CONTENT *inp_wPC,
 
                         const SQ_CONTENT *inp_bPC,
 
                         bool_t probingtype,
 
                         /*@out@*/ unsigned *res,
 
                         /*@out@*/ unsigned *ply)
 
{
 
        int i = 0, j = 0;
 
        tbkey_t id = -1;
 
        dtm_t dtm = 0;
 
 
 
        SQUARE          storage_ws [MAX_LISTSIZE], storage_bs [MAX_LISTSIZE];
 
        SQ_CONTENT  storage_wp [MAX_LISTSIZE], storage_bp [MAX_LISTSIZE];
 
 
 
        SQUARE     *ws = storage_ws;
 
        SQUARE     *bs = storage_bs;
 
        SQ_CONTENT *wp = storage_wp;
 
        SQ_CONTENT *bp = storage_bp;
 
 
 
        SQUARE     *xs;
 
        SQUARE     *ys;
 
        SQ_CONTENT *xp;
 
        SQ_CONTENT *yp;
 
 
 
        SQUARE          tmp_ws [MAX_LISTSIZE], tmp_bs [MAX_LISTSIZE];
 
        SQ_CONTENT  tmp_wp [MAX_LISTSIZE], tmp_bp [MAX_LISTSIZE];
 
 
 
        SQUARE *temps;
 
        bool_t straight = FALSE;
 
 
 
        SQUARE capturer_a, capturer_b, xed = NOSQUARE;
 
 
 
        unsigned int plies;
 
        unsigned int inf;
 
 
 
        bool_t  okdtm  = TRUE;
 
        bool_t  okcall = TRUE;
 
 
 
        /************************************/
 
 
 
        assert (stm 
== WH 
|| stm 
== BL
);  
        /*assert (inp_wPC[0] == KING && inp_bPC[0] == KING );*/
 
        assert ((epsq 
>> 3) == 2 || (epsq 
>> 3) == 5 || epsq 
== NOSQUARE
);  
 
 
        /* VALID ONLY FOR KK!! */
 
        if (inp_wPC[1] == NOPIECE && inp_bPC[1] == NOPIECE) {
 
                index_t dummy_i;
 
                bool_t b = kxk_pctoindex (inp_wSQ, inp_bSQ, &dummy_i);
 
                *res = b? iDRAW: iFORBID;
 
                *ply = 0;
 
                return TRUE;
 
        }
 
 
 
        /* copy input */
 
        list_pc_copy (inp_wPC, wp);
 
        list_pc_copy (inp_bPC, bp);
 
        list_sq_copy (inp_wSQ, ws);
 
        list_sq_copy (inp_bSQ, bs);
 
 
 
        sortlists (ws, wp);
 
        sortlists (bs, bp);
 
 
 
        FOLLOW_label("EGTB_PROBE")
 
 
 
        if (egtb_get_id (wp, bp, &id)) {
 
                FOLLOW_LU("got ID",id)
 
                straight = TRUE;
 
        } else if (egtb_get_id (bp, wp, &id)) {
 
                FOLLOW_LU("rev ID",id)
 
                straight = FALSE;
 
                list_sq_flipNS (ws);
 
                list_sq_flipNS (bs);
 
        temps = ws;
 
        ws = bs;
 
        bs = temps;
 
                stm = Opp(stm);
 
                if (epsq != NOSQUARE) epsq ^= 070;                              /* added */
 
                {SQ_CONTENT *tempp = wp; wp = bp; bp = tempp;}  /* added */
 
        } else {
 
                #if defined(DEBUG)
 
                printf("did not get id...\n");  
                output_state (stm, ws, bs, wp, bp);
 
                #endif
 
                unpackdist (iFORBID, res, ply);
 
                return FALSE;
 
        }
 
 
 
        /* store position... */
 
        list_pc_copy (wp, tmp_wp);
 
        list_pc_copy (bp, tmp_bp);
 
        list_sq_copy (ws, tmp_ws);
 
        list_sq_copy (bs, tmp_bs);
 
 
 
        /* x will be stm and y will be stw */
 
        if (stm == WH) {
 
        xs = ws;
 
        xp = wp;
 
        ys = bs;
 
        yp = bp;
 
    } else {
 
        xs = bs;
 
        xp = bp;
 
        ys = ws;
 
        yp = wp;
 
        }
 
 
 
        okdtm = egtb_get_dtm (id, stm, ws, bs, probingtype, &dtm);
 
 
 
        FOLLOW_LU("dtmok?",okdtm)
 
        FOLLOW_DTM("dtm", dtm)
 
 
 
        if (okdtm) {
 
 
 
                capturer_a = NOSQUARE;
 
                capturer_b = NOSQUARE;
 
 
 
                if (epsq != NOSQUARE) {
 
                        /* captured pawn, trick: from epsquare to captured */
 
                        xed = epsq ^ (1<<3);
 
 
 
                        /* find index captured (j) */
 
                        for (j = 0; ys[j] != NOSQUARE; j++) {
 
                                if (ys[j] == xed) break;
 
                        }
 
 
 
                        /* try first possible ep capture */
 
                        if (0 == (0x88 & (map88(xed) + 1)))
 
                                capturer_a = xed + 1;
 
                        /* try second possible ep capture */
 
                        if (0 == (0x88 & (map88(xed) - 1)))
 
                                capturer_b = xed - 1;
 
 
 
                        if (ys[j] == xed) {
 
 
 
                                /* find capturers (i) */
 
                                for (i = 0; xs[i] != NOSQUARE && okcall; i++) {
 
 
 
                                        if (xp[i]==PAWN && (xs[i]==capturer_a || xs[i]==capturer_b)) {
 
                                                dtm_t epscore = iFORBID;
 
 
 
                                                /* execute capture */
 
                                                xs[i] = epsq;
 
                                                removepiece (ys, yp, j);
 
 
 
                                                okcall = tb_probe_ (Opp(stm), NOSQUARE, ws, bs, wp, bp, probingtype, &inf, &plies);
 
 
 
                                                if (okcall) {
 
                                                        epscore = packdist (inf, plies);
 
                                                        epscore = adjust_up (epscore);
 
 
 
                                                        /* chooses to ep or not */
 
                                                        dtm = bestx (stm, epscore, dtm);
 
                                                }
 
 
 
                                                /* restore position */
 
                                                list_pc_copy (tmp_wp, wp);
 
                                                list_pc_copy (tmp_bp, bp);
 
 
 
                                                list_sq_copy (tmp_ws, ws);
 
                                                list_sq_copy (tmp_bs, bs);
 
                                        }
 
                                }
 
                        }
 
                } /* ep */
 
 
 
                if (straight) {
 
                        unpackdist (dtm, res, ply);
 
                } else {
 
                        unpackdist (inv_dtm (dtm), res, ply);
 
                }
 
        }
 
 
 
        if (!okdtm || !okcall) {
 
                unpackdist (iFORBID, res, ply);
 
        }
 
 
 
        return okdtm && okcall;
 
}
 
 
 
#ifdef _MSC_VER
 
/* to silence warning for sprintf usage */
 
#pragma warning(disable:4996)
 
#endif
 
 
 
static bool_t
 
egtb_filepeek (tbkey_t key, unsigned side, index_t idx, dtm_t *out_dtm)
 
{
 
        FILE *finp;
 
 
 
#define USE_FD
 
 
 
        #if !defined(USE_FD)
 
        char buf[1024];
 
        char *filename = buf;
 
        #endif
 
 
 
        bool_t ok;
 
    dtm_t x=0;
 
        index_t maxindex  = egkey[key].maxindex;
 
 
 
 
 
 
 
        assert (side 
== WH 
|| side 
== BL
);  
 
 
 
 
        #if defined(USE_FD)
 
                if (NULL == (finp = egkey[key].fd) ) {
 
                        if (NULL == (finp = fd_openit (key))) {
 
                                return FALSE;
 
                        }
 
                }
 
        #else
 
                sprintf (buf
, "%s.gtb", egkey
[key
].
str);  
                if (NULL 
== (finp 
= fopen (filename
, "rb"))) {  
                        return FALSE;
 
                }
 
        #endif
 
 
 
        ok = fpark_entry_packed (finp, side, maxindex, idx);
 
        ok = ok && fread_entry_packed (finp, side, &x);
 
 
 
        if (ok) {
 
                *out_dtm = x;
 
        } else
 
                *out_dtm = iFORBID;
 
 
 
        #if !defined(USE_FD)
 
        #endif
 
 
 
        return ok;
 
}
 
 
 
/* will get defined later */
 
static bool_t                   dtm_cache_is_on (void);
 
 
 
static bool_t
 
egtb_get_dtm (tbkey_t k, unsigned stm, const SQUARE *wS, const SQUARE *bS, bool_t probe_hard_flag, dtm_t *dtm)
 
{
 
        bool_t idxavail;
 
        index_t idx;
 
        dtm_t *tab[2];
 
        bool_t (*pc2idx) (const SQUARE *, const SQUARE *, index_t *);
 
 
 
        FOLLOW_label("egtb_get_dtm --> starts")
 
 
 
        if (egkey[k].status == STATUS_MALLOC || egkey[k].status == STATUS_STATICRAM) {
 
 
 
                tab[WH] = egkey[k].egt_w;
 
                tab[BL] = egkey[k].egt_b;
 
                pc2idx  = egkey[k].pctoi;
 
 
 
                idxavail = pc2idx (wS, bS, &idx);
 
 
 
                FOLLOW_LU("indexavail (RAM)",idxavail)
 
 
 
                if (idxavail) {
 
                        *dtm = tab[stm][idx];
 
                } else {
 
                        *dtm = iFORBID;
 
                }
 
 
 
                return TRUE;
 
 
 
        } else if (egkey[k].status == STATUS_ABSENT) {
 
 
 
                pc2idx   = egkey[k].pctoi;
 
                idxavail = pc2idx (wS, bS, &idx);
 
 
 
                FOLLOW_LU("indexavail (HD)",idxavail)
 
 
 
                if (idxavail) {
 
                        bool_t success;
 
 
 
                        /*
 
                        |               LOCK
 
                        *-------------------------------*/
 
                        mythread_mutex_lock (&Egtb_lock);
 
 
 
                        if (dtm_cache_is_on()) {
 
 
 
                                success = get_dtm       (k, stm, idx, dtm, probe_hard_flag);
 
 
 
                                FOLLOW_LU("get_dtm (succ)",success)
 
                                FOLLOW_LU("get_dtm (dtm )",*dtm)
 
 
 
                                        #if defined(DEBUG)
 
                                        if (Uncompressed) {
 
                                                dtm_t   dtm_temp;
 
                                                bool_t  ok;
 
                                                bool_t  success2;
 
 
 
                                                assert (decoding_scheme
() == 0 && GTB_scheme 
== 0);  
 
 
                                                success2 = egtb_filepeek (k, stm, idx, &dtm_temp);
 
                                                ok =  (success == success2) && (!success || *dtm == dtm_temp);
 
                                                if (!ok) {
 
                                                        printf ("\nERROR\nsuccess1=%d sucess2=%d\n"  
                                                                        "k=%d stm=%u idx=%d dtm_peek=%d dtm_cache=%d\n",
 
                                                                        success, success2, k, stm, idx, dtm_temp, *dtm);
 
                                                        fatal_error();
 
                                                }
 
                                        }
 
                                        #endif
 
 
 
                        } else {
 
                                if (probe_hard_flag && Uncompressed)
 
                                        success = egtb_filepeek (k, stm, idx, dtm);
 
                                else
 
                                        success = FALSE;
 
                        }
 
 
 
                        mythread_mutex_unlock (&Egtb_lock);
 
                        /*------------------------------*\
 
                        |               UNLOCK
 
                        */
 
 
 
 
 
                        if (success) {
 
                                return TRUE;
 
                        } else {
 
                                if (probe_hard_flag) /* after probing hard and failing, no chance to succeed later */
 
                                        egkey[k].status = STATUS_REJECT;
 
                                *dtm = iUNKNOWN;
 
                                return FALSE;
 
                        }
 
 
 
                } else {
 
                        *dtm = iFORBID;
 
                        return  TRUE;
 
                }
 
 
 
        } else if (egkey[k].status == STATUS_REJECT) {
 
 
 
                FOLLOW_label("STATUS_REJECT")
 
 
 
                *dtm = iFORBID;
 
                return  FALSE;
 
        } else {
 
 
 
                FOLLOW_label("STATUS_WRONG!")
 
 
 
                *dtm = iFORBID;
 
                return  FALSE;
 
        }
 
 
 
}
 
 
 
static void
 
removepiece (SQUARE *ys, SQ_CONTENT *yp, int j)
 
{
 
    int k;
 
        for (k = j; ys[k] != NOSQUARE; k++) {
 
                ys[k] = ys[k+1];
 
                yp[k] = yp[k+1];
 
        }
 
}
 
 
 
/*
 
|
 
|       mySHARED by probe and build
 
|
 
\*----------------------------------------------------*/
 
 
 
mySHARED /*@NULL@*/ FILE *
 
fd_openit (tbkey_t key)
 
{
 
        int                     i;
 
        tbkey_t                 closingkey;
 
        FILE *                  finp = NULL;
 
        char                    buf[4096];
 
        char *                  filename = buf;
 
        int                     start;
 
        int                             end;
 
        int                             pth;
 
        const char *    extension;
 
 
 
        assert (0 <= key 
&& key 
< MAX_EGKEYS
);  
        assert (0 <= fd.
n && fd.
n <= GTB_MAXOPEN
);  
 
 
        /* test if I reach limit of files open */
 
        if (fd.n == GTB_MAXOPEN) {
 
 
 
                /* fclose the last accessed, first in the list */
 
                closingkey = fd.key[0];
 
                finp = egkey [closingkey].fd;
 
                egkey[closingkey].fd = NULL;
 
                finp = NULL;
 
 
 
                for (i = 1; i < fd.n; i++) {
 
                        fd.key[i-1] = fd.key[i];
 
                }
 
                fd.key[--fd.n] = -1;
 
        }
 
 
 
 
 
        /* set proper extensions to the File */
 
        if (Uncompressed) {
 
                assert (decoding_scheme
() == 0 && GTB_scheme 
== 0);  
                extension = ".gtb";
 
        } else {
 
                extension = Extension[decoding_scheme()];
 
        }
 
 
 
        /* Scan folders to find the File*/
 
        finp = NULL;
 
 
 
        start = egkey[key].pathn;
 
        end   = Gtbpath_end_index;
 
 
 
/*@@
 
printf ("start: %d\n",start);
 
printf ("===================Gtbpath[0]=%s\n",Gtbpath[0]);
 
*/
 
        for (pth = start; NULL == finp && pth < end && Gtbpath[pth] != NULL; pth++) {
 
                const char *path = Gtbpath[pth];
 
/*@@
 
printf ("path: %s\n",path);
 
*/
 
                if (pl == 0) {
 
                                sprintf (buf
, "%s%s%s", path
, egkey
[key
].
str, extension
);  
                } else {
 
                        if (isfoldersep( path[pl-1] )) {
 
                                sprintf (buf
, "%s%s%s", path
, egkey
[key
].
str, extension
);  
                        } else {
 
                                sprintf (buf
, "%s%s%s%s", path
, FOLDERSEP
, egkey
[key
].
str, extension
);  
                        }
 
                }
 
/*printf ("try to open %s   --> ",filename);*/
 
                /* Finally found the file? */
 
                finp 
= fopen (filename
, "rb"); 
/*printf ("%d\n",finp != NULL);*/
 
        }
 
 
 
        /* File was found and opened */
 
        if (NULL != finp) {
 
                fd.key [fd.n++] = key;
 
                egkey[key].fd = finp;
 
                egkey[key].pathn = pth; /* remember succesful path */
 
                eg_was_open[key] = 1;
 
                return finp;
 
        }
 
 
 
        start = 0;
 
        end   = egkey[key].pathn;
 
        for (pth = start; NULL == finp && pth < end && Gtbpath[pth] != NULL; pth++) {
 
                const char *path = Gtbpath[pth];
 
 
 
                if (pl == 0) {
 
                                sprintf (buf
, "%s%s%s", path
, egkey
[key
].
str, extension
);  
                } else {
 
                        if (isfoldersep( path[pl-1] )) {
 
                                sprintf (buf
, "%s%s%s", path
, egkey
[key
].
str, extension
);  
                        } else {
 
                                sprintf (buf
, "%s%s%s%s", path
, FOLDERSEP
, egkey
[key
].
str, extension
);  
                        }
 
                }
 
/*printf ("try to open %s   --> ",filename);*/
 
                /* Finally found the file? */
 
                finp 
= fopen (filename
, "rb"); 
/*printf ("%d\n",finp != NULL);*/
 
        }
 
 
 
 
 
        /* File was found and opened */
 
        if (NULL != finp) {
 
                fd.key [fd.n++] = key;
 
                egkey[key].fd = finp;
 
                egkey[key].pathn = pth; /* remember succesful path */
 
                eg_was_open[key] = 1;
 
        }
 
 
 
        return finp;
 
}
 
 
 
#ifdef _MSC_VER
 
/* to silence warning for sprintf usage */
 
#pragma warning(default:4996)
 
#endif
 
 
 
mySHARED void
 
sortlists (SQUARE *ws, SQ_CONTENT *wp)
 
{
 
        int i, j;
 
        SQUARE ts;
 
        SQ_CONTENT tp;
 
        /* input is sorted */
 
        for (i = 0; wp[i] != NOPIECE; i++) {
 
                for (j = (i+1); wp[j] != NOPIECE; j++) {
 
                        if (wp[j] > wp[i]) {
 
                                tp = wp[i]; wp[i] = wp[j]; wp[j] = tp;
 
                                ts = ws[i]; ws[i] = ws[j]; ws[j] = ts;
 
                        }
 
                }
 
        }
 
}
 
 
 
mySHARED void
 
list_sq_copy (const SQUARE *a, SQUARE *b)
 
{
 
        while (NOSQUARE != (*b++ = *a++))
 
                ;
 
}
 
 
 
mySHARED void
 
list_pc_copy (const SQ_CONTENT *a, SQ_CONTENT *b)
 
{
 
        while (NOPIECE != (*b++ = *a++))
 
                ;
 
}
 
 
 
mySHARED dtm_t
 
inv_dtm (dtm_t x)
 
{
 
        unsigned mat;
 
        assert ( (x 
& iUNKNBIT
) == 0);  
 
 
        if (x == iDRAW || x == iFORBID)
 
                return x;
 
 
 
        mat = (unsigned)x & 3u;
 
        if (mat == iWMATE)
 
                mat = iBMATE;
 
        else
 
                mat = iWMATE;
 
 
 
        x = (dtm_t) (((unsigned)x & ~3u) | mat);
 
 
 
        return x;
 
}
 
 
 
static const char pctoch[] = {'-','p','n','b','r','q','k'};
 
 
 
mySHARED bool_t
 
egtb_get_id (SQ_CONTENT *w, SQ_CONTENT *b, tbkey_t *id)
 
{
 
 
 
        char pcstr[2*MAX_LISTSIZE];
 
        SQ_CONTENT *s;
 
        char *t;
 
        bool_t found;
 
        tbkey_t i;
 
        static tbkey_t cache_i = 0;
 
        size_t h1, h2;
 
 
 
        assert (PAWN 
== 1 && KNIGHT 
== 2 && BISHOP 
== 3 && ROOK 
== 4 && QUEEN 
== 5 && KING 
== 6);  
 
 
        t = pcstr;
 
 
 
        s = w;
 
        while (NOPIECE != *s)
 
                *t++ = pctoch[*s++];
 
        s = b;
 
        while (NOPIECE != *s)
 
                *t++ = pctoch[*s++];
 
 
 
        *t = '\0';
 
 
 
        found 
= (0 == strcmp(pcstr
, egkey
[cache_i
].
str)); 
        if (found) {
 
                *id = cache_i;
 
                return found;
 
        }
 
 
 
        h1 = str_hash_func_1 (pcstr) & (EGKEY_HASH_SIZE - 1);
 
        h2 = str_hash_func_2 (pcstr);
 
        while (1) {
 
                i = egkey_hash[h1];
 
                if (i < 0)
 
                        break;
 
                found 
= (0 == strcmp(pcstr
, egkey
[i
].
str)); 
                if (found)
 
                        break;
 
                h1 = (h1 + h2) & (EGKEY_HASH_SIZE - 1);
 
        }
 
        if (found) {
 
                cache_i = *id = i;
 
        }
 
 
 
        return found;
 
}
 
 
 
mySHARED void
 
list_sq_flipNS (SQUARE *s)
 
{
 
        while (*s != NOSQUARE) {
 
                *s ^= 070;
 
                s++;
 
        }
 
}
 
 
 
mySHARED void
 
unpackdist (dtm_t d, unsigned int *res, unsigned int *ply)
 
{
 
        *ply = (unsigned int)d >> PLYSHIFT;
 
        *res = d & INFOMASK;
 
}
 
 
 
mySHARED dtm_t
 
packdist (unsigned int inf, unsigned int ply)
 
{
 
        return (dtm_t) (inf | ply << PLYSHIFT);
 
}
 
 
 
mySHARED dtm_t
 
adjust_up (dtm_t dist)
 
{
 
        #if 0
 
        static const dtm_t adding[] = {
 
                0, 1<<PLYSHIFT, 1<<PLYSHIFT, 0,
 
                0, 1<<PLYSHIFT, 1<<PLYSHIFT, 0
 
        };
 
        dist += adding [dist&INFOMASK];
 
        return dist;
 
        #else
 
        unsigned udist = (unsigned) dist;
 
        switch (udist & INFOMASK) {
 
                case iWMATE:
 
                case iWMATEt:
 
                case iBMATE:
 
                case iBMATEt:
 
                        udist += (1u << PLYSHIFT);
 
                        break;
 
                default:
 
                        break;
 
        }
 
        return (dtm_t) udist;
 
        #endif
 
}
 
 
 
 
 
mySHARED dtm_t
 
bestx (unsigned stm, dtm_t a, dtm_t b)
 
{
 
        unsigned int key;
 
        static const unsigned int
 
        comparison [4] [4] = {
 
                                /*draw, wmate, bmate, forbid*/
 
        /* draw  */ {0, 3, 0, 0},
 
        /* wmate */ {0, 1, 0, 0},
 
        /* bmate */ {3, 3, 2, 0},
 
        /* forbid*/ {3, 3, 3, 0}
 
 
 
        /* 0 = selectfirst   */
 
        /* 1 = selectlowest  */
 
        /* 2 = selecthighest */
 
        /* 3 = selectsecond  */
 
        };
 
 
 
        static const unsigned int xorkey [2] = {0, 3};
 
        dtm_t retu[4];
 
        dtm_t ret = iFORBID;
 
 
 
        assert (stm 
== WH 
|| stm 
== BL
);  
        assert ((a 
& iUNKNBIT
) == 0 && (b 
& iUNKNBIT
) == 0 );  
 
 
        if (a == iFORBID)
 
                return b;
 
        if (b == iFORBID)
 
                return a;
 
 
 
        retu[0] = a; /* first parameter */
 
        retu[1] = a; /* the lowest by default */
 
        retu[2] = b; /* highest by default */
 
        retu[3] = b; /* second parameter */
 
        if (b < a) {
 
                retu[1] = b;
 
                retu[2] = a;
 
        }
 
 
 
        key = comparison [a&3] [b&3] ^ xorkey[stm];
 
        ret = retu [key];
 
 
 
        return ret;
 
}
 
 
 
 
 
/*--------------------------------------------------------------------------*\
 
 |                                                              PACKING ZONE
 
 *--------------------------------------------------------------------------*/
 
 
 
inline
 
mySHARED dtm_t
 
dtm_unpack (unsigned stm, unsigned char packed)
 
{
 
        unsigned int info, plies, prefx, store, moves;
 
        dtm_t ret;
 
        unsigned int p = packed;
 
 
 
        if (iDRAW == p || iFORBID == p) {
 
                return (dtm_t) p;
 
        }
 
 
 
        info  = (unsigned int) p & 3;
 
        store = (unsigned int) p >> 2;
 
 
 
        if (WH == stm) {
 
                switch (info) {
 
                        case iWMATE:
 
                                                moves = store + 1;
 
                                                plies = moves * 2 - 1;
 
                                                prefx = info;
 
                                                break;
 
 
 
                        case iBMATE:
 
                                                moves = store;
 
                                                plies = moves * 2;
 
                                                prefx = info;
 
                                                break;
 
 
 
                        case iDRAW:
 
                                                moves = store + 1 + 63;
 
                                                plies = moves * 2 - 1;
 
                                                prefx = iWMATE;
 
                                                break;
 
 
 
                        case iFORBID:
 
 
 
                                                moves = store + 63;
 
                                                plies = moves * 2;
 
                                                prefx = iBMATE;
 
                                                break;
 
                        default:
 
            plies = 0;
 
            prefx = 0;
 
                                                break;
 
 
 
                }
 
                ret = (dtm_t) (prefx | (plies << 3));
 
        } else {
 
                switch (info) {
 
                        case iBMATE:
 
                                                moves = store + 1;
 
                                                plies = moves * 2 - 1;
 
                                                prefx = info;
 
                                                break;
 
 
 
                        case iWMATE:
 
                                                moves = store;
 
                                                plies = moves * 2;
 
                                                prefx = info;
 
                                                break;
 
 
 
                        case iDRAW:
 
 
 
                                                if (store == 63) {
 
                                                /*      exception: no position in the 5-man
 
                                                        TBs needs to store 63 for iBMATE
 
                                                        it is then used to indicate iWMATE
 
                                                        when just overflows */
 
                                                        store++;
 
 
 
                                                        moves = store + 63;
 
                                                        plies = moves * 2;
 
                                                        prefx = iWMATE;
 
 
 
                                                        break;
 
                                                }
 
 
 
                                                moves = store + 1 + 63;
 
                                                plies = moves * 2 - 1;
 
                                                prefx = iBMATE;
 
                                                break;
 
 
 
                        case iFORBID:
 
 
 
                                                moves = store + 63;
 
                                                plies = moves * 2;
 
                                                prefx = iWMATE;
 
                                                break;
 
                        default:
 
            plies = 0;
 
            prefx = 0;
 
                                                break;
 
 
 
                }
 
                ret = (dtm_t) (prefx | (plies << 3));
 
        }
 
        return ret;
 
}
 
 
 
 
 
/*
 
static bool_t fwrite_entry_packed (FILE *dest, unsigned side, dtm_t x);
 
*/
 
 
 
 
 
mySHARED bool_t
 
fread_entry_packed (FILE *finp, unsigned side, dtm_t *px)
 
{
 
        unsigned char p[SLOTSIZE];
 
        bool_t ok 
= (SLOTSIZE 
== fread (p
, sizeof(unsigned char), SLOTSIZE
, finp
)); 
        if (ok) {
 
                *px = dtm_unpack (side, p[0]);
 
        }
 
        return ok;
 
}
 
 
 
 
 
mySHARED bool_t
 
fpark_entry_packed  (FILE *finp, unsigned side, index_t max, index_t idx)
 
{
 
        bool_t ok;
 
        index_t i;
 
        long int fseek_i;
 
        index_t sz = (index_t) sizeof(unsigned char);
 
 
 
        assert (side 
== WH 
|| side 
== BL
);  
        i = ((index_t)side * max + idx) * sz;
 
        fseek_i = (long int) i;
 
        ok 
= (0 == fseek (finp
, fseek_i
, SEEK_SET
)); 
        return ok;
 
}
 
 
 
/*----------------------------------------------------*\
 
|
 
|       shared by probe and build
 
|
 
\*/
 
 
 
static size_t
 
hash_func_1 (tbkey_t key, unsigned side, index_t offset)
 
{
 
        size_t h = offset | (key << 1) | side;
 
        h = ((h >> 16) ^ h) * 0x45d9f3b;
 
        h = ((h >> 16) ^ h) * 0x45d9f3b;
 
        h = ((h >> 16) ^ h);
 
        return h;
 
}
 
 
 
static size_t
 
hash_func_2 (tbkey_t key, unsigned side, index_t offset)
 
{
 
        size_t h = offset | (key << 1) | side;
 
        h = ((h >> 16) ^ h) * 0x3335b369;
 
        h = ((h >> 16) ^ h) * 0x3335b369;
 
        h = ((h >> 16) ^ h);
 
        return h * 2 + 1;
 
}
 
 
 
/*---------------------------------------------------------------------*\
 
|                       WDL CACHE Implementation  ZONE
 
\*---------------------------------------------------------------------*/
 
 
 
#define WDL_entries_per_unit 4
 
#define WDL_entry_mask     3
 
static size_t           WDL_units_per_block = 0;
 
 
 
static bool_t           WDL_CACHE_INITIALIZED = FALSE;
 
 
 
typedef unsigned char unit_t; /* block unit */
 
 
 
typedef struct wdl_block        wdl_block_t;
 
 
 
struct wdl_block {
 
        tbkey_t                 key;
 
        unsigned                side;
 
        index_t                 offset;
 
        unit_t                  *p_arr;
 
        wdl_block_t             *prev;
 
        wdl_block_t             *next;
 
};
 
 
 
struct WDL_CACHE {
 
        /* defined at init */
 
        bool_t                  cached;
 
        size_t                  max_blocks;
 
        size_t                  entries_per_block;
 
        unit_t           *      buffer;
 
 
 
        /* flushables */
 
        wdl_block_t     *       top;
 
        wdl_block_t *   bot;
 
        size_t                  n;
 
        wdl_block_t *   blocks; /* was entry */
 
 
 
        /* fast lookup in LRU list */
 
        wdl_block_t**   hash_table;
 
        size_t                  ht_size;
 
        size_t                  ht_used;
 
 
 
        /* counters */
 
        uint64_t                hard;
 
        uint64_t                soft;
 
        uint64_t                hardmisses;
 
        uint64_t                hits;
 
        uint64_t                softmisses;
 
        uint64_t                comparisons;
 
};
 
 
 
struct WDL_CACHE        wdl_cache = {FALSE,0,0,NULL,
 
                                                                 NULL,NULL,0,NULL,
 
                                                                 0,0,0,0,0,0};
 
 
 
 
 
/*---------------------------------------------------------------------*\
 
|                       DTM CACHE Implementation  ZONE
 
\*---------------------------------------------------------------------*/
 
 
 
struct dtm_block;
 
 
 
typedef struct dtm_block dtm_block_t;
 
 
 
struct dtm_block {
 
        tbkey_t                 key;
 
        unsigned                side;
 
        index_t                 offset;
 
        dtm_t                   *p_arr;
 
        dtm_block_t             *prev;
 
        dtm_block_t             *next;
 
};
 
 
 
struct cache_table {
 
        /* defined at init */
 
        bool_t                  cached;
 
        size_t                  max_blocks;
 
        size_t                  entries_per_block;
 
        dtm_t *                 buffer;
 
 
 
        /* flushables */
 
        dtm_block_t     *       top;
 
        dtm_block_t *   bot;
 
        size_t                  n;
 
        dtm_block_t *   entry;
 
 
 
        /* fast lookup in LRU list */
 
        dtm_block_t**   hash_table;
 
        size_t                  ht_size;
 
        size_t                  ht_used;
 
 
 
        /* counters */
 
        uint64_t                hard;
 
        uint64_t                soft;
 
        uint64_t                hardmisses;
 
        uint64_t                hits;
 
        uint64_t                softmisses;
 
        unsigned long   comparisons;
 
};
 
 
 
struct cache_table      dtm_cache = {FALSE,0,0,NULL,
 
                                                                NULL,NULL,0,NULL,
 
                                                                0,0,0,0,0,0};
 
 
 
struct general_counters {
 
        /* counters */
 
        uint64_t                hits;
 
        uint64_t                miss;
 
};
 
 
 
static struct general_counters Drive = {0,0};
 
 
 
 
 
static void             split_index (size_t entries_per_block, index_t i, index_t *o, index_t *r);
 
static dtm_block_t *point_block_to_replace (void);
 
static bool_t           preload_cache (tbkey_t key, unsigned side, index_t idx);
 
static void                     movetotop (dtm_block_t *t);
 
 
 
/*--cache prototypes--------------------------------------------------------*/
 
 
 
/*- WDL --------------------------------------------------------------------*/
 
#ifdef WDL_PROBE
 
static unsigned int             wdl_extract (unit_t *uarr, index_t x);
 
static wdl_block_t *    wdl_point_block_to_replace (void);
 
static void                             wdl_movetotop (wdl_block_t *t);
 
 
 
#if 0
 
static bool_t                   wdl_cache_init (size_t cache_mem);
 
static void                             wdl_cache_flush (void);
 
static bool_t                   get_WDL (tbkey_t key, unsigned side, index_t idx, unsigned int *info_out, bool_t probe_hard_flag);
 
#endif
 
 
 
static bool_t                   wdl_cache_is_on (void);
 
static void                             wdl_cache_reset_counters (void);
 
static void                             wdl_cache_done (void);
 
 
 
static wdl_block_t *    wdl_point_block_to_replace (void);
 
static bool_t                   get_WDL_from_cache (tbkey_t key, unsigned side, index_t idx, unsigned int *out);
 
static void                             wdl_movetotop (wdl_block_t *t);
 
static bool_t                   wdl_preload_cache (tbkey_t key, unsigned side, index_t idx);
 
#endif
 
/*--------------------------------------------------------------------------*/
 
/*- DTM --------------------------------------------------------------------*/
 
static bool_t                   dtm_cache_is_on (void);
 
static void                             dtm_cache_reset_counters (void);
 
static void                             dtm_cache_done (void);
 
 
 
static size_t                   dtm_cache_init (size_t cache_mem);
 
static void                             dtm_cache_flush (void);
 
/*--------------------------------------------------------------------------*/
 
 
 
static bool_t
 
dtm_cache_is_on (void)
 
{
 
        return dtm_cache.cached;
 
}
 
 
 
static void
 
dtm_cache_reset_counters (void)
 
{
 
        dtm_cache.hard = 0;
 
        dtm_cache.soft = 0;
 
        dtm_cache.hardmisses = 0;
 
        dtm_cache.hits = 0;
 
        dtm_cache.softmisses = 0;
 
        dtm_cache.comparisons = 0;
 
        return;
 
}
 
 
 
 
 
static size_t
 
dtm_cache_init (size_t cache_mem)
 
{
 
        unsigned int    i;
 
        dtm_block_t     *p;
 
        size_t                  entries_per_block;
 
        size_t                  max_blocks;
 
        size_t                  block_mem;
 
 
 
        if (DTM_CACHE_INITIALIZED)
 
                dtm_cache_done();
 
 
 
        entries_per_block       = 16 * 1024;  /* fixed, needed for the compression schemes */
 
 
 
        block_mem                       = entries_per_block * sizeof(dtm_t);
 
 
 
        max_blocks                      = cache_mem / block_mem;
 
        if (!Uncompressed && 1 > max_blocks)
 
                max_blocks = 1;
 
        cache_mem                       = max_blocks * block_mem;
 
 
 
 
 
        dtm_cache_reset_counters ();
 
 
 
        dtm_cache.entries_per_block     = entries_per_block;
 
        dtm_cache.max_blocks            = max_blocks;
 
        dtm_cache.cached                        = TRUE;
 
        dtm_cache.top                           = NULL;
 
        dtm_cache.bot                           = NULL;
 
        dtm_cache.n                             = 0;
 
 
 
        if (0 == cache_mem 
|| NULL 
== (dtm_cache.
buffer = (dtm_t 
*)  malloc (cache_mem
))) {  
                dtm_cache.cached = FALSE;
 
                dtm_cache.buffer = NULL;
 
                dtm_cache.entry = NULL;
 
                return 0;
 
        }
 
 
 
        if (0 == max_blocks
|| NULL 
== (dtm_cache.
entry  = (dtm_block_t 
*) malloc (max_blocks 
* sizeof(dtm_block_t
)))) {  
                dtm_cache.cached = FALSE;
 
                dtm_cache.entry = NULL;
 
                dtm_cache.buffer = NULL;
 
                return 0;
 
        }
 
 
 
        for (i = 0; i < max_blocks; i++) {
 
                p = &dtm_cache.entry[i];
 
                p->key          = -1;
 
                p->side         = gtbNOSIDE;
 
                p->offset       = gtbNOINDEX;
 
                p->p_arr        = dtm_cache.buffer + i * entries_per_block;
 
                p->prev         = NULL;
 
                p->next         = NULL;
 
        }
 
 
 
        dtm_cache.ht_size = 1;
 
        while (dtm_cache.ht_size < max_blocks * 4)
 
                dtm_cache.ht_size *= 2;
 
        dtm_cache.ht_used = 0;
 
        dtm_cache.
hash_table = (dtm_block_t
**) malloc (dtm_cache.
ht_size * sizeof(dtm_block_t
*));; 
        if (dtm_cache.hash_table == NULL) {
 
                dtm_cache.cached = FALSE;
 
                dtm_cache.entry = NULL;
 
                dtm_cache.buffer = NULL;
 
                return 0;
 
        }
 
 
 
        for (i = 0; i < dtm_cache.ht_size; i++) {
 
                dtm_cache.hash_table[i] = NULL;
 
        }
 
 
 
        DTM_CACHE_INITIALIZED = TRUE;
 
 
 
        return cache_mem;
 
}
 
 
 
 
 
static void
 
dtm_cache_done (void)
 
{
 
        assert(DTM_CACHE_INITIALIZED
);  
 
 
        dtm_cache.cached = FALSE;
 
        dtm_cache.hard = 0;
 
        dtm_cache.soft = 0;
 
        dtm_cache.hardmisses = 0;
 
        dtm_cache.hits = 0;
 
        dtm_cache.softmisses = 0;
 
        dtm_cache.comparisons = 0;
 
        dtm_cache.max_blocks = 0;
 
        dtm_cache.entries_per_block = 0;
 
 
 
        dtm_cache.top = NULL;
 
        dtm_cache.bot = NULL;
 
        dtm_cache.n = 0;
 
 
 
        if (dtm_cache.buffer != NULL)
 
        dtm_cache.buffer = NULL;
 
 
 
        if (dtm_cache.entry != NULL)
 
        dtm_cache.entry = NULL;
 
 
 
        if (dtm_cache.hash_table != NULL)
 
                free (dtm_cache.
hash_table);  
        dtm_cache.hash_table = NULL;
 
 
 
        DTM_CACHE_INITIALIZED = FALSE;
 
 
 
        return;
 
}
 
 
 
static void
 
dtm_cache_flush (void)
 
{
 
        unsigned int    i;
 
        dtm_block_t     *p;
 
        size_t entries_per_block = dtm_cache.entries_per_block;
 
        size_t max_blocks = dtm_cache.max_blocks;
 
 
 
        dtm_cache.top                           = NULL;
 
        dtm_cache.bot                           = NULL;
 
        dtm_cache.n                             = 0;
 
 
 
        for (i = 0; i < max_blocks; i++) {
 
                p = &dtm_cache.entry[i];
 
                p->key          = -1;
 
                p->side         = gtbNOSIDE;
 
                p->offset       = gtbNOINDEX;
 
                p->p_arr        = dtm_cache.buffer + i * entries_per_block;
 
                p->prev         = NULL;
 
                p->next         = NULL;
 
        }
 
        dtm_cache_reset_counters ();
 
        return;
 
}
 
 
 
 
 
/*---- end tbcache zone ----------------------------------------------------------------------*/
 
 
 
extern bool_t
 
tbcache_is_on (void)
 
{
 
        return dtm_cache_is_on() || wdl_cache_is_on();
 
}
 
 
 
 
 
/* STATISTICS OUTPUT */
 
 
 
extern void
 
tbstats_get (struct TB_STATS *x)
 
{
 
        long unsigned mask = 0xfffffffflu;
 
        uint64_t memory_hits, total_hits;
 
 
 
 
 
        /*
 
        |       WDL CACHE
 
        \*---------------------------------------------------*/
 
 
 
        x->wdl_easy_hits[0] = (long unsigned)(wdl_cache.hits & mask);
 
        x->wdl_easy_hits[1] = (long unsigned)(wdl_cache.hits >> 32);
 
 
 
        x->wdl_hard_prob[0] = (long unsigned)(wdl_cache.hard & mask);
 
        x->wdl_hard_prob[1] = (long unsigned)(wdl_cache.hard >> 32);
 
 
 
        x->wdl_soft_prob[0] = (long unsigned)(wdl_cache.soft & mask);
 
        x->wdl_soft_prob[1] = (long unsigned)(wdl_cache.soft >> 32);
 
 
 
        x->wdl_cachesize    = WDL_cache_size;
 
 
 
        /* occupancy */
 
        x->wdl_occupancy = wdl_cache.max_blocks==0? 0:(double)100.0*(double)wdl_cache.n/(double)wdl_cache.max_blocks;
 
 
 
        /*
 
        |       DTM CACHE
 
        \*---------------------------------------------------*/
 
 
 
        x->dtm_easy_hits[0] = (long unsigned)(dtm_cache.hits & mask);
 
        x->dtm_easy_hits[1] = (long unsigned)(dtm_cache.hits >> 32);
 
 
 
        x->dtm_hard_prob[0] = (long unsigned)(dtm_cache.hard & mask);
 
        x->dtm_hard_prob[1] = (long unsigned)(dtm_cache.hard >> 32);
 
 
 
        x->dtm_soft_prob[0] = (long unsigned)(dtm_cache.soft & mask);
 
        x->dtm_soft_prob[1] = (long unsigned)(dtm_cache.soft >> 32);
 
 
 
        x->dtm_cachesize    = DTM_cache_size;
 
 
 
        /* occupancy */
 
        x->dtm_occupancy = dtm_cache.max_blocks==0? 0:(double)100.0*(double)dtm_cache.n/(double)dtm_cache.max_blocks;
 
 
 
        /*
 
        |       GENERAL
 
        \*---------------------------------------------------*/
 
 
 
        /* memory */
 
        memory_hits = wdl_cache.hits + dtm_cache.hits;
 
        x->memory_hits[0] = (long unsigned)(memory_hits & mask);
 
        x->memory_hits[1] = (long unsigned)(memory_hits >> 32);
 
 
 
        /* hard drive */
 
        x->drive_hits[0] = (long unsigned)(Drive.hits & mask);
 
        x->drive_hits[1] = (long unsigned)(Drive.hits >> 32);
 
 
 
        x->drive_miss[0] = (long unsigned)(Drive.miss & mask);
 
        x->drive_miss[1] = (long unsigned)(Drive.miss >> 32);
 
 
 
        x->bytes_read[0] = (long unsigned)(Bytes_read & mask);
 
        x->bytes_read[1] = (long unsigned)(Bytes_read >> 32);
 
 
 
        x->files_opened = eg_was_open_count();
 
 
 
        /* total */
 
        total_hits = memory_hits + Drive.hits;
 
        x->total_hits[0] = (long unsigned)(total_hits & mask);
 
        x->total_hits[1] = (long unsigned)(total_hits >> 32);
 
 
 
        /* efficiency */
 
        { uint64_t denominator = memory_hits + Drive.hits + Drive.miss;
 
        x->memory_efficiency = 0==denominator? 0: 100.0 * (double)(memory_hits) / (double)(denominator);
 
        }
 
}
 
 
 
 
 
extern bool_t
 
tbcache_init (size_t cache_mem, int wdl_fraction)
 
{
 
        assert (wdl_fraction 
<= WDL_FRACTION_MAX 
&& wdl_fraction 
>= 0);  
 
 
        /* defensive against input */
 
        if (wdl_fraction > WDL_FRACTION_MAX) wdl_fraction = WDL_FRACTION_MAX;
 
        if (wdl_fraction <                0) wdl_fraction = 0;
 
        WDL_FRACTION = wdl_fraction;
 
 
 
        DTM_cache_size = (cache_mem/(size_t)WDL_FRACTION_MAX)*(size_t)(WDL_FRACTION_MAX-WDL_FRACTION);
 
        WDL_cache_size = (cache_mem/(size_t)WDL_FRACTION_MAX)*(size_t)                                  WDL_FRACTION ;
 
 
 
        #ifdef WDL_PROBE
 
        /* returns the actual memory allocated */
 
        DTM_cache_size = dtm_cache_init (DTM_cache_size);
 
        WDL_cache_size = wdl_cache_init (WDL_cache_size);
 
        #else
 
        /* returns the actual memory allocated */
 
        DTM_cache_size = dtm_cache_init (DTM_cache_size);
 
        #endif
 
        tbstats_reset ();
 
        return TRUE;
 
}
 
 
 
extern bool_t
 
tbcache_restart (size_t cache_mem, int wdl_fraction)
 
{
 
        return tbcache_init (cache_mem, wdl_fraction);
 
}
 
 
 
extern void
 
tbcache_done (void)
 
{
 
        dtm_cache_done();
 
        #ifdef WDL_PROBE
 
        wdl_cache_done();
 
        #endif
 
        tbstats_reset ();
 
        return;
 
}
 
 
 
extern void
 
tbcache_flush (void)
 
{
 
        dtm_cache_flush();
 
        #ifdef WDL_PROBE
 
        wdl_cache_flush();
 
        #endif
 
        tbstats_reset ();
 
        return;
 
}
 
 
 
extern void
 
tbstats_reset (void)
 
{
 
        dtm_cache_reset_counters ();
 
        #ifdef WDL_PROBE
 
        wdl_cache_reset_counters ();
 
        #endif
 
        eg_was_open_reset();
 
        Drive.hits = 0;
 
        Drive.miss = 0;
 
        return;
 
}
 
 
 
static void dtm_hash_insert (dtm_block_t * e);
 
 
 
static void
 
dtm_hash_rebuild (void)
 
{
 
        dtm_block_t     * p;
 
        size_t i;
 
 
 
        for (i = 0; i < dtm_cache.ht_size; i++)
 
                dtm_cache.hash_table[i] = NULL;
 
        dtm_cache.ht_used = 0;
 
 
 
        for (p = dtm_cache.top; p != NULL; p = p->prev)
 
                dtm_hash_insert (p);
 
}
 
 
 
static void
 
dtm_hash_insert (dtm_block_t * e)
 
{
 
        size_t h1, h2;
 
 
 
        if (dtm_cache.ht_used > dtm_cache.ht_size * 3 / 4)
 
                dtm_hash_rebuild();
 
 
 
    h1 = hash_func_1 (e->key, e->side, e->offset) & (dtm_cache.ht_size - 1);
 
    h2 = hash_func_2 (e->key, e->side, e->offset);
 
    while (dtm_cache.hash_table[h1])
 
        h1 = (h1 + h2) & (dtm_cache.ht_size - 1);
 
    dtm_cache.hash_table[h1] = e;
 
    dtm_cache.ht_used++;
 
}
 
 
 
static dtm_block_t      *
 
dtm_cache_pointblock (tbkey_t key, unsigned side, index_t idx)
 
{
 
        index_t                 offset;
 
        index_t                 remainder;
 
        dtm_block_t     *       p;
 
        dtm_block_t     *       ret;
 
        size_t                  h1, h2;
 
 
 
        if (!dtm_cache_is_on())
 
                return NULL;
 
 
 
        split_index (dtm_cache.entries_per_block, idx, &offset, &remainder);
 
 
 
        ret   = NULL;
 
 
 
        h1 = hash_func_1 (key, side, offset) & (dtm_cache.ht_size - 1);
 
        h2 = hash_func_2 (key, side, offset);
 
        while (1) {
 
                p = dtm_cache.hash_table[h1];
 
                if (!p)
 
                        break;
 
 
 
                dtm_cache.comparisons++;
 
 
 
                if (key == p->key && side == p->side && offset  == p->offset) {
 
                        ret = p;
 
                        break;
 
                }
 
 
 
                h1 = (h1 + h2) & (dtm_cache.ht_size - 1);
 
        }
 
 
 
        FOLLOW_LU("point_to_dtm_block ok?",(ret!=NULL))
 
 
 
        return ret;
 
}
 
 
 
/****************************************************************************\
 
|
 
|
 
|                       WRAPPERS for ENCODING/DECODING FUNCTIONS ZONE
 
|
 
|
 
\****************************************************************************/
 
 
 
#include "gtb-dec.h"
 
 
 
/*
 
|
 
|       PRE LOAD CACHE AND DEPENDENT FUNCTIONS
 
|
 
\*--------------------------------------------------------------------------*/
 
 
 
struct ZIPINFO {
 
        index_t         extraoffset;
 
        index_t         totalblocks;
 
        index_t *       blockindex;
 
};
 
 
 
struct ZIPINFO Zipinfo[MAX_EGKEYS];
 
 
 
static index_t  egtb_block_getnumber            (tbkey_t key, unsigned side, index_t idx);
 
static index_t  egtb_block_getsize                      (tbkey_t key, index_t idx);
 
static index_t  egtb_block_getsize_zipped       (tbkey_t key, index_t block );
 
static  bool_t  egtb_block_park                         (tbkey_t key, index_t block);
 
static  bool_t  egtb_block_read                         (tbkey_t key, index_t len, unsigned char *buffer);
 
static  bool_t  egtb_block_decode                       (tbkey_t key, index_t z, unsigned char *bz, index_t n, unsigned char *bp);
 
static  bool_t  egtb_block_unpack                       (unsigned side, index_t n, const unsigned char *bp, dtm_t *out);
 
static  bool_t  egtb_file_beready                       (tbkey_t key);
 
static  bool_t  egtb_loadindexes                        (tbkey_t key);
 
static index_t  egtb_block_uncompressed_to_index (tbkey_t key, index_t b);
 
static  bool_t  fread32                                         (FILE *f, unsigned long int *y);
 
 
 
 
 
static unsigned int
 
zipinfo_init (void)
 
{
 
        int i, start, end;
 
        unsigned ret;
 
        bool_t ok, complet[8] = {0,0,0,0,0,0,0,0};
 
        bool_t pa, partial[8] = {0,0,0,0,0,0,0,0};
 
        unsigned int z;
 
        int x, j;
 
 
 
        /* reset all values */
 
        for (i = 0; i < MAX_EGKEYS; i++) {
 
                Zipinfo[i].blockindex = NULL;
 
                Zipinfo[i].extraoffset = 0;
 
                Zipinfo[i].totalblocks = 0;
 
        }
 
 
 
        /* load all values */
 
        start = 0;
 
        end   = 5;
 
        x         = 3;
 
        for (i = start, ok = TRUE, pa = FALSE; i < end; i++) {
 
                ok = NULL != fd_openit(i);
 
                pa = pa || ok;
 
                ok = ok && egtb_loadindexes (i);
 
        }
 
        complet[x] = ok;
 
        partial[x] = pa;
 
 
 
        start = 5;
 
        end   = 35;
 
        x         = 4;
 
        for (i = start, ok = TRUE, pa = FALSE; i < end; i++) {
 
                ok = NULL != fd_openit(i);
 
                pa = pa || ok;
 
                ok = ok && egtb_loadindexes (i);
 
        }
 
        complet[x] = ok;
 
        partial[x] = pa;
 
 
 
        start = 35;
 
        end   = MAX_EGKEYS;
 
        x         = 5;
 
        for (i = start, ok = TRUE, pa = FALSE; i < end; i++) {
 
                ok = NULL != fd_openit(i);
 
                pa = pa || ok;
 
                ok = ok && egtb_loadindexes (i);
 
        }
 
        complet[x] = ok;
 
        partial[x] = pa;
 
 
 
 
 
        for (j = 0, z = 0, x = 3; x < 8; x++) {
 
                if (partial[x]) z |= 1u << j;
 
                j++;
 
                if (complet[x]) z |= 1u << j;
 
                j++;
 
        }
 
 
 
        ret = z;
 
 
 
        return ret;
 
}
 
 
 
static void
 
zipinfo_done (void)
 
{
 
        int i;
 
        bool_t ok;
 
        for (i = 0, ok = TRUE; ok && i < MAX_EGKEYS; i++) {
 
                if (Zipinfo[i].blockindex != NULL) {
 
                        free(Zipinfo
[i
].
blockindex);  
                        Zipinfo[i].blockindex = NULL;
 
                        Zipinfo[i].extraoffset = 0;
 
                        Zipinfo[i].totalblocks = 0;
 
                }
 
        }
 
        return;
 
}
 
 
 
static size_t
 
zipinfo_memory_allocated (void)
 
{
 
        int i;
 
        index_t accum_blocks = 0;
 
        for (i = 0; i < MAX_EGKEYS; i++) {
 
                if (Zipinfo[i].blockindex != NULL) {
 
                        accum_blocks += Zipinfo[i].totalblocks;
 
                }
 
        }
 
        return (size_t)accum_blocks * sizeof(index_t);
 
}
 
 
 
extern size_t
 
tb_indexmemory (void)
 
{
 
        return zipinfo_memory_allocated ();
 
}
 
 
 
static bool_t
 
fread32 (FILE *f, unsigned long int *y)
 
{
 
        enum SIZE {SZ = 4};
 
        int i;
 
        unsigned long int x;
 
        unsigned char p[SZ];
 
        bool_t ok;
 
 
 
        ok 
= (SZ 
== fread (p
, sizeof(unsigned char), SZ
, f
)); 
 
 
        if (ok) {
 
                for (x = 0, i = 0; i < SZ; i++) {
 
                        x |= (unsigned long int)p[i] << (i*8);
 
                }
 
                *y = x;
 
        }
 
        return ok;
 
}
 
 
 
static bool_t
 
egtb_loadindexes (tbkey_t key)
 
{
 
 
 
        unsigned long int blocksize = 1;
 
        unsigned long int tailblocksize1 = 0;
 
        unsigned long int tailblocksize2 = 0;
 
    unsigned long int offset=0;
 
        unsigned long int dummy;
 
        unsigned long int i;
 
        unsigned long int blocks;
 
        unsigned long int n_idx;
 
        unsigned long int idx = 0;
 
        index_t *p;
 
 
 
        bool_t ok;
 
 
 
        FILE *f;
 
 
 
        if (Uncompressed) {
 
                assert (decoding_scheme
() == 0 && GTB_scheme 
== 0);  
                return TRUE; /* no need to load indexes */
 
        }
 
        if (Zipinfo[key].blockindex != NULL)
 
                return TRUE; /* indexes must have been loaded already */
 
 
 
        if (NULL == (f = egkey[key].fd))
 
                return FALSE; /* file was no open */
 
 
 
        /* Get Reserved bytes, blocksize, offset */
 
        ok 
= (0 == fseek (f
, 0, SEEK_SET
)) && 
        fread32 (f, &dummy) &&
 
        fread32 (f, &dummy) &&
 
        fread32 (f, &blocksize) &&
 
        fread32 (f, &dummy) &&
 
        fread32 (f, &tailblocksize1) &&
 
        fread32 (f, &dummy) &&
 
        fread32 (f, &tailblocksize2) &&
 
        fread32 (f, &dummy) &&
 
        fread32 (f, &offset) &&
 
        fread32 (f, &dummy);
 
 
 
        blocks = (offset - 40)/4 -1;
 
        n_idx = blocks + 1;
 
 
 
        p = NULL;
 
 
 
        ok 
= ok 
&& NULL 
!= (p 
= (index_t 
*)malloc (n_idx 
* sizeof(index_t
))); 
 
 
        /* Input of Indexes */
 
        for (i = 0; ok && i < n_idx; i++) {
 
                ok = fread32 (f, &idx);
 
                p
[i
] = (index_t
)idx
; /* reads a 32 bit int, and converts it to index_t */ assert (sizeof(index_t
) >= 4); 
        }
 
 
 
        if (ok) {
 
                Zipinfo[key].extraoffset = 0;
 
                Zipinfo[key].totalblocks = (index_t) n_idx;
 
                Zipinfo[key].blockindex  = p;
 
        }
 
 
 
        if (!ok && p != NULL) {
 
        }
 
 
 
        return ok;
 
}
 
 
 
static index_t
 
egtb_block_uncompressed_to_index (tbkey_t key, index_t b)
 
{
 
        index_t max;
 
        index_t blocks_per_side;
 
        index_t idx;
 
 
 
        max = egkey[key].maxindex;
 
        blocks_per_side = 1 + (max-1) / (index_t)dtm_cache.entries_per_block;
 
 
 
        if (b < blocks_per_side) {
 
                idx = 0;
 
        } else {
 
                b -= blocks_per_side;
 
                idx = max;
 
        }
 
        idx += b * (index_t)dtm_cache.entries_per_block;
 
        return idx;
 
}
 
 
 
 
 
static index_t
 
egtb_block_getnumber (tbkey_t key, unsigned side, index_t idx)
 
{
 
        index_t blocks_per_side;
 
        index_t block_in_side;
 
        index_t max = egkey[key].maxindex;
 
 
 
        blocks_per_side = 1 + (max-1) / (index_t)dtm_cache.entries_per_block;
 
        block_in_side   = idx         / (index_t)dtm_cache.entries_per_block;
 
 
 
        return (index_t)side * blocks_per_side + block_in_side; /* block */
 
}
 
 
 
 
 
static index_t
 
egtb_block_getsize (tbkey_t key, index_t idx)
 
{
 
        index_t blocksz = (index_t) dtm_cache.entries_per_block;
 
        index_t maxindex  = egkey[key].maxindex;
 
        index_t block, offset, x;
 
 
 
        assert (dtm_cache.
entries_per_block <= MAXINDEX_T
);  
        assert (0 <= idx 
&& idx 
< maxindex
);  
 
 
        block = idx / blocksz;
 
        offset = block * blocksz;
 
 
 
        /*
 
        |       adjust block size in case that this is the last block
 
        |       and is shorter than "blocksz"
 
        */
 
        if ( (offset + blocksz) > maxindex)
 
                x = maxindex - offset; /* last block size */
 
        else
 
                x = blocksz; /* size of a normal block */
 
 
 
        return x;
 
}
 
 
 
static index_t
 
egtb_block_getsize_zipped (tbkey_t key, index_t block )
 
{
 
        index_t i, j;
 
        assert (Zipinfo
[key
].
blockindex != NULL
);  
        i = Zipinfo[key].blockindex[block];
 
        j = Zipinfo[key].blockindex[block+1];
 
        return j - i;
 
}
 
 
 
 
 
static bool_t
 
egtb_file_beready (tbkey_t key)
 
{
 
        bool_t success;
 
        success =       (NULL != egkey[key].fd) ||
 
                                (NULL != fd_openit(key) && egtb_loadindexes (key));
 
        return success;
 
}
 
 
 
 
 
static bool_t
 
egtb_block_park  (tbkey_t key, index_t block)
 
{
 
        index_t i;
 
        long fseek_i;
 
        assert (egkey
[key
].
fd != NULL
);  
 
 
        if (Uncompressed) {
 
                assert (decoding_scheme
() == 0 && GTB_scheme 
== 0);  
                i = egtb_block_uncompressed_to_index (key, block);
 
        } else {
 
                assert (Zipinfo
[key
].
blockindex != NULL
);  
                i  = Zipinfo[key].blockindex[block];
 
                i += Zipinfo[key].extraoffset;
 
        }
 
 
 
        fseek_i = (long) i;
 
        return 0 == fseek (egkey
[key
].
fd, fseek_i
, SEEK_SET
);  
}
 
 
 
 
 
static bool_t
 
egtb_block_read (tbkey_t key, index_t len, unsigned char *buffer)
 
{
 
        assert (egkey
[key
].
fd != NULL
);  
        assert (sizeof(size_t) >= sizeof(len
));  
        return ((size_t)len 
== fread (buffer
, sizeof (unsigned char), (size_t)len
, egkey
[key
].
fd));  
}
 
 
 
tbkey_t TB_PROBE_indexing_dummy;
 
 
 
static bool_t
 
egtb_block_decode (tbkey_t key, index_t z, unsigned char *bz, index_t n, unsigned char *bp)
 
/* bz:buffer zipped to bp:buffer packed */
 
{
 
        size_t zz = (size_t) z;
 
        size_t nn = (size_t) n;
 
        TB_PROBE_indexing_dummy = key; /* to silence compiler */
 
        assert (sizeof(size_t) >= sizeof(n
));  
        assert (sizeof(size_t) >= sizeof(z
));  
        return decode (zz-1, bz+1, nn, bp);
 
}
 
 
 
static bool_t
 
egtb_block_unpack (unsigned side, index_t n, const unsigned char *bp, dtm_t *out)
 
/* bp:buffer packed to out:distance to mate buffer */
 
{
 
    index_t i;
 
    if (WH == side) {
 
        for (i = 0; i < n; i++) {
 
            *out++ = dtm_unpack (WH, bp[i]);
 
        }
 
    } else {
 
        for (i = 0; i < n; i++) {
 
            *out++ = dtm_unpack (BL, bp[i]);
 
        }
 
    }
 
        return TRUE;
 
}
 
 
 
static bool_t
 
preload_cache (tbkey_t key, unsigned side, index_t idx)
 
/* output to the least used block of the cache */
 
{
 
        dtm_block_t     *pblock;
 
        dtm_t                   *p;
 
        bool_t                  ok;
 
    unsigned char    Buffer_zipped [EGTB_MAXBLOCKSIZE];
 
    unsigned char    Buffer_packed [EGTB_MAXBLOCKSIZE];
 
 
 
        FOLLOW_label("preload_cache starts")
 
 
 
        if (idx >= egkey[key].maxindex) {
 
                FOLLOW_LULU("Wrong index", __LINE__, idx)
 
                return FALSE;
 
        }
 
 
 
        /* find aged blocked in cache */
 
        pblock = point_block_to_replace();
 
 
 
        if (NULL == pblock)
 
                return FALSE;
 
 
 
        p = pblock->p_arr;
 
 
 
        if (Uncompressed) {
 
 
 
                index_t block = egtb_block_getnumber (key, side, idx);
 
                index_t n     = egtb_block_getsize   (key, idx);
 
 
 
                ok =       egtb_file_beready (key)
 
                                && egtb_block_park   (key, block)
 
                                && egtb_block_read   (key, n, Buffer_packed)
 
                                && egtb_block_unpack (side, n, Buffer_packed, p);
 
 
 
                FOLLOW_LULU("preload_cache", __LINE__, ok)
 
 
 
                assert (decoding_scheme
() == 0 && GTB_scheme 
== 0);  
 
 
                if (ok) { Bytes_read = Bytes_read + (uint64_t) n; }
 
 
 
        } else {
 
 
 
        index_t block = 0;
 
                index_t n = 0;
 
                index_t z = 0;
 
 
 
                ok =       egtb_file_beready (key);
 
 
 
                FOLLOW_LULU("preload_cache", __LINE__, ok)
 
 
 
                if (ok) {
 
                        block = egtb_block_getnumber (key, side, idx);
 
                        n     = egtb_block_getsize   (key, idx);
 
                        z     = egtb_block_getsize_zipped (key, block);
 
                }
 
 
 
                ok =       ok
 
                                && egtb_block_park   (key, block);
 
                FOLLOW_LULU("preload_cache", __LINE__, ok)
 
 
 
                ok =       ok
 
                                && egtb_block_read   (key, z, Buffer_zipped);
 
                FOLLOW_LULU("preload_cache", __LINE__, ok)
 
 
 
        mythread_mutex_unlock (&Egtb_lock);
 
 
 
                ok =       ok
 
                                && egtb_block_decode (key, z, Buffer_zipped, n, Buffer_packed);
 
                FOLLOW_LULU("preload_cache", __LINE__, ok)
 
 
 
        mythread_mutex_lock (&Egtb_lock);
 
            pblock = point_block_to_replace();
 
            p = pblock->p_arr;
 
 
 
                ok =       ok
 
                                && egtb_block_unpack (side, n, Buffer_packed, p);
 
                FOLLOW_LULU("preload_cache", __LINE__, ok)
 
 
 
                if (ok) { Bytes_read = Bytes_read + (uint64_t) z; }
 
        }
 
 
 
        if (ok) {
 
 
 
                index_t                 offset;
 
                index_t                 remainder;
 
                split_index (dtm_cache.entries_per_block, idx, &offset, &remainder);
 
 
 
                pblock->key    = key;
 
                pblock->side   = side;
 
                pblock->offset = offset;
 
                dtm_hash_insert (pblock);
 
        } else {
 
                /* make it unusable */
 
                pblock->key    = -1;
 
                pblock->side   = gtbNOSIDE;
 
                pblock->offset = gtbNOINDEX;
 
        }
 
 
 
        FOLLOW_LU("preload_cache?", ok)
 
 
 
        return ok;
 
}
 
 
 
/****************************************************************************\
 
|
 
|
 
|                                               MEMORY ALLOCATION ZONE
 
|
 
|
 
\****************************************************************************/
 
 
 
 
 
mySHARED void
 
egtb_freemem (int i)
 
{
 
        if (egkey[i].status == STATUS_MALLOC) {
 
                assert (egkey
[i
].
egt_w != NULL
);  
                assert (egkey
[i
].
egt_b != NULL
);  
                egkey[i].egt_w = NULL;
 
                egkey[i].egt_b = NULL;
 
        }
 
        egkey[i].status = STATUS_ABSENT;
 
}
 
 
 
/***************************************************************************/
 
 
 
mySHARED bool_t
 
get_dtm (tbkey_t key, unsigned side, index_t idx, dtm_t *out, bool_t probe_hard_flag)
 
{
 
        bool_t found;
 
 
 
        if (probe_hard_flag) {
 
                dtm_cache.hard++;
 
        } else {
 
                dtm_cache.soft++;
 
        }
 
 
 
        if (get_dtm_from_cache (key, side, idx, out)) {
 
                dtm_cache.hits++;
 
                found = TRUE;
 
        } else if (probe_hard_flag) {
 
                dtm_cache.hardmisses++;
 
                found = preload_cache (key, side, idx) &&
 
                                get_dtm_from_cache (key, side, idx, out);
 
 
 
                if (found) {
 
                        Drive.hits++;
 
                } else {
 
                        Drive.miss++;
 
                }
 
 
 
 
 
        } else {
 
                dtm_cache.softmisses++;
 
                found = FALSE;
 
        }
 
        return found;
 
}
 
 
 
 
 
static bool_t
 
get_dtm_from_cache (tbkey_t key, unsigned side, index_t idx, dtm_t *out)
 
{
 
        index_t         offset;
 
        index_t         remainder;
 
        bool_t          found;
 
        dtm_block_t     *p;
 
 
 
        if (!dtm_cache_is_on())
 
                return FALSE;
 
 
 
        split_index (dtm_cache.entries_per_block, idx, &offset, &remainder);
 
 
 
        found = NULL != (p = dtm_cache_pointblock (key, side, idx));
 
 
 
        if (found) {
 
                *out = p->p_arr[remainder];
 
                movetotop(p);
 
        }
 
 
 
        FOLLOW_LU("get_dtm_from_cache ok?",found)
 
 
 
        return found;
 
}
 
 
 
 
 
static void
 
split_index (size_t entries_per_block, index_t i, index_t *o, index_t *r)
 
{
 
        index_t n;
 
        n  = i / (index_t) entries_per_block;
 
        *o = n * (index_t) entries_per_block;
 
        *r = i - *o;
 
        return;
 
}
 
 
 
 
 
static dtm_block_t *
 
point_block_to_replace (void)
 
{
 
        dtm_block_t *p, *t, *s;
 
 
 
        assert (0 == dtm_cache.
n || dtm_cache.
top != NULL
);  
        assert (0 == dtm_cache.
n || dtm_cache.
bot != NULL
);  
        assert (0 == dtm_cache.
n || dtm_cache.
bot->prev 
== NULL
);  
        assert (0 == dtm_cache.
n || dtm_cache.
top->next 
== NULL
);  
 
 
        /* no cache is being used */
 
        if (dtm_cache.max_blocks == 0)
 
                return NULL;
 
 
 
        if (dtm_cache.n > 0 && -1 == dtm_cache.top->key) {
 
 
 
                /* top entry is unusable, should be the one to replace*/
 
                p = dtm_cache.top;
 
 
 
        } else
 
        if (dtm_cache.n == 0) {
 
 
 
                assert (NULL 
!= dtm_cache.
entry);  
                p = &dtm_cache.entry[dtm_cache.n++];
 
                dtm_cache.top = p;
 
                dtm_cache.bot = p;
 
 
 
                p->prev = NULL;
 
                p->next = NULL;
 
 
 
        } else
 
        if (dtm_cache.n < dtm_cache.max_blocks) { /* add */
 
 
 
                assert (NULL 
!= dtm_cache.
entry);  
                s = dtm_cache.top;
 
                p = &dtm_cache.entry[dtm_cache.n++];
 
                dtm_cache.top = p;
 
 
 
                assert (NULL 
!= p 
&& NULL 
!= s
);  
                s->next = p;
 
                p->prev = s;
 
                p->next = NULL;
 
 
 
        } else if (1 < dtm_cache.max_blocks) { /* replace*/
 
 
 
                assert (NULL 
!= dtm_cache.
bot && NULL 
!= dtm_cache.
top);  
                t = dtm_cache.bot;
 
                s = dtm_cache.top;
 
 
 
                dtm_cache.bot = t->next;
 
                dtm_cache.top = t;
 
 
 
                s->next = t;
 
                t->prev = s;
 
 
 
                dtm_cache.top->next = NULL;
 
 
 
                dtm_cache.bot->prev = NULL;
 
 
 
                p = t;
 
 
 
        } else {
 
 
 
                assert (1 == dtm_cache.
max_blocks);  
                p =     dtm_cache.top;
 
                assert (p 
== dtm_cache.
bot && p 
== dtm_cache.
entry);  
        }
 
 
 
        /* make the information content unusable, it will be replaced */
 
        p->key    = -1;
 
        p->side   = gtbNOSIDE;
 
        p->offset = gtbNOINDEX;
 
 
 
        return p;
 
}
 
 
 
static void
 
movetotop (dtm_block_t *t)
 
{
 
        dtm_block_t *s, *nx, *pv;
 
 
 
 
 
        if (t->next == NULL) /* at the top already */
 
                return;
 
 
 
        /* detach */
 
        pv = t->prev;
 
        nx = t->next;
 
 
 
        if (pv == NULL)  /* at the bottom */
 
                dtm_cache.bot = nx;
 
        else
 
                pv->next = nx;
 
 
 
        if (nx == NULL) /* at the top */
 
                dtm_cache.top = pv;
 
        else
 
                nx->prev = pv;
 
 
 
        /* relocate */
 
        s = dtm_cache.top;
 
        if (s == NULL)
 
                dtm_cache.bot = t;
 
        else
 
                s->next = t;
 
 
 
        t->next = NULL;
 
        t->prev = s;
 
        dtm_cache.top = t;
 
 
 
        return;
 
}
 
 
 
/****************************************************************************\
 
 *
 
 *
 
 *                                                              INDEXING ZONE
 
 *
 
 *
 
 ****************************************************************************/
 
 
 
static void
 
init_indexing (int verbosity)
 
{
 
        index_t a,b,c,d,e,f;
 
 
 
        init_flipt ();
 
 
 
        a = init_kkidx     () ;
 
        b = init_ppidx     () ;
 
        c = init_aaidx     () ;
 
        d = init_aaa       () ;
 
        e = init_pp48_idx  () ;
 
        f = init_ppp48_idx () ;
 
 
 
        if (verbosity) {
 
                printf ("\nGTB supporting tables, Initialization\n");  
                printf ("  Max    kk idx: %8d\n", (int)a 
);  
                printf ("  Max    pp idx: %8d\n", (int)b 
);  
                printf ("  Max    aa idx: %8d\n", (int)c 
);  
                printf ("  Max   aaa idx: %8d\n", (int)d 
);  
                printf ("  Max  pp48 idx: %8d\n", (int)e 
);  
                printf ("  Max ppp48 idx: %8d\n", (int)f 
);  
        }
 
 
 
        if (!reach_was_initialized())
 
                reach_init();
 
 
 
        /* testing used only in development stage */
 
 
 
#ifdef _MSC_VER
 
#pragma warning(disable:4127)
 
#endif
 
 
 
        if (0) {
 
                list_index ();
 
                printf ("\nTEST indexing functions\n");  
 
 
                test_kaakb ();
 
                test_kaabk ();
 
                test_kaaak ();
 
                test_kabbk ();
 
 
 
                test_kapkb ();
 
                test_kabkp ();
 
 
 
                test_kppka ();
 
 
 
                test_kapkp ();
 
                test_kabpk();
 
                test_kaapk ();
 
 
 
                test_kappk ();
 
                test_kaakp ();
 
                test_kppk ();
 
                test_kppkp ();
 
                test_kpppk ();
 
        }
 
 
 
#ifdef _MSC_VER
 
#pragma warning(default:4127)
 
#endif
 
 
 
        return;
 
}
 
 
 
 
 
static index_t
 
init_kkidx (void)
 
/* modifies kkidx[][], wksq[], bksq[] */
 
{
 
        index_t idx;
 
        SQUARE x, y, i, j;
 
 
 
        /* default is noindex */
 
        for (x = 0; x < 64; x++) {
 
                for (y = 0; y < 64; y++) {
 
                        IDX_set_empty(kkidx [x][y]);
 
                }
 
        }
 
 
 
        idx = 0;
 
        for (x = 0; x < 64; x++) {
 
                for (y = 0; y < 64; y++) {
 
 
 
                        /* is x,y illegal? continue */
 
                        if (possible_attack (x, y, wK) || x == y)
 
                                continue;
 
 
 
                        /* normalize */
 
                        /*i <-- x; j <-- y */
 
                        norm_kkindex (x, y, &i, &j);
 
 
 
                        if (IDX_is_empty(kkidx [i][j])) { /* still empty */
 
                                kkidx [i][j] = idx;
 
                                kkidx [x][y] = idx;
 
                                bksq [idx] = i;
 
                                wksq [idx] = j;
 
                                idx++;
 
                        }
 
                }
 
        }
 
 
 
 
 
        return idx;
 
}
 
 
 
 
 
static index_t
 
init_aaidx (void)
 
/* modifies aabase[], aaidx[][] */
 
{
 
        index_t idx;
 
        SQUARE x, y;
 
 
 
        /* default is noindex */
 
        for (x = 0; x < 64; x++) {
 
                for (y = 0; y < 64; y++) {
 
                        IDX_set_empty(aaidx [x][y]);
 
                }
 
        }
 
 
 
        for (idx = 0; idx < MAX_AAINDEX; idx++)
 
                aabase [idx] = 0;
 
 
 
        idx = 0;
 
        for (x = 0; x < 64; x++) {
 
                for (y = x + 1; y < 64; y++) {
 
 
 
                        assert (idx 
== (int)((y 
- x
) + x 
* (127-x
)/2 - 1) );  
 
 
                        if (IDX_is_empty(aaidx [x][y])) { /* still empty */
 
                                aaidx [x] [y] = idx;
 
                                aaidx [y] [x] = idx;
 
                                aabase [idx] = (unsigned char) x;
 
                                idx++;
 
                        } else {
 
                                assert (aaidx 
[x
] [y
] == idx
);  
                        }
 
 
 
 
 
                }
 
        }
 
 
 
 
 
        return idx;
 
}
 
 
 
 
 
static index_t
 
init_ppidx (void)
 
/* modifies ppidx[][], pp_hi24[], pp_lo48[] */
 
{
 
        index_t i, j;
 
        index_t idx = 0;
 
        SQUARE a, b;
 
 
 
        /* default is noindex */
 
        for (i = 0; i < 24; i++) {
 
                for (j = 0; j < 48; j++) {
 
                        IDX_set_empty(ppidx [i][j]);
 
                }
 
        }
 
 
 
        for (idx = 0; idx < MAX_PPINDEX; idx++) {
 
                IDX_set_empty(pp_hi24 [idx]);
 
                IDX_set_empty(pp_lo48 [idx]);
 
        }
 
 
 
        idx = 0;
 
        for (a = H7; a >= A2; a--) {
 
 
 
                if ((a & 07) < 4) /* square in the queen side */
 
                        continue;
 
 
 
                for (b = a - 1; b >= A2; b--) {
 
 
 
                        SQUARE anchor, loosen;
 
 
 
                        pp_putanchorfirst (a, b, &anchor, &loosen);
 
 
 
                        if ((anchor & 07) > 3) { /* square in the king side */
 
                                anchor = flipWE(anchor);
 
                                loosen = flipWE(loosen);
 
                        }
 
 
 
                        i = wsq_to_pidx24 (anchor);
 
                        j = wsq_to_pidx48 (loosen);
 
 
 
                        if (IDX_is_empty(ppidx [i] [j])) {
 
 
 
                ppidx [i] [j] = idx;
 
                pp_hi24 [idx] = i;
 
                pp_lo48 [idx] = j;
 
                                idx++;
 
                        }
 
 
 
                }
 
        }
 
        return idx;
 
}
 
 
 
static void
 
init_flipt (void)
 
{
 
        unsigned int i, j;
 
        for (i = 0; i < 64; i++) {
 
                for (j = 0; j < 64; j++) {
 
                        flipt [i] [j] = flip_type (i, j);
 
                }
 
        }
 
}
 
 
 
/*--- NORMALIZE -------*/
 
 
 
static void
 
norm_kkindex (SQUARE x, SQUARE y, /*@out@*/ SQUARE *pi, /*@out@*/ SQUARE *pj)
 
{
 
        unsigned int rowx, rowy, colx, coly;
 
 
 
 
 
        if (getcol(x) > 3) {
 
                x = flipWE (x); /* x = x ^ 07  */
 
                y = flipWE (y);
 
        }
 
        if (getrow(x) > 3)  {
 
                x = flipNS (x); /* x = x ^ 070  */
 
                y = flipNS (y);
 
        }
 
        rowx = getrow(x);
 
        colx = getcol(x);
 
        if ( rowx > colx ) {
 
                x = flipNW_SE (x); /* x = ((x&7)<<3) | (x>>3) */
 
                y = flipNW_SE (y);
 
        }
 
        rowy = getrow(y);
 
        coly = getcol(y);
 
        if ( rowx == colx && rowy > coly) {
 
                x = flipNW_SE (x);
 
                y = flipNW_SE (y);
 
        }
 
 
 
        *pi = x;
 
        *pj = y;
 
}
 
 
 
static unsigned int
 
flip_type (SQUARE x, SQUARE y)
 
{
 
        unsigned int rowx, rowy, colx, coly;
 
        unsigned int ret = 0;
 
 
 
 
 
 
 
        if (getcol(x) > 3) {
 
                x = flipWE (x); /* x = x ^ 07  */
 
                y = flipWE (y);
 
                ret |= 1;
 
        }
 
        if (getrow(x) > 3)  {
 
                x = flipNS (x); /* x = x ^ 070  */
 
                y = flipNS (y);
 
                ret |= 2;
 
        }
 
        rowx = getrow(x);
 
        colx = getcol(x);
 
        if ( rowx > colx ) {
 
                x = flipNW_SE (x); /* x = ((x&7)<<3) | (x>>3) */
 
                y = flipNW_SE (y);
 
                ret |= 4;
 
        }
 
        rowy = getrow(y);
 
        coly = getcol(y);
 
        if ( rowx == colx && rowy > coly) {
 
                x = flipNW_SE (x);
 
                y = flipNW_SE (y);
 
                ret |= 4;
 
        }
 
        return ret;
 
}
 
 
 
 
 
static void
 
pp_putanchorfirst (SQUARE a, SQUARE b, /*@out@*/ SQUARE *out_anchor, /*@out@*/ SQUARE *out_loosen)
 
{
 
        unsigned int anchor, loosen;
 
 
 
        unsigned int row_b, row_a;
 
        row_b = b & 070;
 
        row_a = a & 070;
 
 
 
        /* default */
 
        anchor = a;
 
        loosen = b;
 
        if (row_b > row_a) {
 
                anchor = b;
 
                loosen = a;
 
        }
 
        else
 
        if (row_b == row_a) {
 
                unsigned int x, col, inv, hi_a, hi_b;
 
                x = a;
 
                col = x & 07;
 
                inv = col ^ 07;
 
                x = (1u<<col) | (1u<<inv);
 
                x &= (x-1);
 
                hi_a = x;
 
 
 
                x = b;
 
                col = x & 07;
 
                inv = col ^ 07;
 
                x = (1u<<col) | (1u<<inv);
 
                x &= (x-1);
 
                hi_b = x;
 
 
 
                if (hi_b > hi_a) {
 
                        anchor = b;
 
                        loosen = a;
 
                }
 
 
 
                if (hi_b < hi_a) {
 
                        anchor = a;
 
                        loosen = b;
 
                }
 
 
 
                if (hi_b == hi_a) {
 
                        if (a < b) {
 
                                anchor = a;
 
                                loosen = b;
 
                        } else {
 
                                anchor = b;
 
                                loosen = a;
 
                        }
 
                }
 
        }
 
 
 
        *out_anchor = anchor;
 
        *out_loosen = loosen;
 
        return;
 
}
 
 
 
 
 
static index_t
 
wsq_to_pidx24 (SQUARE pawn)
 
{
 
        unsigned int idx24;
 
        SQUARE sq = pawn;
 
 
 
        /* input can be only queen side, pawn valid */
 
        assert (A2 
<= pawn 
&& pawn 
< A8
);  
 
 
        sq ^= 070; /* flipNS*/
 
        sq -= 8;   /* down one row*/
 
        idx24 = (sq+(sq&3)) >> 1;
 
        return (index_t) idx24;
 
}
 
 
 
static index_t
 
wsq_to_pidx48 (SQUARE pawn)
 
{
 
        unsigned int idx48;
 
        SQUARE sq = pawn;
 
 
 
        /* input can be both queen or king side, pawn valid square  */
 
        assert (A2 
<= pawn 
&& pawn 
< A8
);  
 
 
        sq ^= 070; /* flipNS*/
 
        sq -= 8;   /* down one row*/
 
        idx48 = sq;
 
        return (index_t)idx48;
 
}
 
 
 
static SQUARE
 
pidx24_to_wsq (index_t a)
 
{
 
        enum  {B11100  = 7u << 2};
 
        unsigned int x = (unsigned int) a;      /* x is pslice */
 
 
 
        x += x & B11100; /* get upper part and double it */
 
        x += 8;          /* add extra row  */
 
        x ^= 070;        /* flip NS */
 
        return (SQUARE) x;
 
}
 
 
 
static SQUARE
 
pidx48_to_wsq (index_t a)
 
{
 
        unsigned int x;
 
        /* x is pslice */
 
        x = (unsigned int)a;
 
        x += 8;          /* add extra row  */
 
        x ^= 070;        /* flip NS */
 
        return x;
 
}
 
 
 
 
 
static void
 
kxk_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        enum  {BLOCK_A = 64};
 
 
 
        index_t a = i / BLOCK_A;
 
        index_t b = i - a * BLOCK_A;
 
 
 
        pw[0] = wksq [a];
 
        pb[0] = bksq [a];
 
        pw[1] = (SQUARE) b;
 
        pw[2] = NOSQUARE;
 
        pb[1] = NOSQUARE;
 
 
 
        assert (kxk_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
static bool_t
 
kxk_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out)
 
{
 
        enum  {BLOCK_A = 64};
 
        SQUARE *p;
 
        SQUARE ws[32], bs[32];
 
        index_t ki;
 
        int i;
 
 
 
        unsigned int ft;
 
 
 
        ft = flip_type (inp_pb[0],inp_pw[0]);
 
 
 
 
 
 
 
        for (i = 0; inp_pw[i] != NOSQUARE; i++) {
 
                ws[i] = inp_pw[i];
 
        }
 
        ws[i] = NOSQUARE;
 
        for (i = 0; inp_pb[i] != NOSQUARE; i++) {
 
                bs[i] = inp_pb[i];
 
        }
 
        bs[i] = NOSQUARE;
 
 
 
        if ((ft & 1) != 0) {
 
                for (p = ws; *p != NOSQUARE; p++)
 
                                *p = flipWE (*p);
 
                for (p = bs; *p != NOSQUARE; p++)
 
                                *p = flipWE (*p);
 
        }
 
 
 
        if ((ft & 2) != 0) {
 
                for (p = ws; *p != NOSQUARE; p++)
 
                                *p = flipNS (*p);
 
                for (p = bs; *p != NOSQUARE; p++)
 
                                *p = flipNS (*p);
 
        }
 
 
 
        if ((ft & 4) != 0) {
 
                for (p = ws; *p != NOSQUARE; p++)
 
                                *p = flipNW_SE (*p);
 
                for (p = bs; *p != NOSQUARE; p++)
 
                                *p = flipNW_SE (*p);
 
        }
 
 
 
        ki = kkidx [bs[0]] [ws[0]]; /* kkidx [black king] [white king] */
 
 
 
        if (IDX_is_empty(ki)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
        *out = ki * BLOCK_A + (index_t) ws[1];
 
        return TRUE;
 
 
 
}
 
 
 
 
 
static void
 
kabk_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        enum  {BLOCK_A = 64*64, BLOCK_B = 64};
 
        index_t a, b, c, r;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r;
 
 
 
        pw[0] = wksq [a];
 
        pb[0] = bksq [a];
 
 
 
        pw[1] = (SQUARE) b;
 
        pw[2] = (SQUARE) c;
 
        pw[3] = NOSQUARE;
 
 
 
        pb[1] = NOSQUARE;
 
 
 
        assert (kabk_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kabk_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out)
 
{
 
        enum  {BLOCK_A = 64*64, BLOCK_B = 64};
 
        SQUARE *p;
 
        SQUARE ws[32], bs[32];
 
        index_t ki;
 
        int i;
 
 
 
        unsigned int ft;
 
 
 
        ft = flip_type (inp_pb[0],inp_pw[0]);
 
 
 
 
 
        for (i = 0; inp_pw[i] != NOSQUARE; i++) {
 
                ws[i] = inp_pw[i];
 
        }
 
        ws[i] = NOSQUARE;
 
        for (i = 0; inp_pb[i] != NOSQUARE; i++) {
 
                bs[i] = inp_pb[i];
 
        }
 
        bs[i] = NOSQUARE;
 
 
 
        if ((ft & 1) != 0) {
 
                for (p = ws; *p != NOSQUARE; p++)
 
                                *p = flipWE (*p);
 
                for (p = bs; *p != NOSQUARE; p++)
 
                                *p = flipWE (*p);
 
        }
 
 
 
        if ((ft & 2) != 0) {
 
                for (p = ws; *p != NOSQUARE; p++)
 
                                *p = flipNS (*p);
 
                for (p = bs; *p != NOSQUARE; p++)
 
                                *p = flipNS (*p);
 
        }
 
 
 
        if ((ft & 4) != 0) {
 
                for (p = ws; *p != NOSQUARE; p++)
 
                                *p = flipNW_SE (*p);
 
                for (p = bs; *p != NOSQUARE; p++)
 
                                *p = flipNW_SE (*p);
 
        }
 
 
 
        ki = kkidx [bs[0]] [ws[0]]; /* kkidx [black king] [white king] */
 
 
 
        if (IDX_is_empty(ki)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
        *out = ki * BLOCK_A + (index_t)ws[1] * BLOCK_B + (index_t)ws[2];
 
        return TRUE;
 
 
 
}
 
 
 
 
 
static void
 
kabkc_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        enum  {BLOCK_A = 64*64*64, BLOCK_B = 64*64, BLOCK_C = 64};
 
        index_t a, b, c, d, r;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r / BLOCK_C;
 
        r -= c * BLOCK_C;
 
        d  = r;
 
 
 
        pw[0] = wksq [a];
 
        pb[0] = bksq [a];
 
 
 
        pw[1] = (SQUARE) b;
 
        pw[2] = (SQUARE) c;
 
        pw[3] = NOSQUARE;
 
 
 
        pb[1] = (SQUARE) d;
 
        pb[2] = NOSQUARE;
 
 
 
        assert (kabkc_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kabkc_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out)
 
{
 
        enum  {N_WHITE = 3, N_BLACK = 2};
 
 
 
        enum  {BLOCK_A = 64*64*64, BLOCK_B = 64*64, BLOCK_C = 64};
 
        SQUARE ws[MAX_LISTSIZE], bs[MAX_LISTSIZE];
 
        index_t ki;
 
        int i;
 
        unsigned int ft;
 
 
 
        #if 0
 
                ft = flip_type (inp_pb[0], inp_pw[0]);
 
        #else
 
                ft = flipt [inp_pb[0]] [inp_pw[0]];
 
        #endif
 
 
 
 
 
        for (i = 0; i < N_WHITE; i++) ws[i] = inp_pw[i]; ws[N_WHITE] = NOSQUARE;
 
        for (i = 0; i < N_BLACK; i++) bs[i] = inp_pb[i]; bs[N_BLACK] = NOSQUARE;
 
 
 
        if ((ft & WE_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipWE (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipWE (bs[i]);
 
        }
 
 
 
        if ((ft & NS_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipNS (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipNS (bs[i]);
 
        }
 
 
 
        if ((ft & NW_SE_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipNW_SE (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipNW_SE (bs[i]);
 
        }
 
 
 
 
 
        ki = kkidx [bs[0]] [ws[0]]; /* kkidx [black king] [white king] */
 
 
 
        if (IDX_is_empty(ki)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
        *out = ki * BLOCK_A + (index_t)ws[1] * BLOCK_B + (index_t)ws[2] * BLOCK_C + (index_t)bs[1];
 
        return TRUE;
 
 
 
}
 
 
 
/* ABC/ ***/
 
 
 
extern void
 
kabck_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        enum  {BLOCK_A = 64*64*64, BLOCK_B = 64*64, BLOCK_C = 64};
 
        index_t a, b, c, d, r;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r / BLOCK_C;
 
        r -= c * BLOCK_C;
 
        d  = r;
 
 
 
        pw[0] = wksq [a];
 
        pb[0] = bksq [a];
 
 
 
        pw[1] = (SQUARE) b;
 
        pw[2] = (SQUARE) c;
 
        pw[3] = (SQUARE) d;
 
        pw[4] = NOSQUARE;
 
 
 
        pb[1] = NOSQUARE;
 
 
 
        assert (kabck_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
extern bool_t
 
kabck_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out)
 
{
 
        enum  {N_WHITE = 4, N_BLACK = 1};
 
        enum  {BLOCK_A = 64*64*64, BLOCK_B = 64*64, BLOCK_C = 64};
 
 
 
        SQUARE ws[MAX_LISTSIZE], bs[MAX_LISTSIZE];
 
        index_t ki;
 
        int i;
 
        unsigned int ft;
 
 
 
        ft = flipt [inp_pb[0]] [inp_pw[0]];
 
 
 
 
 
        for (i = 0; i < N_WHITE; i++) ws[i] = inp_pw[i]; ws[N_WHITE] = NOSQUARE;
 
        for (i = 0; i < N_BLACK; i++) bs[i] = inp_pb[i]; bs[N_BLACK] = NOSQUARE;
 
 
 
        if ((ft & WE_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipWE (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipWE (bs[i]);
 
        }
 
 
 
        if ((ft & NS_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipNS (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipNS (bs[i]);
 
        }
 
 
 
        if ((ft & NW_SE_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipNW_SE (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipNW_SE (bs[i]);
 
        }
 
 
 
 
 
        ki = kkidx [bs[0]] [ws[0]]; /* kkidx [black king] [white king] */
 
 
 
        if (IDX_is_empty(ki)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
        *out = ki * BLOCK_A + (index_t)ws[1] * BLOCK_B + (index_t)ws[2] * BLOCK_C + (index_t)ws[3];
 
        return TRUE;
 
 
 
}
 
 
 
 
 
static void
 
kakb_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        enum  {BLOCK_A = 64*64, BLOCK_B = 64};
 
        index_t a, b, c, r;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r;
 
 
 
        pw[0] = wksq [a];
 
        pb[0] = bksq [a];
 
 
 
        pw[1] = (SQUARE) b;
 
        pw[2] = NOSQUARE;
 
 
 
        pb[1] = (SQUARE) c;
 
        pb[2] = NOSQUARE;
 
 
 
        assert (kakb_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kakb_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out)
 
{
 
        enum  {BLOCK_A = 64*64, BLOCK_B = 64};
 
        SQUARE ws[32], bs[32];
 
        index_t ki;
 
        unsigned int ft;
 
 
 
        #if 0
 
                ft = flip_type (inp_pb[0], inp_pw[0]);
 
        #else
 
                ft = flipt [inp_pb[0]] [inp_pw[0]];
 
        #endif
 
 
 
 
 
        ws[0] = inp_pw[0];
 
        ws[1] = inp_pw[1];
 
        ws[2] = NOSQUARE;
 
 
 
        bs[0] = inp_pb[0];
 
        bs[1] = inp_pb[1];
 
        bs[2] = NOSQUARE;
 
 
 
        if ((ft & 1) != 0) {
 
                ws[0] = flipWE (ws[0]);
 
                ws[1] = flipWE (ws[1]);
 
                bs[0] = flipWE (bs[0]);
 
                bs[1] = flipWE (bs[1]);
 
        }
 
 
 
        if ((ft & 2) != 0) {
 
                ws[0] = flipNS (ws[0]);
 
                ws[1] = flipNS (ws[1]);
 
                bs[0] = flipNS (bs[0]);
 
                bs[1] = flipNS (bs[1]);
 
        }
 
 
 
        if ((ft & 4) != 0) {
 
                ws[0] = flipNW_SE (ws[0]);
 
                ws[1] = flipNW_SE (ws[1]);
 
                bs[0] = flipNW_SE (bs[0]);
 
                bs[1] = flipNW_SE (bs[1]);
 
        }
 
 
 
        ki = kkidx [bs[0]] [ws[0]]; /* kkidx [black king] [white king] */
 
 
 
        if (IDX_is_empty(ki)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
        *out = ki * BLOCK_A + (index_t)ws[1] * BLOCK_B + (index_t)bs[1];
 
        return TRUE;
 
 
 
}
 
 
 
/********************** KAAKB *************************************/
 
 
 
static bool_t   test_kaakb (void);
 
static bool_t   kaakb_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out);
 
static void             kaakb_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
static bool_t
 
test_kaakb (void)
 
{
 
 
 
        enum  {MAXPC = 16+1};
 
        char            str[] = "kaakb";
 
        SQUARE          a, b, c, d, e;
 
        SQUARE          pw[MAXPC], pb[MAXPC];
 
        SQUARE          px[MAXPC], py[MAXPC];
 
 
 
        index_t         i, j;
 
        bool_t          err = FALSE;
 
 
 
 
 
        for (a = 0; a < 64; a++) {
 
                for (b = 0; b < 64; b++) {
 
                for (c = 0; c < 64; c++) {
 
                for (d = 0; d < 64; d++) {
 
                for (e = 0; e < 64; e++) {
 
 
 
                        pw[0] = a;
 
                        pw[1] = b;
 
                        pw[2] = c;
 
                        pw[3] = NOSQUARE;
 
 
 
                        pb[0] = d;
 
                        pb[1] = e;
 
                        pb[2] = NOSQUARE;
 
 
 
                        if (kaakb_pctoindex (pw, pb, &i)) {
 
                                                        kaakb_indextopc (i, px, py);
 
                                                        kaakb_pctoindex (px, py, &j);
 
                                                        if (i != j) {
 
                                                                err = TRUE;
 
                                                        }
 
                        }
 
 
 
                }
 
                }
 
                }
 
                }
 
 
 
        if ((a&1)==0) {
 
        }
 
        }
 
 
 
        if (err)
 
                printf ("> %s NOT passed\n", str
);  
        else
 
                printf ("> %s PASSED\n", str
);  
        return !err;
 
}
 
 
 
static void
 
kaakb_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        enum  {
 
                        BLOCK_B = 64,
 
                        BLOCK_A = BLOCK_B * MAX_AAINDEX
 
                };
 
        index_t a, b, c, r, x, y;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
 
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
 
 
        c  = r;
 
 
 
        assert (i 
== (a 
* BLOCK_A 
+ b 
* BLOCK_B 
+ c
));  
 
 
        pw[0] = wksq [a];
 
        pb[0] = bksq [a];
 
 
 
        x = aabase [b];
 
        y = (b + 1) + x - (x * (127-x)/2);
 
 
 
        pw[1] = (SQUARE) x;
 
        pw[2] = (SQUARE) y;
 
        pw[3] = NOSQUARE;
 
 
 
        pb[1] = (SQUARE) c;
 
        pb[2] = NOSQUARE;
 
 
 
        assert (kaakb_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
static bool_t
 
kaakb_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, /*@out@*/ index_t *out)
 
{
 
        enum  {N_WHITE = 3, N_BLACK = 2};
 
        enum  {
 
                        BLOCK_B = 64,
 
                        BLOCK_A = BLOCK_B * MAX_AAINDEX
 
                };
 
        SQUARE ws[MAX_LISTSIZE], bs[MAX_LISTSIZE];
 
        index_t ki, ai;
 
        unsigned int ft;
 
        int i;
 
 
 
        ft = flipt [inp_pb[0]] [inp_pw[0]];
 
 
 
 
 
        for (i = 0; i < N_WHITE; i++) ws[i] = inp_pw[i]; ws[N_WHITE] = NOSQUARE;
 
        for (i = 0; i < N_BLACK; i++) bs[i] = inp_pb[i]; bs[N_BLACK] = NOSQUARE;
 
 
 
        if ((ft & WE_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipWE (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipWE (bs[i]);
 
        }
 
 
 
        if ((ft & NS_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipNS (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipNS (bs[i]);
 
        }
 
 
 
        if ((ft & NW_SE_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipNW_SE (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipNW_SE (bs[i]);
 
        }
 
 
 
        ki = kkidx [bs[0]] [ws[0]]; /* kkidx [black king] [white king] */
 
        ai = aaidx [ws[1]] [ws[2]];
 
 
 
        if (IDX_is_empty(ki) || IDX_is_empty(ai)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
        *out = ki * BLOCK_A + ai * BLOCK_B + (index_t)bs[1];
 
        return TRUE;
 
}
 
 
 
/****************** End KAAKB *************************************/
 
 
 
/********************** KAAB/K ************************************/
 
 
 
static bool_t   test_kaabk (void);
 
static bool_t   kaabk_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out);
 
static void             kaabk_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
static bool_t
 
test_kaabk (void)
 
{
 
 
 
        enum  {MAXPC = 16+1};
 
        char            str[] = "kaabk";
 
        SQUARE          a, b, c, d, e;
 
        SQUARE          pw[MAXPC], pb[MAXPC];
 
        SQUARE          px[MAXPC], py[MAXPC];
 
 
 
        index_t         i, j;
 
        bool_t          err = FALSE;
 
 
 
 
 
        for (a = 0; a < 64; a++) {
 
                for (b = 0; b < 64; b++) {
 
                for (c = 0; c < 64; c++) {
 
                for (d = 0; d < 64; d++) {
 
                for (e = 0; e < 64; e++) {
 
 
 
                        pw[0] = a;
 
                        pw[1] = b;
 
                        pw[2] = c;
 
                        pw[3] = d;
 
                        pw[4] = NOSQUARE;
 
 
 
                        pb[0] = e;
 
                        pb[1] = NOSQUARE;
 
 
 
                        if (kaabk_pctoindex (pw, pb, &i)) {
 
                                                        kaabk_indextopc (i, px, py);
 
                                                        kaabk_pctoindex (px, py, &j);
 
                                                        if (i != j) {
 
                                                                err = TRUE;
 
                                                        }
 
                        }
 
 
 
                }
 
                }
 
                }
 
                }
 
 
 
        if ((a&1)==0) {
 
        }
 
        }
 
 
 
        if (err)
 
                printf ("> %s NOT passed\n", str
);  
        else
 
                printf ("> %s PASSED\n", str
);  
        return !err;
 
}
 
 
 
static void
 
kaabk_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        enum  {
 
                        BLOCK_B = 64,
 
                        BLOCK_A = BLOCK_B * MAX_AAINDEX
 
                };
 
        index_t a, b, c, r, x, y;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
 
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
 
 
        c  = r;
 
 
 
        assert (i 
== (a 
* BLOCK_A 
+ b 
* BLOCK_B 
+ c
));  
 
 
        pw[0] = wksq [a];
 
        pb[0] = bksq [a];
 
 
 
        x = aabase [b];
 
        y = (b + 1) + x - (x * (127-x)/2);
 
 
 
        pw[1] = (SQUARE) x;
 
        pw[2] = (SQUARE) y;
 
        pw[3] = (SQUARE) c;
 
        pw[4] = NOSQUARE;
 
 
 
        pb[1] = NOSQUARE;
 
 
 
        assert (kaabk_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
static bool_t
 
kaabk_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, /*@out@*/ index_t *out)
 
{
 
        enum  {N_WHITE = 4, N_BLACK = 1};
 
        enum  {
 
                        BLOCK_B = 64,
 
                        BLOCK_A = BLOCK_B * MAX_AAINDEX
 
                };
 
        SQUARE ws[MAX_LISTSIZE], bs[MAX_LISTSIZE];
 
        index_t ki, ai;
 
        unsigned int ft;
 
        int i;
 
 
 
        ft = flipt [inp_pb[0]] [inp_pw[0]];
 
 
 
 
 
        for (i = 0; i < N_WHITE; i++) ws[i] = inp_pw[i]; ws[N_WHITE] = NOSQUARE;
 
        for (i = 0; i < N_BLACK; i++) bs[i] = inp_pb[i]; bs[N_BLACK] = NOSQUARE;
 
 
 
        if ((ft & WE_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipWE (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipWE (bs[i]);
 
        }
 
 
 
        if ((ft & NS_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipNS (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipNS (bs[i]);
 
        }
 
 
 
        if ((ft & NW_SE_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipNW_SE (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipNW_SE (bs[i]);
 
        }
 
 
 
        ki = kkidx [bs[0]] [ws[0]]; /* kkidx [black king] [white king] */
 
        ai = aaidx [ws[1]] [ws[2]];
 
 
 
        if (IDX_is_empty(ki) || IDX_is_empty(ai)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
        *out = ki * BLOCK_A + ai * BLOCK_B + (index_t)ws[3];
 
        return TRUE;
 
}
 
 
 
/****************** End KAAB/K *************************************/
 
 
 
/********************** KABB/K ************************************/
 
 
 
static bool_t   test_kabbk (void);
 
static bool_t   kabbk_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out);
 
static void             kabbk_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
static bool_t
 
test_kabbk (void)
 
{
 
 
 
        enum  {MAXPC = 16+1};
 
        char            str[] = "kabbk";
 
        SQUARE          a, b, c, d, e;
 
        SQUARE          pw[MAXPC], pb[MAXPC];
 
        SQUARE          px[MAXPC], py[MAXPC];
 
 
 
        index_t         i, j;
 
        bool_t          err = FALSE;
 
 
 
 
 
        for (a = 0; a < 64; a++) {
 
                for (b = 0; b < 64; b++) {
 
                for (c = 0; c < 64; c++) {
 
                for (d = 0; d < 64; d++) {
 
                for (e = 0; e < 64; e++) {
 
 
 
                        pw[0] = a;
 
                        pw[1] = b;
 
                        pw[2] = c;
 
                        pw[3] = d;
 
                        pw[4] = NOSQUARE;
 
 
 
                        pb[0] = e;
 
                        pb[1] = NOSQUARE;
 
 
 
                        if (kabbk_pctoindex (pw, pb, &i)) {
 
                                                        kabbk_indextopc (i, px, py);
 
                                                        kabbk_pctoindex (px, py, &j);
 
                                                        if (i != j) {
 
                                                                err = TRUE;
 
                                                        }
 
                        }
 
 
 
                }
 
                }
 
                }
 
                }
 
 
 
        if ((a&1)==0) {
 
        }
 
        }
 
 
 
        if (err)
 
                printf ("> %s NOT passed\n", str
);  
        else
 
                printf ("> %s PASSED\n", str
);  
        return !err;
 
}
 
 
 
static void
 
kabbk_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        enum  {
 
                        BLOCK_B = 64,
 
                        BLOCK_A = BLOCK_B * MAX_AAINDEX
 
                };
 
        index_t a, b, c, r, x, y;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
 
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
 
 
        c  = r;
 
 
 
        assert (i 
== (a 
* BLOCK_A 
+ b 
* BLOCK_B 
+ c
));  
 
 
        pw[0] = wksq [a];
 
        pb[0] = bksq [a];
 
 
 
        x = aabase [b];
 
        y = (b + 1) + x - (x * (127-x)/2);
 
 
 
        pw[1] = (SQUARE) c;
 
        pw[2] = (SQUARE) x;
 
        pw[3] = (SQUARE) y;
 
        pw[4] = NOSQUARE;
 
 
 
        pb[1] = NOSQUARE;
 
 
 
        assert (kabbk_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
static bool_t
 
kabbk_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, /*@out@*/ index_t *out)
 
{
 
        enum  {N_WHITE = 4, N_BLACK = 1};
 
        enum  {
 
                        BLOCK_B = 64,
 
                        BLOCK_A = BLOCK_B * MAX_AAINDEX
 
                };
 
        SQUARE ws[MAX_LISTSIZE], bs[MAX_LISTSIZE];
 
        index_t ki, ai;
 
        unsigned int ft;
 
        int i;
 
 
 
        ft = flipt [inp_pb[0]] [inp_pw[0]];
 
 
 
 
 
        for (i = 0; i < N_WHITE; i++) ws[i] = inp_pw[i]; ws[N_WHITE] = NOSQUARE;
 
        for (i = 0; i < N_BLACK; i++) bs[i] = inp_pb[i]; bs[N_BLACK] = NOSQUARE;
 
 
 
        if ((ft & WE_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipWE (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipWE (bs[i]);
 
        }
 
 
 
        if ((ft & NS_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipNS (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipNS (bs[i]);
 
        }
 
 
 
        if ((ft & NW_SE_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipNW_SE (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipNW_SE (bs[i]);
 
        }
 
 
 
        ki = kkidx [bs[0]] [ws[0]]; /* kkidx [black king] [white king] */
 
        ai = aaidx [ws[2]] [ws[3]];
 
 
 
        if (IDX_is_empty(ki) || IDX_is_empty(ai)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
        *out = ki * BLOCK_A + ai * BLOCK_B + (index_t)ws[1];
 
        return TRUE;
 
}
 
 
 
/********************** End KABB/K *************************************/
 
 
 
/********************** init KAAA/K ************************************/
 
 
 
static index_t
 
aaa_getsubi (sq_t x, sq_t y, sq_t z);
 
 
 
static sq_t             aaa_xyz [MAX_AAAINDEX] [3];
 
static index_t          aaa_base [64];
 
 
 
static index_t
 
init_aaa (void)
 
/* modifies aaa_base[], aaa_xyz[][] */
 
{
 
        index_t comb [64];
 
        index_t accum;
 
        index_t a;
 
 
 
        index_t idx;
 
        SQUARE x, y, z;
 
 
 
        /* getting aaa_base */
 
        comb [0] = 0;
 
        for (a = 1; a < 64; a++) {
 
                comb [a] = a * (a-1) / 2;
 
        }
 
 
 
        accum = 0;
 
        aaa_base [0] = accum;
 
        for (a = 0; a < (64-1); a++) {
 
                accum += comb[a];
 
                aaa_base [a+1] = accum;
 
        }
 
 
 
        assert ((accum 
+ comb
[63]) == MAX_AAAINDEX
);  
        /* end getting aaa_base */
 
 
 
 
 
        /* initialize aaa_xyz [][] */
 
        for (idx = 0; idx < MAX_AAAINDEX; idx++) {
 
                IDX_set_empty (aaa_xyz[idx][0]);
 
                IDX_set_empty (aaa_xyz[idx][1]);
 
                IDX_set_empty (aaa_xyz[idx][2]);
 
        }
 
 
 
        idx = 0;
 
        for (z = 0; z < 64; z++) {
 
                for (y = 0; y < z; y++) {
 
                        for (x = 0; x < y; x++) {
 
 
 
                                assert (idx 
== aaa_getsubi 
(x
, y
, z
));  
 
 
                                aaa_xyz [idx] [0] = x;
 
                                aaa_xyz [idx] [1] = y;
 
                                aaa_xyz [idx] [2] = z;
 
 
 
                                idx++;
 
                        }
 
                }
 
        }
 
 
 
 
 
        return idx;
 
}
 
 
 
 
 
static index_t
 
aaa_getsubi (sq_t x, sq_t y, sq_t z)
 
/* uses aaa_base */
 
{
 
        index_t calc_idx, base;
 
 
 
        assert (x 
< 64 && y 
< 64 && z 
< 64);  
 
 
        base = aaa_base[z];
 
        calc_idx = (index_t)x + ((index_t)y - 1) * (index_t)y / 2 + base;
 
 
 
        return calc_idx;
 
}
 
 
 
/********************** KAAA/K ************************************/
 
 
 
static bool_t   test_kaaak (void);
 
static bool_t   kaaak_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out);
 
static void             kaaak_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
static bool_t
 
test_kaaak (void)
 
{
 
 
 
        enum  {MAXPC = 16+1};
 
        char            str[] = "kaaak";
 
        SQUARE          a, b, c, d, e;
 
        SQUARE          pw[MAXPC], pb[MAXPC];
 
        SQUARE          px[MAXPC], py[MAXPC];
 
 
 
        index_t         i, j;
 
        bool_t          err = FALSE;
 
 
 
 
 
        for (a = 0; a < 64; a++) {
 
                for (b = 0; b < 64; b++) {
 
                for (c = 0; c < 64; c++) {
 
                for (d = 0; d < 64; d++) {
 
                for (e = 0; e < 64; e++) {
 
 
 
                        pw[0] = a;
 
                        pw[1] = b;
 
                        pw[2] = c;
 
                        pw[3] = d;
 
                        pw[4] = NOSQUARE;
 
 
 
                        pb[0] = e;
 
                        pb[1] = NOSQUARE;
 
 
 
                        if (kaaak_pctoindex (pw, pb, &i)) {
 
                                                        kaaak_indextopc (i, px, py);
 
                                                        kaaak_pctoindex (px, py, &j);
 
                                                        if (i != j) {
 
                                                                err = TRUE;
 
                                                        }
 
                        }
 
 
 
                }
 
                }
 
                }
 
                }
 
 
 
        if ((a&1)==0) {
 
        }
 
        }
 
 
 
        if (err)
 
                printf ("> %s NOT passed\n", str
);  
        else
 
                printf ("> %s PASSED\n", str
);  
        return !err;
 
}
 
 
 
static void
 
kaaak_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        enum  {
 
                        BLOCK_A = MAX_AAAINDEX
 
                };
 
        index_t a, b, r;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
 
 
        b  = r;
 
 
 
        assert (i 
== (a 
* BLOCK_A 
+ b
));  
 
 
        pw[0] = wksq [a];
 
        pb[0] = bksq [a];
 
 
 
        pw[1] = aaa_xyz [b] [0];
 
        pw[2] = aaa_xyz [b] [1];
 
        pw[3] = aaa_xyz [b] [2];
 
        pw[4] = NOSQUARE;
 
 
 
        pb[1] = NOSQUARE;
 
 
 
        assert (kaaak_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
static bool_t
 
kaaak_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out)
 
{
 
        enum  {N_WHITE = 4, N_BLACK = 1};
 
        enum  {
 
                        BLOCK_A = MAX_AAAINDEX
 
                };
 
        SQUARE ws[MAX_LISTSIZE], bs[MAX_LISTSIZE];
 
        index_t ki, ai;
 
        unsigned int ft;
 
        int i;
 
 
 
        ft = flipt [inp_pb[0]] [inp_pw[0]];
 
 
 
 
 
        for (i = 0; i < N_WHITE; i++) ws[i] = inp_pw[i]; ws[N_WHITE] = NOSQUARE;
 
        for (i = 0; i < N_BLACK; i++) bs[i] = inp_pb[i]; bs[N_BLACK] = NOSQUARE;
 
 
 
        if ((ft & WE_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipWE (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipWE (bs[i]);
 
        }
 
 
 
        if ((ft & NS_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipNS (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipNS (bs[i]);
 
        }
 
 
 
        if ((ft & NW_SE_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipNW_SE (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipNW_SE (bs[i]);
 
        }
 
 
 
 
 
        {
 
                SQUARE tmp;
 
                if (ws[2] < ws[1]) {
 
            tmp = ws[1];
 
            ws[1] = ws[2];
 
            ws[2] = tmp;
 
                }
 
                if (ws[3] < ws[2]) {
 
            tmp = ws[2];
 
            ws[2] = ws[3];
 
            ws[3] = tmp;
 
                }
 
                if (ws[2] < ws[1]) {
 
            tmp = ws[1];
 
            ws[1] = ws[2];
 
            ws[2] = tmp;
 
                }
 
        }
 
 
 
        ki = kkidx [bs[0]] [ws[0]]; /* kkidx [black king] [white king] */
 
 
 
/*128 == (128 & (((ws[1]^ws[2])-1) | ((ws[1]^ws[3])-1) | ((ws[2]^ws[3])-1)) */
 
 
 
        if (ws[1] == ws[2] || ws[1] == ws[3] || ws[2] == ws[3]) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
 
 
        ai = aaa_getsubi ( ws[1], ws[2], ws[3] );
 
 
 
        if (IDX_is_empty(ki) || IDX_is_empty(ai)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
        *out = ki * BLOCK_A + ai;
 
        return TRUE;
 
}
 
 
 
/****************** End KAAB/K *************************************/
 
 
 
/**********************  KAP/KB ************************************/
 
 
 
static bool_t   test_kapkb (void);
 
static bool_t   kapkb_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out);
 
static void     kapkb_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
static bool_t
 
test_kapkb (void)
 
{
 
 
 
        enum            {MAXPC = 16+1};
 
        char            str[] = "kapkb";
 
        SQUARE          a, b, c, d, e;
 
        SQUARE          pw[MAXPC], pb[MAXPC];
 
        SQUARE          px[MAXPC], py[MAXPC];
 
 
 
        index_t         i, j;
 
        bool_t          err = FALSE;
 
 
 
 
 
        for (a = 0; a < 64; a++) {
 
                for (b = 0; b < 64; b++) {
 
                for (c = 0; c < 64; c++) {
 
                for (d = 0; d < 64; d++) {
 
                for (e = 0; e < 64; e++) {
 
 
 
                        if (c <= H1 || c >= A8)
 
                                continue;
 
 
 
                        pw[0] = a;
 
                        pw[1] = b;
 
                        pw[2] = c;
 
                        pw[3] = NOSQUARE;
 
 
 
                        pb[0] = e;
 
                        pb[1] = d;
 
                        pb[2] = NOSQUARE;
 
 
 
                        if (kapkb_pctoindex (pw, pb, &i)) {
 
                                                        kapkb_indextopc (i, px, py);
 
                                                        kapkb_pctoindex (px, py, &j);
 
                                                        if (i != j) {
 
                                                                err = TRUE;
 
                                                        }
 
                        }
 
 
 
                }
 
                }
 
                }
 
                }
 
 
 
        if ((a&1)==0) {
 
        }
 
        }
 
 
 
        if (err)
 
                printf ("> %s NOT passed\n", str
);  
        else
 
                printf ("> %s PASSED\n", str
);  
        return !err;
 
}
 
 
 
static void
 
kapkb_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        /*---------------------------------------------------------*
 
                inverse work to make sure that the following is valid
 
                index = a * BLOCK_A + b * BLOCK_B + c * BLOCK_C + d * BLOCK_D + e;
 
        *----------------------------------------------------------*/
 
        enum  {B11100  = 7u << 2};
 
        enum  {BLOCK_A = 64*64*64*64, BLOCK_B = 64*64*64, BLOCK_C = 64*64, BLOCK_D = 64};
 
        index_t a, b, c, d, e, r;
 
        index_t x;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r / BLOCK_C;
 
        r -= c * BLOCK_C;
 
        d  = r / BLOCK_D;
 
        r -= d * BLOCK_D;
 
        e  = r;
 
 
 
        /* x is pslice */
 
        x = a;
 
        x += x & B11100; /* get upper part and double it */
 
        x += 8;          /* add extra row  */
 
        x ^= 070;        /* flip NS */
 
 
 
        pw[0] = (SQUARE) b;
 
        pb[0] = (SQUARE) c;
 
        pw[1] = (SQUARE) d;
 
        pw[2] = (SQUARE) x;
 
        pw[3] = NOSQUARE;
 
        pb[1] = (SQUARE) e;
 
        pb[2] = NOSQUARE;
 
 
 
        assert (kapkb_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kapkb_pctoindex (const SQUARE *pw, const SQUARE *pb, index_t *out)
 
{
 
        enum  {BLOCK_A = 64*64*64*64, BLOCK_B = 64*64*64, BLOCK_C = 64*64, BLOCK_D = 64};
 
        index_t pslice;
 
        SQUARE sq;
 
        SQUARE pawn = pw[2];
 
        SQUARE wa   = pw[1];
 
        SQUARE wk   = pw[0];
 
        SQUARE bk   = pb[0];
 
        SQUARE ba   = pb[1];
 
 
 
        assert (A2 
<= pawn 
&& pawn 
< A8
);  
 
 
        if (  !(A2 <= pawn && pawn < A8)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
 
 
        if ((pawn & 07) > 3) { /* column is more than 3. e.g. = e,f,g, or h */
 
                pawn = flipWE (pawn);
 
                wk   = flipWE (wk);
 
                bk   = flipWE (bk);
 
                wa   = flipWE (wa);
 
                ba   = flipWE (ba);
 
        }
 
 
 
        sq = pawn;
 
        sq ^= 070; /* flipNS*/
 
        sq -= 8;   /* down one row*/
 
        pslice = (index_t) ((sq+(sq&3)) >> 1);
 
 
 
        *out = pslice * BLOCK_A + (index_t)wk * BLOCK_B  + (index_t)bk * BLOCK_C + (index_t)wa * BLOCK_D + (index_t)ba;
 
 
 
        return TRUE;
 
}
 
/********************** end KAP/KB ************************************/
 
 
 
/*************************  KAB/KP ************************************/
 
 
 
static bool_t   test_kabkp (void);
 
static bool_t   kabkp_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out);
 
static void     kabkp_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
static bool_t
 
test_kabkp (void)
 
{
 
 
 
        enum            {MAXPC = 16+1};
 
        char            str[] = "kabkp";
 
        SQUARE          a, b, c, d, e;
 
        SQUARE          pw[MAXPC], pb[MAXPC];
 
        SQUARE          px[MAXPC], py[MAXPC];
 
 
 
        index_t         i, j;
 
        bool_t          err = FALSE;
 
 
 
 
 
        for (a = 0; a < 64; a++) {
 
                for (b = 0; b < 64; b++) {
 
                for (c = 0; c < 64; c++) {
 
                for (d = 0; d < 64; d++) {
 
                for (e = 0; e < 64; e++) {
 
 
 
                        if (d <= H1 || d >= A8)
 
                                continue;
 
 
 
                        pw[0] = a;
 
                        pw[1] = b;
 
                        pw[2] = c;
 
                        pw[3] = NOSQUARE;
 
 
 
                        pb[0] = e;
 
                        pb[1] = d;
 
                        pb[2] = NOSQUARE;
 
 
 
                        if (kabkp_pctoindex (pw, pb, &i)) {
 
                                                        kabkp_indextopc (i, px, py);
 
                                                        kabkp_pctoindex (px, py, &j);
 
                                                        if (i != j) {
 
                                                                err = TRUE;
 
                                                        }
 
                        }
 
 
 
                }
 
                }
 
                }
 
                }
 
 
 
        if ((a&1)==0) {
 
        }
 
        }
 
 
 
        if (err)
 
                printf ("> %s NOT passed\n", str
);  
        else
 
                printf ("> %s PASSED\n", str
);  
        return !err;
 
}
 
 
 
static void
 
kabkp_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        /*---------------------------------------------------------*
 
                inverse work to make sure that the following is valid
 
                index = a * BLOCK_A + b * BLOCK_B + c * BLOCK_C + d * BLOCK_D + e;
 
        *----------------------------------------------------------*/
 
        enum  {B11100  = 7u << 2};
 
        enum  {BLOCK_A = 64*64*64*64, BLOCK_B = 64*64*64, BLOCK_C = 64*64, BLOCK_D = 64};
 
        index_t a, b, c, d, e, r;
 
        index_t x;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r / BLOCK_C;
 
        r -= c * BLOCK_C;
 
        d  = r / BLOCK_D;
 
        r -= d * BLOCK_D;
 
        e  = r;
 
 
 
        /* x is pslice */
 
        x = a;
 
        x += x & B11100; /* get upper part and double it */
 
        x += 8;          /* add extra row  */
 
        /*x ^= 070;*/        /* do not flip NS */
 
 
 
        pw[0] = (SQUARE) b;
 
        pb[0] = (SQUARE) c;
 
        pw[1] = (SQUARE) d;
 
        pw[2] = (SQUARE) e;
 
        pw[3] = NOSQUARE;
 
        pb[1] = (SQUARE) x;
 
        pb[2] = NOSQUARE;
 
 
 
        assert (kabkp_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kabkp_pctoindex (const SQUARE *pw, const SQUARE *pb, index_t *out)
 
{
 
        enum  {BLOCK_A = 64*64*64*64, BLOCK_B = 64*64*64, BLOCK_C = 64*64, BLOCK_D = 64};
 
        index_t pslice;
 
        SQUARE sq;
 
        SQUARE pawn = pb[1];
 
        SQUARE wa   = pw[1];
 
        SQUARE wk   = pw[0];
 
        SQUARE bk   = pb[0];
 
        SQUARE wb   = pw[2];
 
 
 
        assert (A2 
<= pawn 
&& pawn 
< A8
);  
 
 
        if (  !(A2 <= pawn && pawn < A8)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
 
 
        if ((pawn & 07) > 3) { /* column is more than 3. e.g. = e,f,g, or h */
 
                pawn = flipWE (pawn);
 
                wk   = flipWE (wk);
 
                bk   = flipWE (bk);
 
                wa   = flipWE (wa);
 
                wb   = flipWE (wb);
 
        }
 
 
 
        sq = pawn;
 
        /*sq ^= 070;*/ /* do not flipNS*/
 
        sq -= 8;   /* down one row*/
 
        pslice = (index_t) ((sq+(sq&3)) >> 1);
 
 
 
        *out = pslice * BLOCK_A + (index_t)wk * BLOCK_B  + (index_t)bk * BLOCK_C + (index_t)wa * BLOCK_D + (index_t)wb;
 
 
 
        return TRUE;
 
}
 
/********************** end KAB/KP ************************************/
 
 
 
 
 
static void
 
kpk_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        /*---------------------------------------------------------*
 
                inverse work to make sure that the following is valid
 
                index = a * BLOCK_A + b * BLOCK_B + c;
 
        *----------------------------------------------------------*/
 
        enum  {B11100  = 7u << 2};
 
        enum  {BLOCK_A = 64*64, BLOCK_B = 64};
 
        index_t a, b, c, r;
 
        index_t x;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r;
 
 
 
        /* x is pslice */
 
        x = a;
 
        x += x & B11100; /* get upper part and double it */
 
        x += 8;          /* add extra row  */
 
        x ^= 070;        /* flip NS */
 
 
 
        pw[1] = (SQUARE) x;
 
        pw[0] = (SQUARE) b;
 
        pb[0] = (SQUARE) c;
 
 
 
        pw[2] = NOSQUARE;
 
        pb[1] = NOSQUARE;
 
 
 
        assert (kpk_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kpk_pctoindex (const SQUARE *pw, const SQUARE *pb, index_t *out)
 
{
 
        enum  {BLOCK_A = 64*64, BLOCK_B = 64};
 
        index_t pslice;
 
        SQUARE sq;
 
        SQUARE pawn = pw[1];
 
        SQUARE wk   = pw[0];
 
        SQUARE bk   = pb[0];
 
 
 
        #ifdef DEBUG
 
        if (  !(A2 <= pawn && pawn < A8)) {
 
                SQ_CONTENT wp[MAX_LISTSIZE], bp[MAX_LISTSIZE];
 
        bp [0] = wp[0] = KING;
 
        wp[1] = PAWN;
 
        wp[2] = bp[1] = NOPIECE;
 
                output_state (0, pw, pb, wp, bp);
 
        }
 
        #endif
 
 
 
        assert (A2 
<= pawn 
&& pawn 
< A8
);  
 
 
        if (  !(A2 <= pawn && pawn < A8)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
 
 
        if ((pawn & 07) > 3) { /* column is more than 3. e.g. = e,f,g, or h */
 
                pawn = flipWE (pawn);
 
                wk   = flipWE (wk);
 
                bk   = flipWE (bk);
 
        }
 
 
 
        sq = pawn;
 
        sq ^= 070; /* flipNS*/
 
        sq -= 8;   /* down one row*/
 
        pslice = (index_t) ((sq+(sq&3)) >> 1);
 
 
 
        *out = pslice * BLOCK_A + (index_t)wk * BLOCK_B  + (index_t)bk;
 
 
 
        return TRUE;
 
}
 
 
 
 
 
/**********************  KPP/K ************************************/
 
 
 
static bool_t   test_kppk (void);
 
static bool_t   kppk_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out);
 
static void             kppk_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
static bool_t
 
test_kppk (void)
 
{
 
 
 
        enum            {MAXPC = 16+1};
 
        char            str[] = "kppk";
 
        SQUARE          a, b, c, d;
 
        SQUARE          pw[MAXPC], pb[MAXPC];
 
        SQUARE          px[MAXPC], py[MAXPC];
 
 
 
        index_t         i, j;
 
        bool_t          err = FALSE;
 
 
 
 
 
        for (b = 0; b < 64; b++) {
 
                for (c = 0; c < 64; c++) {
 
                        sq_t anchor1, anchor2, loosen1, loosen2;
 
                        if (c <= H1 || c >= A8)
 
                                continue;
 
                        if (b <= H1 || b >= A8)
 
                                continue;
 
 
 
                        pp_putanchorfirst (b, c, &anchor1, &loosen1);
 
                        pp_putanchorfirst (c, b, &anchor2, &loosen2);
 
                        if (!(anchor1 == anchor2 && loosen1 == loosen2)) {
 
                                printf ("Output depends on input in pp_outanchorfirst()\n input:%u, %u\n",(unsigned)b
,(unsigned)c
);  
                                fatal_error();
 
                        }
 
                }
 
        }
 
 
 
 
 
        for (a = 0; a < 64; a++) {
 
                for (b = 0; b < 64; b++) {
 
                for (c = 0; c < 64; c++) {
 
                for (d = 0; d < 64; d++) {
 
 
 
 
 
                        if (c <= H1 || c >= A8)
 
                                continue;
 
                        if (b <= H1 || b >= A8)
 
                                continue;
 
 
 
 
 
                        pw[0] = a;
 
                        pw[1] = b;
 
                        pw[2] = c;
 
                        pw[3] = NOSQUARE;
 
 
 
                        pb[0] = d;
 
                        pb[1] = NOSQUARE;
 
 
 
                        if (kppk_pctoindex (pw, pb, &i)) {
 
                                                        kppk_indextopc (i, px, py);
 
                                                        kppk_pctoindex (px, py, &j);
 
                                                        if (i != j) {
 
                                                                err = TRUE;
 
                                                        }
 
                        }
 
 
 
 
 
                }
 
                }
 
                }
 
 
 
        if ((a&1)==0) {
 
        }
 
        }
 
 
 
        if (err)
 
                printf ("> %s NOT passed\n", str
);  
        else
 
                printf ("> %s PASSED\n", str
);  
        return !err;
 
}
 
 
 
static void
 
kppk_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        /*---------------------------------------------------------*
 
                inverse work to make sure that the following is valid
 
                index = a * BLOCK_A + b * BLOCK_B + c;
 
        *----------------------------------------------------------*/
 
        enum  {B11100  = 7u << 2};
 
        enum  {BLOCK_A = 64*64, BLOCK_B = 64};
 
        index_t a, b, c, r;
 
        index_t m, n;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r;
 
 
 
        m = pp_hi24 [a];
 
        n = pp_lo48 [a];
 
 
 
        pw[0] = (SQUARE) b;
 
        pb[0] = (SQUARE) c;
 
        pb[1] = NOSQUARE;
 
 
 
        pw[1] = pidx24_to_wsq (m);
 
        pw[2] = pidx48_to_wsq (n);
 
 
 
        pw[3] = NOSQUARE;
 
 
 
 
 
        assert (A2 
<= pw
[1] && pw
[1] < A8
);  
        assert (A2 
<= pw
[2] && pw
[2] < A8
);  
 
 
#ifdef DEBUG
 
        if (!(kppk_pctoindex (pw, pb, &a) && a == i)) {
 
                pc_t wp[] = {KING, PAWN, PAWN, NOPIECE};
 
                pc_t bp[] = {KING, NOPIECE};
 
                printf("Indexes not matching: input:%d, output:%d\n", i
, a
);  
                print_pos (pw, pb, wp, bp);
 
        }
 
#endif
 
 
 
        assert (kppk_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kppk_pctoindex (const SQUARE *pw, const SQUARE *pb, index_t *out)
 
{
 
        enum  {BLOCK_A = 64*64, BLOCK_B = 64};
 
        index_t pp_slice;
 
        SQUARE anchor, loosen;
 
 
 
        SQUARE wk     = pw[0];
 
        SQUARE pawn_a = pw[1];
 
        SQUARE pawn_b = pw[2];
 
        SQUARE bk     = pb[0];
 
        index_t i, j;
 
 
 
        #ifdef DEBUG
 
        if (!(A2 <= pawn_a && pawn_a < A8)) {
 
                printf ("\n\nsquare of pawn_a: %s\n", Square_str
[pawn_a
]);  
                printf(" wk %s\n p1 %s\n p2 %s\n bk %s\n"  
                        , Square_str[wk]
 
                        , Square_str[pawn_a]
 
                        , Square_str[pawn_b]
 
                        , Square_str[bk]
 
                        );
 
        }
 
        #endif
 
 
 
        assert (A2 
<= pawn_a 
&& pawn_a 
< A8
);  
        assert (A2 
<= pawn_b 
&& pawn_b 
< A8
);  
 
 
        pp_putanchorfirst (pawn_a, pawn_b, &anchor, &loosen);
 
 
 
        if ((anchor & 07) > 3) { /* column is more than 3. e.g. = e,f,g, or h */
 
                anchor = flipWE (anchor);
 
                loosen = flipWE (loosen);
 
                wk     = flipWE (wk);
 
                bk     = flipWE (bk);
 
        }
 
 
 
        i = wsq_to_pidx24 (anchor);
 
        j = wsq_to_pidx48 (loosen);
 
 
 
        pp_slice = ppidx [i] [j];
 
 
 
        if (IDX_is_empty(pp_slice)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
 
 
        assert (pp_slice 
< MAX_PPINDEX 
);  
 
 
        *out = pp_slice * BLOCK_A + (index_t)wk * BLOCK_B  + (index_t)bk;
 
 
 
        return TRUE;
 
}
 
/****************** end  KPP/K ************************************/
 
 
 
static void
 
kakp_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        /*---------------------------------------------------------*
 
                inverse work to make sure that the following is valid
 
                index = a * BLOCK_A + b * BLOCK_B + c * BLOCK_C + d;
 
        *----------------------------------------------------------*/
 
        enum  {B11100  = 7u << 2};
 
        enum  {BLOCK_A = 64*64*64, BLOCK_B = 64*64, BLOCK_C = 64};
 
        index_t a, b, c, d, r;
 
        index_t x;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r / BLOCK_C;
 
        r -= c * BLOCK_C;
 
        d  = r;
 
 
 
        /* x is pslice */
 
        x = a;
 
        x += x & B11100; /* get upper part and double it */
 
        x += 8;          /* add extra row  */
 
/*      x ^= 070;   */     /* flip NS */
 
 
 
        pw[0] = (SQUARE) b;
 
        pb[0] = (SQUARE) c;
 
        pw[1] = (SQUARE) d;
 
        pb[1] = (SQUARE) x;
 
        pw[2] = NOSQUARE;
 
        pb[2] = NOSQUARE;
 
 
 
        assert (kakp_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kakp_pctoindex (const SQUARE *pw, const SQUARE *pb, index_t *out)
 
{
 
        enum  {BLOCK_A = 64*64*64, BLOCK_B = 64*64, BLOCK_C = 64};
 
        index_t pslice;
 
        SQUARE sq;
 
        SQUARE pawn = pb[1];
 
        SQUARE wa   = pw[1];
 
        SQUARE wk   = pw[0];
 
        SQUARE bk   = pb[0];
 
 
 
        assert (A2 
<= pawn 
&& pawn 
< A8
);  
 
 
        if (  !(A2 <= pawn && pawn < A8)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
 
 
        if ((pawn & 07) > 3) { /* column is more than 3. e.g. = e,f,g, or h */
 
                pawn = flipWE (pawn);
 
                wk   = flipWE (wk);
 
                bk   = flipWE (bk);
 
                wa   = flipWE (wa);
 
        }
 
 
 
        sq = pawn;
 
        /*sq ^= 070;*/ /* flipNS*/
 
        sq -= 8;   /* down one row*/
 
        pslice = (index_t) ((sq+(sq&3)) >> 1);
 
 
 
        *out = pslice * BLOCK_A + (index_t)wk * BLOCK_B  + (index_t)bk * BLOCK_C + (index_t)wa;
 
 
 
        return TRUE;
 
}
 
 
 
 
 
static void
 
kapk_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        /*---------------------------------------------------------*
 
                inverse work to make sure that the following is valid
 
                index = a * BLOCK_A + b * BLOCK_B + c * BLOCK_C + d;
 
        *----------------------------------------------------------*/
 
        enum  {B11100  = 7u << 2};
 
        enum  {BLOCK_A = 64*64*64, BLOCK_B = 64*64, BLOCK_C = 64};
 
        index_t a, b, c, d, r;
 
        index_t x;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r / BLOCK_C;
 
        r -= c * BLOCK_C;
 
        d  = r;
 
 
 
        /* x is pslice */
 
        x = a;
 
        x += x & B11100; /* get upper part and double it */
 
        x += 8;          /* add extra row  */
 
        x ^= 070;        /* flip NS */
 
 
 
        pw[0] = (SQUARE) b;
 
        pb[0] = (SQUARE) c;
 
        pw[1] = (SQUARE) d;
 
        pw[2] = (SQUARE) x;
 
        pw[3] = NOSQUARE;
 
        pb[1] = NOSQUARE;
 
 
 
        assert (kapk_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kapk_pctoindex (const SQUARE *pw, const SQUARE *pb, index_t *out)
 
{
 
        enum  {BLOCK_A = 64*64*64, BLOCK_B = 64*64, BLOCK_C = 64};
 
        index_t pslice;
 
        SQUARE sq;
 
        SQUARE pawn = pw[2];
 
        SQUARE wa   = pw[1];
 
        SQUARE wk   = pw[0];
 
        SQUARE bk   = pb[0];
 
 
 
        assert (A2 
<= pawn 
&& pawn 
< A8
);  
 
 
        if (  !(A2 <= pawn && pawn < A8)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
 
 
        if ((pawn & 07) > 3) { /* column is more than 3. e.g. = e,f,g, or h */
 
                pawn = flipWE (pawn);
 
                wk   = flipWE (wk);
 
                bk   = flipWE (bk);
 
                wa   = flipWE (wa);
 
        }
 
 
 
        sq = pawn;
 
        sq ^= 070; /* flipNS*/
 
        sq -= 8;   /* down one row*/
 
        pslice = (index_t) ((sq+(sq&3)) >> 1);
 
 
 
        *out = pslice * BLOCK_A + (index_t)wk * BLOCK_B  + (index_t)bk * BLOCK_C + (index_t)wa;
 
 
 
        return TRUE;
 
}
 
 
 
 
 
static void
 
kaak_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        enum  {BLOCK_A = MAX_AAINDEX};
 
        index_t a, b, r, x, y;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r;
 
 
 
        assert (i 
== (a 
* BLOCK_A 
+ b
));  
 
 
        pw[0] = wksq [a];
 
        pb[0] = bksq [a];
 
 
 
        x = aabase [b];
 
        y = (b + 1) + x - (x * (127-x)/2);
 
 
 
        pw[1] = (SQUARE) x;
 
        pw[2] = (SQUARE) y;
 
        pw[3] = NOSQUARE;
 
 
 
        pb[1] = NOSQUARE;
 
 
 
        assert (kaak_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kaak_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out)
 
{
 
        enum  {N_WHITE = 3, N_BLACK = 1};
 
        enum  {BLOCK_A = MAX_AAINDEX};
 
        SQUARE ws[MAX_LISTSIZE], bs[MAX_LISTSIZE];
 
        index_t ki, ai;
 
        unsigned int ft;
 
        SQUARE i;
 
 
 
        ft = flipt [inp_pb[0]] [inp_pw[0]];
 
 
 
 
 
    for (i = 0; i < N_WHITE; i++) ws[i] = inp_pw[i];
 
    ws[N_WHITE] = NOSQUARE;
 
    for (i = 0; i < N_BLACK; i++) bs[i] = inp_pb[i];
 
    bs[N_BLACK] = NOSQUARE;
 
 
 
        if ((ft & WE_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipWE (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipWE (bs[i]);
 
        }
 
 
 
        if ((ft & NS_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipNS (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipNS (bs[i]);
 
        }
 
 
 
        if ((ft & NW_SE_FLAG) != 0) {
 
                for (i = 0; i < N_WHITE; i++) ws[i] = flipNW_SE (ws[i]);
 
                for (i = 0; i < N_BLACK; i++) bs[i] = flipNW_SE (bs[i]);
 
        }
 
 
 
        ki = kkidx [bs[0]] [ws[0]]; /* kkidx [black king] [white king] */
 
        ai = (index_t) aaidx [ws[1]] [ws[2]];
 
 
 
        if (IDX_is_empty(ki) || IDX_is_empty(ai)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
        *out = ki * BLOCK_A + ai;
 
        return TRUE;
 
}
 
 
 
/**********************  KPP/KA ************************************/
 
 
 
static bool_t   test_kppka (void);
 
static bool_t   kppka_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out);
 
static void             kppka_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
static bool_t
 
test_kppka (void)
 
{
 
 
 
        enum            {MAXPC = 16+1};
 
        char            str[] = "kppka";
 
        SQUARE          a, b, c, d, e;
 
        SQUARE          pw[MAXPC], pb[MAXPC];
 
        SQUARE          px[MAXPC], py[MAXPC];
 
 
 
        index_t         i, j;
 
        bool_t          err = FALSE;
 
 
 
 
 
        for (a = 0; a < 64; a++) {
 
                for (b = 0; b < 64; b++) {
 
                for (c = 0; c < 64; c++) {
 
                for (d = 0; d < 64; d++) {
 
                for (e = 0; e < 64; e++) {
 
 
 
                        if (c <= H1 || c >= A8)
 
                                continue;
 
                        if (b <= H1 || b >= A8)
 
                                continue;
 
 
 
 
 
                        pw[0] = a;
 
                        pw[1] = b;
 
                        pw[2] = c;
 
                        pw[3] = NOSQUARE;
 
 
 
                        pb[0] = e;
 
                        pb[1] = d;
 
                        pb[2] = NOSQUARE;
 
 
 
                        if (kppka_pctoindex (pw, pb, &i)) {
 
                                                        kppka_indextopc (i, px, py);
 
                                                        kppka_pctoindex (px, py, &j);
 
                                                        if (i != j) {
 
                                                                err = TRUE;
 
                                                        }
 
                        }
 
 
 
                }
 
                }
 
                }
 
                }
 
 
 
        if ((a&1)==0) {
 
        }
 
        }
 
 
 
        if (err)
 
                printf ("> %s NOT passed\n", str
);  
        else
 
                printf ("> %s PASSED\n", str
);  
        return !err;
 
}
 
 
 
 
 
static void
 
kppka_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        /*---------------------------------------------------------*
 
                inverse work to make sure that the following is valid
 
                index = a * BLOCK_A + b * BLOCK_B + c * BLOCK_C + d;
 
        *----------------------------------------------------------*/
 
 
 
        enum  {BLOCK_A = 64*64*64, BLOCK_B = 64*64, BLOCK_C = 64};
 
        index_t a, b, c, d, r;
 
        index_t m, n;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r / BLOCK_C;
 
        r -= c * BLOCK_C;
 
        d  = r;
 
 
 
        m = pp_hi24 [a];
 
        n = pp_lo48 [a];
 
 
 
        pw[0] = (SQUARE) b;
 
        pw[1] = pidx24_to_wsq (m);
 
        pw[2] = pidx48_to_wsq (n);
 
        pw[3] = NOSQUARE;
 
 
 
        pb[0] = (SQUARE) c;
 
        pb[1] = (SQUARE) d;
 
        pb[2] = NOSQUARE;
 
 
 
 
 
        assert (A2 
<= pw
[1] && pw
[1] < A8
);  
        assert (A2 
<= pw
[2] && pw
[2] < A8
);  
        assert (kppka_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kppka_pctoindex (const SQUARE *pw, const SQUARE *pb, index_t *out)
 
{
 
        enum  {BLOCK_A = 64*64*64, BLOCK_B = 64*64, BLOCK_C = 64};
 
        index_t pp_slice;
 
        index_t i, j;
 
 
 
        SQUARE anchor, loosen;
 
 
 
        SQUARE wk     = pw[0];
 
        SQUARE pawn_a = pw[1];
 
        SQUARE pawn_b = pw[2];
 
        SQUARE bk     = pb[0];
 
        SQUARE ba         = pb[1];
 
 
 
 
 
        assert (A2 
<= pawn_a 
&& pawn_a 
< A8
);  
        assert (A2 
<= pawn_b 
&& pawn_b 
< A8
);  
 
 
        pp_putanchorfirst (pawn_a, pawn_b, &anchor, &loosen);
 
 
 
        if ((anchor & 07) > 3) { /* column is more than 3. e.g. = e,f,g, or h */
 
                anchor = flipWE (anchor);
 
                loosen = flipWE (loosen);
 
                wk     = flipWE (wk);
 
                bk     = flipWE (bk);
 
                ba         = flipWE (ba);
 
        }
 
 
 
        i = wsq_to_pidx24 (anchor);
 
        j = wsq_to_pidx48 (loosen);
 
 
 
        pp_slice = ppidx [i] [j];
 
 
 
        if (IDX_is_empty(pp_slice)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
 
 
        assert (pp_slice 
< MAX_PPINDEX 
);  
 
 
        *out = pp_slice * (index_t)BLOCK_A + (index_t)wk * (index_t)BLOCK_B  + (index_t)bk * (index_t)BLOCK_C + (index_t)ba;
 
 
 
        return TRUE;
 
}
 
 
 
/********************** end KPP/KA ************************************/
 
 
 
/**********************  KAPP/K ************************************/
 
 
 
static bool_t   test_kappk (void);
 
static bool_t   kappk_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out);
 
static void             kappk_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
static bool_t
 
test_kappk (void)
 
{
 
 
 
        enum            {MAXPC = 16+1};
 
        char            str[] = "kappk";
 
        SQUARE          a, b, c, d, e;
 
        SQUARE          pw[MAXPC], pb[MAXPC];
 
        SQUARE          px[MAXPC], py[MAXPC];
 
 
 
        index_t         i, j;
 
        bool_t          err = FALSE;
 
 
 
 
 
        for (a = 0; a < 64; a++) {
 
                for (b = 0; b < 64; b++) {
 
                for (c = 0; c < 64; c++) {
 
                for (d = 0; d < 64; d++) {
 
                for (e = 0; e < 64; e++) {
 
 
 
                        if (c <= H1 || c >= A8)
 
                                continue;
 
                        if (b <= H1 || b >= A8)
 
                                continue;
 
 
 
 
 
                        pw[0] = a;
 
                        pw[1] = d;
 
                        pw[2] = b;
 
                        pw[3] = c;
 
                        pw[4] = NOSQUARE;
 
 
 
                        pb[0] = e;
 
                        pb[1] = NOSQUARE;
 
 
 
                        if (kappk_pctoindex (pw, pb, &i)) {
 
                                                        kappk_indextopc (i, px, py);
 
                                                        kappk_pctoindex (px, py, &j);
 
                                                        if (i != j) {
 
                                                                err = TRUE;
 
                                                        }
 
                        }
 
 
 
                }
 
                }
 
                }
 
                }
 
 
 
        if ((a&1)==0) {
 
        }
 
        }
 
 
 
        if (err)
 
                printf ("> %s NOT passed\n", str
);  
        else
 
                printf ("> %s PASSED\n", str
);  
        return !err;
 
}
 
 
 
 
 
static void
 
kappk_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        /*---------------------------------------------------------*
 
                inverse work to make sure that the following is valid
 
                index = a * BLOCK_A + b * BLOCK_B + c * BLOCK_C + d;
 
        *----------------------------------------------------------*/
 
 
 
        enum  {BLOCK_A = 64*64*64, BLOCK_B = 64*64, BLOCK_C = 64};
 
        index_t a, b, c, d, r;
 
        index_t m, n;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r / BLOCK_C;
 
        r -= c * BLOCK_C;
 
        d  = r;
 
 
 
        m = pp_hi24 [a];
 
        n = pp_lo48 [a];
 
 
 
        pw[0] = (SQUARE) b;
 
        pw[1] = (SQUARE) d;
 
        pw[2] = pidx24_to_wsq (m);
 
        pw[3] = pidx48_to_wsq (n);
 
        pw[4] = NOSQUARE;
 
 
 
        pb[0] = (SQUARE) c;
 
        pb[1] = NOSQUARE;
 
 
 
 
 
        assert (A2 
<= pw
[3] && pw
[3] < A8
);  
        assert (A2 
<= pw
[2] && pw
[2] < A8
);  
        assert (kappk_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kappk_pctoindex (const SQUARE *pw, const SQUARE *pb, index_t *out)
 
{
 
        enum  {BLOCK_A = 64*64*64, BLOCK_B = 64*64, BLOCK_C = 64};
 
        index_t pp_slice;
 
        SQUARE anchor, loosen;
 
 
 
        SQUARE wk     = pw[0];
 
        SQUARE wa         = pw[1];
 
        SQUARE pawn_a = pw[2];
 
        SQUARE pawn_b = pw[3];
 
        SQUARE bk     = pb[0];
 
 
 
        index_t i, j;
 
 
 
        assert (A2 
<= pawn_a 
&& pawn_a 
< A8
);  
        assert (A2 
<= pawn_b 
&& pawn_b 
< A8
);  
 
 
        pp_putanchorfirst (pawn_a, pawn_b, &anchor, &loosen);
 
 
 
        if ((anchor & 07) > 3) { /* column is more than 3. e.g. = e,f,g, or h */
 
                anchor = flipWE (anchor);
 
                loosen = flipWE (loosen);
 
                wk     = flipWE (wk);
 
                bk     = flipWE (bk);
 
                wa         = flipWE (wa);
 
        }
 
 
 
        i = wsq_to_pidx24 (anchor);
 
        j = wsq_to_pidx48 (loosen);
 
 
 
        pp_slice = ppidx [i] [j];
 
 
 
        if (IDX_is_empty(pp_slice)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
 
 
        assert (pp_slice 
< MAX_PPINDEX 
);  
 
 
        *out = pp_slice * (index_t)BLOCK_A + (index_t)wk * (index_t)BLOCK_B  + (index_t)bk * (index_t)BLOCK_C + (index_t)wa;
 
 
 
        return TRUE;
 
}
 
 
 
/********************** end KAPP/K ************************************/
 
 
 
/**********************  KAPP/K ************************************/
 
 
 
static bool_t   test_kapkp (void);
 
static bool_t   kapkp_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out);
 
static void             kapkp_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
static bool_t
 
test_kapkp (void)
 
{
 
 
 
        enum            {MAXPC = 16+1};
 
        char            str[] = "kapkp";
 
        SQUARE          a, b, c, d, e;
 
        SQUARE          pw[MAXPC], pb[MAXPC];
 
        SQUARE          px[MAXPC], py[MAXPC];
 
 
 
        index_t         i, j;
 
        bool_t          err = FALSE;
 
 
 
 
 
        for (a = 0; a < 64; a++) {
 
                for (b = 0; b < 64; b++) {
 
                for (c = 0; c < 64; c++) {
 
                for (d = 0; d < 64; d++) {
 
                for (e = 0; e < 64; e++) {
 
 
 
                        if (c <= H1 || c >= A8)
 
                                continue;
 
                        if (b <= H1 || b >= A8)
 
                                continue;
 
 
 
 
 
                        pw[0] = a;
 
                        pw[1] = d;
 
                        pw[2] = b;
 
                        pw[3] = NOSQUARE;
 
 
 
                        pb[0] = e;
 
                        pb[1] = c;
 
                        pb[2] = NOSQUARE;
 
 
 
                        if (kapkp_pctoindex (pw, pb, &i)) {
 
                                                        kapkp_indextopc (i, px, py);
 
                                                        kapkp_pctoindex (px, py, &j);
 
                                                        if (i != j) {
 
                                                                err = TRUE;
 
                                                        }
 
                        }
 
 
 
                }
 
                }
 
                }
 
                }
 
 
 
        if ((a&1)==0) {
 
        }
 
        }
 
 
 
        if (err)
 
                printf ("> %s NOT passed\n", str
);  
        else
 
                printf ("> %s PASSED\n", str
);  
        return !err;
 
}
 
 
 
 
 
static bool_t
 
kapkp_pctoindex (const SQUARE *pw, const SQUARE *pb, index_t *out)
 
{
 
        enum  {BLOCK_A = 64*64*64, BLOCK_B = 64*64, BLOCK_C = 64};
 
        index_t pp_slice;
 
        SQUARE anchor, loosen;
 
 
 
        SQUARE wk     = pw[0];
 
        SQUARE wa         = pw[1];
 
        SQUARE pawn_a = pw[2];
 
        SQUARE bk     = pb[0];
 
        SQUARE pawn_b = pb[1];
 
        index_t m, n;
 
 
 
        assert (A2 
<= pawn_a 
&& pawn_a 
< A8
);  
        assert (A2 
<= pawn_b 
&& pawn_b 
< A8
);  
        assert (pw
[3] == NOSQUARE 
&& pb
[2] == NOSQUARE
);  
 
 
        anchor = pawn_a;
 
        loosen = pawn_b;
 
 
 
        if ((anchor & 07) > 3) { /* column is more than 3. e.g. = e,f,g, or h */
 
                anchor = flipWE (anchor);
 
                loosen = flipWE (loosen);
 
                wk     = flipWE (wk);
 
                bk     = flipWE (bk);
 
                wa         = flipWE (wa);
 
        }
 
 
 
        m = wsq_to_pidx24 (anchor);
 
        n = (index_t)loosen - 8;
 
 
 
        pp_slice = m * 48 + n;
 
 
 
        if (IDX_is_empty(pp_slice)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
 
 
        assert (pp_slice 
< (64*MAX_PpINDEX
) );  
 
 
        *out = pp_slice * (index_t)BLOCK_A + (index_t)wk * (index_t)BLOCK_B  + (index_t)bk * (index_t)BLOCK_C + (index_t)wa;
 
 
 
        return TRUE;
 
}
 
 
 
static void
 
kapkp_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        /*---------------------------------------------------------*
 
                inverse work to make sure that the following is valid
 
                index = a * BLOCK_A + b * BLOCK_B + c * BLOCK_C + d;
 
        *----------------------------------------------------------*/
 
        enum  {BLOCK_A = 64*64*64, BLOCK_B = 64*64, BLOCK_C = 64};
 
        enum  {block_m = 48};
 
        index_t a, b, c, d, r;
 
        index_t m, n;
 
        SQUARE sq_m, sq_n;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r / BLOCK_C;
 
        r -= c * BLOCK_C;
 
        d  = r;
 
 
 
        /* unpack a, which is pslice, into m and n */
 
        r = a;
 
        m  = r / block_m;
 
        r -= m * block_m;
 
        n  = r ;
 
 
 
        sq_m = pidx24_to_wsq (m);
 
        sq_n = (SQUARE) n + 8;
 
 
 
        pw[0] = (SQUARE) b;
 
        pb[0] = (SQUARE) c;
 
        pw[1] = (SQUARE) d;
 
        pw[2] = sq_m;
 
        pb[1] = sq_n;
 
        pw[3] = NOSQUARE;
 
        pb[2] = NOSQUARE;
 
 
 
        assert (A2 
<= sq_m 
&& sq_m 
< A8
);  
        assert (A2 
<= sq_n 
&& sq_n 
< A8
);  
        assert (kapkp_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
/********************** end KAP/KP ************************************/
 
 
 
/**********************  KABP/K ************************************/
 
 
 
static bool_t   test_kabpk (void);
 
static bool_t   kabpk_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out);
 
static void             kabpk_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
static bool_t
 
test_kabpk (void)
 
{
 
 
 
        enum            {MAXPC = 16+1};
 
        char            str[] = "kabpk";
 
        SQUARE          a, b, c, d, e;
 
        SQUARE          pw[MAXPC], pb[MAXPC];
 
        SQUARE          px[MAXPC], py[MAXPC];
 
 
 
        index_t         i, j;
 
        bool_t          err = FALSE;
 
 
 
 
 
        for (a = 0; a < 64; a++) {
 
                for (b = 0; b < 64; b++) {
 
                for (c = 0; c < 64; c++) {
 
                for (d = 0; d < 64; d++) {
 
                for (e = 0; e < 64; e++) {
 
 
 
                        if (d <= H1 || d >= A8)
 
                                continue;
 
 
 
                        pw[0] = a;
 
                        pw[1] = b;
 
                        pw[2] = c;
 
                        pw[3] = d;
 
                        pw[4] = NOSQUARE;
 
 
 
                        pb[0] = e;
 
                        pb[1] = NOSQUARE;
 
 
 
                        if (kabpk_pctoindex (pw, pb, &i)) {
 
                                                        kabpk_indextopc (i, px, py);
 
                                                        kabpk_pctoindex (px, py, &j);
 
                                                        if (i != j) {
 
                                                                err = TRUE;
 
                                                        }
 
                        }
 
 
 
                }
 
                }
 
                }
 
                }
 
 
 
        if ((a&1)==0) {
 
        }
 
        }
 
 
 
        if (err)
 
                printf ("> %s NOT passed\n", str
);  
        else
 
                printf ("> %s PASSED\n", str
);  
        return !err;
 
}
 
 
 
 
 
static void
 
kabpk_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
 
 
        /*---------------------------------------------------------*
 
                inverse work to make sure that the following is valid
 
                index = a * BLOCK_A + b * BLOCK_B + c * BLOCK_C + d * BLOCK_D + e;
 
        *----------------------------------------------------------*/
 
        enum  {BLOCK_A = 64*64*64*64, BLOCK_B = 64*64*64, BLOCK_C = 64*64, BLOCK_D = 64};
 
        index_t a, b, c, d, e, r;
 
        SQUARE x;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r / BLOCK_C;
 
        r -= c * BLOCK_C;
 
        d  = r / BLOCK_D;
 
        r -= d * BLOCK_D;
 
        e  = r;
 
 
 
        x = pidx24_to_wsq(a);
 
 
 
        pw[0] = (SQUARE) b;
 
        pw[1] = (SQUARE) d;
 
        pw[2] = (SQUARE) e;
 
        pw[3] = x;
 
        pw[4] = NOSQUARE;
 
 
 
        pb[0] = (SQUARE) c;
 
        pb[1] = NOSQUARE;
 
 
 
        assert (kabpk_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kabpk_pctoindex (const SQUARE *pw, const SQUARE *pb, index_t *out)
 
{
 
        enum  {BLOCK_A = 64*64*64*64, BLOCK_B = 64*64*64, BLOCK_C = 64*64, BLOCK_D = 64};
 
        index_t pslice;
 
 
 
        SQUARE wk   = pw[0];
 
        SQUARE wa   = pw[1];
 
        SQUARE wb   = pw[2];
 
        SQUARE pawn = pw[3];
 
        SQUARE bk   = pb[0];
 
 
 
        assert (A2 
<= pawn 
&& pawn 
< A8
);  
 
 
        if ((pawn & 07) > 3) { /* column is more than 3. e.g. = e,f,g, or h */
 
                pawn = flipWE (pawn);
 
                wk   = flipWE (wk);
 
                bk   = flipWE (bk);
 
                wa   = flipWE (wa);
 
                wb   = flipWE (wb);
 
        }
 
 
 
        pslice = wsq_to_pidx24 (pawn);
 
 
 
        *out = pslice * (index_t)BLOCK_A + (index_t)wk * (index_t)BLOCK_B  + (index_t)bk * (index_t)BLOCK_C + (index_t)wa * (index_t)BLOCK_D + (index_t)wb;
 
 
 
        return TRUE;
 
}
 
 
 
/********************** end KABP/K ************************************/
 
 
 
/**********************  KAAP/K ************************************/
 
 
 
static bool_t   test_kaapk (void);
 
static bool_t   kaapk_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out);
 
static void             kaapk_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
static bool_t
 
test_kaapk (void)
 
{
 
 
 
        enum            {MAXPC = 16+1};
 
        char            str[] = "kaapk";
 
        SQUARE          a, b, c, d, e;
 
        SQUARE          pw[MAXPC], pb[MAXPC];
 
        SQUARE          px[MAXPC], py[MAXPC];
 
 
 
        index_t         i, j;
 
        bool_t          err = FALSE;
 
 
 
 
 
        for (a = 0; a < 64; a++) {
 
                for (b = 0; b < 64; b++) {
 
                for (c = 0; c < 64; c++) {
 
                for (d = 0; d < 64; d++) {
 
                for (e = 0; e < 64; e++) {
 
 
 
                        if (d <= H1 || d >= A8)
 
                                continue;
 
 
 
                        pw[0] = a;
 
                        pw[1] = b;
 
                        pw[2] = c;
 
                        pw[3] = d;
 
                        pw[4] = NOSQUARE;
 
 
 
                        pb[0] = e;
 
                        pb[1] = NOSQUARE;
 
 
 
                        if (kaapk_pctoindex (pw, pb, &i)) {
 
                                                        kaapk_indextopc (i, px, py);
 
                                                        kaapk_pctoindex (px, py, &j);
 
                                                        if (i != j) {
 
                                                                err = TRUE;
 
                                                        }
 
                        }
 
 
 
                }
 
                }
 
                }
 
                }
 
 
 
        if ((a&1)==0) {
 
        }
 
        }
 
 
 
        if (err)
 
                printf ("> %s NOT passed\n", str
);  
        else
 
                printf ("> %s PASSED\n", str
);  
        return !err;
 
}
 
 
 
 
 
static void
 
kaapk_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        /*---------------------------------------------------------*
 
                inverse work to make sure that the following is valid
 
                index = a * BLOCK_A + b * BLOCK_B + c * BLOCK_C + d;
 
        *----------------------------------------------------------*/
 
        enum    {BLOCK_C = MAX_AAINDEX
 
                        ,BLOCK_B = 64*BLOCK_C
 
                        ,BLOCK_A = 64*BLOCK_B
 
        };
 
        index_t a, b, c, d, r;
 
        index_t x, y, z;
 
 
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r / BLOCK_C;
 
        r -= c * BLOCK_C;
 
        d  = r;
 
 
 
        z = (index_t) pidx24_to_wsq(a);
 
 
 
        /* split d into x, y*/
 
        x = aabase [d];
 
        y = (d + 1) + x - (x * (127-x)/2);
 
 
 
        assert (aaidx
[x
][y
] == aaidx
[y
][x
]);  
 
 
 
 
        pw[0] = (SQUARE) b;
 
        pw[1] = (SQUARE) x;
 
        pw[2] = (SQUARE) y;
 
        pw[3] = (SQUARE) z;
 
        pw[4] = NOSQUARE;
 
 
 
        pb[0] = (SQUARE) c;
 
        pb[1] = NOSQUARE;
 
 
 
        assert (kaapk_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kaapk_pctoindex (const SQUARE *pw, const SQUARE *pb, index_t *out)
 
{
 
        enum    {BLOCK_C = MAX_AAINDEX
 
                        ,BLOCK_B = 64*BLOCK_C
 
                        ,BLOCK_A = 64*BLOCK_B
 
        };
 
        index_t aa_combo, pslice;
 
 
 
        SQUARE wk   = pw[0];
 
        SQUARE wa   = pw[1];
 
        SQUARE wa2  = pw[2];
 
        SQUARE pawn = pw[3];
 
        SQUARE bk   = pb[0];
 
 
 
        assert (A2 
<= pawn 
&& pawn 
< A8
);  
 
 
        if ((pawn & 07) > 3) { /* column is more than 3. e.g. = e,f,g, or h */
 
                pawn = flipWE (pawn);
 
                wk   = flipWE (wk);
 
                bk   = flipWE (bk);
 
                wa   = flipWE (wa);
 
                wa2  = flipWE (wa2);
 
        }
 
 
 
        pslice = wsq_to_pidx24 (pawn);
 
 
 
        aa_combo = (index_t) aaidx [wa] [wa2];
 
 
 
        if (IDX_is_empty(aa_combo)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
 
 
        *out = pslice * (index_t)BLOCK_A + (index_t)wk * (index_t)BLOCK_B  + (index_t)bk * (index_t)BLOCK_C + aa_combo;
 
 
 
 
 
        return TRUE;
 
}
 
 
 
/********************** end KAAP/K ************************************/
 
 
 
/**********************  KAA/KP ************************************/
 
 
 
static bool_t   test_kaakp (void);
 
static bool_t   kaakp_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out);
 
static void             kaakp_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
static bool_t
 
test_kaakp (void)
 
{
 
 
 
        enum            {MAXPC = 16+1};
 
        char            str[] = "kaakp";
 
        SQUARE          a, b, c, d, e;
 
        SQUARE          pw[MAXPC], pb[MAXPC];
 
        SQUARE          px[MAXPC], py[MAXPC];
 
 
 
        index_t         i, j;
 
        bool_t          err = FALSE;
 
 
 
 
 
        for (a = 0; a < 64; a++) {
 
                for (b = 0; b < 64; b++) {
 
                for (c = 0; c < 64; c++) {
 
                for (d = 0; d < 64; d++) {
 
                for (e = 0; e < 64; e++) {
 
 
 
                        if (d <= H1 || d >= A8)
 
                                continue;
 
 
 
                        pw[0] = a;
 
                        pw[1] = b;
 
                        pw[2] = c;
 
                        pw[3] = NOSQUARE;
 
 
 
                        pb[0] = e;
 
                        pb[1] = d;
 
                        pb[2] = NOSQUARE;
 
 
 
                        if (kaakp_pctoindex (pw, pb, &i)) {
 
                                                        kaakp_indextopc (i, px, py);
 
                                                        kaakp_pctoindex (px, py, &j);
 
                                                        if (i != j) {
 
                                                                err = TRUE;
 
                                                        }
 
                        }
 
 
 
                }
 
                }
 
                }
 
                }
 
 
 
        if ((a&1)==0) {
 
        }
 
        }
 
 
 
        if (err)
 
                printf ("> %s NOT passed\n", str
);  
        else
 
                printf ("> %s PASSED\n", str
);  
        return !err;
 
}
 
 
 
 
 
static void
 
kaakp_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        /*---------------------------------------------------------*
 
                inverse work to make sure that the following is valid
 
                index = a * BLOCK_A + b * BLOCK_B + c * BLOCK_C + d;
 
        *----------------------------------------------------------*/
 
        enum    {BLOCK_C = MAX_AAINDEX
 
                        ,BLOCK_B = 64*BLOCK_C
 
                        ,BLOCK_A = 64*BLOCK_B
 
        };
 
        index_t a, b, c, d, r;
 
        index_t x, y, z;
 
        SQUARE zq;
 
 
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r / BLOCK_C;
 
        r -= c * BLOCK_C;
 
        d  = r;
 
 
 
        zq = pidx24_to_wsq(a);
 
        z  = (index_t)flipNS(zq);
 
 
 
 
 
        /* split d into x, y*/
 
        x = aabase [d];
 
        y = (d + 1) + x - (x * (127-x)/2);
 
 
 
        assert (aaidx
[x
][y
] == aaidx
[y
][x
]);  
 
 
 
 
        pw[0] = (SQUARE)b;
 
        pw[1] = (SQUARE)x;
 
        pw[2] = (SQUARE)y;
 
        pw[3] = NOSQUARE;
 
 
 
        pb[0] = (SQUARE)c;
 
        pb[1] = (SQUARE)z;
 
        pb[2] = NOSQUARE;
 
 
 
        assert (kaakp_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kaakp_pctoindex (const SQUARE *pw, const SQUARE *pb, index_t *out)
 
{
 
        enum    {BLOCK_C = MAX_AAINDEX
 
                        ,BLOCK_B = 64*BLOCK_C
 
                        ,BLOCK_A = 64*BLOCK_B
 
        };
 
        index_t aa_combo, pslice;
 
 
 
        SQUARE wk   = pw[0];
 
        SQUARE wa   = pw[1];
 
        SQUARE wa2  = pw[2];
 
        SQUARE bk   = pb[0];
 
        SQUARE pawn = pb[1];
 
 
 
        assert (A2 
<= pawn 
&& pawn 
< A8
);  
 
 
        if ((pawn & 07) > 3) { /* column is more than 3. e.g. = e,f,g, or h */
 
                pawn = flipWE (pawn);
 
                wk   = flipWE (wk);
 
                bk   = flipWE (bk);
 
                wa   = flipWE (wa);
 
                wa2  = flipWE (wa2);
 
        }
 
 
 
        pawn = flipNS(pawn);
 
        pslice = wsq_to_pidx24 (pawn);
 
 
 
        aa_combo = (index_t)aaidx [wa] [wa2];
 
 
 
        if (IDX_is_empty(aa_combo)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
 
 
        *out = pslice * (index_t)BLOCK_A + (index_t)wk * (index_t)BLOCK_B  + (index_t)bk * (index_t)BLOCK_C + aa_combo;
 
 
 
 
 
        return TRUE;
 
}
 
 
 
/********************** end KAA/KP ************************************/
 
 
 
/**********************  KPP/KP ************************************/
 
/*
 
index_t         pp48_idx[48][48];
 
sq_t            pp48_sq_x[MAX_PP48_INDEX];
 
sq_t            pp48_sq_y[MAX_PP48_INDEX];
 
*/
 
static bool_t   test_kppkp (void);
 
static bool_t   kppkp_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out);
 
static void             kppkp_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
static sq_t map24_b   (sq_t s);
 
static sq_t unmap24_b (index_t i);
 
 
 
static index_t
 
init_pp48_idx (void)
 
/* modifies pp48_idx[][], pp48_sq_x[], pp48_sq_y[] */
 
{
 
        enum  {MAX_I = 48, MAX_J = 48};
 
        SQUARE i, j;
 
        index_t idx = 0;
 
        SQUARE a, b;
 
 
 
        /* default is noindex */
 
        for (i = 0; i < MAX_I; i++) {
 
                for (j = 0; j < MAX_J; j++) {
 
                        IDX_set_empty (pp48_idx [i][j]);
 
                }
 
        }
 
 
 
        for (idx = 0; idx < MAX_PP48_INDEX; idx++) {
 
                pp48_sq_x [idx] = NOSQUARE;
 
                pp48_sq_y [idx] = NOSQUARE;
 
        }
 
 
 
        idx = 0;
 
        for (a = H7; a >= A2; a--) {
 
 
 
                for (b = a - 1; b >= A2; b--) {
 
 
 
                        i = flipWE( flipNS (a) ) - 8;
 
                        j = flipWE( flipNS (b) ) - 8;
 
 
 
                        if (IDX_is_empty(pp48_idx [i] [j])) {
 
 
 
                                pp48_idx  
[i
][j
]= idx
;  assert (idx 
< MAX_PP48_INDEX
); 
                                pp48_idx  [j][i]= idx;
 
                                pp48_sq_x 
[idx
] = i
;    assert (i 
< MAX_I
); 
                                pp48_sq_y 
[idx
] = j
;    assert (j 
< MAX_J
); 
                                idx++;
 
                        }
 
                }
 
        }
 
        assert (idx 
== MAX_PP48_INDEX
);  
        return idx;
 
}
 
 
 
 
 
 
 
static bool_t
 
test_kppkp (void)
 
{
 
 
 
        enum            {MAXPC = 16+1};
 
        char            str[] = "kppkp";
 
        SQUARE          a, b, c, d, e;
 
        SQUARE          pw[MAXPC], pb[MAXPC];
 
        SQUARE          px[MAXPC], py[MAXPC];
 
 
 
        index_t         i, j;
 
        bool_t          err = FALSE;
 
 
 
 
 
        for (a = 0; a < 64; a++) {
 
                for (b = 0; b < 64; b++) {
 
                for (c = 0; c < 64; c++) {
 
                for (d = 0; d < 64; d++) {
 
                for (e = 0; e < 64; e++) {
 
 
 
                        if (c <= H1 || c >= A8)
 
                                continue;
 
                        if (b <= H1 || b >= A8)
 
                                continue;
 
                        if (d <= H1 || d >= A8)
 
                                continue;
 
 
 
                        pw[0] = a;
 
                        pw[1] = b;
 
                        pw[2] = c;
 
                        pw[3] = NOSQUARE;
 
 
 
                        pb[0] = e;
 
                        pb[1] = d;
 
                        pb[2] = NOSQUARE;
 
 
 
                        if (kppkp_pctoindex (pw, pb, &i)) {
 
                                                        kppkp_indextopc (i, px, py);
 
                                                        kppkp_pctoindex (px, py, &j);
 
                                                        if (i != j) {
 
                                                                err = TRUE;
 
                                                        }
 
                        }
 
 
 
                }
 
                }
 
                }
 
                }
 
 
 
        if ((a&1)==0) {
 
        }
 
        }
 
 
 
        if (err)
 
                printf ("> %s NOT passed\n", str
);  
        else
 
                printf ("> %s PASSED\n", str
);  
        return !err;
 
}
 
 
 
 
 
static void
 
kppkp_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        /*---------------------------------------------------------*
 
                inverse work to make sure that the following is valid
 
                index = a * BLOCK_A + b * BLOCK_B + c * BLOCK_C + d;
 
        *----------------------------------------------------------*/
 
 
 
        enum  {BLOCK_A = MAX_PP48_INDEX*64*64, BLOCK_B = 64*64, BLOCK_C = 64};
 
        index_t a, b, c, d, r;
 
        SQUARE m, n;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r / BLOCK_C;
 
        r -= c * BLOCK_C;
 
        d  = r;
 
 
 
        m = pp48_sq_x [b];
 
        n = pp48_sq_y [b];
 
 
 
        pw[0] = (SQUARE)c;
 
        pw[1] = flipWE(flipNS(m+8));
 
        pw[2] = flipWE(flipNS(n+8));
 
        pw[3] = NOSQUARE;
 
 
 
        pb[0] = (SQUARE)d;
 
        pb[1] = (SQUARE)unmap24_b (a);
 
        pb[2] = NOSQUARE;
 
 
 
 
 
        assert (A2 
<= pw
[1] && pw
[1] < A8
);  
        assert (A2 
<= pw
[2] && pw
[2] < A8
);  
        assert (A2 
<= pb
[1] && pb
[1] < A8
);  
        assert (kppkp_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kppkp_pctoindex (const SQUARE *pw, const SQUARE *pb, index_t *out)
 
{
 
        enum  {BLOCK_A = MAX_PP48_INDEX*64*64, BLOCK_B = 64*64, BLOCK_C = 64};
 
        index_t pp48_slice;
 
 
 
        SQUARE wk     = pw[0];
 
        SQUARE pawn_a = pw[1];
 
        SQUARE pawn_b = pw[2];
 
        SQUARE bk     = pb[0];
 
        SQUARE pawn_c = pb[1];
 
        SQUARE i, j, k;
 
 
 
        assert (A2 
<= pawn_a 
&& pawn_a 
< A8
);  
        assert (A2 
<= pawn_b 
&& pawn_b 
< A8
);  
        assert (A2 
<= pawn_c 
&& pawn_c 
< A8
);  
 
 
        if ((pawn_c & 07) > 3) { /* column is more than 3. e.g. = e,f,g, or h */
 
                wk     = flipWE (wk);
 
                pawn_a = flipWE (pawn_a);
 
                pawn_b = flipWE (pawn_b);
 
                bk     = flipWE (bk);
 
                pawn_c = flipWE (pawn_c);
 
        }
 
 
 
        i = flipWE( flipNS (pawn_a) ) - 8;
 
        j = flipWE( flipNS (pawn_b) ) - 8;
 
        k = map24_b (pawn_c); /* black pawn, so low indexes mean more advanced 0 == A2 */
 
 
 
        pp48_slice = pp48_idx [i] [j];
 
 
 
        if (IDX_is_empty(pp48_slice)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
 
 
        assert (pp48_slice 
< MAX_PP48_INDEX 
);  
 
 
        *out = (index_t)k * (index_t)BLOCK_A + pp48_slice * (index_t)BLOCK_B + (index_t)wk * (index_t)BLOCK_C  + (index_t)bk;
 
 
 
        return TRUE;
 
}
 
 
 
static sq_t
 
map24_b (sq_t s)
 
{
 
        s -= 8;
 
        return ((s&3)+s)>>1;
 
}
 
 
 
static sq_t
 
unmap24_b (index_t i)
 
{
 
        return (sq_t) ((i&(4+8+16)) + i + 8);
 
}
 
 
 
/********************** end KPP/KP ************************************/
 
 
 
/**********************  KPPP/K ************************************/
 
 
 
static const sq_t itosq[48] = {
 
        H7,G7,F7,E7,
 
        H6,G6,F6,E6,
 
        H5,G5,F5,E5,
 
        H4,G4,F4,E4,
 
        H3,G3,F3,E3,
 
        H2,G2,F2,E2,
 
        D7,C7,B7,A7,
 
        D6,C6,B6,A6,
 
        D5,C5,B5,A5,
 
        D4,C4,B4,A4,
 
        D3,C3,B3,A3,
 
        D2,C2,B2,A2
 
};
 
 
 
static bool_t   test_kpppk (void);
 
static bool_t   kpppk_pctoindex (const SQUARE *inp_pw, const SQUARE *inp_pb, index_t *out);
 
static void             kpppk_indextopc (index_t i, SQUARE *pw, SQUARE *pb);
 
 
 
static index_t
 
init_ppp48_idx (void)
 
/* modifies ppp48_idx[][], ppp48_sq_x[], ppp48_sq_y[], ppp48_sq_z[] */
 
{
 
        enum  {MAX_I = 48, MAX_J = 48, MAX_K = 48};
 
        SQUARE i, j, k;
 
        index_t idx = 0;
 
        SQUARE a, b, c;
 
        int x, y, z;
 
 
 
        /* default is noindex */
 
        for (i = 0; i < MAX_I; i++) {
 
                for (j = 0; j < MAX_J; j++) {
 
                        for (k = 0; k < MAX_K; k++) {
 
                                IDX_set_empty(ppp48_idx [i][j][k]);
 
                        }
 
                }
 
        }
 
 
 
        for (idx = 0; idx < MAX_PPP48_INDEX; idx++) {
 
                ppp48_sq_x [idx] = (uint8_t)NOSQUARE;
 
                ppp48_sq_y [idx] = (uint8_t)NOSQUARE;
 
                ppp48_sq_z [idx] = (uint8_t)NOSQUARE;
 
        }
 
 
 
        idx = 0;
 
        for (x = 0; x < 48; x++) {
 
                for (y = x+1; y < 48; y++) {
 
                        for (z = y+1; z < 48; z++) {
 
 
 
                                a = itosq [x];
 
                                b = itosq [y];
 
                                c = itosq [z];
 
 
 
                                if (!in_queenside(b) || !in_queenside(c))
 
                                                continue;
 
 
 
                                i = a - 8;
 
                                j = b - 8;
 
                                k = c - 8;
 
 
 
                                if (IDX_is_empty(ppp48_idx [i] [j] [k])) {
 
 
 
                                        ppp48_idx  [i][j][k] = idx;
 
                                        ppp48_idx  [i][k][j] = idx;
 
                                        ppp48_idx  [j][i][k] = idx;
 
                                        ppp48_idx  [j][k][i] = idx;
 
                                        ppp48_idx  [k][i][j] = idx;
 
                                        ppp48_idx  [k][j][i] = idx;
 
                                        ppp48_sq_x 
[idx
] = (uint8_t) i
;         assert (i 
< MAX_I
); 
                                        ppp48_sq_y 
[idx
] = (uint8_t) j
;         assert (j 
< MAX_J
); 
                                        ppp48_sq_z 
[idx
] = (uint8_t) k
;         assert (k 
< MAX_K
); 
                                        idx++;
 
                                }
 
                        }
 
                }
 
        }
 
 
 
/*      assert (idx == MAX_PPP48_INDEX);*/
 
        return idx;
 
}
 
 
 
static bool_t
 
test_kpppk (void)
 
{
 
 
 
        enum            {MAXPC = 16+1};
 
        char            str[] = "kpppk";
 
        SQUARE          a, b, c, d, e;
 
        SQUARE          pw[MAXPC], pb[MAXPC];
 
        SQUARE          px[MAXPC], py[MAXPC];
 
 
 
        index_t         i, j;
 
        bool_t          err = FALSE;
 
 
 
 
 
        for (a = 0; a < 64; a++) {
 
                for (b = 0; b < 64; b++) {
 
                for (c = 0; c < 64; c++) {
 
                for (d = 0; d < 64; d++) {
 
                for (e = 0; e < 64; e++) {
 
 
 
                        if (c <= H1 || c >= A8)
 
                                continue;
 
                        if (b <= H1 || b >= A8)
 
                                continue;
 
                        if (d <= H1 || d >= A8)
 
                                continue;
 
 
 
                        pw[0] = a;
 
                        pw[1] = b;
 
                        pw[2] = c;
 
                        pw[3] = d;
 
                        pw[4] = NOSQUARE;
 
 
 
                        pb[0] = e;
 
                        pb[1] = NOSQUARE;
 
 
 
                        if (kpppk_pctoindex (pw, pb, &i)) {
 
                                                        kpppk_indextopc (i, px, py);
 
                                                        kpppk_pctoindex (px, py, &j);
 
                                                        if (i != j) {
 
                                                                err = TRUE;
 
                                                        }
 
                        }
 
 
 
                }
 
                }
 
                }
 
                }
 
 
 
        if ((a&1)==0) {
 
        }
 
        }
 
 
 
        if (err)
 
                printf ("> %s NOT passed\n", str
);  
        else
 
                printf ("> %s PASSED\n", str
);  
        return !err;
 
}
 
 
 
 
 
static void
 
kpppk_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        /*---------------------------------------------------------*
 
                inverse work to make sure that the following is valid
 
                index = a * BLOCK_A + b * BLOCK_B + c * BLOCK_C + d;
 
        *----------------------------------------------------------*/
 
 
 
        enum  {BLOCK_A = 64*64, BLOCK_B = 64};
 
        index_t a, b, c, r;
 
        SQUARE m, n, o;
 
 
 
        r  = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r;
 
 
 
        m = ppp48_sq_x [a];
 
        n = ppp48_sq_y [a];
 
        o = ppp48_sq_z [a];
 
 
 
 
 
        pw[0] = (SQUARE)b;
 
        pw[1] = m + 8;
 
        pw[2] = n + 8;
 
        pw[3] = o + 8;
 
        pw[4] = NOSQUARE;
 
 
 
        pb[0] = (SQUARE)c;
 
        pb[1] = NOSQUARE;
 
 
 
 
 
        assert (A2 
<= pw
[1] && pw
[1] < A8
);  
        assert (A2 
<= pw
[2] && pw
[2] < A8
);  
        assert (A2 
<= pw
[3] && pw
[3] < A8
);  
        assert (kpppk_pctoindex 
(pw
, pb
, &a
) && a 
== i
);  
 
 
        return;
 
}
 
 
 
 
 
static bool_t
 
kpppk_pctoindex (const SQUARE *pw, const SQUARE *pb, index_t *out)
 
{
 
        enum  {BLOCK_A = 64*64, BLOCK_B = 64};
 
        index_t ppp48_slice;
 
 
 
        SQUARE wk     = pw[0];
 
        SQUARE pawn_a = pw[1];
 
        SQUARE pawn_b = pw[2];
 
        SQUARE pawn_c = pw[3];
 
 
 
        SQUARE bk     = pb[0];
 
 
 
        SQUARE i, j, k;
 
 
 
        assert (A2 
<= pawn_a 
&& pawn_a 
< A8
);  
        assert (A2 
<= pawn_b 
&& pawn_b 
< A8
);  
        assert (A2 
<= pawn_c 
&& pawn_c 
< A8
);  
 
 
        i = pawn_a - 8;
 
        j = pawn_b - 8;
 
        k = pawn_c - 8;
 
 
 
        ppp48_slice = ppp48_idx [i] [j] [k];
 
 
 
        if (IDX_is_empty(ppp48_slice)) {
 
                wk     = flipWE (wk);
 
                pawn_a = flipWE (pawn_a);
 
                pawn_b = flipWE (pawn_b);
 
                pawn_c = flipWE (pawn_c);
 
                bk     = flipWE (bk);
 
        }
 
 
 
        i = pawn_a - 8;
 
        j = pawn_b - 8;
 
        k = pawn_c - 8;
 
 
 
        ppp48_slice = ppp48_idx [i] [j] [k];
 
 
 
        if (IDX_is_empty(ppp48_slice)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
 
 
        assert (ppp48_slice 
< MAX_PPP48_INDEX 
);  
 
 
        *out = (index_t)ppp48_slice * BLOCK_A + (index_t)wk * BLOCK_B  + (index_t)bk;
 
 
 
        return TRUE;
 
}
 
 
 
 
 
/********************** end KPPP/K ************************************/
 
 
 
 
 
static bool_t
 
kpkp_pctoindex (const SQUARE *pw, const SQUARE *pb, index_t *out)
 
{
 
        enum  {BLOCK_A = 64*64, BLOCK_B = 64};
 
        SQUARE pp_slice;
 
        SQUARE anchor, loosen;
 
 
 
        SQUARE wk     = pw[0];
 
        SQUARE bk     = pb[0];
 
        SQUARE pawn_a = pw[1];
 
        SQUARE pawn_b = pb[1];
 
 
 
        SQUARE m, n;
 
 
 
        #ifdef DEBUG
 
        if (!(A2 <= pawn_a && pawn_a < A8)) {
 
                printf ("\n\nsquare of pawn_a: %s\n", Square_str
[pawn_a
]);  
                printf(" wk %s\n p1 %s\n p2 %s\n bk %s\n"  
                        , Square_str[wk]
 
                        , Square_str[pawn_a]
 
                        , Square_str[pawn_b]
 
                        , Square_str[bk]
 
                        );
 
        }
 
        #endif
 
 
 
        assert (A2 
<= pawn_a 
&& pawn_a 
< A8
);  
        assert (A2 
<= pawn_b 
&& pawn_b 
< A8
);  
        assert (pw
[2] == NOSQUARE 
&& pb
[2] == NOSQUARE
);  
 
 
        /*pp_putanchorfirst (pawn_a, pawn_b, &anchor, &loosen);*/
 
        anchor = pawn_a;
 
        loosen = pawn_b;
 
 
 
        if ((anchor & 07) > 3) { /* column is more than 3. e.g. = e,f,g, or h */
 
                anchor = flipWE (anchor);
 
                loosen = flipWE (loosen);
 
                wk     = flipWE (wk);
 
                bk     = flipWE (bk);
 
        }
 
 
 
        m = (SQUARE)wsq_to_pidx24 (anchor);
 
        n = loosen - 8;
 
 
 
        pp_slice = m * 48 + n;
 
 
 
        if (IDX_is_empty(pp_slice)) {
 
                *out = NOINDEX;
 
                return FALSE;
 
        }
 
 
 
        assert (pp_slice 
< MAX_PpINDEX 
);  
 
 
        *out = (index_t) (pp_slice * BLOCK_A + wk * BLOCK_B  + bk);
 
 
 
        return TRUE;
 
}
 
 
 
 
 
static void
 
kpkp_indextopc (index_t i, SQUARE *pw, SQUARE *pb)
 
{
 
        /*---------------------------------------------------------*
 
                inverse work to make sure that the following is valid
 
                index = a * BLOCK_A + b * BLOCK_B + c;
 
        *----------------------------------------------------------*/
 
        enum  {B11100  = 7u << 2};
 
        enum  {BLOCK_A = 64*64, BLOCK_B = 64};
 
        enum  {block_m = 48};
 
        index_t a, b, c, r;
 
        index_t m, n;
 
        SQUARE sq_m, sq_n;
 
 
 
        r = i;
 
        a  = r / BLOCK_A;
 
        r -= a * BLOCK_A;
 
        b  = r / BLOCK_B;
 
        r -= b * BLOCK_B;
 
        c  = r;
 
 
 
        /* unpack a, which is pslice, into m and n */
 
        r = a;
 
        m  = r / block_m;
 
        r -= m * block_m;
 
        n  = r ;
 
 
 
        sq_m  = pidx24_to_wsq (m);
 
        sq_n  = (SQUARE)n + 8;
 
 
 
        pw[0] = (SQUARE)b;
 
        pb[0] = (SQUARE)c;
 
        pw[1] = sq_m;
 
        pb[1] = sq_n;
 
        pw[2] = NOSQUARE;
 
        pb[2] = NOSQUARE;
 
 
 
        assert (A2 
<= pw
[1] && pw
[1] < A8
);  
        assert (A2 
<= pb
[1] && pb
[1] < A8
);  
 
 
        return;
 
}
 
 
 
 
 
/****************************************************************************\
 
 *
 
 *
 
 *                                                              DEBUG ZONE
 
 *
 
 *
 
 ****************************************************************************/
 
 
 
#if defined(DEBUG)
 
static void
 
print_pos (const sq_t *ws, const sq_t *bs, const pc_t *wp, const pc_t *bp)
 
{
 
        int i;
 
        for (i = 0; ws[i] != NOSQUARE; i++) {
 
                printf ("%s%s ", P_str
[wp
[i
]], Square_str
[ws
[i
]]);  
        }
 
        for (i = 0; bs[i] != NOSQUARE; i++) {
 
                printf ("%s%s ", P_str
[bp
[i
]], Square_str
[bs
[i
]]);  
        }
 
}
 
#endif
 
 
 
#if defined(DEBUG) || defined(FOLLOW_EGTB)
 
static void
 
output_state (unsigned stm, const SQUARE *wSQ, const SQUARE *bSQ,
 
                                                                const SQ_CONTENT *wPC, const SQ_CONTENT *bPC)
 
{
 
        int i;
 
        assert (stm 
== WH 
|| stm 
== BL
);  
 
 
        printf("\n%s to move\n", stm
==WH
?"White":"Black");  
        for (i = 0; wSQ[i] != NOSQUARE; i++) {
 
                printf("%s%s ", P_str
[wPC
[i
]], Square_str
[wSQ
[i
]]);  
        }
 
        for (i = 0; bSQ[i] != NOSQUARE; i++) {
 
                printf("%s%s ", P_str
[bPC
[i
]], Square_str
[bSQ
[i
]]);  
        }
 
}
 
#endif
 
 
 
static void
 
list_index (void)
 
{
 
        enum  {START_GTB = 0, END_GTB = (MAX_EGKEYS)};
 
        int i;
 
        index_t accum = 0;
 
        printf ("\nIndex for each GTB\n");  
                printf ("%3s: %7s  %7s   %7s   %7s\n" , "i", "TB", "RAM-slice", "RAM-max", "HD-cumulative");  
        for (i = START_GTB; i < END_GTB; i++) {
 
                index_t indiv_k  = egkey[i].maxindex * (index_t)sizeof(dtm_t) * 2/1024;
 
                accum += indiv_k;
 
                printf ("%3d: %7s %8luk %8luk %8luM\n", i
, egkey
[i
].
str, (long unsigned)(indiv_k
/egkey
[i
].
slice_n),  
                                                                                                        (long unsigned)indiv_k, (long unsigned)accum/1024/2);
 
        }
 
        return;
 
}
 
 
 
/**************************************************************************************************************
 
 
 
 NEW_WDL
 
 
 
**************************************************************************************************************/
 
 
 
/*---------------------------------------------------------------------*\
 
|                       WDL CACHE Implementation  ZONE
 
\*---------------------------------------------------------------------*/
 
 
 
/*
 
|                       WDL CACHE Statics
 
\*---------------------------------------------------------------------*/
 
 
 
/*--------------------------------------------------------------------------*/
 
static unsigned int             wdl_extract (unit_t *uarr, index_t x);
 
static wdl_block_t *    wdl_point_block_to_replace (void);
 
static void                             wdl_movetotop (wdl_block_t *t);
 
 
 
#if 0
 
static bool_t                   wdl_cache_init (size_t cache_mem);
 
static void                             wdl_cache_flush (void);
 
static bool_t                   get_WDL (tbkey_t key, unsigned side, index_t idx, unsigned int *info_out, bool_t probe_hard_flag);
 
#endif
 
 
 
static bool_t                   wdl_cache_is_on (void);
 
static void                             wdl_cache_reset_counters (void);
 
static void                             wdl_cache_done (void);
 
 
 
static wdl_block_t *    wdl_point_block_to_replace (void);
 
static bool_t                   get_WDL_from_cache (tbkey_t key, unsigned side, index_t idx, unsigned int *out);
 
static void                             wdl_movetotop (wdl_block_t *t);
 
static bool_t                   wdl_preload_cache (tbkey_t key, unsigned side, index_t idx);
 
 
 
/*--------------------------------------------------------------------------*/
 
 
 
/*---------------------------------------------------------------------*\
 
|                       WDL CACHE Maintainance
 
\*---------------------------------------------------------------------*/
 
 
 
 
 
static size_t
 
wdl_cache_init (size_t cache_mem)
 
{
 
        unsigned int    i;
 
        wdl_block_t     *p;
 
        size_t                  entries_per_block;
 
        size_t                  max_blocks;
 
        size_t                  block_mem;
 
 
 
        if (WDL_CACHE_INITIALIZED)
 
                wdl_cache_done();
 
 
 
        entries_per_block       = 16 * 1024;  /* fixed, needed for the compression schemes */
 
 
 
        WDL_units_per_block     = entries_per_block / WDL_entries_per_unit;
 
        block_mem                       = WDL_units_per_block * sizeof(unit_t);
 
 
 
        max_blocks                      = cache_mem / block_mem;
 
        cache_mem                       = max_blocks * block_mem;
 
 
 
 
 
        wdl_cache_reset_counters ();
 
 
 
        wdl_cache.entries_per_block = entries_per_block;
 
        wdl_cache.max_blocks            = max_blocks;
 
        wdl_cache.cached                        = TRUE;
 
        wdl_cache.top                           = NULL;
 
        wdl_cache.bot                           = NULL;
 
        wdl_cache.n                             = 0;
 
 
 
        if (0 == cache_mem 
|| NULL 
== (wdl_cache.
buffer = (unit_t 
*) malloc (cache_mem
))) {  
                wdl_cache.cached = FALSE;
 
                return 0;
 
        }
 
 
 
        if (0 == max_blocks
|| NULL 
== (wdl_cache.
blocks = (wdl_block_t 
*) malloc (max_blocks 
* sizeof(wdl_block_t
)))) {  
                wdl_cache.cached = FALSE;
 
                return 0;
 
        }
 
 
 
        for (i = 0; i < max_blocks; i++) {
 
                p = &wdl_cache.blocks[i];
 
                p->key          = -1;
 
                p->side         = gtbNOSIDE;
 
                p->offset       = gtbNOINDEX;
 
                p->p_arr        = wdl_cache.buffer + i * WDL_units_per_block;
 
                p->prev         = NULL;
 
                p->next         = NULL;
 
        }
 
 
 
        wdl_cache.ht_size = 1;
 
        while (wdl_cache.ht_size < max_blocks * 4)
 
                wdl_cache.ht_size *= 2;
 
        wdl_cache.ht_used = 0;
 
        wdl_cache.
hash_table = (wdl_block_t
**) malloc (wdl_cache.
ht_size * sizeof(wdl_block_t
*));; 
        if (wdl_cache.hash_table == NULL) {
 
                wdl_cache.cached = FALSE;
 
                wdl_cache.blocks = NULL;
 
                wdl_cache.buffer = NULL;
 
                return 0;
 
        }
 
 
 
        for (i = 0; i < wdl_cache.ht_size; i++) {
 
                wdl_cache.hash_table[i] = NULL;
 
        }
 
 
 
        WDL_CACHE_INITIALIZED = TRUE;
 
 
 
        return cache_mem;
 
}
 
 
 
 
 
static void
 
wdl_cache_done (void)
 
{
 
        assert(WDL_CACHE_INITIALIZED
);  
 
 
        wdl_cache.cached = FALSE;
 
        wdl_cache.hard = 0;
 
        wdl_cache.soft = 0;
 
        wdl_cache.hardmisses = 0;
 
        wdl_cache.hits = 0;
 
        wdl_cache.softmisses = 0;
 
        wdl_cache.comparisons = 0;
 
        wdl_cache.max_blocks = 0;
 
        wdl_cache.entries_per_block = 0;
 
 
 
        wdl_cache.top = NULL;
 
        wdl_cache.bot = NULL;
 
        wdl_cache.n = 0;
 
 
 
        if (wdl_cache.buffer != NULL)
 
        wdl_cache.buffer = NULL;
 
 
 
        if (wdl_cache.blocks != NULL)
 
        wdl_cache.blocks = NULL;
 
 
 
        if (wdl_cache.hash_table != NULL)
 
                free (wdl_cache.
hash_table);  
        wdl_cache.hash_table = NULL;
 
 
 
        WDL_CACHE_INITIALIZED = FALSE;
 
        return;
 
}
 
 
 
 
 
static void
 
wdl_cache_flush (void)
 
{
 
        unsigned int    i;
 
        wdl_block_t     *p;
 
        size_t max_blocks = wdl_cache.max_blocks;
 
 
 
        wdl_cache.top                           = NULL;
 
        wdl_cache.bot                           = NULL;
 
        wdl_cache.n                             = 0;
 
 
 
        for (i = 0; i < max_blocks; i++) {
 
                p = &wdl_cache.blocks[i];
 
                p->key          = -1;
 
                p->side         = gtbNOSIDE;
 
                p->offset       = gtbNOINDEX;
 
                p->p_arr        = wdl_cache.buffer + i * WDL_units_per_block;
 
                p->prev         = NULL;
 
                p->next         = NULL;
 
        }
 
 
 
        wdl_cache_reset_counters  ();
 
 
 
        return;
 
}
 
 
 
 
 
static void
 
wdl_cache_reset_counters (void)
 
{
 
        wdl_cache.hard = 0;
 
        wdl_cache.soft = 0;
 
        wdl_cache.hardmisses = 0;
 
        wdl_cache.hits = 0;
 
        wdl_cache.softmisses = 0;
 
        wdl_cache.comparisons = 0;
 
        return;
 
}
 
 
 
 
 
static bool_t
 
wdl_cache_is_on (void)
 
{
 
        return wdl_cache.cached;
 
}
 
 
 
/****************************************************************************\
 
|                                               Replacement
 
\****************************************************************************/
 
 
 
static wdl_block_t *
 
wdl_point_block_to_replace (void)
 
{
 
        wdl_block_t *p, *t, *s;
 
 
 
        assert (0 == wdl_cache.
n || wdl_cache.
top != NULL
);  
        assert (0 == wdl_cache.
n || wdl_cache.
bot != NULL
);  
        assert (0 == wdl_cache.
n || wdl_cache.
bot->prev 
== NULL
);  
        assert (0 == wdl_cache.
n || wdl_cache.
top->next 
== NULL
);  
 
 
        if (wdl_cache.n > 0 && -1 == wdl_cache.top->key) {
 
 
 
                /* top blocks is unusable, should be the one to replace*/
 
                p = wdl_cache.top;
 
 
 
        } else
 
        if (wdl_cache.n == 0) {
 
 
 
                p = &wdl_cache.blocks[wdl_cache.n++];
 
                wdl_cache.top = p;
 
                wdl_cache.bot = p;
 
 
 
                p->prev = NULL;
 
                p->next = NULL;
 
 
 
        } else
 
        if (wdl_cache.n < wdl_cache.max_blocks) { /* add */
 
 
 
                s = wdl_cache.top;
 
                p = &wdl_cache.blocks[wdl_cache.n++];
 
                wdl_cache.top = p;
 
 
 
                s->next = p;
 
                p->prev = s;
 
                p->next = NULL;
 
 
 
        } else {                       /* replace*/
 
 
 
                t = wdl_cache.bot;
 
                s = wdl_cache.top;
 
                wdl_cache.bot = t->next;
 
                wdl_cache.top = t;
 
 
 
                s->next = t;
 
                t->prev = s;
 
                wdl_cache.top->next = NULL;
 
                wdl_cache.bot->prev = NULL;
 
 
 
                p = t;
 
        }
 
 
 
        /* make the information content unusable, it will be replaced */
 
        p->key    = -1;
 
        p->side   = gtbNOSIDE;
 
        p->offset = gtbNOINDEX;
 
 
 
        return p;
 
}
 
 
 
/****************************************************************************\
 
|
 
|                                               NEW PROBING ZONE
 
|
 
\****************************************************************************/
 
 
 
static unsigned int     wdl_extract (unit_t *uarr, index_t x);
 
static bool_t           get_WDL_from_cache (tbkey_t key, unsigned side, index_t idx, unsigned int *info_out);
 
static unsigned         dtm2WDL(dtm_t dtm);
 
static void                     wdl_movetotop (wdl_block_t *t);
 
static bool_t           wdl_preload_cache (tbkey_t key, unsigned side, index_t idx);
 
static void                     dtm_block_2_wdl_block(dtm_block_t *g, wdl_block_t *w, size_t n);
 
 
 
static bool_t
 
get_WDL (tbkey_t key, unsigned side, index_t idx, unsigned int *info_out, bool_t probe_hard_flag)
 
{
 
        dtm_t dtm;
 
        bool_t found;
 
 
 
        found = get_WDL_from_cache (key, side, idx, info_out);
 
 
 
        if (found) {
 
                wdl_cache.hits++;
 
        } else {
 
                /* may probe soft */
 
                found = get_dtm (key, side, idx, &dtm, probe_hard_flag);
 
                if (found) {
 
                        *info_out = dtm2WDL(dtm);
 
                        /* move cache info from dtm_cache to WDL_cache */
 
                        if (wdl_cache_is_on())
 
                                wdl_preload_cache (key, side, idx);
 
                }
 
        }
 
 
 
        if (probe_hard_flag) {
 
                wdl_cache.hard++;
 
                if (!found) {
 
                        wdl_cache.hardmisses++;
 
                }
 
        } else {
 
                wdl_cache.soft++;
 
                if (!found) {
 
                        wdl_cache.softmisses++;
 
                }
 
        }
 
 
 
        return found;
 
}
 
 
 
static void wdl_hash_insert (wdl_block_t * e);
 
 
 
static void
 
wdl_hash_rebuild (void)
 
{
 
        wdl_block_t     * p;
 
        size_t i;
 
 
 
        for (i = 0; i < wdl_cache.ht_size; i++)
 
                wdl_cache.hash_table[i] = NULL;
 
        wdl_cache.ht_used = 0;
 
 
 
        for (p = wdl_cache.top; p != NULL; p = p->prev)
 
                wdl_hash_insert (p);
 
}
 
 
 
static void
 
wdl_hash_insert (wdl_block_t * e)
 
{
 
        size_t h1, h2;
 
 
 
        if (wdl_cache.ht_used > wdl_cache.ht_size * 3 / 4)
 
                wdl_hash_rebuild();
 
 
 
    h1 = hash_func_1 (e->key, e->side, e->offset) & (wdl_cache.ht_size - 1);
 
    h2 = hash_func_2 (e->key, e->side, e->offset);
 
    while (wdl_cache.hash_table[h1])
 
        h1 = (h1 + h2) & (wdl_cache.ht_size - 1);
 
    wdl_cache.hash_table[h1] = e;
 
    wdl_cache.ht_used++;
 
}
 
 
 
static bool_t
 
get_WDL_from_cache (tbkey_t key, unsigned side, index_t idx, unsigned int *out)
 
{
 
        index_t         offset;
 
        index_t         remainder;
 
        wdl_block_t     *p;
 
        wdl_block_t     *ret;
 
        size_t          h1, h2;
 
 
 
        if (!wdl_cache_is_on())
 
                return FALSE;
 
 
 
        split_index (wdl_cache.entries_per_block, idx, &offset, &remainder);
 
 
 
        ret = NULL;
 
 
 
        h1 = hash_func_1 (key, side, offset) & (wdl_cache.ht_size - 1);
 
        h2 = hash_func_2 (key, side, offset);
 
        while (1) {
 
                p = wdl_cache.hash_table[h1];
 
                if (!p)
 
                        break;
 
 
 
                wdl_cache.comparisons++;
 
 
 
                if (key == p->key && side == p->side && offset  == p->offset) {
 
                        ret = p;
 
                        break;
 
                }
 
 
 
                h1 = (h1 + h2) & (wdl_cache.ht_size - 1);
 
        }
 
 
 
        if (ret != NULL) {
 
                *out = wdl_extract (ret->p_arr, remainder);
 
                wdl_movetotop(ret);
 
        }
 
 
 
        FOLLOW_LU("get_wdl_from_cache ok?",(ret != NULL))
 
 
 
        return ret != NULL;
 
}
 
 
 
static unsigned int
 
wdl_extract (unit_t *uarr, index_t x)
 
{
 
        index_t width = 2;
 
        index_t nu = x/WDL_entries_per_unit;
 
        index_t y  = x - (nu * WDL_entries_per_unit);
 
        return (uarr[nu] >> (y*width)) & WDL_entry_mask;
 
}
 
 
 
static void
 
wdl_movetotop (wdl_block_t *t)
 
{
 
        wdl_block_t *s, *nx, *pv;
 
 
 
 
 
        if (t->next == NULL) /* at the top already */
 
                return;
 
 
 
        /* detach */
 
        pv = t->prev;
 
        nx = t->next;
 
 
 
        if (pv == NULL)  /* at the bottom */
 
                wdl_cache.bot = nx;
 
        else
 
                pv->next = nx;
 
 
 
        if (nx == NULL) /* at the top */
 
                wdl_cache.top = pv;
 
        else
 
                nx->prev = pv;
 
 
 
        /* relocate */
 
        s = wdl_cache.top;
 
        if (s == NULL)
 
                wdl_cache.bot = t;
 
        else
 
                s->next = t;
 
 
 
        t->next = NULL;
 
        t->prev = s;
 
        wdl_cache.top = t;
 
 
 
        return;
 
}
 
 
 
/****************************************************************************************************/
 
 
 
static bool_t
 
wdl_preload_cache (tbkey_t key, unsigned side, index_t idx)
 
/* output to the least used block of the cache */
 
{
 
        dtm_block_t             *dtm_block;
 
        wdl_block_t     *to_modify;
 
        bool_t                  ok;
 
 
 
        FOLLOW_label("wdl preload_cache starts")
 
 
 
        if (idx >= egkey[key].maxindex) {
 
                FOLLOW_LULU("Wrong index", __LINE__, idx)
 
                return FALSE;
 
        }
 
 
 
        /* find fresh block in dtm cache */
 
        dtm_block = dtm_cache_pointblock (key, side, idx);
 
 
 
        /* find aged blocked in wdl cache */
 
        to_modify = wdl_point_block_to_replace ();
 
 
 
        ok = !(NULL == dtm_block || NULL == to_modify);
 
 
 
        if (!ok)
 
                return FALSE;
 
 
 
        /* transform and move a block */
 
        dtm_block_2_wdl_block(dtm_block, to_modify, dtm_cache.entries_per_block);
 
 
 
        if (ok) {
 
                index_t                 offset;
 
                index_t                 remainder;
 
                split_index (wdl_cache.entries_per_block, idx, &offset, &remainder);
 
 
 
                to_modify->key    = key;
 
                to_modify->side   = side;
 
                to_modify->offset = offset;
 
                wdl_hash_insert (to_modify);
 
        } else {
 
                /* make it unusable */
 
                to_modify->key    = -1;
 
                to_modify->side   = gtbNOSIDE;
 
                to_modify->offset = gtbNOINDEX;
 
        }
 
 
 
        FOLLOW_LU("wdl preload_cache?", ok)
 
 
 
        return ok;
 
}
 
 
 
/****************************************************************************************************/
 
 
 
static void
 
dtm_block_2_wdl_block(dtm_block_t *g, wdl_block_t *w, size_t n)
 
{
 
        int width = 2;
 
        int shifting;
 
        size_t i;
 
        int j;
 
        unsigned int x ,y;
 
         dtm_t *s = g->p_arr;
 
        unit_t *d = w->p_arr;
 
 
 
        for (i = 0, y = 0; i < n; i++) {
 
                j =  i & 3; /* modulo WDL_entries_per_unit */
 
                x = dtm2WDL(s[i]);
 
                shifting = j * width;
 
                y |= (x << shifting);
 
 
 
                if (j == 3) {
 
                        d[i/WDL_entries_per_unit] = (unit_t) y;
 
                        y = 0;
 
                }
 
        }
 
 
 
        if (0 != (n & 3)) { /* not multiple of 4 */
 
                d[(n-1)/WDL_entries_per_unit] = (unit_t) y; /* save the rest     */
 
                y = 0;
 
        }
 
 
 
        return;
 
}
 
 
 
static unsigned
 
dtm2WDL(dtm_t dtm)
 
{
 
        return (unsigned) dtm & 3;
 
}
 
 
 
 
 
/**************************/
 
#ifdef WDL_PROBE
 
 
 
static unsigned int     inv_wdl(unsigned w);
 
static bool_t   egtb_get_wdl (tbkey_t k, unsigned stm, const SQUARE *wS, const SQUARE *bS, bool_t probe_hard_flag, unsigned int *wdl);
 
 
 
static bool_t
 
tb_probe_wdl
 
                        (unsigned stm,
 
                         const SQUARE *inp_wSQ,
 
                         const SQUARE *inp_bSQ,
 
                         const SQ_CONTENT *inp_wPC,
 
                         const SQ_CONTENT *inp_bPC,
 
                         bool_t probingtype,
 
                         /*@out@*/ unsigned *res)
 
{
 
        tbkey_t id = -1;
 
        unsigned int wdl = iUNKNOWN;
 
 
 
        SQUARE          storage_ws [MAX_LISTSIZE], storage_bs [MAX_LISTSIZE];
 
        SQ_CONTENT  storage_wp [MAX_LISTSIZE], storage_bp [MAX_LISTSIZE];
 
 
 
        SQUARE     *ws = storage_ws;
 
        SQUARE     *bs = storage_bs;
 
        SQ_CONTENT *wp = storage_wp;
 
        SQ_CONTENT *bp = storage_bp;
 
        SQUARE          tmp_ws [MAX_LISTSIZE], tmp_bs [MAX_LISTSIZE];
 
        SQ_CONTENT  tmp_wp [MAX_LISTSIZE], tmp_bp [MAX_LISTSIZE];
 
 
 
        SQUARE *temps;
 
        bool_t straight = FALSE;
 
 
 
        bool_t  okcall  = TRUE;
 
        unsigned ply_;
 
        unsigned *ply = &ply_;
 
 
 
        /************************************/
 
 
 
        assert (stm 
== WH 
|| stm 
== BL
);  
 
 
        /* VALID ONLY FOR KK!! */
 
        if (inp_wPC[1] == NOPIECE && inp_bPC[1] == NOPIECE) {
 
                index_t dummy_i;
 
                bool_t b = kxk_pctoindex (inp_wSQ, inp_bSQ, &dummy_i);
 
                *res = b? iDRAW: iFORBID;
 
                *ply = 0;
 
                return TRUE;
 
        }
 
 
 
        /* copy input */
 
        list_pc_copy (inp_wPC, wp);
 
        list_pc_copy (inp_bPC, bp);
 
        list_sq_copy (inp_wSQ, ws);
 
        list_sq_copy (inp_bSQ, bs);
 
 
 
        sortlists (ws, wp);
 
        sortlists (bs, bp);
 
 
 
        FOLLOW_label("EGTB_PROBE")
 
 
 
        if (egtb_get_id (wp, bp, &id)) {
 
                FOLLOW_LU("got ID",id)
 
                straight = TRUE;
 
        } else if (egtb_get_id (bp, wp, &id)) {
 
                FOLLOW_LU("rev ID",id)
 
                straight = FALSE;
 
                list_sq_flipNS (ws);
 
                list_sq_flipNS (bs);
 
        temps = ws;
 
        ws = bs;
 
        bs = temps;
 
                stm = Opp(stm);
 
                /* no enpassant in this fuction, so no adjustment */
 
                {SQ_CONTENT *tempp = wp; wp = bp; bp = tempp;}  /* added */
 
        } else {
 
                #if defined(DEBUG)
 
                printf("did not get id...\n");  
                output_state (stm, ws, bs, wp, bp);
 
                #endif
 
                unpackdist (iFORBID, res, ply);
 
                return FALSE;
 
        }
 
 
 
        /* store position... */
 
        list_pc_copy (wp, tmp_wp);
 
        list_pc_copy (bp, tmp_bp);
 
        list_sq_copy (ws, tmp_ws);
 
        list_sq_copy (bs, tmp_bs);
 
 
 
        /* x will be stm and y will be stw */
 
/*
 
        if (stm == WH) {
 
        xs = ws;
 
        xp = wp;
 
        ys = bs;
 
        yp = bp;
 
    } else {
 
        xs = bs;
 
        xp = bp;
 
        ys = ws;
 
        yp = wp;
 
        }
 
*/
 
        okcall = egtb_get_wdl (id, stm, ws, bs, probingtype, &wdl);
 
 
 
        FOLLOW_LU("dtmok?",okcall)
 
        FOLLOW_DTM("wdl", wdl)
 
 
 
        if (okcall) {
 
 
 
                /*assert(epsq == NOSQUARE); */
 
 
 
                if (straight) {
 
                        *res = wdl;
 
                } else {
 
                        *res = inv_wdl (wdl);
 
                }
 
        } else {
 
                        unpackdist (iFORBID, res, ply);
 
        }
 
 
 
        return okcall;
 
}
 
 
 
static unsigned int
 
inv_wdl(unsigned w)
 
{
 
        unsigned r = tb_UNKNOWN;
 
        switch (w) {
 
                case tb_DRAW:    r = tb_DRAW;    break;
 
                case tb_WMATE:   r = tb_BMATE;   break;
 
                case tb_BMATE:   r = tb_WMATE;   break;
 
                case tb_FORBID:  r = tb_FORBID;  break;
 
                case tb_UNKNOWN: r = tb_UNKNOWN; break;
 
                default:         r = tb_UNKNOWN; break;
 
        }
 
        return r;
 
}
 
 
 
static bool_t
 
egtb_get_wdl (tbkey_t k, unsigned stm, const SQUARE *wS, const SQUARE *bS, bool_t probe_hard_flag, unsigned int *wdl)
 
{
 
        bool_t idxavail;
 
        index_t idx;
 
        dtm_t *tab[2];
 
        bool_t (*pc2idx) (const SQUARE *, const SQUARE *, index_t *);
 
 
 
        FOLLOW_label("egtb_get_wdl --> starts")
 
 
 
        if (egkey[k].status == STATUS_MALLOC || egkey[k].status == STATUS_STATICRAM) {
 
 
 
                tab[WH] = egkey[k].egt_w;
 
                tab[BL] = egkey[k].egt_b;
 
                pc2idx  = egkey[k].pctoi;
 
 
 
                idxavail = pc2idx (wS, bS, &idx);
 
 
 
                FOLLOW_LU("indexavail (RAM)",idxavail)
 
 
 
                if (idxavail) {
 
                        *wdl = dtm2WDL(tab[stm][idx]);
 
                } else {
 
                        *wdl = dtm2WDL(iFORBID);
 
                }
 
 
 
                return FALSE;
 
 
 
        } else if (egkey[k].status == STATUS_ABSENT) {
 
 
 
                pc2idx   = egkey[k].pctoi;
 
                idxavail = pc2idx (wS, bS, &idx);
 
 
 
                FOLLOW_LU("indexavail (HD)",idxavail)
 
 
 
                if (idxavail) {
 
                        bool_t success;
 
 
 
                        /*
 
                        |               LOCK
 
                        *-------------------------------*/
 
                        mythread_mutex_lock (&Egtb_lock);
 
 
 
                        success = get_WDL (k, stm, idx, wdl, probe_hard_flag);
 
                        FOLLOW_LU("get_wld (succ)",success)
 
                        FOLLOW_LU("get_wld (wdl )",*wdl)
 
 
 
                        /* this may not be needed */
 
                        if (!success) {
 
                                dtm_t dtm;
 
                                unsigned res, ply;
 
                                if (probe_hard_flag && Uncompressed) {
 
                                        success = egtb_filepeek (k, stm, idx, &dtm);
 
                                        unpackdist (dtm, &res, &ply);
 
                                        *wdl = res;
 
                                }
 
                                else
 
                                        success = FALSE;
 
                        }
 
 
 
                        mythread_mutex_unlock (&Egtb_lock);
 
                        /*------------------------------*\
 
                        |               UNLOCK
 
                        */
 
 
 
                        if (success) {
 
                                return TRUE;
 
                        } else {
 
                                if (probe_hard_flag) /* after probing hard and failing, no chance to succeed later */
 
                                        egkey[k].status = STATUS_REJECT;
 
                                *wdl = dtm2WDL(iUNKNOWN);
 
                                return FALSE;
 
                        }
 
 
 
                } else {
 
                        *wdl = dtm2WDL(iFORBID);
 
                        return  TRUE;
 
                }
 
        } else if (egkey[k].status == STATUS_REJECT) {
 
                FOLLOW_label("STATUS_REJECT")
 
                *wdl = dtm2WDL(iFORBID);
 
                return  FALSE;
 
        } else {
 
                FOLLOW_label("STATUS_WRONG!")
 
                *wdl = dtm2WDL(iFORBID);
 
                return  FALSE;
 
        }
 
 
 
}
 
#endif