
#include "RobboLito.h"
#include "RobboTotalBase.h"
#include "RobboTripleBase.h"

void TotalBaseInit ()
{
  int pi1, pi2, pi3, pi4;
  int i;
  InitTotalBaseUtility (FALSE);
  NUM_TOTAL_BASES = 0;
  for (pi1 = 0; pi1 < 16; pi1++)
    for (pi2 = 0; pi2 < 16; pi2++)
      for (pi3 = 0; pi3 < 16; pi3++)
	for (pi4 = 0; pi4 < 16; pi4++)
	  TotalBaseTable[pi1][pi2][pi3][pi4] = -1;
  TABLE_TOTAL_BASES = malloc (MAX_TABLES * sizeof (RobboTotalBase));
  for (i = 0; i < MAX_TABLES; i++)
    (TABLE_TOTAL_BASES + i)->Fdata = NULL;
  for (i = 0; i < MAX_TABLES; i++)
    (TABLE_TOTAL_BASES + i)->indici = NULL;
  InitInitTotalBaseCache (1);
  TOT_INDICI = 0;
}

void total_iniz ()
{
  TOTAL_VERBOSO = 0;
  TotalBaseInit ();
  READY_TRIPLE_BASE ();
  NUM_TRIPLE_BASES = 0;
}

int RegisterRobboTotalBases ()
{
  char DIR[1024];
  DeRegisterRobboTotalBases ();
  strcpy (TOTAL_BASE_DIRECTORY, ROBBO_TOTAL_DIR);
  sprintf (DIR, "%s", TOTAL_BASE_DIRECTORY);
  GetTotalBase (DIR);
  sprintf (DIR, "%s/3", TOTAL_BASE_DIRECTORY);
  GetTotalBase (DIR);
  sprintf (DIR, "%s/4", TOTAL_BASE_DIRECTORY);
  GetTotalBase (DIR);
  sprintf (DIR, "%s/5", TOTAL_BASE_DIRECTORY);
  GetTotalBase (DIR);
  sprintf (DIR, "%s/6", TOTAL_BASE_DIRECTORY);
  GetTotalBase (DIR);
  sprintf (DIR, "%s/51", TOTAL_BASE_DIRECTORY);
  GetTotalBase (DIR);
  sprintf (DIR, "%s/42", TOTAL_BASE_DIRECTORY);
  GetTotalBase (DIR);
  sprintf (DIR, "%s/33", TOTAL_BASE_DIRECTORY);
  GetTotalBase (DIR);
  sprintf (DIR, "%s/Z", TOTAL_BASE_DIRECTORY);
  GetTotalBase (DIR);
  sprintf (DIR, "%s/345Z", TOTAL_BASE_DIRECTORY);
  GetTotalBase (DIR);
  sprintf (DIR, "%s/6Z", TOTAL_BASE_DIRECTORY);
  GetTotalBase (DIR);
  SEND ("info string "
	"%d RobboTotalBases registered with " TYPE_64_BIT " indici %dmb\n",
	NUM_TOTAL_BASES, TOT_INDICI, (int) ((TOT_INDICI * 4) >> 20));
  return TRUE;
}

int DeRegisterRobboTotalBases ()
{
  int pi1, pi2, pi3, pi4, i;
  RobboTotalBase* tb;
  for (i = 0; i < NUM_TOTAL_BASES; i++)
    {
      tb = (TABLE_TOTAL_BASES + i);
      if (tb->indici)
	free (tb->indici);
      if (tb->Fdata)
	fclose (tb->Fdata);
      tb->Fdata = NULL;
    }
  NUM_TOTAL_BASES = 0;
  TOT_INDICI = 0;
  for (pi1 = 0; pi1 < 16; pi1++)
    for (pi2 = 0; pi2 < 16; pi2++)
      for (pi3 = 0; pi3 < 16; pi3++)
	for (pi4 = 0; pi4 < 16; pi4++)
	  TotalBaseTable[pi1][pi2][pi3][pi4] = -1;
  SetTotalBaseCache (CURRENT_TOTAL_BASE_CACHE);
  return TRUE;
}

int UnLoadRobboTripleBases ()
{
  CleanupTriple ();
  ROBBO_LOAD = FALSE;
  return TRUE;
}

