
#if (defined(CON_ROBBO_BUILD) && defined (UTILITIES))
#include "RobboLito.h"
#include "RobboTripleBase.h"
#include "RobboTotalBase.h"

#ifndef UTILITIES
void DrawBoard (typePOS* POSITION)
{
  char C[16] = "0PNKBBRQ";
  char ARR[256];
  int t, c, u;
  printf ("      +---+---+---+---+---+---+---+---+\n");
  for (t = R8; t >= R1; t--)
    {
      printf("   %i  |", t+1);
      for (c = FA; c <= FH; c++)
	{
	  u = POSITION->sq[c + 8 * t];
	  if (u >= 8)
	    printf ("<%c>", C[u - 8]);
	  else if (u > 0)
	    printf (" %c ", C[u]);
	  else if ((c + t) & 1)
	    printf ("   ");
	  else
	    printf (" . ");
	  printf ("|");
	}
      printf ("\n      +---+---+---+---+---+---+---+---+\n");
    }
  printf ("        a   b   c   d   e   f   g   h\n");
  EmitFen (POSITION, ARR);
  printf ("%s\n", ARR);
}
#endif

static char ENUMn[65] =
  { A1, A2, B1, B2, A3, A4, B3, B4, C1, C2, D1, D2, C3, C4, D3, D4,
    A8, A7, B8, B7, A6, A5, B6, B5, C8, C7, D8, D7, C6, C5, D6, D5,
    H1, H2, G1, G2, H3, H4, G3, G4, F1, F2, E1, E2, F3, F4, E3, E4,
    H8, H7, G8, G7, H6, H5, G6, G5, F8, F7, E8, E7, F6, F5, E6, E5, -1 };
static char ENUM_BI_PED[49] =
  { 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, -1 };
static char ENUM_BLOCKED[41] =
  { 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, -1 };
static char ENUM0[2] = { -2, -1 };

int p[4];
volatile int KING_GET;
MUTEX_TYPE VERIFY_SMP[1];

