/* Pepito v1.59  -- file: probe.c --
   Copyright (c) 2000-02 Carlos del Cacho

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   Contact the author: guggenjaimito@yahoo.com
*/

/* Funciones para acceder a las tablas de finales de Eugene Nalimov !!! */

#ifndef UNIQUE_SOURCE_FILE
#  include "datos.h"
#endif

#if defined (_MSC_VER)
#define	TB_FASTCALL	__fastcall
#else
#define	TB_FASTCALL
#endif

typedef int     square;
typedef unsigned long INDEX;
typedef int     color;
typedef int     piece;

#define L_pageL	65536
#define L_tbbe_ssL      ((L_pageL - 4) / 2)
#define L_bev_broken    (L_tbbe_ssL + 1)        /* illegal or busted */
#define L_bev_mi1       L_tbbe_ssL      /* mate in 1 move */
#define L_bev_mimin     1       /* mate in 32766 moves */
#define L_bev_draw      0       /* draw */
#define L_bev_limax     (-1)    /* mated in 32765 moves */
#define L_bev_li0       (-L_tbbe_ssL)   /* mated in 0 moves */
#define	L_bev_limaxx    (-L_tbbe_ssL - 1)       /* mated in 32766 moves */
#define	L_bev_miminx    (-L_tbbe_ssL - 2)       /* mate in 32767 moves */

typedef         INDEX(TB_FASTCALL * PfnCalcIndex)
                (square *, square *, square, int fInverse);

#define FRegistered FRegisteredFun
#define PfnIndCalc PfnIndCalcFun

extern int      IDescFindFromCounters(int *);
extern int      FRegisteredFun(int, color);
extern          PfnCalcIndex PfnIndCalcFun(int, color);
extern int      TB_FASTCALL L_TbtProbeTable(int, color, INDEX);
extern int      IInitializeTb(char *pszPath);
extern int      FTbSetCacheSize(void *pv, unsigned long cbSize);



void           *EGTB_cache = NULL;

#define NEW
#define XX                   64
#define Sq_to_EGTB(a)        (((7-((a)>>3)) << 3) + ((a) & 7))

#ifndef LINUX
#define inline
#endif


inline square   SqFindKing(square * sq)
{
    return sq[4];
}

inline square   SqFindFirst(square * sq, piece pi)
{
    if (pi == sq[1])
        return sq[5];
    if (pi == sq[2])
        return sq[6];
    return sq[7];
}

inline square   SqFindSecond(square * sq, piece pi)
{
    if (pi == sq[1] && pi == sq[2])
        return sq[6];
    return sq[7];
}

inline square   SqFindThird(square * sq, piece pi)
{
    return sq[7];
}

inline square   SqFindOne(square * sq, piece pi)
{
    return sq[5];
}

//-----------------------------------------------------------------
int             InitTB()
{
    char           *EGTB_ENV = getenv("EGTB_PATH");
    if (EGTB_ENV != NULL)
        strcpy(EGTB_PATH, EGTB_ENV);
    else if (EGTB_PATH == NULL)
        strcpy(EGTB_PATH, ".");
    Nalimov = Min(IInitializeTb(EGTB_PATH), 5);

    if (Nalimov) {
        EGTB_cache = realloc(EGTB_cache, EGTB_CSIZE);
        FTbSetCacheSize(EGTB_cache, EGTB_CSIZE);
    }
    return 0;
}
//-----------------------------------------------------------------
int             ProbeTB(int ply)
{
    int            *psqW;
    int            *psqB;
    int             rgiCounters[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    int             iTb;
    int             side;
    int             fInvert;
    int             sqEnP;
    int             wi = 1,
                    W[8] = {6, 0, 0, 0, 0, 0, 0, 0};
    int             bi = 1,
                    B[8] = {6, 0, 0, 0, 0, 0, 0, 0};
    int             tbScore = -1;
    entero64        piezas;
    int             casilla;

    INDEX           ind;

// PintaTablero(Tablero);

    W[4] = Sq_to_EGTB(PosReyB);
    B[4] = Sq_to_EGTB(PosReyN);

    tab.egtb_probes++;

    piezas = Blancas ^ ReyB;
    while (piezas) {
        casilla = Msb(piezas);
        piezas ^= MASK[casilla];
        rgiCounters[Tablero[casilla] - 1]++;
        W[wi] = Tablero[casilla];
        W[wi + 4] = Sq_to_EGTB(casilla);
        wi++;
    }

    piezas = Negras ^ ReyN;
    while (piezas) {
        casilla = Lsb(piezas);
        piezas ^= MASK[casilla];
        rgiCounters[Tablero[casilla] - 2]++;
        B[bi] = Tablero[casilla] - 6;
        B[bi + 4] = Sq_to_EGTB(casilla);
        bi++;
    }

/* Print("rgiCounters: ");
 for (i=0;i<10;i++)
   Print("%d ",rgiCounters[i]);
 Print("\n");

 Print("Wpieces: ");
 for (i=0;i<8;i++)
   Print("%d ",W[i]);
 Print("\n");

 Print("Bpieces: ");
 for (i=0;i<8;i++)
   Print("%d ",B[i]);
 Print("\n");
*/
    iTb = IDescFindFromCounters(rgiCounters);

    if (iTb == 0)
        return -1;

    if (iTb > 0) {
        side = Turno ^ 1;
        fInvert = 0;
        psqW = W;
        psqB = B;
    } else {
        side = Turno;
        fInvert = 1;
        psqW = B;
        psqB = W;
        iTb = -iTb;
    }

    if (!FRegistered(iTb, side))
        return -1;              // error (no se encontró tabla)
    if (AlPaso != 64)
        sqEnP = Sq_to_EGTB(AlPaso);
    else
        sqEnP = 64;
// Print("Alpaso: %d, Ep: %d\n", AlPaso,sqEnP);

    ind = PfnIndCalc(iTb, side) (psqW, psqB, sqEnP, fInvert);

    // FReadTableToMemory (iTb, side, NULL);
    tbScore = L_TbtProbeTable(iTb, side, ind);

    if (tbScore == L_bev_broken)
        return -1;


    if (tbScore > 0)
        return ((tbScore - L_bev_mi1 - 1) * 2 + JAQUE_MATE - ply);
    if (tbScore < 0)
        return ((tbScore + L_bev_mi1) * 2 - JAQUE_MATE + ply);
    return 0;                   // tablas
}

//------------------------------------------------------------------------
int             Worth_Probing_EGTB()
{
    if (Turno)
        return ((MaterialB - MaterialN - tab.rmat_diff - 3 * PEON_VAL) < 0);
    else
        return ((MaterialN - MaterialB + tab.rmat_diff - 3 * PEON_VAL) < 0);
}