int LoadRobboTripleBases ()
{
  char DIR[1024];
  CleanupTriple ();
  ROBBO_LOAD = TRUE;
  strcpy (TRIPLE_DIR, ROBBO_TRIPLE_DIR);
  sprintf (DIR, "%s", TRIPLE_DIR);
  GetTripleBase (DIR);
  sprintf (DIR, "%s/2", TRIPLE_DIR);
  GetTripleBase (DIR);
  sprintf (DIR, "%s/3", TRIPLE_DIR);
  GetTripleBase (DIR);
  sprintf (DIR, "%s/4", TRIPLE_DIR);
  GetTripleBase (DIR);
  sprintf (DIR, "%s/5", TRIPLE_DIR);
  GetTripleBase (DIR);
  sprintf (DIR, "%s/6", TRIPLE_DIR);
  GetTripleBase (DIR);
  sprintf (DIR, "%s/51", TRIPLE_DIR);
  GetTripleBase (DIR);
  sprintf (DIR, "%s/42", TRIPLE_DIR);
  GetTripleBase (DIR);
  sprintf (DIR, "%s/33", TRIPLE_DIR);
  GetTripleBase (DIR);
  sprintf (DIR, "%s/345Z", TRIPLE_DIR);
  GetTripleBase (DIR);
  sprintf (DIR, "%s/Z", TRIPLE_DIR);
  GetTripleBase (DIR);
  sprintf (DIR, "%s/6Z", TRIPLE_DIR);
  GetTripleBase (DIR);
  triple_statistica ();
  return TRUE;
}

#define IsCheck \
 ( POSITION->wtm ? \
   (wBitboardK & POSITION->DYN->bAtt) :   (bBitboardK & POSITION->DYN->wAtt) )

#define IS_ILLEGAL \
 ( !POSITION->wtm ? \
   (wBitboardK & POSITION->DYN->bAtt) :   (bBitboardK & POSITION->DYN->wAtt) )

boolean Robbo_mossa (typePOS* POSITION, uint32* am, int* v, int* cap)
{
  int va, v2, av = 0xff, zv = 0x00, cp;
  typeMoveList mossa_lista[256];
  typeMoveList* q;
  uint32 m;
  if (POSITION->DYN->oo)
    return FALSE;
  if (!RobboTotalBaseScore (POSITION, &va) || va == dPERD0)
    return FALSE;
  Mobility (POSITION);
  if (IsCheck)
    EvasionMoves (POSITION, mossa_lista, 0xffffffffffffffff);
  else
    {
      q = CaptureMoves (POSITION, mossa_lista, 0xffffffffffffffff);
      OrdinaryMoves (POSITION, q);
    }
  for (q = mossa_lista; q->move; q++)
    {
      m = q->move & 0x7fff;
      POSITION->StackHeight = 0; /* HACK */
      Make (POSITION, m);
      POSITION->StackHeight = 1; /* HACK */
      Mobility (POSITION);
      if (IS_ILLEGAL)
	{
	  Undo (POSITION, m);
	  POSITION->StackHeight = 1; /* HACK */
	  continue;
	}
      if (!RobboTotalBaseScore (POSITION, &v2))
	{
	  Undo (POSITION, m);
	  POSITION->StackHeight = 1; /* HACK */
	  return FALSE;
	}
      if (DISCO_PERDITA (va))
	{
	  uint32 m3;
	  int v3;
	  if (!Robbo_mossa (POSITION, &m3, &v3, &cp))
	    {
	      Undo (POSITION, m);
	      POSITION->StackHeight = 1; /* HACK */
	      return FALSE;
	    }
	  if (v3 > zv &&
	      ((!POSITION->DYN->cp && !(m & FLAG_MASK) &&
		((!cp && (!(m3 & FLAG_MASK)))))
	       || va <= dPERD0 + 1))
	    {
	      *am = m;
	      *v = zv = v3;
	      *cap = POSITION->DYN->cp;
	    }
	}
      Undo (POSITION, m);
      POSITION->StackHeight = 1; /* HACK */
      if (DISCO_PATTA (va) && DISCO_PATTA (v2))
	{
	  *am = m;
	  *v = dPATT;
	  *cap = FALSE; /* HACK */
	  return TRUE;
	}
      if (DISCO_VITTORIA (va) && DISCO_PERDITA (v2))
	{
	  if (POSITION->sq[TO (m)] || (m & FLAG_MASK))
	    {
	      *am = m;
	      *v = v2;
	      *cap = TRUE; /* HACK */
	      return TRUE;
	    }
	  if (v2 < av)
	    {
	      *am = m;
	      *v = av = v2;
	      *cap = FALSE; /* HACK */
	    }
	}
    }
  return TRUE;
}