void* SMP_Verify(void* Void)
{
  int i, j, x, sq;
  char* E[4];
  int wK, bK, kg;
  int v[4];
  int s[4];
  uint64 add = 0, fail;
  uint64 O;
  int triple, total;
  typePOS POSITION[1];

  POSITION->DYN_ROOT = malloc (MAXIMUM_PLY * sizeof(typeDYNAMIC));
  POSITION->DYN = POSITION->DYN_ROOT + 1;
  POSITION->wtm = TRUE;
  POSITION->DYN->reversible = 0;
  POSITION->DYN->ep = POSITION->DYN->oo = 0;
  for (sq = A1; sq <= H8; sq++)
    POSITION->sq[sq] = 0;
  for (i = 0; i < 4; i++)
    {
      if (!p[i])
	E[i] = ENUM0;
      else if (p[i] == wEnumP || p[i] == bEnumP)
	E[i] = ENUM_BI_PED; 
      else if (p[i] == BlockedPawn)
	E[i] = ENUM_BLOCKED;
      else
	E[i] = ENUMn;
    }
  while (TRUE)
    {
      LOCK (VERIFY_SMP);
      kg = KING_GET++;
      UNLOCK (VERIFY_SMP);
      if (kg >= 0100 * 0100)
	return NULL;
      wK = kg & 077;
      bK = kg >> 06;
      if ((AttK[wK] & SqSet[bK]) || (wK == bK))
	continue;
      for (v[0] = 0; (s[0] = E[0][v[0]]) != -1; v[0]++)
	for (v[1] = 0; (s[1] = E[1][v[1]]) != -1; v[1]++)
	  for (v[2] = 0; (s[2] = E[2][v[2]]) != -1; v[2]++)
	    for (v[3] = 0; (s[3] = E[3][v[3]]) != -1; v[3]++)
	      {
		if (wK == s[0] || bK == s[0] || wK == s[1] || bK == s[1] ||
		    wK == s[2] || bK == s[2] || wK == s[3] || bK == s[3])
		  continue;
		if (p[1] && s[0] == s[1])
		  continue;
		if (p[2] && (s[0] == s[2] || s[1] == s[2]))
		  continue;
		if (p[3] && (s[0] == s[3] || s[1] == s[3] || s[2] == s[3]))
		  continue;
		if (p[0] == BlockedPawn && p[0] == p[1] &&
		    s[1] == s[0] + 1 && FILE (s[0]) != FH)
		  continue;
		if (p[0] == BlockedPawn && p[0] == p[2] &&
		    s[2] == s[0] + 1 && FILE (s[0]) != FH)
		  continue;
		if (p[0] == BlockedPawn && p[0] == p[3] &&
		    s[3] == s[0] + 1 && FILE (s[0]) != FH)
		  continue;
		
		if (p[1] == BlockedPawn && p[1] == p[0] &&
		    s[0] == s[1] + 1 && FILE (s[1]) != FH)
		  continue;
		if (p[1] == BlockedPawn && p[1] == p[2] &&
		    s[2] == s[1] + 1 && FILE (s[1]) != FH)
		  continue;
		if (p[1] == BlockedPawn && p[1] == p[3] &&
		    s[3] == s[1] + 1 && FILE (s[1]) != FH)
		  continue;
		
		if (p[2] == BlockedPawn && p[2] == p[0] &&
		    s[0] == s[2] + 1 && FILE (s[2]) != FH)
		  continue;
		if (p[2] == BlockedPawn && p[2] == p[1] &&
		    s[1] == s[2] + 1 && FILE (s[2]) != FH)
		  continue;
		if (p[2] == BlockedPawn && p[2] == p[3] &&
		    s[3] == s[2] + 1 && FILE (s[2]) != FH)
		  continue;
		
		if (p[3] == BlockedPawn && p[3] == p[0] &&
		    s[0] == s[3] + 1 && FILE (s[3]) != FH)
		  continue;
		if (p[3] == BlockedPawn && p[3] == p[1] &&
		    s[1] == s[3] + 1 && FILE (s[3]) != FH)
		  continue;
		if (p[3] == BlockedPawn && p[3] == p[2] &&
		    s[2] == s[3] + 1 && FILE (s[3]) != FH)
		  continue;
		
		if (p[0] == BlockedPawn &&
		    (wK == s[0] + 8 || bK == s[0] + 8 ||
		     (p[1] && s[0] + 8 == s[1]) ||
		     (p[2] && s[0] + 8 == s[2]) ||
		     (p[3] && s[0] + 8 == s[3])))
		  continue;
		if (p[1] == BlockedPawn &&
		    (wK == s[1] + 8 || bK == s[1] + 8 ||
		     (p[0] && s[1] + 8 == s[0]) ||
		     (p[2] && s[1] + 8 == s[2]) ||
		     (p[3] && s[1] + 8 == s[3])))
		  continue;
		if (p[2] == BlockedPawn &&
		    (wK == s[2] + 8 || bK == s[2] + 8 ||
		     (p[0] && s[2] + 8 == s[0]) ||
		     (p[1] && s[2] + 8 == s[1]) ||
		     (p[3] && s[2] + 8 == s[3])))
		  continue;
		if (p[3] == BlockedPawn &&
		    (wK == s[3] + 8 || bK == s[3] + 8 ||
		     (p[0] && s[3] + 8 == s[0]) ||
		     (p[1] && s[3] + 8 == s[1]) ||
		     (p[2] && s[3] + 8 == s[2])))
		  continue;
		wBitboardQ = wBitboardR = wBitboardBL = 
		  wBitboardBD = wBitboardN = wBitboardP = 0;
		bBitboardQ = bBitboardR = bBitboardBL = 
		  bBitboardBD = bBitboardN = bBitboardP = 0;
		POSITION->wKsq = wK;
		POSITION->bKsq = bK;
		wBitboardK = SqSet[wK];
		bBitboardK = SqSet[bK];
		POSITION->sq[wK] = wEnumK;
		POSITION->sq[bK] = bEnumK;
		for (j = 0; j < 4; j++)
		  {
		    x = s[j];
		    if (p[j])
		      POSITION->sq[x] = p[j];
		    if (p[j] == BlockedPawn)
		      {
			POSITION->sq[x] = wEnumP;
			POSITION->sq[x + 8] = bEnumP;
		      }
		    if (p[j] == wEnumB)
		      {
			if (SqSet[x] & LIGHT)
			  POSITION->sq[x] = wEnumBL;
			else
			  POSITION->sq[x] = wEnumBD;
		      }
		    if (p[j] == bEnumB)
		      {
			if (SqSet[x] & LIGHT)
			  POSITION->sq[x] = bEnumBL;
			else
			  POSITION->sq[x] = bEnumBD;
		      }
		    switch (p[j])
		      {
		      case wEnumQ:
			wBitboardQ |= SqSet[x];
			break;
		      case wEnumR:
			wBitboardR |= SqSet[x];
			break;
		      case wEnumB:
			if (SqSet[x] & LIGHT)
			  wBitboardBL |= SqSet[x];
			if (SqSet[x] & DARK)
			  wBitboardBD |= SqSet[x];
			break;
		      case wEnumN:
			wBitboardN |= SqSet[x];
			break;
		      case wEnumP:
			wBitboardP |= SqSet[x];
			break;
		      case bEnumQ:
			bBitboardQ |= SqSet[x];
			break;
		      case bEnumR:
			bBitboardR |= SqSet[x];
			break;
		      case bEnumB:
			if (SqSet[x] & LIGHT)
			  bBitboardBL |= SqSet[x];
			if (SqSet[x] & DARK)
			  bBitboardBD |= SqSet[x];
			break;
		      case bEnumN:
			bBitboardN |= SqSet[x];
			break;
		      case bEnumP:
			bBitboardP |= SqSet[x];
			break;
		      case BlockedPawn:
			wBitboardP |= SqSet[x];
			bBitboardP |= SqSet[x + 8];
			break;
		      }
		  }
		wBitboardOcc = wBitboardK | wBitboardQ | wBitboardR |
		  wBitboardBL | wBitboardBD | wBitboardN | wBitboardP;
		bBitboardOcc = bBitboardK | bBitboardQ | bBitboardR |
		  bBitboardBL | bBitboardBD | bBitboardN | bBitboardP;
		O = POSITION->OccupiedBW = wBitboardOcc | bBitboardOcc;
		POSITION->wtm = FALSE; /* TRUE / FALSE */ /* in the either */
#ifndef MAGIC_BITBOARDS
		POSITION->OccupiedL45 = 0;
		POSITION->OccupiedL90 = 0;
		POSITION->OccupiedR45 = 0;
		while (O)
		  {
		    b = BSF (O);
		    BitClear (b, O);
		    POSITION->OccupiedL45 |= SqSet[Left45[b]];
		    POSITION->OccupiedL90 |= SqSet[Left90[b]];
		    POSITION->OccupiedR45 |= SqSet[Right45[b]];
		  }
#endif
		Mobility (POSITION);
                if (POPCNT (POSITION->DYN->bKcheck) >= 3 ||
		    POPCNT (POSITION->DYN->wKcheck) >= 3)
                  goto END;
		if (IS_ILLEGAL)
		  goto END;
		if (!TRIPLE_VALUE (POSITION, &triple, FALSE, TRUE)) /* Impale! */
		  {
#if 1
		    printf ("TripleBase failed\n");
#else
		    fail++;
		    continue;
#endif
		  }
		if (!RobboTotalBaseScore (POSITION, &total))
		  printf ("TotalBase failed\n");
		add++;
		if ((add & 0xfffff) == 0)
		  printf ("Done %lld Fail %lld\n", add, fail);
		if (total == dPATT)
		  total = 0;
		else if (total == dVITT)
		  total = 1;
		else
		  total = -1;
		if (total != triple)
		  printf ("VerBad %lld %d+%d %d|%d|%d|%d trip:%d tot:%d\n",
			  add, wK, bK, s[0], s[1], s[2], s[3], triple, total);
		if (total != triple)
		  DrawBoard (POSITION);
		if (total != triple)
		  exit (1);
	      END:
		for (j = 0; j < 4; j++)
		  if (p[j])
		    POSITION->sq[s[j]] = 0;
		for (j = 0; j < 4; j++)
		  if (p[j] == BlockedPawn)
		    POSITION->sq[8 + s[j]] = 0;
		POSITION->sq[wK] = POSITION->sq[bK] = 0;
	      }
    }
  return NULL;
}

void VerifyTripleBase (int* P) /* efgh */
{
  uint64 C;
  int cpu, NUM_CPUS;
  p[0] = P[0];
  p[1] = P[1];
  p[3] = P[3];
  p[2] = P[2];
  printf ("Start %d|%d|%d|%d\n", p[0], p[1], p[2], p[3]);
  KING_GET = 0;
  NUM_CPUS = 4;
  LOCK_INIT (VERIFY_SMP);
  C = GetClock ();
  for (cpu = 0; cpu < NUM_CPUS; cpu++)
    PTHREAD_CREATE (&PTHREAD[cpu], NULL, SMP_Verify, NULL);
  for (cpu = 0; cpu < NUM_CPUS; cpu++)
    PTHREAD_JOIN (PTHREAD[cpu]);
  printf ("%.2fs AllDone %d|%d|%d|%d\n",
	  (GetClock() - C) / 1000000.0, p[0], p[1], p[2], p[3]);
}
#endif
