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

void MakeTotalBlockIndex (char *);
void MakeTripleBlockIndex (char *);
void main_line (typePOS *); /* Robbo_glue.c */

int PVHashClear () { return 0; }
void HashClear () {}
void EvalHashClear () {}
int PawnHashReset() { return 0; }
void ResetHistory () {}
void ResetPositionalGain () {}
int InitMaterialValue () { return 0; }
void InitStatic () {}
void InitRandom32 () {}
boolean WhiteSEE (typePOS * POS, uint32 x) { return FALSE; }
boolean BlackSEE (typePOS * POS, uint32 x) { return FALSE; }
int TRIPLE_BASE_TABLE[16][16][16][16]; /* ? */

boolean VERIFY = FALSE;
void total_loop (typePOS * POS) /* void? */
{
}

void do_triple_directory (char * INPUT)
{
  strcpy (ROBBO_TRIPLE_DIR, INPUT);
  LoadRobboTripleBases ();
  SEND ("Fact: TripleDirectory %s loaded\n", INPUT);
}

void do_total_directory (char * INPUT)
{
  strcpy (ROBBO_TOTAL_DIR, INPUT);
  RegisterRobboTotalBases ();
  SEND ("Fact: TotalDirectory %s loaded\n", INPUT);
}

void do_set_position (typePOS * POS, char * INPUT)
{
  InitPosition (POS, INPUT);
  if (!BOARD_IS_OK)
    SEND ("Remand: Board buys not the conforming\n");
  else
    SEND ("Fact: Position set %s\n", INPUT);
}

boolean RobboTotalBaseScoreWrapper (typePOS * POSITION, int * va)
{
  int va2;
  if (!RobboTotalBaseScore (POSITION, va))
    return FALSE;
  if (!VERIFY || !TRIPLE_VALUE (POSITION, &va2, FALSE, TRUE))
    return TRUE;
  if (DISCO_PERDITA (*va) && va2 != -1)
    SEND ("Error in result: Total %d (loss) Triple %d. Demand for report!\n", *va, va2);
  if (DISCO_PATTA (*va) && va2 != 0)
    SEND ("Error in result: Total %d (draw) Triple %d. Demand for report!\n", *va, va2);
  if (DISCO_VITTORIA (*va) && va2 != 1)
    SEND ("Error in result: Total %d (win) Triple %d. Demand for report!\n", *va, va2);
  return TRUE;
}

boolean do_total_result (typePOS * POSITION)
{
  int va;
  if (!ROBBO_TOTAL_CONDITION (POSITION) || !RobboTotalBaseScoreWrapper (POSITION, &va))
    return FALSE;
  SEND ("TotalResult is %d\n", va);
  return TRUE;
}

boolean do_triple_result (typePOS * POSITION)
{
  int va;
  if (!ROBBO_TRIPLE_CONDITION (POSITION) || !TRIPLE_VALUE (POSITION, &va, FALSE, TRUE))
    return FALSE;
  SEND ("TripleResult is %d\n", va);
  return TRUE;
}

boolean do_result (typePOS * POS)
{
  int va;
  if (do_total_result (POS))
    return TRUE;
  if (do_triple_result (POS))
    return TRUE;
  SEND ("Result is not possible\n");
  return FALSE;
}

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

void ExpandFullWin (typePOS* POSITION, char* MOVE_STRING)
{
  typeMoveList LIST[256];
  typeMoveList* list;
  typeMoveList* p;
  int best = 0xff, va;
  list = CaptureMoves (POSITION, LIST, POSITION->OccupiedBW);
  list = OrdinaryMoves (POSITION, list);
  for (p = LIST; p < list; p++)
    {
      Make (POSITION, p->move);
      Mobility (POSITION);
      if (IS_ILLEGAL)
	{
	  Undo (POSITION, p->move);
	  continue;
	}
      if (!RobboTotalBaseScoreWrapper (POSITION, &va))
	{
	  Undo (POSITION, p->move);
	  SEND ("move %s TotalResult %d nototal\n", MOVE_STRING, 1);
	  return;
	}
      if (DISCO_PERDITA (va) &&
	  (POSITION->DYN->cp || MoveIsProm (p->move) || MoveIsEP (p->move)))
	va = 3; /* HACK */
      if (DISCO_PERDITA (va) && va < best)
	best = va;
      Undo (POSITION, p->move);
    }
  if (best == 0xff)
    SEND ("move %s TotalResult %d best0\n", MOVE_STRING, 1);
  else
    SEND ("move %s TotalResult %d\n", MOVE_STRING, 0x1000 + 1 + (best - 3));
}

void do_move_results (typePOS * POSITION)
{
  typeMoveList LIST[256];
  typeMoveList* list;
  typeMoveList* p;
  int va;
  char STRING[16];
  if (!do_result (POSITION))
    return;
  list = CaptureMoves (POSITION, LIST, POSITION->OccupiedBW);
  list = OrdinaryMoves (POSITION, list);
  for (p = LIST; p < list; p++)
    {
      Make (POSITION, p->move);
      Mobility (POSITION);
      if (IS_ILLEGAL)
	{
	  Undo (POSITION, p->move);
	  continue;
	}
      if (RobboTotalBaseScoreWrapper (POSITION, &va))
	{
	  if (DISCO_PERDITA (va) &&
	      (POSITION->DYN->cp || MoveIsProm (p->move) || MoveIsEP (p->move)))
	    SEND ("move %s TotalResult %d\n", Notate (p->move, STRING), 3);
	  else if (DISCO_VITTORIA (va) &&
	      (POSITION->DYN->cp || MoveIsProm (p->move) || MoveIsEP (p->move)))
	    SEND ("move %s TotalResult %d\n", Notate (p->move, STRING), 0x1000);
	  else if (!DISCO_VITTORIA (va))
	    SEND ("move %s TotalResult %d\n", Notate (p->move, STRING), va);
	  else
	    ExpandFullWin (POSITION, Notate (p->move, STRING));
	}
      else if (TRIPLE_VALUE (POSITION, &va, FALSE, TRUE))
	SEND ("move %s TripleResult %d\n", Notate (p->move, STRING), va);
      else
	SEND ("move %s NoResultKnown -100\n", Notate (p->move, STRING));
      Undo (POSITION, p->move);
    }
  SEND ("Complete with moves\n");
}

