//#define ZEROCACHE 1
/*
 * util.c - C source for GNU CHESS
 *
 * Copyright (c) 1988,1989,1990 John Stanback
 * Copyright (c) 1992 Free Software Foundation
 *
 * This file is part of GNU CHESS.
 *
 * GNU Chess 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.
 *
 * GNU Chess 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 GNU Chess; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include "gnuchess.h"
unsigned int __aligned TTadd = 1;
short int __aligned recycle;
short int __aligned ISZERO = 1;
extern char mvstr[8][8];
#ifdef CACHE
extern struct etable __far __aligned etab[2][ETABLE];
#endif

int
parse (FILE * fd, short unsigned int *mv, short int side, char *opening)
{
  register int c, i, r1, r2, c1, c2;
  char s[128];
  char *p;

  while ((c = getc (fd)) == ' ' || c == '\n') ;
  i = 0;
  s[0] = (char) c;
  if (c == '!')
    {
      p = opening;
      do
	{
	  *p++ = c;
	  c = getc (fd);
	  if (c == '\n' || c == EOF)
	    {
	      *p = '\0';
	      return 0;
	    }
      } while (true);
    }
  while (c != '?' && c != ' ' && c != '\t' && c != '\n' && c != EOF)
    s[++i] = (char) (c = getc (fd));
  s[++i] = '\0';
  if (c == EOF)
    return (-1);
  if (s[0] == '!' || s[0] == ';' || i < 3)
    {
      while (c != '\n' && c != EOF)
	c = getc (fd);
      return (0);
    }
  if (s[4] == 'o')
    *mv = ((side == black) ? LONGBLACKCASTLE : LONGWHITECASTLE);
  else if (s[0] == 'o')
    *mv = ((side == black) ? BLACKCASTLE : WHITECASTLE);
  else
    {
      c1 = s[0] - 'a';
      r1 = s[1] - '1';
      c2 = s[2] - 'a';
      r2 = s[3] - '1';
      *mv = (locn (r1, c1) << 8) | locn (r2, c2);
    }
  if (c == '?')
    {				/* Bad move, not for the program to play */
      *mv |= 0x8000;		/* Flag it ! */
      c = getc (fd);
    }
  return (1);
}

#ifdef OLDTTABLE

#if ttblsz

#define CB(i) (unsigned char) ((color[2 * (i)] ? 0x80 : 0)\
	       | (board[2 * (i)] << 4)\
	       | (color[2 * (i) + 1] ? 0x8 : 0)\
	       | (board[2 * (i) + 1]))

int
ProbeTTable (short int side,
	     short int depth,
	     short int ply,
	     short int *alpha,
	     short int *beta,
	     short int *score)

/*
 * Look for the current board position in the transposition table.
 */

{
  register struct hashentry *ptbl;
  register /*unsigned*/ short i= 0;  /*to match new type of rehash --tpm*/

  ptbl = &ttable[side][hashkey % (ttblsize)];

  while (true)
    {
      if (ptbl->depth == 0)
	return false;
      if (ptbl->hashbd == hashbd)
	break;
      if (++i > rehash)
	return false;
      ptbl++;
    }

  /* rehash max rehash times */
  PV = SwagHt = ptbl->mv; // this is out of loop, in loop was wierd
  if ((ptbl->depth >= (short) depth))
    {
#ifdef HASHTEST
      for (i = 0; i < 32; i++)
	{
	  if (ptbl->bd[i] != CB (i))
	    {
#ifndef BAREBONES
	      HashCol++;
	      ShowMessage (CP[199]);	/*ttable collision detected*/
#endif
	      break;
	    }
	}
#endif /* HASHTEST */


//      PV = SwagHt = ptbl->mv; // was in loop in 4PL64 moved out for better perf
#ifndef BAREBONES
      HashCnt++;
#endif
      if (ptbl->flags & truescore)
	{
	  *score = ptbl->score;
	  /* adjust *score so moves to mate is from root */
	  if (*score > 9000)
	    *score -= ply;
	  else if (*score < -9000)
	    *score += ply;
	  *beta = -20000;
	}
      else if (ptbl->flags & lowerbound)
	{
	  if (ptbl->score > *alpha)
	    *alpha = ptbl->score; //  - 1;  FIX by K. Sian, was ptbl->score - 1
	}
      return (true);
    }
  return (false);
}



#ifndef V4PL66
int
PutInTTable (short side,
             short score,
             short depth,
             short ply,
             short alpha,
             short beta,
             unsigned short mv)

/*
 * Store the current board position in the transposition table.
 */

