mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2024-11-24 11:52:35 +01:00
8040 lines
178 KiB
C
8040 lines
178 KiB
C
/*
|
|
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 char Buffer_zipped [EGTB_MAXBLOCKSIZE];
|
|
static unsigned char Buffer_packed [EGTB_MAXBLOCKSIZE];
|
|
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) {
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
#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}
|
|
|
|
};
|
|
|
|
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;
|
|
|
|
psize = strlen(newpath) + 1;
|
|
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;
|
|
|
|
psize = strlen(newpath) + 1;
|
|
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++;
|
|
}
|
|
|
|
free(mpath);
|
|
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];
|
|
free(p);
|
|
}
|
|
/* cast to deal with const poisoning */
|
|
q = (void *) ps;
|
|
free(q);
|
|
}
|
|
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)
|
|
free(p);
|
|
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(char *s, const char *tail, size_t max) {strncat(s, tail, max - strlen(s) - 1);}
|
|
|
|
char *
|
|
tb_init (int verbosity, int decoding_sch, const char **paths)
|
|
{
|
|
unsigned int zi;
|
|
int paths_ok;
|
|
char *ret_str;
|
|
char localstr[256];
|
|
|
|
assert(!TB_INITIALIZED);
|
|
|
|
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;
|
|
assert(Gtbpath!=NULL);
|
|
sjoin(ini_str,"\nGTB PATHS\n",INISIZE);
|
|
for (g = 0; Gtbpath[g] != NULL; g++) {
|
|
const char *p = Gtbpath[g];
|
|
if (0 == g) {
|
|
sprintf (localstr," main: %s\n", p);
|
|
} else {
|
|
sprintf (localstr," #%d: %s\n", g, p);
|
|
}
|
|
sjoin(ini_str,localstr,INISIZE);
|
|
}
|
|
}
|
|
|
|
if (!paths_ok && verbosity) {
|
|
sjoin (ini_str,"\nGTB PATHS not initialized\n",INISIZE);
|
|
}
|
|
|
|
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 (ini_str," File Open Memory initialization = **FAILED**\n",INISIZE);
|
|
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 (ini_str,"\nGTB initialization\n",INISIZE);
|
|
sprintf (localstr," Compression Scheme = %d\n", GTB_scheme);
|
|
sjoin (ini_str,localstr,INISIZE);
|
|
}
|
|
|
|
zi = zipinfo_init();
|
|
|
|
TB_AVAILABILITY = zi;
|
|
|
|
if (verbosity) {
|
|
if (0 == zi) {
|
|
sjoin (ini_str," Compression Indexes = **FAILED**\n",INISIZE);
|
|
} else {
|
|
int n, bit;
|
|
|
|
n = 3; bit = 1;
|
|
if (zi&(1u<<bit))
|
|
sprintf (localstr," Compression Indexes (%d-pc) = PASSED\n",n);
|
|
else
|
|
sprintf (localstr," Compression Indexes (%d-pc) = **FAILED**\n",n);
|
|
sjoin (ini_str,localstr,INISIZE);
|
|
|
|
n = 4; bit = 3;
|
|
if (zi&(1u<<bit))
|
|
sprintf (localstr," Compression Indexes (%d-pc) = PASSED\n",n);
|
|
else
|
|
sprintf (localstr," Compression Indexes (%d-pc) = **FAILED**\n",n);
|
|
sjoin (ini_str,localstr,INISIZE);
|
|
|
|
n = 5; bit = 5;
|
|
if (zi&(1u<<bit))
|
|
sprintf (localstr," Compression Indexes (%d-pc) = PASSED\n",n);
|
|
else
|
|
sprintf (localstr," Compression Indexes (%d-pc) = **FAILED**\n",n);
|
|
sjoin (ini_str,localstr,INISIZE);
|
|
}
|
|
sjoin (ini_str,"\n",INISIZE);
|
|
}
|
|
|
|
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)
|
|
{
|
|
assert(TB_INITIALIZED);
|
|
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;
|
|
|
|
assert(pfd != NULL);
|
|
|
|
for (i = 0; i < pfd->n; i++) {
|
|
closingkey = pfd->key[i];
|
|
finp = egkey [closingkey].fd;
|
|
fclose (finp);
|
|
egkey[closingkey].fd = NULL;
|
|
pfd->key[i] = -1;
|
|
}
|
|
pfd->n = 0;
|
|
free(pfd->key);
|
|
}
|
|
|
|
/****************************************************************************\
|
|
|
|
|
|
|
|
| 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;
|
|
|
|
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 (Uncompressed);
|
|
assert (side == WH || side == BL);
|
|
assert (out_dtm != NULL);
|
|
assert (idx >= 0);
|
|
assert (key < MAX_EGKEYS);
|
|
|
|
|
|
#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)
|
|
fclose (finp);
|
|
#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 {
|
|
assert(Uncompressed);
|
|
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!")
|
|
|
|
assert(0);
|
|
*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;
|
|
assert (finp != NULL);
|
|
fclose (finp);
|
|
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;
|
|
}
|
|
|
|
assert (fd.n < GTB_MAXOPEN);
|
|
|
|
/* 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];
|
|
size_t pl = strlen(path);
|
|
/*@@
|
|
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];
|
|
size_t pl = strlen(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;
|
|
}
|
|
|
|
#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;
|
|
|
|
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;
|
|
}
|
|
|
|
for (i = 0, found = FALSE; !found && egkey[i].str != NULL; i++) {
|
|
found = (0 == strcmp(pcstr, egkey[i].str));
|
|
}
|
|
if (found) {
|
|
cache_i = *id = i - 1;
|
|
}
|
|
|
|
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)
|
|
{
|
|
assert (inf <= INFOMASK);
|
|
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
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
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;
|
|
assert(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;
|
|
assert(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);
|
|
assert (finp != NULL);
|
|
assert (idx >= 0);
|
|
i = ((index_t)side * max + idx) * sz;
|
|
fseek_i = (long int) i;
|
|
assert (fseek_i >= 0);
|
|
ok = (0 == fseek (finp, fseek_i, SEEK_SET));
|
|
return ok;
|
|
}
|
|
|
|
/*----------------------------------------------------*\
|
|
|
|
|
| shared by probe and build
|
|
|
|
|
\*/
|
|
|
|
|
|
/*---------------------------------------------------------------------*\
|
|
| 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 */
|
|
|
|
/* 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;
|
|
|
|
/* 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;
|
|
free (dtm_cache.buffer);
|
|
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_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)
|
|
free (dtm_cache.buffer);
|
|
dtm_cache.buffer = NULL;
|
|
|
|
if (dtm_cache.entry != NULL)
|
|
free (dtm_cache.entry);
|
|
dtm_cache.entry = 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 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;
|
|
|
|
if (!dtm_cache_is_on())
|
|
return NULL;
|
|
|
|
split_index (dtm_cache.entries_per_block, idx, &offset, &remainder);
|
|
|
|
ret = NULL;
|
|
|
|
for (p = dtm_cache.top; p != NULL; p = p->prev) {
|
|
|
|
dtm_cache.comparisons++;
|
|
|
|
if (key == p->key && side == p->side && offset == p->offset) {
|
|
ret = p;
|
|
break;
|
|
}
|
|
}
|
|
|
|
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;
|
|
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;
|
|
assert (n_idx <= MAXINDEX_T);
|
|
Zipinfo[key].totalblocks = (index_t) n_idx;
|
|
Zipinfo[key].blockindex = p;
|
|
}
|
|
|
|
if (!ok && p != NULL) {
|
|
free(p);
|
|
}
|
|
|
|
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);
|
|
assert (key < MAX_EGKEYS);
|
|
|
|
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;
|
|
assert (key < MAX_EGKEYS);
|
|
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;
|
|
assert (fseek_i >= 0);
|
|
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;
|
|
for (i = 0; i < n; i++) {
|
|
*out++ = dtm_unpack (side, 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;
|
|
|
|
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)
|
|
|
|
ok = ok
|
|
&& egtb_block_decode (key, z, Buffer_zipped, n, Buffer_packed);
|
|
FOLLOW_LULU("preload_cache", __LINE__, ok)
|
|
|
|
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;
|
|
} 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);
|
|
free (egkey[i].egt_w);
|
|
free (egkey[i].egt_b);
|
|
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;
|
|
|
|
assert (NULL != 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;
|
|
|
|
assert (dtm_cache.top);
|
|
dtm_cache.top->next = NULL;
|
|
|
|
assert (dtm_cache.bot);
|
|
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;
|
|
|
|
assert (t != NULL);
|
|
|
|
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;
|
|
assert (s != NULL);
|
|
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++;
|
|
}
|
|
}
|
|
}
|
|
|
|
assert (idx == MAX_KKINDEX);
|
|
|
|
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);
|
|
assert (aabase [idx] == x);
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
assert (idx == MAX_AAINDEX);
|
|
|
|
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;
|
|
assert (idx < MAX_PPINDEX);
|
|
pp_hi24 [idx] = i;
|
|
assert (i < 24);
|
|
pp_lo48 [idx] = j;
|
|
assert (j < 48);
|
|
idx++;
|
|
}
|
|
|
|
}
|
|
}
|
|
assert (idx == MAX_PPINDEX);
|
|
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;
|
|
|
|
assert (x < 64);
|
|
assert (y < 64);
|
|
|
|
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;
|
|
|
|
assert (x < 64);
|
|
assert (y < 64);
|
|
|
|
|
|
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);
|
|
assert ((pawn & 07) < 4);
|
|
|
|
sq ^= 070; /* flipNS*/
|
|
sq -= 8; /* down one row*/
|
|
idx24 = (sq+(sq&3)) >> 1;
|
|
assert (idx24 < 24);
|
|
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;
|
|
assert (idx48 < 48);
|
|
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 */
|
|
assert (a < 24);
|
|
|
|
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;
|
|
assert (a < 48);
|
|
/* 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]);
|
|
|
|
assert (ft < 8);
|
|
|
|
|
|
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]);
|
|
|
|
assert (ft < 8);
|
|
|
|
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
|
|
|
|
assert (ft < 8);
|
|
|
|
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]];
|
|
|
|
assert (ft < 8);
|
|
|
|
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
|
|
|
|
assert (ft < 8);
|
|
|
|
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;
|
|
|
|
printf ("%8s ", str);
|
|
|
|
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;
|
|
}
|
|
assert (i == j);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((a&1)==0) {
|
|
printf(".");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
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]];
|
|
|
|
assert (ft < 8);
|
|
|
|
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;
|
|
|
|
printf ("%8s ", str);
|
|
|
|
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;
|
|
}
|
|
assert (i == j);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((a&1)==0) {
|
|
printf(".");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
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]];
|
|
|
|
assert (ft < 8);
|
|
|
|
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;
|
|
|
|
printf ("%8s ", str);
|
|
|
|
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;
|
|
}
|
|
assert (i == j);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((a&1)==0) {
|
|
printf(".");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
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]];
|
|
|
|
assert (ft < 8);
|
|
|
|
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++;
|
|
}
|
|
}
|
|
}
|
|
|
|
assert (idx == MAX_AAAINDEX);
|
|
|
|
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);
|
|
assert (x < y && y < z);
|
|
|
|
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;
|
|
|
|
printf ("%8s ", str);
|
|
|
|
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;
|
|
}
|
|
assert (i == j);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((a&1)==0) {
|
|
printf(".");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
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));
|
|
assert (b < BLOCK_A);
|
|
|
|
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]];
|
|
|
|
assert (ft < 8);
|
|
|
|
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;
|
|
|
|
printf ("%8s ", str);
|
|
|
|
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;
|
|
}
|
|
assert (i == j);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((a&1)==0) {
|
|
printf(".");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
printf ("%8s ", str);
|
|
|
|
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;
|
|
}
|
|
assert (i == j);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((a&1)==0) {
|
|
printf(".");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
printf ("%8s ", str);
|
|
|
|
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;
|
|
}
|
|
assert (i == j);
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((a&1)==0) {
|
|
printf(".");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
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]];
|
|
|
|
assert (ft < 8);
|
|
|
|
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;
|
|
|
|
printf ("%8s ", str);
|
|
|
|
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;
|
|
}
|
|
assert (i == j);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((a&1)==0) {
|
|
printf(".");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
printf ("%8s ", str);
|
|
|
|
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;
|
|
}
|
|
assert (i == j);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((a&1)==0) {
|
|
printf(".");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
printf ("%8s ", str);
|
|
|
|
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;
|
|
}
|
|
assert (i == j);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((a&1)==0) {
|
|
printf(".");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
printf ("%8s ", str);
|
|
|
|
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;
|
|
}
|
|
assert (i == j);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((a&1)==0) {
|
|
printf(".");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
printf ("%8s ", str);
|
|
|
|
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;
|
|
}
|
|
assert (i == j);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((a&1)==0) {
|
|
printf(".");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
assert (i >= 0);
|
|
|
|
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]);
|
|
assert (aaidx[x][y] == d);
|
|
|
|
|
|
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;
|
|
|
|
assert (*out >= 0);
|
|
|
|
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;
|
|
|
|
printf ("%8s ", str);
|
|
|
|
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;
|
|
}
|
|
assert (i == j);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((a&1)==0) {
|
|
printf(".");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
assert (i >= 0);
|
|
|
|
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]);
|
|
assert (aaidx[x][y] == d);
|
|
|
|
|
|
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;
|
|
|
|
assert (*out >= 0);
|
|
|
|
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;
|
|
|
|
printf ("%8s ", str);
|
|
|
|
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;
|
|
}
|
|
assert (i == j);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((a&1)==0) {
|
|
printf(".");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
printf ("%8s ", str);
|
|
|
|
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;
|
|
}
|
|
assert (i == j);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((a&1)==0) {
|
|
printf(".");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
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;
|
|
printf ("White: ");
|
|
for (i = 0; ws[i] != NOSQUARE; i++) {
|
|
printf ("%s%s ", P_str[wp[i]], Square_str[ws[i]]);
|
|
}
|
|
printf ("\nBlack: ");
|
|
for (i = 0; bs[i] != NOSQUARE; i++) {
|
|
printf ("%s%s ", P_str[bp[i]], Square_str[bs[i]]);
|
|
}
|
|
printf ("\n");
|
|
}
|
|
#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");
|
|
printf("W: ");
|
|
for (i = 0; wSQ[i] != NOSQUARE; i++) {
|
|
printf("%s%s ", P_str[wPC[i]], Square_str[wSQ[i]]);
|
|
}
|
|
printf("\n");
|
|
printf("B: ");
|
|
for (i = 0; bSQ[i] != NOSQUARE; i++) {
|
|
printf("%s%s ", P_str[bPC[i]], Square_str[bSQ[i]]);
|
|
}
|
|
printf("\n\n");
|
|
}
|
|
#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);
|
|
}
|
|
printf ("\n");
|
|
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;
|
|
free (wdl_cache.buffer);
|
|
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_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)
|
|
free (wdl_cache.buffer);
|
|
wdl_cache.buffer = NULL;
|
|
|
|
if (wdl_cache.blocks != NULL)
|
|
free (wdl_cache.blocks);
|
|
wdl_cache.blocks = 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 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;
|
|
|
|
if (!wdl_cache_is_on())
|
|
return FALSE;
|
|
|
|
split_index (wdl_cache.entries_per_block, idx, &offset, &remainder);
|
|
|
|
ret = NULL;
|
|
for (p = wdl_cache.top; p != NULL; p = p->prev) {
|
|
|
|
wdl_cache.comparisons++;
|
|
|
|
if (key == p->key && side == p->side && offset == p->offset) {
|
|
ret = p;
|
|
break;
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
assert (t != NULL);
|
|
|
|
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;
|
|
assert (s != NULL);
|
|
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;
|
|
} 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) {
|
|
assert(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!")
|
|
assert(0);
|
|
*wdl = dtm2WDL(iFORBID);
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
|