void inform ()
{
  int pale[12] = { 0, 7, 6, 4, 2, 1, 8, 15, 14, 12, 10, 9 };
  int a, b, c, d;
  int v, j;
  char BUFFER[256];
  for (d = 0; d < 12; d++)  for (c = d; c < 12; c++)
      for (b = c; b < 12; b++)  for (a = b; a < 12; a++)
	  {
	    sprintf (BUFFER, "%c%c%c%c ",
		     'a' + pale[d], 'a' + pale[c], 'a' + pale[b], 'a' + pale[a]);
	    v = TotalBaseTable[pale[a]][pale[b]][pale[c]][pale[d]];
	    if (v != -1)
	      {
		RobboTotalBase* TOTAL;
		v = v & 0xffff;
		TOTAL = TABLE_TOTAL_BASES + v;
		strcat (BUFFER, "COMP.");
		strcat (BUFFER, TOTAL->string);
		strcat (BUFFER, " ");
		for (j = 0; j < 4; j++)
		  if (TOTAL->efgh[j] != -1 && TOTAL->efgh[j] != 0xffff)
		    {
		      int w = TOTAL->efgh[j] & 0xffff;
		      if (w == v)
			continue;
		      strcat (BUFFER, "COMP.");
		      strcat (BUFFER, (TABLE_TOTAL_BASES + w)->string);
		      strcat (BUFFER, " ");
		    }
	      }
	    v = TRIPLE_BASE_TABLE[pale[a]][pale[b]][pale[c]][pale[d]];
	    if (v != -1)
	      {
		RobboTripleBase* TRIPLE;
		v = v & 0xffff;
		TRIPLE = TABLE_TRIPLE_BASES + v;
		strcat (BUFFER, TRIPLE->path);
		strcat (BUFFER, " ");
		for (j = 0; j < 4; j++)
		  if (TRIPLE->efgh[j] != -1 && TRIPLE->efgh[j] != 0xffff)
		    {
		      int w = TRIPLE->efgh[j] & 0xffff;
		      if (w == v)
			continue;
		      strcat (BUFFER, (TABLE_TRIPLE_BASES + w)->path);
		      strcat (BUFFER, " ");
		    }
	      }
	    if (strlen (BUFFER) == 5)
	      continue;
	    strcat (BUFFER, "\n");
	    SEND (BUFFER);
	  }
  SEND ("Informatory complete\n");
}

void attend_loop ()
{
  char INPUT[1024];
  typePOS POSITION[1];
  POSITION->DYN_ROOT = malloc (MAXIMUM_PLY * sizeof (typeDYNAMIC));
  POSITION->DYN = POSITION->DYN_ROOT + 1;
  while (TRUE)
    {
      fgets (INPUT, 256, stdin);
      if (INPUT[strlen (INPUT) - 1] == '\n')
	INPUT[strlen (INPUT) - 1] = 0;
      if (!strcmp (INPUT, "quit"))
	return;
      if (!strcmp (INPUT, "setup Robbo check"))
	SEND ("check for Robbo\n");
      if (!memcmp (INPUT, "TripleDirectory ", 16))
	do_triple_directory (INPUT + 16);
      if (!memcmp (INPUT, "TotalDirectory ", 15))
	do_total_directory (INPUT + 15);
      if (!memcmp (INPUT, "fen ", 4))
	do_set_position (POSITION, INPUT);
      if (!strcmp (INPUT, "verify"))
	VERIFY = TRUE;
      if (!strcmp (INPUT, "result"))
	do_result (POSITION);
      if (!strcmp (INPUT, "move-results"))
	do_move_results (POSITION);
      if (!strcmp (INPUT, "inform"))
	inform ();
      if (!strcmp (INPUT, "mainline"))
	main_line (POSITION);
      if (!memcmp (INPUT, "TotalBlockIndex", 15))
	MakeTotalBlockIndex (INPUT + 16);
      if (!memcmp (INPUT, "TripleBlockIndex", 16))
	MakeTripleBlockIndex (INPUT + 17);
    }
}

int main (int argc, char ** argv)
{
  TRY_LARGE_PAGES = FALSE;
  InitSlab (4);
  TotalBaseInit ();
  InitInitTotalBaseCache (64);
  READY_TRIPLE_BASE ();
  NUM_TRIPLE_BASES = 0;
  SetTripleBaseCache (64);
  SEND ("ready in RobboExplorer\n");
  TOTAL_VERBOSO = 0;
  BULK_BYTES = BULK_IND = 0;
  LOAD_COUNT = BULK_COUNT = DIRECT_COUNT = 0;
  TRIVIALLY_COUNT = 0;
  strcpy (ROBBO_TRIPLE_DIR, "");
  strcpy (ROBBO_TOTAL_DIR, "");
  attend_loop ();
  return 0;
}