{
  register struct hashentry *ptbl;
  register /*unsigned*/ short i = 0;    /*to match new type of rehash --tpm*/

  ptbl = &ttable[side][hashkey % ttblsize];
  while (true)
    {
      if (ptbl->depth == 0 || ptbl->hashbd == hashbd)
        break;
      if (++i > rehash)
        {
#ifndef BAREBONES
          THashCol++;
#endif
          ptbl += recycle;
          break;
        }
      ptbl++;
    }

  TTadd++;
#ifndef BAREBONES
  HashAdd++;
#endif
  ptbl->hashbd = hashbd;
  ptbl->depth = (unsigned char) depth;
  ptbl->mv = mv;
#ifdef DEBUG
  if (debuglevel & 32)
    {
      algbr (mv >> 8, mv & 0xff, 0);
      printf ("-add-> h=%lx d=%d s=%d p=%d a=%d b=%d %s\n", hashbd, depth,
                 score , ply, alpha, beta, mvstr);
    }
#endif
  if (score > beta)
    {
      ptbl->flags = lowerbound;
      ptbl->score = beta + 1;
    }
  else
    {
      ptbl->flags = truescore;
      /* adjust score so moves to mate is from this ply */
      if (score > 9000)
        score += ply;
      else if (score < -9000)
        score -= ply;
      ptbl->score = score;
    }

#ifdef HASHTEST
  for (i = 0; i < 32; i++)
    {
      ptbl->bd[i] = CB (i);
    }
#endif /* HASHTEST */
  return true;
}

#else
int
PutInTTable (short int side,
	     short int score,
	     short int depth,
	     short int ply,
	     short int alpha,
	     short int beta,
	     short unsigned int mv)

/*
 * Store the current board position in the transposition table.
 */

{
  register struct hashentry *ptbl;
  register /*unsigned*/ short i= 0;  /*to match new type of rehash --tpm*/

  ptbl = &ttable[side][hashkey % (ttblsize)];

  while (true)
    {
//      if (ptbl->depth == 0 || ptbl->hashbd == hashbd)
//	break;
       if (ptbl->depth == 0) break;
       else if(ptbl->hashbd == hashbd  && ptbl->depth > depth && abs(score) <9000) 
         return false;
       else if (ptbl->hashbd == hashbd) break;
      if (++i > rehash)
	{
#ifndef BAREBONES
	  THashCol++;
#endif
	  ptbl += recycle;
	  break;
	}
      ptbl++;
    }

#ifndef BAREBONES
  TTadd++;
  HashAdd++;
#endif
  /* adjust score so moves to mate is from this ply */
  if (score > 9000)
    score += ply;
  else if (score < -9000)
    score -= ply;
  ptbl->hashbd = hashbd;
  ptbl->depth = (unsigned char) depth;
  ptbl->score = score;
  ptbl->mv = mv;
#ifdef DEBUG4
  if (debuglevel & 32)
    {
      algbr (mv >> 8, mv & 0xff, 0);
      printf ("-add-> h=%lx d=%d s=%d p=%d a=%d b=%d %s\n", hashbd, depth, score, ply, alpha, beta, mvstr);
    }
#endif
  if (score > beta)
    {
      ptbl->flags = lowerbound;
      ptbl->score = beta + 1;
    }
  else
    ptbl->flags = truescore;

#ifdef HASHTEST
  for (i = 0; i < 32; i++)
    {
      ptbl->bd[i] = CB (i);
    }
#endif /* HASHTEST */
  return true;
}
#endif // 4pl66

   
// static struct hashentry *ttagew, *ttageb;

void
ZeroTTable (void)
{
//   register struct hashentry *w, *b;

/* I am adding these 2 memsets! */
 if (!TTadd)
  return;
#ifndef AMIGA
  memset((char *)ttable[0],0,sizeof(struct hashentry)*(ttblsize+rehash));
  memset((char *)ttable[1],0,sizeof(struct hashentry)*(ttblsize+rehash));
#else
  ClearMem(ttable[0],sizeof(struct hashentry)*(ttblsize+rehash));
  ClearMem(ttable[1],sizeof(struct hashentry)*(ttblsize+rehash));
#endif
#ifdef ZEROCACHE
#ifdef CACHE
#ifndef AMIGA
   memset ((char *) etab, 0, sizeof (etab));
#else
   ClearMem(etab,sizeof(etab));
#endif // amiga
#endif // cache
#endif // zerocache
    TTadd = 0; 
}

#ifdef HASHFILE
int Fbdcmp(char *a,char *b)
{
	register int i;
	for(i = 0;i<32;i++)
		if(a[i] != b[i])return false;
	return true;
}
int
ProbeFTable (short int side,
	     short int depth,
	     short int ply,
	     short int *alpha,
	     short int *beta,
	     short int *score)

