[comp.sources.misc] v19i076: gnuchess - gnuchess version 3.1+, Part04/07

mwm@hasler.ascom.ch (Mike McGann) (05/17/91)

Submitted-by: Mike McGann <mwm@hasler.ascom.ch>
Posting-number: Volume 19, Issue 76
Archive-name: gnuchess/part04

#!/bin/sh
# do not concatenate these parts, unpack them in order with /bin/sh
# file gnuchess.c continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 4; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
	echo 'x - still skipping gnuchess.c'
else
echo 'x - continuing file gnuchess.c'
sed 's/^X//' << 'SHAR_EOF' >> 'gnuchess.c' &&
X    {
X      root->flags |= draw;
X      DRAW = "No moves";
X    }
X  if (iop == 2)
X    return;
X  if (Book == NULL)
X    hint = PrVar[2];
X  ElapsedTime (1);
X
X  if (score > -9999 && rpt <= 2)
X    {
X      MakeMove (side, root, &tempb, &tempc, &tempsf, &tempst, &INCscore);
X      algbr (root->f, root->t, (short) root->flags);
X    }
X  else
X    algbr (0, 0, 0);
X  OutputMove ();
X  if (score == -9999 || score == 9998)
X    flag.mate = true;
X  if (flag.mate)
X    hint = 0;
X  if ((board[root->t] == pawn) || (root->flags & (capture | cstlmask)))
X    {
X      Game50 = GameCnt;
X      ZeroRPT ();
X    }
X  g = &GameList[GameCnt];
X  g->score = score;
X  g->nodes = NodeCnt;
X  g->time = (short) et;
X  g->depth = Sdepth;
X  g->flags = root->flags;
X  if (TCflag)
X    {
X      TimeControl.clock[side] -= (et + OperatorTime);
X      if (--TimeControl.moves[side] == 0)
X	SetTimeControl ();
X    }
X  if ((root->flags & draw) && flag.bothsides)
X    flag.mate = true;
X  if (GameCnt > 190)
X    flag.mate = true;		/* out of move store, you loose */
X  player = xside;
X  Sdepth = 0;
X  fflush (stdin);
}
X
int
parse (FILE * fd, short unsigned int *mv, short int side)
{
X  int c, i, r1, r2, c1, c2;
X  char s[100];
X  while ((c = getc (fd)) == ' ') ;
X  i = 0;
X  s[0] = (char) c;
X  while (c != ' ' && c != '\n' && c != EOF)
X    s[++i] = (char) (c = getc (fd));
X  s[++i] = '\0';
X  if (c == EOF)
X    return (-1);
X  if (s[0] == '!' || s[0] == ';' || i < 3)
X    {
X      while (c != '\n' && c != EOF)
X	c = getc (fd);
X      return (0);
X    }
X  if (s[4] == 'o')
X    *mv = (side == black) ? 0x3C3A : 0x0402;
X  else if (s[0] == 'o')
X    *mv = (side == black) ? 0x3C3E : 0x0406;
X  else
X    {
X      c1 = s[0] - 'a';
X      r1 = s[1] - '1';
X      c2 = s[2] - 'a';
X      r2 = s[3] - '1';
X      *mv = (locn (r1, c1) << 8) | locn (r2, c2);
X    }
X  return (1);
}
X
void
GetOpenings (void)
X
/*
X   Read in the Opening Book file and parse the algebraic notation for a move
X   into an unsigned integer format indicating the from and to square. Create
X   a linked list of opening lines of play, with entry->next pointing to the
X   next line and entry->move pointing to a chunk of memory containing the
X   moves. More Opening lines of up to 256 half moves may be added to
X   gnuchess.book.
*/
#ifndef BOOK
#define BOOK "/usr/games/lib/gnuchess.book"
#endif /* BOOK */
{
X  FILE *fd;
X  int c, i, j, side;
X  /* char buffr[2048]; */
X  struct BookEntry *entry;
X  unsigned short mv, *mp, tmp[100];
X
X  if ((fd = fopen (BOOK, "r")) == NULL)
X    fd = fopen ("gnuchess.book", "r");
X  if (fd != NULL)
X    {
X      /* setvbuf(fd,buffr,_IOFBF,2048); */
X      Book = NULL;
X      i = 0;
X      side = white;
X      while ((c = parse (fd, &mv, side)) >= 0)
X	if (c == 1)
X	  {
X	    tmp[++i] = mv;
X	    side = otherside[side];
X	  }
X	else if (c == 0 && i > 0)
X	  {
X	    entry = (struct BookEntry *) malloc (sizeof (struct BookEntry));
X	    mp = (unsigned short *) malloc ((i + 1) * sizeof (unsigned short));
X	    if (!entry || !mp)
X	      {
X		Book = NULL;
X		ShowMessage ("warning: can't load book, out of memory.");
X		return;
X	      }
X	    entry->mv = mp;
X	    entry->next = Book;
X	    Book = entry;
X	    for (j = 1; j <= i; j++)
X	      *(mp++) = tmp[j];
X	    *mp = 0;
X	    i = 0;
X	    side = white;
X	  }
X      fclose (fd);
X      BKBook = Book;
X    }
X  else
X    ShowMessage ("warning: can't find book.");
}
X
X
void
OpeningBook (unsigned short *hint)
X
/*
X  Go thru each of the opening lines of play and check for a match with the
X  current game listing. If a match occurs, generate a random number. If this
X  number is the largest generated so far then the next move in this line
X  becomes the current "candidate". After all lines are checked, the
X  candidate move is put at the top of the Tree[] array and will be played by
X  the program. Note that the program does not handle book transpositions.
*/
X
{
X  short j, pnt;
X  unsigned short m, *mp;
X  unsigned r, r0;
X  struct BookEntry *p;
X
X  srand ((unsigned int) time ((long *) 0));
X  r0 = m = 0;
X  p = Book;
X  while (p != NULL)
X    {
X      mp = p->mv;
X      for (j = 1; j <= GameCnt; j++)
X	if (GameList[j].gmove != *(mp++))
X	  break;
X      if (j > GameCnt)
X	if ((r = urand ()) > r0)
X	  {
X	    r0 = r;
X	    m = *mp;
X	    *hint = *(++mp);
X	  }
X      p = p->next;
X    }
X
X  for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
X    if (((Tree[pnt].f << 8) | Tree[pnt].t) == m)
X      Tree[pnt].score = 0;
X  pick (TrPnt[1], TrPnt[2] - 1);
X  if (Tree[TrPnt[1]].score < 0)
X    Book = NULL;
}
X
X
inline void
repetition (short int *cnt)
X
/*
X  Check for draw by threefold repetition.
*/
X
{
X  register short i, c, f, t;
X  short b[64];
X  unsigned short m;
X
X  *cnt = c = 0;
X  if (GameCnt > Game50 + 3)
X    {
#ifdef NOMEMSET
X      for (i = 0; i < 64; b[i++] = 0) ;
#else
X      memset ((char *) b, 0, sizeof (b));
#endif /* NOMEMSET */
X      for (i = GameCnt; i > Game50; i--)
X	{
X	  m = GameList[i].gmove;
X	  f = m >> 8;
X	  t = m & 0xFF;
X	  if (++b[f] == 0)
X	    c--;
X	  else
X	    c++;
X	  if (--b[t] == 0)
X	    c--;
X	  else
X	    c++;
X	  if (c == 0)
X	    (*cnt)++;
X	}
X    }
}
X
X
int
search (short int side,
X	short int ply,
X	short int depth,
X	short int alpha,
X	short int beta,
X	short unsigned int *bstline,
X	short int *rpt)
X
/*
X   Perform an alpha-beta search to determine the score for the current board
X   position. If depth <= 0 only capturing moves, pawn promotions and
X   responses to check are generated and searched, otherwise all moves are
X   processed. The search depth is modified for check evasions, certain
X   re-captures and threats. Extensions may continue for up to 11 ply beyond
X   the nominal search depth.
X */
X
#define UpdateSearchStatus \
{\
X   if (flag.post) ShowCurrentMove(pnt,node->f,node->t);\
X     if (pnt > TrPnt[1])\
X       {\
X	  d = best-Zscore; e = best-node->score;\
X	    if (best < alpha) ExtraTime = 10*ResponseTime;\
X	    else if (d > -zwndw && e > 4*zwndw) ExtraTime = -ResponseTime/3;\
X	    else if (d > -zwndw) ExtraTime = 0;\
X	    else if (d > -3*zwndw) ExtraTime = ResponseTime;\
X	    else if (d > -9*zwndw) ExtraTime = 3*ResponseTime;\
X	    else ExtraTime = 5*ResponseTime;\
X	    }\
X	    }
#define prune (cf && score+node->score < alpha)
#define ReCapture (flag.rcptr && score > alpha && score < beta &&\
X		   ply > 2 && CptrFlag[ply-1] && CptrFlag[ply-2])
/* && depth == Sdepth-ply+1 */
#define Parry (hung[side] > 1 && ply == Sdepth+1)
#define MateThreat (ply < Sdepth+4 && ply > 4 &&\
X		    ChkFlag[ply-2] && ChkFlag[ply-4] &&\
X		    ChkFlag[ply-2] != ChkFlag[ply-4])
X
{
X  register short j, pnt;
X  short best, tempb, tempc, tempsf, tempst;
X  short xside, pbst, d, e, cf, score, rcnt, slk, InChk;
X  unsigned short mv, nxtline[maxdepth];
X  struct leaf *node, tmp;
X
X  NodeCnt++;
X  xside = otherside[side];
X
X  if ((ply <= Sdepth + 3) && rpthash[side][hashkey & 0xFF] > 0)
X    repetition (rpt);
X  else
X    *rpt = 0;
X  /* Detect repetitions a bit earlier. SMC. 12/89 */
X  if (*rpt == 1 && ply > 1)
X    return (0);
X  /* if (*rpt >= 2) return(0); */
X  /* slk is lone king indicator for either side */
X  score = evaluate (side, ply, alpha, beta, INCscore, &slk, &InChk);
X  if (score > 9000)
X    {
X      bstline[ply] = 0;
X      return (score);
X    }
X  if (depth > 0)
X    {
X      /* Allow opponent a chance to check again */
X      if (InChk)
X	depth = (depth < 2) ? 2 : depth;
X      else if (PawnThreat[ply - 1] || ReCapture)
X	++depth;
X    }
X  else
X    {
X      if (score >= alpha && (InChk || PawnThreat[ply - 1] || Parry))
X	depth = 1;
X      else if (score <= beta && MateThreat)
X	depth = 1;
X    }
X
#if ttblsz
X  if (depth > 0 && flag.hash && ply > 1)
X    {
X      if (ProbeTTable (side, depth, &alpha, &beta, &score) == true)
X	{
X	  bstline[ply] = PV;
X	  bstline[ply + 1] = 0;
X	  if (beta == -20000)
X	    return (score);
X	  if (alpha > beta)
X	    return (alpha);
X	}
#ifdef HASHFILE
X      else if (hashfile && (depth > HashDepth) && (GameCnt < HashMoveLimit)
X	       && (ProbeFTable (side, depth, &alpha, &beta, &score) == true))
X	{
X	  PutInTTable (side, score, depth, alpha, beta, PV);
X	  bstline[ply] = PV;
X	  bstline[ply + 1] = 0;
X	  if (beta == -20000)
X	    return (score);
X	  if (alpha > beta)
X	    return (alpha);
X	}
#endif /* HASHFILE */
X    }
#endif /* ttblsz */
X  d = (Sdepth == 1) ? 7 : 11;
X  if (ply > Sdepth + d || (depth < 1 && score > beta))
X    return (score);		/* score >= beta ?? */
X
X  if (ply > 1)
X    if (depth > 0)
X      MoveList (side, ply);
X    else
X      CaptureList (side, ply);
X
X  if (TrPnt[ply] == TrPnt[ply + 1])
X    return (score);
X
X  cf = (depth < 1 && ply > Sdepth + 1 && !ChkFlag[ply - 2] && !slk);
X
X  best = (depth > 0) ? -12000 : score;
X  if (best > alpha)
X    alpha = best;
X  /* look at each move until no more or beta cutoff */
X  for (pnt = pbst = TrPnt[ply];
X       pnt < TrPnt[ply + 1] && best < beta;	/* best < beta ?? */
X       pnt++)
X    {
X      /* find the most interesting looking of the remaining moves */
X      if (ply > 1)
X	pick (pnt, TrPnt[ply + 1] - 1);
X      node = &Tree[pnt];
X      mv = (node->f << 8) | node->t;
X      nxtline[ply + 1] = 0;
X      if (prune)
X	break;			/* alpha cutoff */
X      if (ply == 1)
X	UpdateSearchStatus;
X
X      if (!(node->flags & exact))
X	{
X	  /* make the move and go deeper */
X	  MakeMove (side, node, &tempb, &tempc, &tempsf, &tempst, &INCscore);
X	  CptrFlag[ply] = (node->flags & capture);
X	  PawnThreat[ply] = (node->flags & pwnthrt);
X	  Tscore[ply] = node->score;
X	  PV = node->reply;
X	  node->score = -search (xside, ply + 1,
X				 (depth > 0) ? depth - 1 : 0,
X				 -beta, -alpha,
X				 nxtline, &rcnt);
X	  if (abs (node->score) > 9000)
X	    node->flags |= exact;
X	  else if (rcnt == 1)
X	    node->score /= 2;
X	  /* but why doesnt this detect draws??? */
X	  if (rcnt >= 2 || GameCnt - Game50 > 99 ||
X	      (node->score == 9999 - ply && !ChkFlag[ply]))
X	    {
X	      node->flags |= (draw | exact);
X	      DRAW = "";
X	      node->score = (side == computer) ? contempt : -contempt;
X	    }
X	  node->reply = nxtline[ply + 1];
X	  /* reset to try next move */
X	  UnmakeMove (side, node, &tempb, &tempc, &tempsf, &tempst);
X	}
X      if (node->score > best && !flag.timeout)
X	{
X	  if (depth > 0 && node->score > alpha && !(node->flags & exact))
X	    node->score += depth;
X	  best = node->score;
X	  pbst = pnt;
X	  if (best > alpha)
X	    alpha = best;
X	  for (j = ply + 1; nxtline[j] > 0; j++)
X	    bstline[j] = nxtline[j];
X	  bstline[j] = 0;
X	  bstline[ply] = mv;
#ifdef DEBUG
X          if(ply == 1)
X	    ShowDBLine ("IS", ply, depth, alpha, beta, score, &bstline[ply-1]);
#endif /*DEBUG*/
X	  if (ply == 1)
X	    {
X	      if (best > root->score)
X		{
X		  tmp = Tree[pnt];
X		  for (j = pnt - 1; j >= 0; j--)
X		    Tree[j + 1] = Tree[j];
X		  Tree[0] = tmp;
X		  pbst = 0;
X		}
X	      if (Sdepth > 2)
X		if (best > beta)
X		  ShowResults (best, bstline, '+');
X		else if (best < alpha)
X		  ShowResults (best, bstline, '-');
X		else
X		  ShowResults (best, bstline, '&');
X	    }
X	}
X      if (NodeCnt > ETnodes)
X	ElapsedTime (0);
X      if (flag.timeout)
X	return (-Tscore[ply - 1]);
X    }
X
X  node = &Tree[pbst];
X  mv = (node->f << 8) | node->t;
#if ttblsz
X  if (flag.hash && ply <= Sdepth && *rpt == 0 && best == alpha)
X    {
X      if (PutInTTable (side, best, depth, alpha, beta, mv)
#ifdef HASHFILE
X	  && hashfile && (depth > HashDepth) && (GameCnt < HashMoveLimit))
X	{
X	  PutInFTable (side, best, depth, alpha, beta, node->f, node->t);
X	}
#else
X	);
#endif /* HASHFILE */
X    }
#endif /* ttblsz */
X  if (depth > 0)
X    {
X      j = (node->f << 6) | node->t;
X      if (side == black)
X	j |= 0x1000;
X      if (history[j] < 150)
X	history[j] += (unsigned char) 2 *depth;
X
X      if (node->t != (GameList[GameCnt].gmove & 0xFF))
X	if (best <= beta)
X	  killr3[ply] = mv;
X	else if (mv != killr1[ply])
X	  {
X	    killr2[ply] = killr1[ply];
X	    killr1[ply] = mv;
X	  }
X      if (best > 9000)
X	killr0[ply] = mv;
X      else
X	killr0[ply] = 0;
X    }
X  return (best);
}
X
#if ttblsz
/*
X  hashbd contains a 32 bit "signature" of the board position. hashkey
X  contains a 16 bit code used to address the hash table. When a move is
X  made, XOR'ing the hashcode of moved piece on the from and to squares with
X  the hashbd and hashkey values keeps things current.
*/
#define UpdateHashbd(side, piece, f, t) \
{\
X  if ((f) >= 0)\
X    {\
X      hashbd ^= hashcode[side][piece][f].bd;\
X      hashkey ^= hashcode[side][piece][f].key;\
X    }\
X  if ((t) >= 0)\
X    {\
X      hashbd ^= hashcode[side][piece][t].bd;\
X      hashkey ^= hashcode[side][piece][t].key;\
X    }\
}
X
#define CB(i) (unsigned char) ((color[2 * (i)] ? 0x80 : 0)\
X	       | (board[2 * (i)] << 4)\
X	       | (color[2 * (i) + 1] ? 0x8 : 0)\
X	       | (board[2 * (i) + 1]))
X
int
ProbeTTable (short int side,
X	     short int depth,
X	     short int *alpha,
X	     short int *beta,
X	     short int *score)
X
/*
X  Look for the current board position in the transposition table.
*/
X
{
X  register struct hashentry *ptbl;
X  register unsigned short i;
X
X  ptbl = &ttable[side][hashkey & (ttblsz - 1)];
X
X  /* rehash max rehash times */
X  for (i = 1; ptbl->hashbd != hashbd && i <= rehash; i++)
X    ptbl = &ttable[side][(hashkey + i) & (ttblsz - 1)];
X  if ((short) ptbl->depth >= depth && ptbl->hashbd == hashbd)
X    {
X      HashCnt++;
#ifdef HASHTEST
X      for (i = 0; i < 32; i++)
X	{
X	  if (ptbl->bd[i] != CB (i))
X	    {
X	      HashCol++;
X	      ShowMessage ("ttable collision detected");
X	      break;
X	    }
X	}
#endif /* HASHTEST */
X
X      PV = ptbl->mv;
X      if (ptbl->flags & truescore)
X	{
X	  *score = ptbl->score;
X	  *beta = -20000;
X	}
#if 0				/* commented out, why? */
X      else if (ptbl->flags & upperbound)
X	{
X	  if (ptbl->score < *beta)
X	    *beta = ptbl->score + 1;
X	}
#endif
X      else if (ptbl->flags & lowerbound)
X	{
X	  if (ptbl->score > *alpha)
X	    *alpha = ptbl->score - 1;
X	}
X      return (true);
X    }
X  return (false);
}
X
int
PutInTTable (short int side,
X	     short int score,
X	     short int depth,
X	     short int alpha,
X	     short int beta,
X	     short unsigned int mv)
X
/*
X  Store the current board position in the transposition table.
*/
X
{
X  register struct hashentry *ptbl;
X  register unsigned short i;
X
X  ptbl = &ttable[side][hashkey & (ttblsz - 1)];
X
X  /* rehash max rehash times */
X  for (i = 1; depth < ptbl->depth && ptbl->hashbd != hashbd && i <= rehash; i++)
X    ptbl = &ttable[side][(hashkey + i) & (ttblsz - 1)];
X  if (depth >= ptbl->depth || ptbl->hashbd != hashbd)
X    {
X      HashAdd++;
X      ptbl->hashbd = hashbd;
X      ptbl->depth = (unsigned char) depth;
X      ptbl->score = score;
X      ptbl->mv = mv;
X      if (score < alpha)
X	ptbl->flags = upperbound;
X      else if (score > beta)
X	ptbl->flags = lowerbound;
X      else
X	ptbl->flags = truescore;
#ifdef HASHTEST
X      for (i = 0; i < 32; i++)
X	{
X	  ptbl->bd[i] = CB (i);
X	}
#endif /* HASHTEST */
X      return true;
X    }
X  return false;
}
X
void
ZeroTTable (void)
{
X  register int side, i;
X
X  if (flag.hash)
X    for (side = white; side <= black; side++)
X      for (i = 0; i < ttblsz; i++)
X	ttable[side][i].depth = 0;
}
X
#ifdef HASHFILE
int
ProbeFTable (short int side,
X	     short int depth,
X	     short int *alpha,
X	     short int *beta,
X	     short int *score)
X
/*
X  Look for the current board position in the persistent transposition table.
*/
X
{
X  register unsigned short i, j;
X  register unsigned long hashix;
X  short s;
X  struct fileentry new, t;
X
X  hashix = ((side == white) ? (hashkey & 0xFFFFFFFE) : (hashkey | 1)) & filesz;
X
X  for (i = 0; i < 32; i++)
X    new.bd[i] = CB (i);
X  new.flags = 0;
X  if (Mvboard[kingP[side]] == 0)
X    {
X      if (Mvboard[qrook[side]] == 0)
X	new.flags |= queencastle;
X      if (Mvboard[krook[side]] == 0)
X	new.flags |= kingcastle;
X    }
X
X  for (i = 0; i < frehash; i++)
X    {
X      fseek (hashfile,
X	     sizeof (struct fileentry) * ((hashix + 2 * i) & (filesz)),
X	     SEEK_SET);
X      fread (&t, sizeof (struct fileentry), 1, hashfile);
X      for (j = 0; j < 32; j++)
X	if (t.bd[j] != new.bd[j])
X	  break;
X      if (((short) t.depth >= depth) && (j >= 32)
X	  && (new.flags == (t.flags & (kingcastle | queencastle))))
X	{
X	  FHashCnt++;
X	  PV = (t.f << 8) | t.t;
X	  s = (t.sh << 8) | t.sl;
X	  if (t.flags & truescore)
X	    {
X	      *score = s;
X	      *beta = -20000;
X	    }
X	  else if (t.flags & lowerbound)
X	    {
X	      if (s > *alpha)
X		*alpha = s - 1;
X	    }
X	  return (true);
X	}
X    }
X  return (false);
}
X
void
PutInFTable (short int side,
X	     short int score,
X	     short int depth,
X	     short int alpha,
X	     short int beta,
X	     short unsigned int f,
X	     short unsigned int t)
X
/*
X  Store the current board position in the persistent transposition table.
*/
X
{
X  register unsigned short i;
X  register unsigned long hashix;
X  struct fileentry new, tmp;
X
X  FHashAdd++;
X  hashix = ((side == white) ? (hashkey & 0xFFFFFFFE) : (hashkey | 1)) & filesz;
X  for (i = 0; i < 32; i++)
X    new.bd[i] = CB (i);
X  new.f = (unsigned char) f;
X  new.t = (unsigned char) t;
X  if (score < alpha)
X    new.flags = upperbound;
X  else
X    new.flags = (score > beta) ? lowerbound : truescore;
X  if (Mvboard[kingP[side]] == 0)
X    {
X      if (Mvboard[qrook[side]] == 0)
X	new.flags |= queencastle;
X      if (Mvboard[krook[side]] == 0)
X	new.flags |= kingcastle;
X    }
X  new.depth = (unsigned char) depth;
X  new.sh = (unsigned char) (score >> 8);
X  new.sl = (unsigned char) (score & 0xFF);
X
X  for (i = 0; i < frehash; i++)
X    {
X      fseek (hashfile,
X	     sizeof (struct fileentry) * ((hashix + 2 * i) & (filesz)),
X	     SEEK_SET);
X      fread (&tmp, sizeof (struct fileentry), 1, hashfile);
X      if ((short) tmp.depth <= depth)
X	{
X	  fseek (hashfile,
X		 sizeof (struct fileentry) * ((hashix + 2 * i) & (filesz)),
X		 SEEK_SET);
X	  fwrite (&new, sizeof (struct fileentry), 1, hashfile);
X	  break;
X	}
X    }
}
X
#endif /* HASHFILE */
#endif /* ttblsz */
X
void
ZeroRPT (void)
{
X  register int side, i;
X
X  for (side = white; side <= black; side++)
X    for (i = 0; i < 256; i++)
X      rpthash[side][i] = 0;
}
X
#define Link(from,to,flag,s) \
{\
X   node->f = from; node->t = to;\
X     node->reply = 0;\
X       node->flags = flag;\
X	 node->score = s;\
X	   ++node;\
X	     ++TrPnt[ply+1];\
X	     }
X
static inline void
LinkMove (short int ply,
X	  short int f,
X	  short int t,
X	  short int flag,
X	  short int xside)
X
/*
X  Add a move to the tree.  Assign a bonus to order the moves
X  as follows:
X  1. Principle variation
X  2. Capture of last moved piece
X  3. Other captures (major pieces first)
X  4. Killer moves
X  5. "history" killers
*/
X
{
X  register short s, z;
X  register unsigned short mv;
X  register struct leaf *node;
X  extern char mvstr[4][6];
X
X  node = &Tree[TrPnt[ply + 1]];
X  mv = (f << 8) | t;
X  s = 0;
X  if (mv == Swag0)
X    s = 2000;
X  else if (mv == Swag1)
X    s = 60;
X  else if (mv == Swag2)
X    s = 50;
X  else if (mv == Swag3)
X    s = 40;
X  else if (mv == Swag4)
X    s = 30;
X  z = (f << 6) | t;
X  if (xside == white)
X    z |= 0x1000;
X  s += history[z];
X  if (color[t] != neutral)
X    {
X      if (t == TOsquare)
X	s += 500;
X      s += value[board[t]] - board[f];
X    }
X  if (board[f] == pawn)
X    if (row (t) == 0 || row (t) == 7)
X      {
X	flag |= promote;
X	s += 800;
X	Link (f, t, flag | queen, s - 20000);
X	s -= 200;
X	Link (f, t, flag | knight, s - 20000);
X	s -= 50;
X	Link (f, t, flag | rook, s - 20000);
X	flag |= bishop;
X	s -= 50;
X      }
X    else if (row (t) == 1 || row (t) == 6)
X      {
X	flag |= pwnthrt;
X	s += 600;
X      }
X  Link (f, t, flag, s - 20000);
}
X
X
static inline void
GenMoves (short int ply, short int sq, short int side, short int xside)
X
/*
X  Generate moves for a piece. The moves are taken from the precalulated
X  array nextpos/nextdir. If the board is free, next move is choosen from
X  nextpos else from nextdir.
*/
X
{
X  register short u, piece;
X  register unsigned char *ppos, *pdir;
X
X  piece = board[sq];
X  ppos = nextpos[ptype[side][piece]][sq];
X  pdir = nextdir[ptype[side][piece]][sq];
X  if (piece == pawn)
X    {
X      u = ppos[sq];		/* follow no captures thread */
X      if (color[u] == neutral)
X	{
X	  LinkMove (ply, sq, u, 0, xside);
X	  u = ppos[u];
X	  if (color[u] == neutral)
X	    LinkMove (ply, sq, u, 0, xside);
X	}
X      u = pdir[sq];		/* follow captures thread */
X      if (color[u] == xside)
X	LinkMove (ply, sq, u, capture, xside);
X      else if (u == epsquare)
X	LinkMove (ply, sq, u, capture | epmask, xside);
X      u = pdir[u];
X      if (color[u] == xside)
X	LinkMove (ply, sq, u, capture, xside);
X      else if (u == epsquare)
X	LinkMove (ply, sq, u, capture | epmask, xside);
X    }
X  else
X    {
X      u = ppos[sq];
X      do
X	{
X	  if (color[u] == neutral)
X	    {
X	      LinkMove (ply, sq, u, 0, xside);
X	      u = ppos[u];
X	    }
X	  else
X	    {
X	      if (color[u] == xside)
X		LinkMove (ply, sq, u, capture, xside);
X	      u = pdir[u];
X	    }
X      } while (u != sq);
X    }
}
X
void
MoveList (short int side, short int ply)
X
/*
X  Fill the array Tree[] with all available moves for side to play. Array
X  TrPnt[ply] contains the index into Tree[] of the first move at a ply.
*/
X
{
X  register short i, xside, f;
X
X  xside = otherside[side];
X  TrPnt[ply + 1] = TrPnt[ply];
X  Swag0 = (PV) ? killr0[ply] : PV;
X  Swag1 = killr1[ply];
X  Swag2 = killr2[ply];
X  Swag3 = killr3[ply];
X  Swag4 = (ply > 2) ? killr1[ply - 2] : 0;
X  for (i = PieceCnt[side]; i >= 0; i--)
X    GenMoves (ply, PieceList[side][i], side, xside);
X  if (!castld[side])
X    {
X      f = PieceList[side][0];
X      if (castle (side, f, f + 2, 0))
X	{
X	  LinkMove (ply, f, f + 2, cstlmask, xside);
X	}
X      if (castle (side, f, f - 2, 0))
X	{
X	  LinkMove (ply, f, f - 2, cstlmask, xside);
X	}
X    }
}
X
void
CaptureList (short int side, short int ply)
X
/*
X  Fill the array Tree[] with all available cature and promote moves for
X  side to play. Array TrPnt[ply] contains the index into Tree[]
X  of the first move at a ply.
*/
X
{
X  register short u, sq, xside;
X  register struct leaf *node;
X  register unsigned char *ppos, *pdir;
X  short i, piece, *PL, r7;
X
X  xside = otherside[side];
X  TrPnt[ply + 1] = TrPnt[ply];
X  node = &Tree[TrPnt[ply]];
X  r7 = rank7[side];
X  PL = PieceList[side];
X  for (i = 0; i <= PieceCnt[side]; i++)
X    {
X      sq = PL[i];
X      piece = board[sq];
X      if (sweep[piece])
X	{
X	  ppos = nextpos[piece][sq];
X	  pdir = nextdir[piece][sq];
X	  u = ppos[sq];
X	  do
X	    {
X	      if (color[u] == neutral)
X		u = ppos[u];
X	      else
X		{
X		  if (color[u] == xside)
X		    Link (sq, u, capture, value[board[u]] + svalue[board[u]] - piece);
X		  u = pdir[u];
X		}
X	  } while (u != sq);
X	}
X      else
X	{
X	  pdir = nextdir[ptype[side][piece]][sq];
X	  if (piece == pawn && row (sq) == r7)
X	    {
X	      u = pdir[sq];
X	      if (color[u] == xside)
X		Link (sq, u, capture | promote | queen, valueQ);
X	      u = pdir[u];
X	      if (color[u] == xside)
X		Link (sq, u, capture | promote | queen, valueQ);
X	      ppos = nextpos[ptype[side][piece]][sq];
X	      u = ppos[sq];	/* also generate non capture promote */
X	      if (color[u] == neutral)
X		Link (sq, u, promote | queen, valueQ);
X	    }
X	  else
X	    {
X	      u = pdir[sq];
X	      do
X		{
X		  if (color[u] == xside)
X		    Link (sq, u, capture, value[board[u]] + svalue[board[u]] - piece);
X		  u = pdir[u];
X	      } while (u != sq);
X	    }
X	}
X    }
}
X
X
int
castle (short int side, short int kf, short int kt, short int iop)
X
/* Make or Unmake a castling move. */
X
{
X  register short rf, rt, t0, xside;
X
X  xside = otherside[side];
X  if (kt > kf)
X    {
X      rf = kf + 3;
X      rt = kt - 1;
X    }
X  else
X    {
X      rf = kf - 4;
X      rt = kt + 1;
X    }
X  if (iop == 0)
X    {
X      if (kf != kingP[side] ||
X	  board[kf] != king ||
X	  board[rf] != rook ||
X	  Mvboard[kf] != 0 ||
X	  Mvboard[rf] != 0 ||
X	  color[kt] != neutral ||
X	  color[rt] != neutral ||
X	  color[kt - 1] != neutral ||
X	  SqAtakd (kf, xside) ||
X	  SqAtakd (kt, xside) ||
X	  SqAtakd (rt, xside))
X	return (false);
X    }
X  else
X    {
X      if (iop == 1)
X	{
X	  castld[side] = true;
X	  Mvboard[kf]++;
X	  Mvboard[rf]++;
X	}
X      else
X	{
X	  castld[side] = false;
X	  Mvboard[kf]--;
X	  Mvboard[rf]--;
X	  t0 = kt;
X	  kt = kf;
X	  kf = t0;
X	  t0 = rt;
X	  rt = rf;
X	  rf = t0;
X	}
X      board[kt] = king;
X      color[rt] = color[kt] = side;
X      Pindex[kt] = 0;
X      board[kf] = no_piece;
X      color[rf] = color[kf] = neutral;
X      board[rt] = rook;
X      Pindex[rt] = Pindex[rf];
X      board[rf] = no_piece;
X      PieceList[side][Pindex[kt]] = kt;
X      PieceList[side][Pindex[rt]] = rt;
#if ttblsz
X      UpdateHashbd (side, king, kf, kt);
X      UpdateHashbd (side, rook, rf, rt);
#endif /* ttblsz */
X    }
X  return (true);
}
X
X
void
EnPassant (short int xside, short int f, short int t, short int iop)
X
/*
X  Make or unmake an en passant move.
*/
X
{
X  register short l;
X
X  l = (t > f) ? t - 8 : t + 8;
X  if (iop == 1)
X    {
X      board[l] = no_piece;
X      color[l] = neutral;
X    }
X  else
X    {
X      board[l] = pawn;
X      color[l] = xside;
X    }
X  InitializeStats ();
}
X
X
static inline void
UpdatePieceList (short int side, short int sq, short int iop)
X
/*
X  Update the PieceList and Pindex arrays when a piece is captured or when a
X  capture is unmade.
*/
X
{
X  register short i;
X  if (iop == 1)
X    {
X      PieceCnt[side]--;
X      for (i = Pindex[sq]; i <= PieceCnt[side]; i++)
X	{
X	  PieceList[side][i] = PieceList[side][i + 1];
X	  Pindex[PieceList[side][i]] = i;
X	}
X    }
X  else
X    {
X      PieceCnt[side]++;
X      PieceList[side][PieceCnt[side]] = sq;
X      Pindex[sq] = PieceCnt[side];
X    }
}
X
void
MakeMove (short int side,
X	  struct leaf * node,
X	  short int *tempb,
X	  short int *tempc,
X	  short int *tempsf,
X	  short int *tempst,
X	  short int *INCscore)
X
/*
X  Update Arrays board[], color[], and Pindex[] to reflect the new board
X  position obtained after making the move pointed to by node. Also update
X  miscellaneous stuff that changes when a move is made.
*/
X
{
X  register short f, t, xside, ct, cf;
X
X  xside = otherside[side];
X  GameCnt++;
X  f = node->f;
X  t = node->t;
X  epsquare = -1;
X  FROMsquare = f;
X  TOsquare = t;
X  *INCscore = 0;
X  GameList[GameCnt].gmove = (f << 8) | t;
X  GameList[GameCnt].flags = node->flags;
X  if (node->flags & cstlmask)
X    {
X      GameList[GameCnt].piece = no_piece;
X      GameList[GameCnt].color = side;
X      (void) castle (side, f, t, 1);
X    }
X  else
X    {
X      if (!(node->flags & capture) && (board[f] != pawn))
X	rpthash[side][hashkey & 0xFF]++;
X      *tempc = color[t];
X      *tempb = board[t];
X      *tempsf = svalue[f];
X      *tempst = svalue[t];
X      GameList[GameCnt].piece = *tempb;
X      GameList[GameCnt].color = *tempc;
X      if (*tempc != neutral)
X	{
X	  UpdatePieceList (*tempc, t, 1);
X	  if (*tempb == pawn)
X	    --PawnCnt[*tempc][column (t)];
X	  if (board[f] == pawn)
X	    {
X	      --PawnCnt[side][column (f)];
X	      ++PawnCnt[side][column (t)];
X	      cf = column (f);
X	      ct = column (t);
X	      if (PawnCnt[side][ct] > 1 + PawnCnt[side][cf])
X		*INCscore -= 15;
X	      else if (PawnCnt[side][ct] < 1 + PawnCnt[side][cf])
X		*INCscore += 15;
X	      else if (ct == 0 || ct == 7 || PawnCnt[side][ct + ct - cf] == 0)
X		*INCscore -= 15;
X	    }
X	  mtl[xside] -= value[*tempb];
X	  if (*tempb == pawn)
X	    pmtl[xside] -= valueP;
#if ttblsz
X	  UpdateHashbd (xside, *tempb, -1, t);
#endif /* ttblsz */
X	  *INCscore += *tempst;
X	  Mvboard[t]++;
X	}
X      color[t] = color[f];
X      board[t] = board[f];
X      svalue[t] = svalue[f];
X      Pindex[t] = Pindex[f];
X      PieceList[side][Pindex[t]] = t;
X      color[f] = neutral;
X      board[f] = no_piece;
X      if (board[t] == pawn)
X	if (t - f == 16)
X	  epsquare = f + 8;
X	else if (f - t == 16)
X	  epsquare = f - 8;
X      if (node->flags & promote)
X	{
X	  board[t] = node->flags & pmask;
X	  if (board[t] == queen)
X	    HasQueen[side]++;
X	  else if (board[t] == rook)
X	    HasRook[side]++;
X	  else if (board[t] == bishop)
X	    HasBishop[side]++;
X	  else if (board[t] == knight)
X	    HasKnight[side]++;
X	  --PawnCnt[side][column (t)];
X	  mtl[side] += value[board[t]] - valueP;
X	  pmtl[side] -= valueP;
#if ttblsz
X	  UpdateHashbd (side, pawn, f, -1);
X	  UpdateHashbd (side, board[t], f, -1);
#endif /* ttblsz */
X	  *INCscore -= *tempsf;
X	}
X      if (node->flags & epmask)
X	EnPassant (xside, f, t, 1);
X      else
#if ttblsz
X	UpdateHashbd (side, board[t], f, t);
#else
X	 /* NOOP */ ;
#endif /* ttblsz */
X      Mvboard[f]++;
X    }
}
X
void
UnmakeMove (short int side,
X	    struct leaf * node,
X	    short int *tempb,
X	    short int *tempc,
X	    short int *tempsf,
X	    short int *tempst)
X
/*
X  Take back a move.
*/
X
{
X  register short f, t, xside;
X
X  xside = otherside[side];
X  f = node->f;
X  t = node->t;
X  epsquare = -1;
X  GameCnt--;
X  if (node->flags & cstlmask)
X    (void) castle (side, f, t, 2);
X  else
X    {
X      color[f] = color[t];
X      board[f] = board[t];
X      svalue[f] = *tempsf;
X      Pindex[f] = Pindex[t];
X      PieceList[side][Pindex[f]] = f;
X      color[t] = *tempc;
X      board[t] = *tempb;
X      svalue[t] = *tempst;
X      if (node->flags & promote)
X	{
X	  board[f] = pawn;
X	  ++PawnCnt[side][column (t)];
X	  mtl[side] += valueP - value[node->flags & pmask];
X	  pmtl[side] += valueP;
#if ttblsz
X	  UpdateHashbd (side, (short) node->flags & pmask, -1, t);
X	  UpdateHashbd (side, pawn, -1, t);
#endif /* ttblsz */
X	}
X      if (*tempc != neutral)
X	{
X	  UpdatePieceList (*tempc, t, 2);
X	  if (*tempb == pawn)
X	    ++PawnCnt[*tempc][column (t)];
X	  if (board[f] == pawn)
X	    {
X	      --PawnCnt[side][column (t)];
X	      ++PawnCnt[side][column (f)];
X	    }
X	  mtl[xside] += value[*tempb];
X	  if (*tempb == pawn)
X	    pmtl[xside] += valueP;
#if ttblsz
X	  UpdateHashbd (xside, *tempb, -1, t);
#endif /* ttblsz */
X	  Mvboard[t]--;
X	}
X      if (node->flags & epmask)
X	EnPassant (xside, f, t, 2);
X      else
#if ttblsz
X	UpdateHashbd (side, board[f], f, t);
#else
X	 /* NOOP */ ;
#endif /* ttblsz */
X      Mvboard[f]--;
X      if (!(node->flags & capture) && (board[f] != pawn))
X	rpthash[side][hashkey & 0xFF]--;
X    }
}
X
X
void
InitializeStats (void)
X
/*
X  Scan thru the board seeing what's on each square. If a piece is found,
X  update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also
X  determine the material for each side and set the hashkey and hashbd
X  variables to represent the current board position. Array
X  PieceList[side][indx] contains the location of all the pieces of either
X  side. Array Pindex[sq] contains the indx into PieceList for a given
X  square.
*/
X
{
X  register short i, sq;
X  epsquare = -1;
X  for (i = 0; i < 8; i++)
X    PawnCnt[white][i] = PawnCnt[black][i] = 0;
X  mtl[white] = mtl[black] = pmtl[white] = pmtl[black] = 0;
X  PieceCnt[white] = PieceCnt[black] = 0;
#if ttblsz
X  hashbd = hashkey = 0;
#endif /* ttblsz */
X  for (sq = 0; sq < 64; sq++)
X    if (color[sq] != neutral)
X      {
X	mtl[color[sq]] += value[board[sq]];
X	if (board[sq] == pawn)
X	  {
X	    pmtl[color[sq]] += valueP;
X	    ++PawnCnt[color[sq]][column (sq)];
X	  }
X	Pindex[sq] = (board[sq] == king) ? 0 : ++PieceCnt[color[sq]];
X	PieceList[color[sq]][Pindex[sq]] = sq;
#if ttblsz
X	hashbd ^= hashcode[color[sq]][board[sq]][sq].bd;
X	hashkey ^= hashcode[color[sq]][board[sq]][sq].key;
#endif /* ttblsz */
X      }
}
X
X
int
SqAtakd (short int sq, short int side)
X
/*
X  See if any piece with color 'side' ataks sq.  First check pawns then Queen,
X  Bishop, Rook and King and last Knight.
*/
X
{
X  register short u;
X  register unsigned char *ppos, *pdir;
X  short xside;
X
X  xside = otherside[side];
X  pdir = nextdir[ptype[xside][pawn]][sq];
X  u = pdir[sq];			/* follow captures thread */
X  if (u != sq)
X    {
X      if (board[u] == pawn && color[u] == side)
X	return (true);
X      u = pdir[u];
X      if (u != sq && board[u] == pawn && color[u] == side)
X	return (true);
X    }
X  /* king capture */
X  if (distance (sq, PieceList[side][0]) == 1)
X    return (true);
X  /* try a queen bishop capture */
X  ppos = nextpos[bishop][sq];
X  pdir = nextdir[bishop][sq];
X  u = ppos[sq];
X  do
X    {
X      if (color[u] == neutral)
X	u = ppos[u];
X      else
X	{
X	  if (color[u] == side && (board[u] == queen || board[u] == bishop))
X	    return (true);
X	  u = pdir[u];
X	}
X  } while (u != sq);
X  /* try a queen rook capture */
X  ppos = nextpos[rook][sq];
X  pdir = nextdir[rook][sq];
X  u = ppos[sq];
X  do
X    {
X      if (color[u] == neutral)
X	u = ppos[u];
X      else
X	{
X	  if (color[u] == side && (board[u] == queen || board[u] == rook))
X	    return (true);
X	  u = pdir[u];
X	}
X  } while (u != sq);
X  /* try a knight capture */
X  pdir = nextdir[knight][sq];
X  u = pdir[sq];
X  do
X    {
X      if (color[u] == side && board[u] == knight)
X	return (true);
X      u = pdir[u];
X  } while (u != sq);
X  return (false);
}
X
static inline void
ataks (short int side, short int *a)
X
/*
X  Fill array atak[][] with info about ataks to a square.  Bits 8-15 are set
X  if the piece (king..pawn) ataks the square.  Bits 0-7 contain a count of
X  total ataks to the square.
*/
X
{
X  register short u, c, sq;
X  register unsigned char *ppos, *pdir;
X  short i, piece, *PL;
X
#ifdef NOMEMSET
X  for (u = 64; u; a[--u] = 0) ;
#else
X  memset ((char *) a, 0, 64 * sizeof (a[0]));
#endif /* NOMEMSET */
X  PL = PieceList[side];
X  for (i = PieceCnt[side]; i >= 0; i--)
X    {
X      sq = PL[i];
X      piece = board[sq];
X      c = control[piece];
X      if (sweep[piece])
X	{
X	  ppos = nextpos[piece][sq];
X	  pdir = nextdir[piece][sq];
X	  u = ppos[sq];
X	  do
X	    {
X	      a[u] = ++a[u] | c;
X	      u = (color[u] == neutral) ? ppos[u] : pdir[u];
X	  } while (u != sq);
X	}
X      else
X	{
X	  pdir = nextdir[ptype[side][piece]][sq];
X	  u = pdir[sq];		/* follow captures thread for pawns */
X	  do
X	    {
X	      a[u] = ++a[u] | c;
X	      u = pdir[u];
X	  } while (u != sq);
X	}
X    }
}
X
X
/* ............    POSITIONAL EVALUATION ROUTINES    ............ */
X
int
evaluate (short int side,
X	  short int ply,
X	  short int alpha,
X	  short int beta,
X	  short int INCscore,
X	  short int *slk,
X	  short int *InChk)
X
/*
X  Compute an estimate of the score by adding the positional score from the
X  previous ply to the material difference. If this score falls inside a
X  window which is 180 points wider than the alpha-beta window (or within a
X  50 point window during quiescence search) call ScorePosition() to
X  determine a score, otherwise return the estimated score. If one side has
X  only a king and the other either has no pawns or no pieces then the
X  function ScoreLoneKing() is called.
*/
X
{
X  register short evflag, xside;
X  short s;
X
X  xside = otherside[side];
X  s = -Pscore[ply - 1] + mtl[side] - mtl[xside] - INCscore;
X  hung[white] = hung[black] = 0;
X  *slk = ((mtl[white] == valueK && (pmtl[black] == 0 || emtl[black] == 0)) ||
X	  (mtl[black] == valueK && (pmtl[white] == 0 || emtl[white] == 0)));
X
X  if (*slk)
X    evflag = false;
X  else
X    evflag = (ply == 1 || ply < Sdepth ||
X	      ((ply == Sdepth + 1 || ply == Sdepth + 2) &&
X	       (s > alpha - xwndw && s < beta + xwndw)) ||
X	      (ply > Sdepth + 2 && s >= alpha - 25 && s <= beta + 25));
X
X  if (evflag)
X    {
X      EvalNodes++;
X      ataks (side, atak[side]);
X      if (Anyatak (side, PieceList[xside][0]))
X	return (10001 - ply);
X      ataks (xside, atak[xside]);
X      *InChk = Anyatak (xside, PieceList[side][0]);
X      ScorePosition (side, &s);
X    }
X  else
X    {
X      if (SqAtakd (PieceList[xside][0], side))
X	return (10001 - ply);
X      *InChk = SqAtakd (PieceList[side][0], xside);
X      if (*slk)
X	ScoreLoneKing (side, &s);
X    }
X
X  Pscore[ply] = s - mtl[side] + mtl[xside];
X  if (*InChk)
X    ChkFlag[ply - 1] = Pindex[TOsquare];
X  else
X    ChkFlag[ply - 1] = 0;
X  return (s);
}
X
X
static inline int
ScoreKPK (short int side,
X	  short int winner,
X	  short int loser,
X	  short int king1,
X	  short int king2,
X	  short int sq)
X
/*
X  Score King and Pawns versus King endings.
*/
X
{
X  register short s, r;
X
X  if (PieceCnt[winner] == 1)
X    s = 50;
X  else
X    s = 120;
X  if (winner == white)
X    {
X      if (side == loser)
X	r = row (sq) - 1;
X      else
X	r = row (sq);
X      if (row (king2) >= r && distance (sq, king2) < 8 - r)
X	s += 10 * row (sq);
X      else
X	s = 500 + 50 * row (sq);
X      if (row (sq) < 6)
X	sq += 16;
X      else if (row (sq) == 6)
X	sq += 8;
X    }
X  else
X    {
X      if (side == loser)
X	r = row (sq) + 1;
X      else
X	r = row (sq);
X      if (row (king2) <= r && distance (sq, king2) < r + 1)
X	s += 10 * (7 - row (sq));
X      else
X	s = 500 + 50 * (7 - row (sq));
X      if (row (sq) > 1)
X	sq -= 16;
X      else if (row (sq) == 1)
X	sq -= 8;
X    }
X  s += 8 * (taxicab (king2, sq) - taxicab (king1, sq));
X  return (s);
}
X
X
static inline int
ScoreKBNK (short int winner, short int king1, short int king2)
X
X
/*
X  Score King+Bishop+Knight versus King endings.
X  This doesn't work all that well but it's better than nothing.
*/
X
{
X  register short s, sq, KBNKsq = 0;
X
X  for (sq = 0; sq < 64; sq++)
X    if (board[sq] == bishop)
X      if (row (sq) % 2 == column (sq) % 2)
X	KBNKsq = 0;
X      else
X	KBNKsq = 7;
X
X  s = emtl[winner] - 300;
X  if (KBNKsq == 0)
X    s += KBNK[king2];
X  else
X    s += KBNK[locn (row (king2), 7 - column (king2))];
X  s -= taxicab (king1, king2);
X  s -= distance (PieceList[winner][1], king2);
X  s -= distance (PieceList[winner][2], king2);
X  return (s);
}
X
X
void
ScoreLoneKing (short int side, short int *score)
X
/*
X  Static evaluation when loser has only a king and winner has no pawns or no
X  pieces.
*/
X
{
X  register short winner, loser, king1, king2, s, i;
X
X  UpdateWeights ();
X  if (mtl[white] > mtl[black])
X    winner = white;
X  else
X    winner = black;
X  loser = otherside[winner];
X  king1 = PieceList[winner][0];
X  king2 = PieceList[loser][0];
X
X  s = 0;
X
X  if (pmtl[winner] > 0)
X    for (i = 1; i <= PieceCnt[winner]; i++)
X      s += ScoreKPK (side, winner, loser, king1, king2, PieceList[winner][i]);
X
X  else if (emtl[winner] == valueB + valueN)
X    s = ScoreKBNK (winner, king1, king2);
X
X  else if (emtl[winner] > valueB)
X    s = 500 + emtl[winner] - DyingKing[king2] - 2 * distance (king1, king2);
X
X  if (side == winner)
X    *score = s;
X  else
X    *score = -s;
}
X
X
static inline void
BRscan (short int sq, short int *s, short int *mob)
X
/*
X  Find Bishop and Rook mobility, XRAY attacks, and pins. Increment the
X  hung[] array if a pin is found.
*/
{
X  register short u, piece, pin;
X  register unsigned char *ppos, *pdir;
X  short *Kf;
X
X  Kf = Kfield[c1];
X  *mob = 0;
X  piece = board[sq];
X  ppos = nextpos[piece][sq];
X  pdir = nextdir[piece][sq];
X  u = ppos[sq];
X  pin = -1;			/* start new direction */
X  do
X    {
X      *s += Kf[u];
X      if (color[u] == neutral)
X	{
X	  (*mob)++;
X	  if (ppos[u] == pdir[u])
X	    pin = -1;		/* oops new direction */
X	  u = ppos[u];
X	}
X      else if (pin < 0)
X	{
X	  if (board[u] == pawn || board[u] == king)
X	    u = pdir[u];
X	  else
X	    {
X	      if (ppos[u] != pdir[u])
X		pin = u;	/* not on the edge and on to find a pin */
X	      u = ppos[u];
X	    }
X	}
X      else
X	{
X	  if (color[u] == c2 && (board[u] > piece || atk2[u] == 0))
X	    {
X	      if (color[pin] == c2)
X		{
X		  *s += PINVAL;
X		  if (atk2[pin] == 0 ||
X		      atk1[pin] > control[board[pin]] + 1)
X		    ++hung[c2];
X		}
X	      else
X		*s += XRAY;
X	    }
X	  pin = -1;		/* new direction */
X	  u = pdir[u];
X	}
X  } while (u != sq);
}
X
X
static inline void
KingScan (short int sq, short int *s)
X
/*
X  Assign penalties if king can be threatened by checks, if squares
X  near the king are controlled by the enemy (especially the queen),
X  or if there are no pawns near the king.
X  The following must be true:
X  board[sq] == king
X  c1 == color[sq]
X  c2 == otherside[c1]
*/
X
#define ScoreThreat \
X	if (color[u] != c2)\
X  	if (atk1[u] == 0 || (atk2[u] & 0xFF) > 1) ++cnt;\
X  	else *s -= 3
X
{
X  register short u;
X  register unsigned char *ppos, *pdir;
X  register short cnt, ok;
X
X  cnt = 0;
X  if (HasBishop[c2] || HasQueen[c2])
X    {
X      ppos = nextpos[bishop][sq];
X      pdir = nextdir[bishop][sq];
X      u = ppos[sq];
X      do
X	{
X	  if (atk2[u] & ctlBQ)
X	    ScoreThreat;
X	  u = (color[u] == neutral) ? ppos[u] : pdir[u];
X      } while (u != sq);
X    }
X  if (HasRook[c2] || HasQueen[c2])
X    {
X      ppos = nextpos[rook][sq];
X      pdir = nextdir[rook][sq];
X      u = ppos[sq];
X      do
X	{
X	  if (atk2[u] & ctlRQ)
X	    ScoreThreat;
X	  u = (color[u] == neutral) ? ppos[u] : pdir[u];
X      } while (u != sq);
X    }
X  if (HasKnight[c2])
X    {
X      pdir = nextdir[knight][sq];
X      u = pdir[sq];
X      do
X	{
X	  if (atk2[u] & ctlNN)
X	    ScoreThreat;
X	  u = pdir[u];
X      } while (u != sq);
X    }
X  *s += (KSFTY * KTHRT[cnt]) / 16;
X
X  cnt = 0;
X  ok = false;
X  pdir = nextpos[king][sq];
X  u = pdir[sq];
X  do
X    {
X      if (board[u] == pawn)
X	ok = true;
X      if (atk2[u] > atk1[u])
X	{
X	  ++cnt;
X	  if (atk2[u] & ctlQ)
X	    if (atk2[u] > ctlQ + 1 && atk1[u] < ctlQ)
X	      *s -= 4 * KSFTY;
X	}
X      u = pdir[u];
X  } while (u != sq);
X  if (!ok)
X    *s -= KSFTY;
X  if (cnt > 1)
X    *s -= KSFTY;
}
X
X
static inline int
trapped (short int sq)
X
/*
X  See if the attacked piece has unattacked squares to move to.
X  The following must be true:
X  c1 == color[sq]
X  c2 == otherside[c1]
*/
X
{
X  register short u, piece;
X  register unsigned char *ppos, *pdir;
X
X  piece = board[sq];
X  ppos = nextpos[ptype[c1][piece]][sq];
X  pdir = nextdir[ptype[c1][piece]][sq];
X  if (piece == pawn)
X    {
X      u = ppos[sq];		/* follow no captures thread */
X      if (color[u] == neutral)
X	{
X	  if (atk1[u] >= atk2[u])
X	    return (false);
X	  if (atk2[u] < ctlP)
X	    {
X	      u = ppos[u];
X	      if (color[u] == neutral && atk1[u] >= atk2[u])
X		return (false);
X	    }
X	}
X      u = pdir[sq];		/* follow captures thread */
X      if (color[u] == c2)
X	return (false);
X      u = pdir[u];
X      if (color[u] == c2)
X	return (false);
X    }
X  else
X    {
X      u = ppos[sq];
X      do
X	{
X	  if (color[u] != c1)
X	    if (atk2[u] == 0 || board[u] >= piece)
X	      return (false);
X	  u = (color[u] == neutral) ? ppos[u] : pdir[u];
X      } while (u != sq);
X    }
X  return (true);
}
X
X
static inline int
PawnValue (short int sq, short int side)
X
/*
X  Calculate the positional value for a pawn on 'sq'.
*/
X
{
X  register short j, fyle, rank;
X  register short s, a1, a2, in_square, r, e;
X
X  a1 = (atk1[sq] & 0x4FFF);
X  a2 = (atk2[sq] & 0x4FFF);
X  rank = row (sq);
X  fyle = column (sq);
X  s = 0;
X  if (c1 == white)
X    {
X      s = Mwpawn[sq];
X      if ((sq == 11 && color[19] != neutral)
X	  || (sq == 12 && color[20] != neutral))
X	s += PEDRNK2B;
X      if ((fyle == 0 || PC1[fyle - 1] == 0)
X	  && (fyle == 7 || PC1[fyle + 1] == 0))
X	s += ISOLANI[fyle];
X      else if (PC1[fyle] > 1)
X	s += PDOUBLED;
X      if (a1 < ctlP && atk1[sq + 8] < ctlP)
X	{
X	  s += BACKWARD[a2 & 0xFF];
X	  if (PC2[fyle] == 0)
X	    s += PWEAKH;
X	  if (color[sq + 8] != neutral)
X	    s += PBLOK;
X	}
X      if (PC2[fyle] == 0)
X	{
X	  if (side == black)
X	    r = rank - 1;
X	  else
X	    r = rank;
X	  in_square = (row (bking) >= r && distance (sq, bking) < 8 - r);
X	  if (a2 == 0 || side == white)
X	    e = 0;
X	  else
X	    e = 1;
X	  for (j = sq + 8; j < 64; j += 8)
X	    if (atk2[j] >= ctlP)
X	      {
X		e = 2;
X		break;
X	      }
X	    else if (atk2[j] > 0 || color[j] != neutral)
X	      e = 1;
X	  if (e == 2)
X	    s += (stage * PassedPawn3[rank]) / 10;
X	  else if (in_square || e == 1)
X	    s += (stage * PassedPawn2[rank]) / 10;
X	  else if (emtl[black] > 0)
X	    s += (stage * PassedPawn1[rank]) / 10;
X	  else
X	    s += PassedPawn0[rank];
X	}
X    }
X  else if (c1 == black)
X    {
X      s = Mbpawn[sq];
X      if ((sq == 51 && color[43] != neutral)
X	  || (sq == 52 && color[44] != neutral))
X	s += PEDRNK2B;
X      if ((fyle == 0 || PC1[fyle - 1] == 0) &&
X	  (fyle == 7 || PC1[fyle + 1] == 0))
X	s += ISOLANI[fyle];
X      else if (PC1[fyle] > 1)
X	s += PDOUBLED;
X      if (a1 < ctlP && atk1[sq - 8] < ctlP)
X	{
X	  s += BACKWARD[a2 & 0xFF];
X	  if (PC2[fyle] == 0)
X	    s += PWEAKH;
X	  if (color[sq - 8] != neutral)
X	    s += PBLOK;
X	}
X      if (PC2[fyle] == 0)
X	{
X	  if (side == white)
X	    r = rank + 1;
X	  else
X	    r = rank;
X	  in_square = (row (wking) <= r && distance (sq, wking) < r + 1);
X	  if (a2 == 0 || side == black)
X	    e = 0;
X	  else
X	    e = 1;
X	  for (j = sq - 8; j >= 0; j -= 8)
X	    if (atk2[j] >= ctlP)
X	      {
X		e = 2;
X		break;
X	      }
X	    else if (atk2[j] > 0 || color[j] != neutral)
X	      e = 1;
X	  if (e == 2)
X	    s += (stage * PassedPawn3[7 - rank]) / 10;
X	  else if (in_square || e == 1)
X	    s += (stage * PassedPawn2[7 - rank]) / 10;
X	  else if (emtl[white] > 0)
X	    s += (stage * PassedPawn1[7 - rank]) / 10;
X	  else
X	    s += PassedPawn0[7 - rank];
X	}
X    }
X  if (a2 > 0)
X    {
X      if (a1 == 0 || a2 > ctlP + 1)
X	{
X	  s += HUNGP;
X	  ++hung[c1];
X	  if (trapped (sq))
X	    ++hung[c1];
X	}
X      else if (a2 > a1)
X	s += ATAKD;
X    }
X  return (s);
}
X
X
static inline int
KnightValue (short int sq, short int side)
X
/*
X  Calculate the positional value for a knight on 'sq'.
*/
X
{
X  register short s, a2, a1;
X
X  s = Mknight[c1][sq];
X  a2 = (atk2[sq] & 0x4FFF);
X  if (a2 > 0)
X    {
X      a1 = (atk1[sq] & 0x4FFF);
X      if (a1 == 0 || a2 > ctlBN + 1)
X	{
X	  s += HUNGP;
X	  ++hung[c1];
X	  if (trapped (sq))
X	    ++hung[c1];
X	}
X      else if (a2 >= ctlBN || a1 < ctlP)
X	s += ATAKD;
X    }
X  return (s);
}
X
X
static inline int
BishopValue (short int sq, short int side)
X
/*
X  Calculate the positional value for a bishop on 'sq'.
*/
X
{
X  register short a2, a1;
X  short s, mob;
X
X  s = Mbishop[c1][sq];
X  BRscan (sq, &s, &mob);
X  s += BMBLTY[mob];
X  a2 = (atk2[sq] & 0x4FFF);
X  if (a2 > 0)
X    {
X      a1 = (atk1[sq] & 0x4FFF);
X      if (a1 == 0 || a2 > ctlBN + 1)
X	{
X	  s += HUNGP;
X	  ++hung[c1];
X	  if (trapped (sq))
X	    ++hung[c1];
X	}
X      else if (a2 >= ctlBN || a1 < ctlP)
X	s += ATAKD;
X    }
X  return (s);
}
X
X
static inline int
RookValue (short int sq, short int side)
X
/*
X  Calculate the positional value for a rook on 'sq'.
*/
X
{
X  register short fyle, a2, a1;
X  short s, mob;
X
X  s = RookBonus;
X  BRscan (sq, &s, &mob);
X  s += RMBLTY[mob];
X  fyle = column (sq);
X  if (PC1[fyle] == 0)
X    s += RHOPN;
X  if (PC2[fyle] == 0)
X    s += RHOPNX;
X  if (pmtl[c2] > 100 && row (sq) == rank7[c1])
X    s += 10;
X  if (stage > 2)
X    s += 14 - taxicab (sq, EnemyKing);
X  a2 = (atk2[sq] & 0x4FFF);
X  if (a2 > 0)
X    {
X      a1 = (atk1[sq] & 0x4FFF);
X      if (a1 == 0 || a2 > ctlR + 1)
X	{
X	  s += HUNGP;
X	  ++hung[c1];
X
X	  if (trapped (sq))
X	    ++hung[c1];
X	}
X      else if (a2 >= ctlR || a1 < ctlP)
X	s += ATAKD;
X    }
X  return (s);
}
X
X
static inline int
QueenValue (short int sq, short int side)
X
/*
X  Calculate the positional value for a queen on 'sq'.
*/
X
{
X  register short s, a2, a1;
X
X  s = (distance (sq, EnemyKing) < 3) ? 12 : 0;
X  if (stage > 2)
X    s += 14 - taxicab (sq, EnemyKing);
X  a2 = (atk2[sq] & 0x4FFF);
X  if (a2 > 0)
X    {
X      a1 = (atk1[sq] & 0x4FFF);
X      if (a1 == 0 || a2 > ctlQ + 1)
X	{
X	  s += HUNGP;
X	  ++hung[c1];
X	  if (trapped (sq))
X	    ++hung[c1];
X	}
X      else if (a2 >= ctlQ || a1 < ctlP)
X	s += ATAKD;
X    }
X  return (s);
}
X
X
static inline int
KingValue (short int sq, short int side)
X
/*
X  Calculate the positional value for a king on 'sq'.
*/
X
{
X  register short fyle, a2, a1;
X  short s;
X
X  s = Mking[c1][sq];
X  if (KSFTY > 0)
X    if (Developed[c2] || stage > 0)
X      KingScan (sq, &s);
X  if (castld[c1])
X    s += KCASTLD;
X  else if (Mvboard[kingP[c1]])
X    s += KMOVD;
X
X  fyle = column (sq);
X  if (PC1[fyle] == 0)
X    s += KHOPN;
X  if (PC2[fyle] == 0)
X    s += KHOPNX;
X  switch (fyle)
X    {
X    case 5:
X      if (PC1[7] == 0)
X	s += KHOPN;
X      if (PC2[7] == 0)
X	s += KHOPNX;
X      /* Fall through */
X    case 4:
X    case 6:
X    case 0:
X      if (PC1[fyle + 1] == 0)
X	s += KHOPN;
X      if (PC2[fyle + 1] == 0)
X	s += KHOPNX;
X      break;
X    case 2:
X      if (PC1[0] == 0)
X	s += KHOPN;
X      if (PC2[0] == 0)
X	s += KHOPNX;
X      /* Fall through */
X    case 3:
X    case 1:
X    case 7:
X      if (PC1[fyle - 1] == 0)
X	s += KHOPN;
X      if (PC2[fyle - 1] == 0)
X	s += KHOPNX;
X      break;
X    default:
X      /* Impossible! */
X      break;
X    }
X
X  a2 = (atk2[sq] & 0x4FFF);
X  if (a2 > 0)
X    {
X      a1 = (atk1[sq] & 0x4FFF);
X      if (a1 == 0 || a2 > ctlK + 1)
X	{
X	  s += HUNGP;
X	  ++hung[c1];
X	}
X      else
X	s += ATAKD;
X    }
X  return (s);
}
X
X
void
ScorePosition (short int side, short int *score)
X
/*
X  Perform normal static evaluation of board position. A score is generated
X  for each piece and these are summed to get a score for each side.
*/
X
{
X  register short sq, s, i, xside;
X  short pscore[2];
X
X  UpdateWeights ();
X  xside = otherside[side];
X  pscore[white] = pscore[black] = 0;
X
X  for (c1 = white; c1 <= black; c1++)
X    {
X      c2 = otherside[c1];
X      atk1 = atak[c1];
X      atk2 = atak[c2];
X      PC1 = PawnCnt[c1];
X      PC2 = PawnCnt[c2];
X      for (i = PieceCnt[c1]; i >= 0; i--)
X	{
X	  sq = PieceList[c1][i];
X	  switch (board[sq])
X	    {
X	    case pawn:
X	      s = PawnValue (sq, side);
X	      break;
SHAR_EOF
true || echo 'restore of gnuchess.c failed'
fi
echo 'End of  part 4'
echo 'File gnuchess.c is continued in part 5'
echo 5 > _shar_seq_.tmp
exit 0
exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.