
#include "RobboLito_def.h"
#include "RobboTotalBase.h"
#include <string.h>

uint64 AttN[0100]; /* demand */

static int HOP[8] = { 6, 10, 17, 15, -6, -10, -15, -17 };

static void InitAttN ()
{
  int x, y, sq;
  for (x = 0; x < 0100; x++)
    {
      AttN[x] = 0ULL;
      for (y = 0; y < 010; y++)
        {
          sq = x + HOP[y];
          if ((sq < 0) || (sq > 077))
            continue;
          if ((FileDistance (x, sq) > 2) || (RankDistance (x, sq) > 2))
            continue;
          AttN[x] |= (1ULL << sq);
        }
    }
}

uint64 SqSet[0100];
uint64 AttK[0100];

static void InitKingNormal ()
{
  int a, b, s = 0;
  for (a = A1; a <= H8; a++)
    for (b = A1; b <= H8; b++)
      {
	if (a == b || AttK[a] & SqSet[b])
	  {
	    RE_normale[64 * b + a] = -1;
	    continue;
	  }
	if (!(TRIANGOLO & SqSet[a]))
	  {
	    RE_normale[64 * b + a] = -1;
	    continue;
	  }
	if (MARGINE & SqSet[a] && !(TRI_MAR & SqSet[b]))
	  {
	    RE_normale[64 * b + a] = -1;
	    continue;
	  }
	RE_normale[64 * b + a] = s++;
      }
}

static void InitKingPedone ()
{
  int a, b, s = 0;
  for (a = A1; a <= H8; a++)
    for (b = A1; b <= H8; b++)
      {
	if (a == b || AttK[a] & SqSet[b])
	  {
	    RE_pedone[64 * b + a] = -1;
	    continue;
	  }
	if (FILE (a) >= FE)
	  {
	    RE_pedone[64 * b + a] = -1;
	    continue;
	  }
	RE_pedone[64 * b + a] = s++;
      }
}

static void InitInverse ()
{
  int wK, bK;
  for (wK = A1; wK <= H8; wK++)
    for (bK = A1; bK <= H8; bK++)
      {
	if (RE_normale[64 * wK + bK] != -1)
	  inverso_normale_re[RE_normale[64 * wK + bK]] = (wK << 6) | bK;
	if (RE_pedone[64 * wK + bK] != -1)
	  inverso_pedone_re[RE_pedone[64 * wK + bK]] = (wK << 6) | bK;
      }
}

static void InitDoubleSquare ()
{
  int a, b, s = 0;
  for (a = A1; a <= H8; a++)
    for (b = A1; b < a; b++)
      Sq2Normal[s++] = a | (b << 6);
  s = 0;
  for (a = A2; a <= H7; a++)
    for (b = A2; b < a; b++)
      Sq2Pawn[s++] = a | (b << 6);
  s = 0;
  for (a = A2; a <= H6; a++)
    for (b = A2; b < a; b++)
      Sq2Blocked[s++] = a | (b << 6);
}

static void iniz_triplo3 ()
{
  int a, b, c, s = 0;
  for (a = A1; a <= H8; a++)
    for (b = A1; b < a; b++)
      for (c = A1; c < b; c++)
	Sq3normale[s++] = a | (b << 6) | (c << 12);
  s = 0;
  for (a = A2; a <= H7; a++)
    for (b = A2; b < a; b++)
      for (c = A2; c < b; c++)
	Sq3pedone[s++] = a | (b << 6) | (c << 12);
  s = 0;
  for (a = A2; a <= H6; a++)
    for (b = A2; b < a; b++)
      for (c = A2; c < b; c++)
	Sq3blocked[s++] = a | (b << 6) | (c << 12);
}