extern uint32 ROOT_BEST_MOVE;
boolean RobboFare (typePOS* POSITION)
{
  int va, v2, cp;
  uint32 m;
  POSITION->DYN->HASH ^= 0xfa73e65b089c41d2;
  SEARCH_ROBBO_BASES = TRUE;
  Eval (POSITION, -0x7fff0000, 0x7fff0000, 0);
  POSITION->DYN->HASH ^= 0xfa73e65b089c41d2;
  if (POSITION->DYN->exact)
    SEARCH_ROBBO_BASES = FALSE;
  else
    SEARCH_ROBBO_BASES = TRUE;
  if (!ROBBO_TOTAL_CONDITION (POSITION) || !RobboTotalBaseScore (POSITION, &va))
    return FALSE;
  if (!Robbo_mossa (POSITION, &m, &v2, &cp))
    return FALSE;
  if (DISCO_PATTA (va))
    {
      SEND ("info depth 0 score cp 0 pv %s\n", Notate (m, STRING1[POSITION->cpu]));
      ROOT_BEST_MOVE = m;
      return TRUE;
    }
  if (DISCO_PERDITA (va))
    {
      SEND ("info depth 0 score cp %d pv %s\n",
	    -28000 + 1000 * POPCNT (POSITION->OccupiedBW) + v2,
	    Notate (m, STRING1[POSITION->cpu]));
      ROOT_BEST_MOVE = m;
      return TRUE;
    }
  if (DISCO_VITTORIA (va))
    {
      SEND ("info depth 0 score cp %d pv %s\n",
	    28000 - 1000 * POPCNT (POSITION->OccupiedBW) - v2,
	    Notate (m, STRING1[POSITION->cpu]));
      ROOT_BEST_MOVE = m;
      return TRUE;
    }
  return FALSE;
}

static void main_line_iterate (typePOS* POSITION)
{
  int va, v2, cp;
  uint32 m;
  (POSITION->DYN + 1)->move = MOVE_NONE;
  Mobility (POSITION);
  if (!RobboTotalBaseScore (POSITION, &va))
    {
      SEND ("info string Failure in main_line\n");      
      (POSITION->DYN + 1)->move = MOVE_NONE;
      POSITION->StackHeight = 0; /* HACK */
      return;
    }
  if (!Robbo_mossa (POSITION, &m, &v2, &cp))
    {
      (POSITION->DYN + 1)->move = MOVE_NONE;
      POSITION->StackHeight = 0; /* HACK */
      return;
    }
  if (va == dPATT)
    {
      POSITION->StackHeight = 0; /* HACK */
      Make (POSITION, m);
      POSITION->StackHeight = 1; /* HACK */
      Undo (POSITION, m);
      return;
    }
  m &= 0x7fff;
  POSITION->StackHeight = 0; /* HACK */
  Make (POSITION, m);
  POSITION->StackHeight = 1; /* HACK */
  main_line_iterate (POSITION);
  Undo (POSITION, m);
  POSITION->StackHeight = 1; /* HACK */
}

void main_line (typePOS* POSITION)
{
  typeDYNAMIC* p;
  char STRING[16];
  int va;
  main_line_iterate (POSITION);
  if (!RobboTotalBaseScore (POSITION, &va) || va == dROTT)
    {
      SEND ("info string Failure in main_line\n");
      return;
    }
  sprintf (STRING, "%d", va - dPERD0);
  printf ("mainline (%c%s): ", (va == dVITT) ? 'W' : ((va == dPATT) ? 'D' : 'L'),
	  (va < dPERD0) ? "" : STRING);
  for (p = POSITION->DYN + 1; p->move; p++)
    printf ("%s ", Notate (p->move & 0x7fff, STRING));
  SEND ("\n");
}