/*
 * Look for the current board position in the persistent transposition table.
 */

{
  register short int i;
  register unsigned long hashix;
  struct fileentry new, t;

  hashix = ((side == white) ? (hashkey & 0xFFFFFFFE) : (hashkey | 1)) & filesz;

  for (i = 0; i < 32; i++)
    new.bd[i] = CB (i);
  new.flags = 0;
  if (Mvboard[kingP[side]] == 0)
    {
      if (Mvboard[qrook[side]] == 0)
	new.flags |= queencastle;
      if (Mvboard[krook[side]] == 0)
	new.flags |= kingcastle;
    }
  for (i = 0; i < frehash; i++)
    {
      fseek (hashfile,
	     sizeof (struct fileentry) * ((hashix + 2 * i) & (filesz)),
	     SEEK_SET);
      fread (&t, sizeof (struct fileentry), 1, hashfile);
      if (!t.depth) break;
       if(!Fbdcmp(t.bd, new.bd)) continue;
      if (((short int) t.depth >= depth) 
	  && (new.flags == (unsigned short)(t.flags & (kingcastle | queencastle))))
	{
#ifndef BAREBONES
	  FHashCnt++;
#endif
	  PV = (t.f << 8) | t.t;
	  *score = (t.sh << 8) | t.sl;
	  /* adjust *score so moves to mate is from root */
	  if (*score > 9000)
	    *score -= ply;
	  else if (*score < -9000)
	    *score += ply;
	  if (t.flags & truescore)
	    {
	      *beta = -20000;
	    }
	  else if (t.flags & lowerbound)
	    {
	      if (*score > *alpha)
		*alpha = *score - 1;
	    }
	  else if (t.flags & upperbound)
	    {
	      if (*score < *beta)
		*beta = *score + 1;
	    }
	  return (true);
	}
    }
  return (false);
}

void
PutInFTable (short int side,
	     short int score,
	     short int depth,
	     short int ply,
	     short int alpha,
	     short int beta,
	     short unsigned int f,
	     short unsigned int t)

/*
 * Store the current board position in the persistent transposition table.
 */

{
  register unsigned short i;
  register unsigned long hashix;
  struct fileentry new, tmp;

  hashix = ((side == white) ? (hashkey & 0xFFFFFFFE) : (hashkey | 1)) & filesz;
  for (i = 0; i < 32; i++) new.bd[i] = CB (i);
  new.f = (unsigned char) f;
  new.t = (unsigned char) t;
  if (score < alpha)
    new.flags = upperbound;
  else
    new.flags = ((score > beta) ? lowerbound : truescore);
  if (Mvboard[kingP[side]] == 0)
    {
      if (Mvboard[qrook[side]] == 0)
	new.flags |= queencastle;
      if (Mvboard[krook[side]] == 0)
	new.flags |= kingcastle;
    }
  new.depth = (unsigned char) depth;
  /* adjust *score so moves to mate is from root */
  if (score > 9000)
    score += ply;
  else if (score < -9000)
    score -= ply;


  new.sh = (unsigned char) (score >> 8);
  new.sl = (unsigned char) (score & 0xFF);

  for (i = 0; i < frehash; i++)
    {
      fseek (hashfile,
	     sizeof (struct fileentry) * ((hashix + 2 * i) & (filesz)),
	     SEEK_SET);
      if(fread (&tmp, sizeof (struct fileentry), 1, hashfile) == NULL){ShowMessage("hashfile");exit(1);}
      if (tmp.depth && !Fbdcmp(tmp.bd,new.bd))continue;
      if(tmp.depth == depth)break;
      if (!tmp.depth || (short) tmp.depth < depth)
	{
	  fseek (hashfile,
		 sizeof (struct fileentry) * ((hashix + 2 * i) & (filesz)),
		 SEEK_SET);
	  fwrite (&new, sizeof (struct fileentry), 1, hashfile);
#ifndef BAREBONES
          FHashAdd++;
#endif
	  break;
	}
    }
}

#endif /* HASHFILE */
#endif /* ttblsz */

void
ZeroRPT (void)
{
#ifdef NOMEMSET
  register int side, i;
  for (side = white; side <= black; side++)
    for (i = 0; i < 256;)
      rpthash[side][i++] = 0;
#else
#ifndef AMIGA
   if(ISZERO){memset ((char *) rpthash, 0, sizeof (rpthash));ISZERO=0;}
#else
   if(ISZERO){ClearMem(rpthash, sizeof (rpthash));ISZERO=0;}
#endif
#endif
}

#endif //OLDTTABLE