static void iniz_lanc ()
{
  int wK, bK, K1, K2, u, sq;
  for (wK = A1; wK <= H8; wK++)
    for (bK = A1; bK <= H8; bK++)
      {
	K1 = bK;
	K2 = wK;
	u = 0;
	if (FILE (K1) >= FE)
	  {
	    u = 4;
	    LANCnor (4, K1);
	    LANCnor (4, K2);
	  }
	if (RANK (K1) >= R5)
	  {
	    u |= 2;
	    LANCnor (2, K1);
	    LANCnor (2, K2);
	  }
	if (RANK (K1) == FILE (K1) && RANK (K2) > FILE (K2))
	  u |= 1;
	else if (RANK (K1) > FILE (K1))
	  u |= 1;
	oLANC[wK][bK] = u;
      }
  for (sq = A1; sq <= H8; sq++)
    {
      lanc_pedone[0][sq] = sq;
      lanc_pedone[1][sq] = lanc_vert[sq];
      lanc_pedone[2][sq] = lanc_oriz[sq];
      lanc_pedone[3][sq] = (FH - FILE (sq)) + 8 * (R8 - RANK (sq));
    }
}

static void iniz_lanc_normale ()
{
  int i, sq, w;
  for (i = 0; i < 8; i++)
    for (sq = A1; sq <= H8; sq++)
      {
	w = sq;
	if (i & 4)
	  w = lanc_oriz[w];
	if (i & 2)
	  w = lanc_vert[w];
	if (i & 1)
	  w = lanc_diag[w];
	lanc_norm[i][sq] = w;
      }
}

static void InitDoubleSame ()
{
  int i, j;
  for (i = A1; i <= H8; i++)
    for (j = A1; j <= H8; j++)
      {
	STESSO2[i][j] =
	  (i > j) ? (i * (i + 1)) / 2 + j - i : (j * (j + 1)) / 2 + i - j;
      }
}

static void iniz_triplo ()
{
  int i, j, k, mas, mez, min;
  for (i = A1; i <= H8; i++)
    for (j = A1; j <= H8; j++)
      for (k = A1; k <= H8; k++)
	{
	  mas = MAX (MAX (i, j), k);
	  min = MIN (MIN (i, j), k);
	  if (i == mas)
	    mez = MAX (j, k);
	  if (j == mas)
	    mez = MAX (i, k);
	  if (k == mas)
	    mez = MAX (i, j);
	  STESSO3[i][j][k] = (mas * (mas - 1) * (mas - 2)) / 6 +
	                     (mez * (mez + 1)) / 2 - mez + min;
	}
}

static void pila_lanc ()
{
  int pi, sq;
  for (pi = 0; pi < 16; pi++)
    col_scamb[pi] = pi ^ 8;
  col_scamb[0] = 0;
  col_scamb[8] = 8;
  for (sq = A1; sq <= H8; sq++)
    {
      lanc_oriz[sq] = (FH - FILE (sq)) + 8 * RANK (sq);
      lanc_vert[sq] = FILE (sq) + 8 * (R8 - RANK (sq));
      lanc_diag[sq] = 8 * FILE (sq) + RANK (sq);
    }
}

boolean ITBU_DONE = FALSE;

void InitTotalBaseUtility ()
{
  int sq, i, j;
  if (ITBU_DONE)
    return;
  ITBU_DONE = TRUE;
  for (sq = A1; sq <= H8; sq++)
    SqSet[sq] = (1ULL << sq);
  for (i = A1; i <= H8; i++)
    {
      AttK[i] = 0;
      for (j = A1; j <= H8; j++)
        {
          if (MAX (FileDistance (i, j), RankDistance (i, j)) == 1)
            AttK[i] |= (1ULL << j);
        }
    }
  pila_lanc ();
  strcpy (TOTAL_BASE_DIRECTORY, "RobboTotalBase");
  strcpy (COMPRESSA_PREFISSO, "iCOMP.");
  InitAttN ();
  InitKingNormal ();
  InitKingPedone ();
  InitInverse ();
  InitDoubleSquare ();
  iniz_triplo3 ();
  iniz_lanc_normale ();
  iniz_lanc ();
  InitDoubleSame ();
  iniz_triplo ();
}

#include <stdarg.h>

static MUTEX_TYPE* SEND_LOCK = NULL;
void InitSend ()
{ SEND_LOCK = malloc (sizeof (MUTEX_TYPE)); LOCK_INIT (SEND_LOCK); }
void SEND (char* fmt, ...)
{
  va_list Value;
  if (!SEND_LOCK)
    InitSend ();
  LOCK (SEND_LOCK);
  va_start (Value, fmt);
  vfprintf (stdout, fmt, Value);
  va_end (Value);
  fflush (stdout);
  UNLOCK (SEND_LOCK);
}
