/*
 * eval.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"
#include "ataks.h"
short int sscore[2];
/* Backward pawn bonus indexed by # of attackers on the square */
static const short BACKWARD[16] =
{-6, -10, -15, -21, -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, -28};

/* Bishop mobility bonus indexed by # reachable squares */
static const short BMBLTY[14] =
{-2, 0, 2, 4, 6, 8, 10, 12, 13, 14, 15, 16, 16, 16};

/* Rook mobility bonus indexed by # reachable squares */
static const short RMBLTY[15] =
{0, 2, 4, 6, 8, 10, 11, 12, 13, 14, 14, 14, 14, 14, 14};

/* Positional values for a dying king */
static const short DyingKing[64] =
{0, 8, 16, 24, 24, 16, 8, 0,
 8, 32, 40, 48, 48, 40, 32, 8,
 16, 40, 56, 64, 64, 56, 40, 16,
 24, 48, 64, 72, 72, 64, 48, 24,
 24, 48, 64, 72, 72, 64, 48, 24,
 16, 40, 56, 64, 64, 56, 40, 16,
 8, 32, 40, 48, 48, 40, 32, 8,
 0, 8, 16, 24, 24, 16, 8, 0};

/* Isoloted pawn penalty by rank */
static const short ISOLANI[8] =
{-12, -16, -20, -24, -24, -20, -16, -12};

/* table for King Bishop Knight endings */
static const short KBNK[64] =
{99, 90, 80, 70, 60, 50, 40, 40,
 90, 80, 60, 50, 40, 30, 20, 40,
 80, 60, 40, 30, 20, 10, 30, 50,
 70, 50, 30, 10, 0, 20, 40, 60,
 60, 40, 20, 0, 10, 30, 50, 70,
 50, 30, 10, 20, 30, 40, 60, 80,
 40, 20, 30, 40, 50, 60, 80, 90,
 40, 40, 50, 60, 70, 80, 90, 99};

/* penalty for threats to king, indexed by number of such threats */
static const short KTHRT[36] =
{0, -8, -20, -36, -52, -68, -80, -80, -80, -80, -80, -80,
 -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80,
 -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80};

/* King positional bonus inopening stage */
static const short KingOpening[64] =
{0, 0, -4, -10, -10, -4, 0, 0,
 -4, -4, -8, -12, -12, -8, -4, -4,
 -12, -16, -20, -20, -20, -20, -16, -12,
 -16, -20, -24, -24, -24, -24, -20, -16,
 -16, -20, -24, -24, -24, -24, -20, -16,
 -12, -16, -20, -20, -20, -20, -16, -12,
 -4, -4, -8, -12, -12, -8, -4, -4,
 0, 0, -4, -10, -10, -4, 0, 0};

/* King positional bonus in end stage */
static const short KingEnding[64] =
{0, 6, 12, 18, 18, 12, 6, 0,
 6, 12, 18, 24, 24, 18, 12, 6,
 12, 18, 24, 30, 30, 24, 18, 12,
 18, 24, 30, 36, 36, 30, 24, 18,
 18, 24, 30, 36, 36, 30, 24, 18,
 12, 18, 24, 30, 30, 24, 18, 12,
 6, 12, 18, 24, 24, 18, 12, 6,
 0, 6, 12, 18, 18, 12, 6, 0};

/* Passed pawn positional bonus */
static const short PassedPawn0[8] =
{0, 60, 80, 120, 200, 360, 600, 800};
static const short PassedPawn1[8] =
{0, 30, 40, 60, 100, 180, 300, 800};
static const short PassedPawn2[8] =
{0, 15, 25, 35, 50, 90, 140, 800};
static const short PassedPawn3[8] =
{0, 5, 10, 15, 20, 30, 140, 800};

/* Knight positional bonus */
static const short pknight[64] =
{0, 4, 8, 10, 10, 8, 4, 0,
 4, 8, 16, 20, 20, 16, 8, 4,
 8, 16, 24, 28, 28, 24, 16, 8,
 10, 20, 28, 32, 32, 28, 20, 10,
 10, 20, 28, 32, 32, 28, 20, 10,
 8, 16, 24, 28, 28, 24, 16, 8,
 4, 8, 16, 20, 20, 16, 8, 4,
 0, 4, 8, 10, 10, 8, 4, 0};

/* Bishop positional bonus */
static const short pbishop[64] =
{14, 14, 14, 14, 14, 14, 14, 14,
 14, 22, 18, 18, 18, 18, 22, 14,
 14, 18, 22, 22, 22, 22, 18, 14,
 14, 18, 22, 22, 22, 22, 18, 14,
 14, 18, 22, 22, 22, 22, 18, 14,
 14, 18, 22, 22, 22, 22, 18, 14,
 14, 22, 18, 18, 18, 18, 22, 14,
 14, 14, 14, 14, 14, 14, 14, 14};

/* Pawn positional bonus */
static const short PawnAdvance[64] =
{0, 0, 0, 0, 0, 0, 0, 0,
 4, 4, 4, 0, 0, 4, 4, 4,
 6, 8, 2, 10, 10, 2, 8, 6,
 6, 8, 12, 16, 16, 12, 8, 6,
 8, 12, 16, 24, 24, 16, 12, 8,
 12, 16, 24, 32, 32, 24, 16, 12,
 12, 16, 24, 32, 32, 24, 16, 12,
 0, 0, 0, 0, 0, 0, 0, 0};
#if !defined NOSCORESPACE
#ifdef BLACKAG0
/* Space positional bonus */
static const short SpaceBonusB[64] =
{0, 0, 0, 0, 0, 0, 0, 0,
 0, 0, 2, 2, 2, 2, 0, 0,
 1, 1, 2, 4, 4, 2, 1, 1,
 0, 0, 3, 4, 4, 3, 0, 0,
 0, 0, 5, 5, 5, 5, 0, 0,
 0, 0, 4, 4, 7, 7, 0, 0,
 0, 0, 0, 0, 0, 0, 0, 0,
 0, 0, 0, 0, 0, 0, 0, 0};
#elif defined BLACKAG1
/* Space positional bonus */
static const short SpaceBonusB[64] =
{1, 1, 1, 1, 1, 1, 1, 1,
 1, 1, 2, 2, 2, 2, 1, 1,
 1, 1, 2, 3, 3, 2, 1, 1,
 1, 1, 2, 4, 4, 2, 1, 1,
 1, 1, 3, 5, 5, 3, 1, 1,
 1, 1, 3, 6, 6, 3, 1, 1,
 1, 1, 3, 7, 7, 3, 1, 1,
 1, 1, 1, 1, 1, 1, 1, 1};
#elif defined BLACKAG2
/* Space positional bonus */
static const short SpaceBonusB[64] =
{1, 1, 1, 1, 1, 1, 1, 1,
 1, 1, 2, 2, 2, 2, 1, 1,
 1, 1, 3, 3, 3, 3, 1, 1,
 1, 1, 4, 4, 4, 4, 1, 1,
 1, 1, 5, 6, 6, 5, 1, 1,
 1, 1, 6, 7, 7, 6, 1, 1,
 1, 1, 7, 8, 8, 7, 1, 1,
 1, 1, 1, 1, 1, 1, 1, 1};
#elif defined BLACKAG3
/* Space positional bonus */
static const short SpaceBonusB[64] =
{0, 0, 0, 0, 0, 0, 0, 0,
 0, 0, 2, 2, 2, 2, 0, 0,
 0, 0, 3, 3, 3, 3, 0, 0,
 0, 0, 4, 4, 4, 3, 0, 0,
 0, 0, 6, 6, 4, 4, 0, 0,
 0, 0, 7, 7, 5, 5, 0, 0,
 0, 0, 8, 8, 7, 7, 0, 0,
 0, 0, 0, 0, 0, 0, 0, 0};
#elif defined BLACKAG4
/* Space positional bonus */
static const short SpaceBonusB[64] =
{1, 1, 1, 1, 1, 1, 1, 1,
 1, 1, 2, 4, 4, 2, 1, 1,
 1, 1, 2, 4, 4, 2, 1, 1,
 1, 1, 2, 4, 4, 2, 1, 1,
 1, 1, 2, 4, 4, 2, 1, 1,
 1, 1, 2, 4, 4, 2, 1, 1,
 1, 1, 2, 4, 4, 2, 1, 1,
 1, 1, 1, 1, 1, 1, 1, 1};
#endif

#ifdef WHITEAG0
/* Space positional bonus */
static const short SpaceBonusW[64] =
{0, 0, 0, 0, 0, 0, 0, 0,
 0, 0, 5, 5, 5, 5, 0, 0,
 0, 0, 3, 4, 4, 3, 0, 0,
 0, 0, 2, 4, 4, 2, 0, 0,
 0, 0, 1, 4, 4, 1, 0, 0,
 0, 0, 1, 4, 4, 1, 0, 0,
 0, 0, 1, 2, 2, 1, 0, 0,
 0, 0, 0, 0, 0, 0, 0, 0};
#elif defined WHITEAG1
/* Space positional bonus */
static const short SpaceBonusW[64] =
{1, 1, 1, 1, 1, 1, 1, 1,
 1, 1, 3, 7, 7, 3, 1, 1,
 1, 1, 3, 6, 6, 3, 1, 1,
 1, 1, 3, 5, 5, 3, 1, 1,
 1, 1, 2, 4, 4, 2, 1, 1,
 1, 1, 2, 3, 3, 2, 1, 1,
 1, 1, 2, 2, 2, 2, 1, 1,
 1, 1, 1, 1, 1, 1, 1, 1};
#elif defined WHITEAG2
/* Space positional bonus */
static const short SpaceBonusW[64] =
{1, 1, 1, 1, 1, 1, 1, 1,
 1, 1, 7, 8, 8, 7, 1, 1,
 1, 1, 6, 7, 7, 6, 1, 1,
 1, 1, 5, 6, 6, 5, 1, 1,
 1, 1, 4, 4, 4, 4, 1, 1,
 1, 1, 3, 3, 3, 3, 1, 1,
 1, 1, 2, 2, 2, 2, 1, 1,
 1, 1, 1, 1, 1, 1, 1, 1};
#elif defined WHITEAG3
/* Space positional bonus */
static const short SpaceBonusW[64] =
{0, 0, 0, 0, 0, 0, 0, 0,
 0, 0, 8, 8, 7, 7, 0, 0,
 0, 0, 7, 7, 5, 5, 0, 0,
 0, 0, 6, 6, 4, 4, 0, 0,
 0, 0, 4, 4, 4, 3, 0, 0,
 0, 0, 3, 3, 3, 3, 0, 0,
 0, 0, 2, 2, 2, 2, 0, 0,
 0, 0, 0, 0, 0, 0, 0, 0};
#elif defined WHITEAG4
/* Space positional bonus */
static const short SpaceBonusW[64] =
{1, 1, 1, 1, 1, 1, 1, 1,
 1, 1, 2, 4, 4, 2, 1, 1,
 1, 1, 2, 4, 4, 2, 1, 1,
 1, 1, 2, 4, 4, 2, 1, 1,
 1, 1, 2, 4, 4, 2, 1, 1,
 1, 1, 2, 4, 4, 2, 1, 1,
 1, 1, 2, 4, 4, 2, 1, 1,
 1, 1, 1, 1, 1, 1, 1, 1};
#endif
#endif

short Mwpawn[64], Mbpawn[64], Mknight[2][64], Mbishop[2][64];
static short Mking[2][64], Kfield[2][64];
static short c1, c2, *atk1, *atk2, *PC1, *PC2, atak[2][64];
short emtl[2];
static short PawnBonus, BishopBonus, RookBonus;
static short KNIGHTPOST, KNIGHTSTRONG, BISHOPSTRONG, KATAK;
static short PEDRNK2B, PWEAKH, PADVNCM, PADVNCI, PAWNSHIELD, PDOUBLED,
 PBLOK;
static short RHOPN, RHOPNX, KHOPN, KHOPNX, KSFTY;
static short ATAKD, HUNGP, HUNGX, KCASTLD, KMOVD, XRAY, PINVAL;
short pscore[2];
short tmtl;

/* ............    POSITIONAL EVALUATION ROUTINES    ............ */

/*
 * Inputs are:
 * pmtl[side] - value of pawns
 * mtl[side]  - value of all material
 * emtl[side] - vaule of all material - value of pawns - value of king
 * hung[side] - count of hung pieces
 * Tscore[ply] - search tree score for ply
 * ply
 * Pscore[ply] - positional score for ply ply
 * INCscore    - bonus score or penalty for certain positions
 * slk - single lone king flag
 * Sdepth - search goal depth
 * xwndw - evaluation window about alpha/beta
 * EWNDW - second evaluation window about alpha/beta
 * ChkFlag[ply]- checking piece at level ply or 0 if no check
 */
inline
short
ScoreKPK (short int side,
	  short int winner,
	  short int loser,
	  short int king1,
	  register short int king2,
	  register short int sq)

/*
 * Score King and Pawns versus King endings.
 */

{
  register short s, r;

  s = ((PieceCnt[winner] == 1) ? 50 : 120);
  if (winner == white)
    {
      r = row (sq) - ((side == loser) ? 1 : 0);
      if (row (king2) >= r && distance (sq, king2) < 8 - r)
	s += 10 * row (sq);
      else
	s = 500 + 50 * row (sq);
      if (row (sq) < 6)
	sq += 16;
      else if (row (sq) == 6)
	sq += 8;
    }
  else
    {
      r = row (sq) + ((side == loser) ? 1 : 0);
      if (row (king2) <= r && distance (sq, king2) < r + 1)
	s += 10 * (7 - row (sq));
      else
	s = 500 + 50 * (7 - row (sq));
      if (row (sq) > 1)
	sq -= 16;
      else if (row (sq) == 1)
	sq -= 8;
    }
  s += 8 * (taxicab (king2, sq) - taxicab (king1, sq));
#if defined(AMIGADB)&&defined(LATTICE)
  {
  if (abs(s) >= 10000)
	flash(),fprintf(stderr, "eval1: s = %d\n", s);
  return (s);
  }
#else
  return (s);
#endif
}


inline
short
ScoreKBNK (short int winner, short int king1, short int king2)


/*
 * Score King+Bishop+Knight versus King endings. This doesn't work all that
 * well but it's better than nothing.
 */

{
  register short s, sq, KBNKsq = 0;

  for (sq = 0; sq < 64; sq++)
    if (board[sq] == bishop)
      KBNKsq = (((row (sq) % 2) == (column (sq) % 2)) ? 0 : 7);

  s = emtl[winner] - 300;
  s += ((KBNKsq == 0) ? KBNK[king2] : KBNK[locn (row (king2), 7 - column (king2))]);
  s -= ((taxicab (king1, king2) + distance (PieceList[winner][1], king2) + distance (PieceList[winner][2], king2)));
#if defined(AMIGADB)&&defined(LATTICE)
  {
  if (abs(s) >= 10000)
	flash(),fprintf(stderr, "eval2: s = %d\n", s);
  return (s);
  }
#else
  return (s);
#endif
}

inline
short int
ScoreLoneKing (short int side)

/*
 * Static evaluation when loser has only a king and winner has no pawns or no
 * pieces.
 */

{
  register short winner, loser, king1, king2, s, i;

  UpdateWeights ();
  winner = ((mtl[white] > mtl[black]) ? white : black);
  loser = winner ^ 1;
  king1 = PieceList[winner][0];
  king2 = PieceList[loser][0];

  s = 0;

  if (pmtl[winner] > 0)
    for (i = 1; i <= PieceCnt[winner]; i++)
      s += ScoreKPK (side, winner, loser, king1, king2, PieceList[winner][i]);

  else if (emtl[winner] == valueB + valueN)
    s = ScoreKBNK (winner, king1, king2);

  else if (emtl[winner] > valueB)
    s = 500 + emtl[winner] - DyingKing[king2] - 2 * distance (king1, king2);

#if defined(AMIGADB)&&defined(LATTICE)
  {
  if (abs((side == winner) ? s : -s) >= 10000)
	flash(),fprintf(stderr, "eval3: (side == winner) ? s : -s = %d\n", (side == winner) ? s : -s);
  return ((side == winner) ? s : -s);
  }
#else
  return ((side == winner) ? s : -s);
#endif
}

short
evaluate (register short int side,
	  register short int ply,
	  register short int alpha,
	  register short int beta,
	  short int INCscore,
	  short int *slk,	/* output single lone king */
	  short int *InChk)	/* output Check flag */

/*
 * Compute an estimate of the score by adding the positional score from the
 * previous ply to the material difference. If this score falls inside a
 * window which is 180 points wider than the alpha-beta window (or within a
 * 50 point window during quiescence search) call ScorePosition() to
 * determine a score, otherwise return the estimated score. If one side has
 * only a king and the other either has no pawns or no pieces then the
 * function ScoreLoneKing() is called.
 */

{
  register short evflag, xside;
  short s;

  xside = side ^ 1;
  s = -Pscore[ply - 1] + mtl[side] - mtl[xside] - INCscore;
  hung[white] = hung[black] = 0;
  *slk = ((mtl[white] == valueK && (pmtl[black] == 0 || emtl[black] == 0)) ||
	  (mtl[black] == valueK && (pmtl[white] == 0 || emtl[white] == 0)));

  if (*slk)
    evflag = false;
  else
    /* should we use the estimete or score the position */
    evflag = (ply == 1 ||
	      ((ply <= Sdepth)) ||
	      ((ply == Sdepth + 1 || ply == (Sdepth + 2)) && (s > (alpha - xwndw) && s < (beta + xwndw))) ||
       (ply > (Sdepth + 2) && s >= (alpha - EWNDW) && s <= (beta + EWNDW)));
#ifdef DEBUG4
  if (debuglevel & 1)
    evflag = true;
#endif
  if (evflag)
    {
      /* score the position */
      ataks (side, atak[side]);
      if (Anyatak (side, PieceList[xside][0]))
	return (10001 - ply);
      ataks (xside, atak[xside]);
      *InChk = Anyatak (xside, PieceList[side][0]);
      EvalNodes++;
      s = ScorePosition (side);
    }
  else
    {
      /* use the estimate but look at check and slk */
      if (SqAtakd (PieceList[xside][0], side))
	return (10001 - ply);
      *InChk = SqAtakd (PieceList[side][0], xside);
      if (*slk)
	s = ScoreLoneKing (side);
    }

  Pscore[ply] = s - mtl[side] + mtl[xside];
  ChkFlag[ply - 1] = ((*InChk) ? Pindex[TOsquare] : 0);
#if defined(AMIGADB)&&defined(LATTICE)
  {
  if (abs(s) >= 10000)
	flash(),fprintf(stderr, "eval4: s = %d\n", s);
  return (s);
  }
#else
  return (s);
#endif
}

inline
void
BRscan (short int sq, register short int *s, short int *mob)

/*
 * Find Bishop and Rook mobility, XRAY attacks, and pins. Increment the
 * hung[] array if a pin is found.
 */
{
  register short u, pin;
  register unsigned char *ppos, *pdir;
  short piece, *Kf;

  Kf = Kfield[c1];
  *mob = 0;
  piece = board[sq];
  ppos = nextpos[piece][sq];
  pdir = nextdir[piece][sq];
  u = ppos[sq];
  pin = -1;			/* start new direction */
  do
    {
      *s += Kf[u];
      if (color[u] == neutral)
	{
	  (*mob)++;
	  if (ppos[u] == pdir[u])
	    pin = -1;		/* oops new direction */
	  u = ppos[u];
	}
      else if (pin < 0)
	{
	  if (board[u] == pawn || board[u] == king)
	    u = pdir[u];
	  else
	    {
	      if (ppos[u] != pdir[u])
		pin = u;	/* not on the edge and on to find a pin */
	      u = ppos[u];
	    }
	}
      else
	{
	  if (color[u] == c2 && (board[u] > piece || atk2[u] == 0))
	    {
	      if (color[pin] == c2)
		{
		  *s += PINVAL;
		  if (atk2[pin] == 0 || atk1[pin] > control[board[pin]] + 1)
		    ++hung[c2];
		}
	      else
		*s += XRAY;
	    }
	  pin = -1;		/* new direction */
	  u = pdir[u];
	}
  } while (u != sq);
}

inline
short int
KingScan (register short int sq)

/*
 * Assign penalties if king can be threatened by checks, if squares near the
 * king are controlled by the enemy (especially the queen), or if there are
 * no pawns near the king. The following must be true: board[sq] == king c1
 * == color[sq] c2 == otherside[c1]
 */

#define ScoreThreat \
	if (color[u] != c2)\
  	if (atk1[u] == 0 || (atk2[u] & 0xFF) > 1) ++cnt;\
  	else s -= 3

{
  register short int s;
  register short u;
  register unsigned char *ppos, *pdir;
  register short cnt, ok;

  s = 0;
  cnt = 0;
  if (HasBishop[c2] || HasQueen[c2])
    {
      ppos = nextpos[bishop][sq];
      pdir = nextdir[bishop][sq];
      u = ppos[sq];
      do
	{
	  if (atk2[u] & ctlBQ)
	    ScoreThreat;
	  u = ((color[u] == neutral) ? ppos[u] : pdir[u]);
      } while (u != sq);
    }
  if (HasRook[c2] || HasQueen[c2])
    {
      ppos = nextpos[rook][sq];
      pdir = nextdir[rook][sq];
      u = ppos[sq];
      do
	{
	  if (atk2[u] & ctlRQ)
	    ScoreThreat;
	  u = ((color[u] == neutral) ? ppos[u] : pdir[u]);
      } while (u != sq);
    }
  if (HasKnight[c2])
    {
      pdir = nextdir[knight][sq];
      u = pdir[sq];
      do
	{
	  if (atk2[u] & ctlNN)
	    ScoreThreat;
	  u = pdir[u];
      } while (u != sq);
    }
  s += (KSFTY * KTHRT[cnt]) / 16;

  cnt = 0;
  ok = false;
  pdir = nextpos[king][sq];
  u = pdir[sq];
  do
    {
      if (board[u] == pawn)
	ok = true;
      if (atk2[u] > atk1[u])
	{
	  ++cnt;
	  if (atk2[u] & ctlQ)
	    if (atk2[u] > ctlQ + 1 && atk1[u] < ctlQ)
	      s -= 4 * KSFTY;
	}
      u = pdir[u];
  } while (u != sq);
  if (!ok)
    s -= KSFTY;
  if (cnt > 1)
    s -= (KSFTY);
#if defined(AMIGADB)&&defined(LATTICE)
  {
  if (abs(s) >= 10000)
	flash(),fprintf(stderr, "eval5: s = %d\n", s);
  return (s);
  }
#else
  return (s);
#endif
}

inline
int
trapped (register short int sq)

/*
 * See if the attacked piece has unattacked squares to move to. The following
 * must be true: c1 == color[sq] c2 == otherside[c1]
 */

{
  register short u, piece;
  register unsigned char *ppos, *pdir;

  piece = board[sq];
  ppos = nextpos[ptype[c1][piece]][sq];
  pdir = nextdir[ptype[c1][piece]][sq];
  if (piece == pawn)
    {
      u = ppos[sq];		/* follow no captures thread */
      if (color[u] == neutral)
	{
	  if (atk1[u] >= atk2[u])
	    return (false);
	  if (atk2[u] < ctlP)
	    {
	      u = ppos[u];
	      if (color[u] == neutral && atk1[u] >= atk2[u])
		return (false);
	    }
	}
      u = pdir[sq];		/* follow captures thread */
      if (color[u] == c2)
	return (false);
      u = pdir[u];
      if (color[u] == c2)
	return (false);
    }
  else
    {
      u = ppos[sq];
      do
	{
	  if (color[u] != c1)
	    if (atk2[u] == 0 || board[u] >= piece)
	      return (false);
	  u = ((color[u] == neutral) ? ppos[u] : pdir[u]);
      } while (u != sq);
    }
  return (true);
}


static inline short
PawnValue(short int sq, short int side)
/*
 * Calculate the positional value for a pawn on 'sq'.
 */

{
	register short  j, fyle, rank;
	register short  s, a1, a2, in_square, r, e;

	a1 = (atk1[sq] & 0x4FFF);
	a2 = (atk2[sq] & 0x4FFF);
	rank = row(sq);
	fyle = column(sq);
	s = 0;
	if (c1 == white) {
		s = Mwpawn[sq];
		if ((sq == 11 && color[19] != neutral)
		    || (sq == 12 && color[20] != neutral))
			s += PEDRNK2B;
		if ((fyle == 0 || PC1[fyle - 1] == 0)
		    && (fyle == 7 || PC1[fyle + 1] == 0))
			s += ISOLANI[fyle];
		else if (PC1[fyle] > 1)
			s += PDOUBLED;
		if (a1 < ctlP && atk1[sq + 8] < ctlP) {
			s += BACKWARD[a2 & 0xFF];
			if (PC2[fyle] == 0)
				s += PWEAKH;
			if (color[sq + 8] != neutral)
				s += PBLOK;
		}
		if (PC2[fyle] == 0) {
			if (side == black)
				r = rank - 1;
			else
				r = rank;
			in_square = (row(bking) >= r && distance(sq, bking) < 8 - r);
			if (a2 == 0 || side == white)
				e = 0;
			else
				e = 1;
			for (j = sq + 8; j < 64; j += 8)
				if (atk2[j] >= ctlP) {
					e = 2;
					break;
				} else if (atk2[j] > 0 || color[j] != neutral)
					e = 1;
			if (e == 2)
				s += (stage * PassedPawn3[rank]) / 10;
			else if (in_square || e == 1)
				s += (stage * PassedPawn2[rank]) / 10;
			else if (emtl[black] > 0)
				s += (stage * PassedPawn1[rank]) / 10;
			else
				s += PassedPawn0[rank];
		}
	} else if (c1 == black) {
		s = Mbpawn[sq];
		if ((sq == 51 && color[43] != neutral)
		    || (sq == 52 && color[44] != neutral))
			s += PEDRNK2B;
		if ((fyle == 0 || PC1[fyle - 1] == 0) &&
		    (fyle == 7 || PC1[fyle + 1] == 0))
			s += ISOLANI[fyle];
		else if (PC1[fyle] > 1)
			s += PDOUBLED;
		if (a1 < ctlP && atk1[sq - 8] < ctlP) {
			s += BACKWARD[a2 & 0xFF];
			if (PC2[fyle] == 0)
				s += PWEAKH;
			if (color[sq - 8] != neutral)
				s += PBLOK;
		}
		if (PC2[fyle] == 0) {
			if (side == white)
				r = rank + 1;
			else
				r = rank;
			in_square = (row(wking) <= r && distance(sq, wking) < r + 1);
			if (a2 == 0 || side == black)
				e = 0;
			else
				e = 1;
			for (j = sq - 8; j >= 0; j -= 8)
				if (atk2[j] >= ctlP) {
					e = 2;
					break;
				} else if (atk2[j] > 0 || color[j] != neutral)
					e = 1;
			if (e == 2)
				s += (stage * PassedPawn3[7 - rank]) / 10;
			else if (in_square || e == 1)
				s += (stage * PassedPawn2[7 - rank]) / 10;
			else if (emtl[white] > 0)
				s += (stage * PassedPawn1[7 - rank]) / 10;
			else
				s += PassedPawn0[7 - rank];
		}
	}
	if (a2 > 0) {
		if (a1 == 0 || a2 > ctlP + 1) {
			s += HUNGP;
			++hung[c1];
			if (trapped(sq))
				++hung[c1];
		} else if (a2 > a1)
			s += ATAKD;
	}
#if defined(AMIGADB)&&defined(LATTICE)
  {
  if (abs(s) >= 10000)
	flash(),fprintf(stderr, "eval6: s = %d\n", s);
  return (s);
  }
#else
	return (s);
#endif
}
inline
short
KnightValue (short int sq, short int side)

/*
 * Calculate the positional value for a knight on 'sq'.
 */

{
  register short s, a2, a1;

  s = Mknight[c1][sq];
  a2 = (atk2[sq] & 0x4FFF);
  if (a2 > 0)
    {
      a1 = (atk1[sq] & 0x4FFF);
      if (a1 == 0 || a2 > ctlBN + 1)
	{
	  s += HUNGP;
	  ++hung[c1];
	  if (trapped (sq))
	    ++hung[c1];
	}
      else if (a2 >= ctlBN || a1 < ctlP)
	s += ATAKD;
    }
#if defined(AMIGADB)&&defined(LATTICE)
  {
  if (abs(s) >= 10000)
	flash(),fprintf(stderr, "eval7: s = %d\n", s);
  return (s);
  }
#else
  return (s);
#endif
}

inline
short
BishopValue (short int sq, short int side)

/*
 * Calculate the positional value for a bishop on 'sq'.
 */

{
  register short a2, a1;
  short s, mob;

  s = Mbishop[c1][sq];
  BRscan (sq, &s, &mob);
  s += BMBLTY[mob];
  a2 = (atk2[sq] & 0x4FFF);
  if (a2 > 0)
    {
      a1 = (atk1[sq] & 0x4FFF);
      if (a1 == 0 || a2 > ctlBN + 1)
	{
	  s += HUNGP;
	  ++hung[c1];
	  if (trapped (sq))
	    ++hung[c1];
	}
      else if (a2 >= ctlBN || a1 < ctlP)
	s += ATAKD;
    }
#if defined(AMIGADB)&&defined(LATTICE)
  {
  if (abs(s) >= 10000)
	flash(),fprintf(stderr, "eval8: s = %d\n", s);
  return (s);
  }
#else
  return (s);
#endif
}

inline
short
RookValue (register short int sq, short int side)

/*
 * Calculate the positional value for a rook on 'sq'.
 */

{
  register short fyle, a2, a1;
  short s, mob;

  s = RookBonus;
  BRscan (sq, &s, &mob);
  s += RMBLTY[mob];
  fyle = column (sq);
  if (PC1[fyle] == 0)
    s += RHOPN;
  if (PC2[fyle] == 0)
    s += RHOPNX;
  if (pmtl[c2] > 100 && row (sq) == rank7[c1])
    s += 10;
  if (stage > 2)
    s += 14 - taxicab (sq, EnemyKing);
  a2 = (atk2[sq] & 0x4FFF);
  if (a2 > 0)
    {
      a1 = (atk1[sq] & 0x4FFF);
      if (a1 == 0 || a2 > ctlR + 1)
	{
	  s += HUNGP;
	  ++hung[c1];

	  if (trapped (sq))
	    ++hung[c1];
	}
      else if (a2 >= ctlR || a1 < ctlP)
	s += ATAKD;
    }
#if defined(AMIGADB)&&defined(LATTICE)
  {
  if (abs(s) >= 10000)
	flash(),fprintf(stderr, "eval9: s = %d\n", s);
  return (s);
  }
#else
  return (s);
#endif
}

inline
short
QueenValue (register short int sq, short int side)

/*
 * Calculate the positional value for a queen on 'sq'.
 */

{
  register short s, a2, a1;

  s = ((distance (sq, EnemyKing) < 3) ? 12 : 0);
  if (stage > 2)
    s += 14 - taxicab (sq, EnemyKing);
  a2 = (atk2[sq] & 0x4FFF);
  if (a2 > 0)
    {
      a1 = (atk1[sq] & 0x4FFF);
      if (a1 == 0 || a2 > ctlQ + 1)
	{
	  s += HUNGP;
	  ++hung[c1];
	  if (trapped (sq))
	    ++hung[c1];
	}
      else if (a2 >= ctlQ || a1 < ctlP)
	s += ATAKD;
    }
#if defined(AMIGADB)&&defined(LATTICE)
  {
  if (abs(s) >= 10000)
	flash(),fprintf(stderr, "eval10: s = %d\n", s);
  return (s);
  }
#else
  return (s);
#endif
}

inline
short
KingValue (short int sq, short int side)

/*
 * Calculate the positional value for a king on 'sq'.
 */

{
  register short fyle, a2, a1;
  short s;
  s = (emtl[side ^ 1] > KINGPOSLIMIT) ? Mking[c1][sq] : Mking[c1][sq] / 2;
  if (KSFTY > 0)
    if (Developed[c2] || stage > 0)
      s += KingScan (sq);
  if (castld[c1])
    s += KCASTLD;
  else if (Mvboard[kingP[c1]])
    s += KMOVD;

  fyle = column (sq);
  if (PC1[fyle] == 0)
    s += KHOPN;
  if (PC2[fyle] == 0)
    s += KHOPNX;
  switch (fyle)
    {
    case 5:
      if (PC1[7] == 0)
	s += KHOPN;
      if (PC2[7] == 0)
	s += KHOPNX;
      /* Fall through */
    case 4:
    case 6:
    case 0:
      if (PC1[fyle + 1] == 0)
	s += KHOPN;
      if (PC2[fyle + 1] == 0)
	s += KHOPNX;
      break;
    case 2:
      if (PC1[0] == 0)
	s += KHOPN;
      if (PC2[0] == 0)
	s += KHOPNX;
      /* Fall through */
    case 3:
    case 1:
    case 7:
      if (PC1[fyle - 1] == 0)
	s += KHOPN;
      if (PC2[fyle - 1] == 0)
	s += KHOPNX;
      break;
    default:
      /* Impossible! */
      break;
    }

  a2 = (atk2[sq] & 0x4FFF);
  if (a2 > 0)
    {
      a1 = (atk1[sq] & 0x4FFF);
      if (a1 == 0 || a2 > ctlK + 1)
	{
	  s += HUNGP;
	  ++hung[c1];
	}
      else
	s += ATAKD;
    }
#if defined(AMIGADB)&&defined(LATTICE)
  {
  if (abs(s) >= 10000)
	flash(),fprintf(stderr, "eval11: s = %d\n", s);
  return (s);
  }
#else
  return (s);
#endif
}

#if !defined NOSCORESPACE
inline
void
ScoreSpace (void)
{
  register short *b, *w, *sw, *sb;
  register short sBl, sWh;
  sBl = sWh = 0;
  for (b = &atak[black][63], w = &atak[white][63], sw = &SpaceBonusW[63], sb = &SpaceBonusB[63];
       sw > &SpaceBonusW[0];
       b--, w--, sw--, sb--)
    {
      if (*b > *w)
	{
	  if (*b > ctlR)
	    sBl += *sb;
	}
      else if (*b < *w)
	if (*w > ctlR)
	  sWh += *sw;
    }
  pscore[white] += (sWh);
  pscore[black] += (sBl);
  sscore[white] = sWh;
  sscore[black] = sBl;
}

#endif



short int
ScorePosition (register short int side)

/*
 * Perform normal static evaluation of board position. A score is generated
 * for each piece and these are summed to get a score for each side.
 */

{
  register short int score;
  register short sq, s, i, xside;

  UpdateWeights ();
  xside = side ^ 1;
  hung[white]= hung[black] = pscore[white] = pscore[black] = 0;
#if !defined NOSCORESPACE
  if (stage < SCORESPLIM)
    ScoreSpace ();
#endif
  for (c1 = white; c1 <= black; c1++)
    {
      c2 = c1 ^ 1;
      /* atk1 is array of atacks on squares by my side */
      atk1 = atak[c1];
      /* atk2 is array of atacks on squares by other side */
      atk2 = atak[c2];
      /* same for PC1 and PC2 */
      PC1 = PawnCnt[c1];
      PC2 = PawnCnt[c2];
      for (i = PieceCnt[c1]; i >= 0; i--)
	{
	  sq = PieceList[c1][i];
	  switch (board[sq])
	    {
	    case pawn:
	      s = PawnValue (sq, side);
	      break;
	    case knight:
	      s = KnightValue (sq, side);
	      break;
	    case bishop:
	      s = BishopValue (sq, side);
	      break;
	    case rook:
	      s = RookValue (sq, side);
	      break;
	    case queen:
	      s = QueenValue (sq, side);
	      break;
	    case king:
	      s = KingValue (sq, side);
	      break;
	    default:
	      s = 0;
	      break;
	    }
	  pscore[c1] += s;
	  svalue[sq] = s;
	}
    }
  if (hung[side] > 1)
    pscore[side] += HUNGX;
  if (hung[xside] > 1)
    pscore[xside] += HUNGX;

  score = mtl[side] - mtl[xside] + pscore[side] - pscore[xside] + 10;
  if (dither)
    {
      if (flag.hash)
	srand (starttime + (unsigned int) hashbd);
      score += urand () % dither;
    }

  if (score > 0 && pmtl[side] == 0)
    if (emtl[side] < valueR)
      score = 0;
    else if (score < valueR)
      score /= 2;
  if (score < 0 && pmtl[xside] == 0)
    if (emtl[xside] < valueR)
      score = 0;
    else if (-score < valueR)
      score /= 2;

  if (mtl[xside] == valueK && emtl[side] > valueB)
    score += 200;
  if (mtl[side] == valueK && emtl[xside] > valueB)
    score -= 200;
#if defined(AMIGADB)&&defined(LATTICE)
  {
  if (abs(score) >= 10000)
	flash(),fprintf(stderr, "eval12: score = %d\n", score);
  return (score);
  }
#else
  return (score);
#endif
}
static inline void
BlendBoard (const short int a[64], const short int b[64], short int c[64])
{
  register int sq, s;
  s = 10 - stage;
  for (sq = 0; sq < 64; sq++)
    c[sq] = ((a[sq] * s) + (b[sq] * stage)) / 10;
}


static inline void
CopyBoard (const short int a[64], short int b[64])
{
  register short *sqa, *sqb;
  for (sqa = a, sqb = b; sqa < a + 64;)
    *sqb++ = *sqa++;
}


void
ExaminePosition (void)

/*
 * This is done one time before the search is started. Set up arrays Mwpawn,
 * Mbpawn, Mknight, Mbishop, Mking which are used in the SqValue() function
 * to determine the positional value of each piece.
 */

{
  register short i, sq;
  short wpadv, bpadv, wstrong, bstrong, z, side, pp, j, k, val, Pd, fyle,
   rank;
  static short PawnStorm = false;

  ataks (white, atak[white]);
  ataks (black, atak[black]);
  UpdateWeights ();
  HasKnight[white] = HasKnight[black] = 0;
  HasBishop[white] = HasBishop[black] = 0;
  HasRook[white] = HasRook[black] = 0;
  HasQueen[white] = HasQueen[black] = 0;
  for (side = white; side <= black; side++)
    for (i = PieceCnt[side]; i >= 0; i--)
      switch (board[PieceList[side][i]])
	{
	case knight:
	  ++HasKnight[side];
	  break;
	case bishop:
	  ++HasBishop[side];
	  break;
	case rook:
	  ++HasRook[side];
	  break;
	case queen:
	  ++HasQueen[side];
	  break;
	}
  if (!Developed[white])
    Developed[white] = (board[1] != knight && board[2] != bishop &&
			board[5] != bishop && board[6] != knight);
  if (!Developed[black])
    Developed[black] = (board[57] != knight && board[58] != bishop &&
			board[61] != bishop && board[62] != knight);
  if (!PawnStorm && stage < 5)
    PawnStorm = ((column (wking) < 3 && column (bking) > 4) ||
		 (column (wking) > 4 && column (bking) < 3));

  CopyBoard (pknight, Mknight[white]);
  CopyBoard (pknight, Mknight[black]);
  CopyBoard (pbishop, Mbishop[white]);
  CopyBoard (pbishop, Mbishop[black]);
  BlendBoard (KingOpening, KingEnding, Mking[white]);
  BlendBoard (KingOpening, KingEnding, Mking[black]);

  for (sq = 0; sq < 64; sq++)
    {
      fyle = column (sq);
      rank = row (sq);
      wstrong = bstrong = true;
      for (i = sq; i < 64; i += 8)
	if (Patak (black, i))
	  {
	    wstrong = false;
	    break;
	  }
      for (i = sq; i >= 0; i -= 8)
	if (Patak (white, i))
	  {
	    bstrong = false;
	    break;
	  }
      wpadv = bpadv = PADVNCM;
      if ((fyle == 0 || PawnCnt[white][fyle - 1] == 0) && (fyle == 7 || PawnCnt[white][fyle + 1] == 0))
	wpadv = PADVNCI;
      if ((fyle == 0 || PawnCnt[black][fyle - 1] == 0) && (fyle == 7 || PawnCnt[black][fyle + 1] == 0))
	bpadv = PADVNCI;
      Mwpawn[sq] = (wpadv * PawnAdvance[sq]) / 10;
      Mbpawn[sq] = (bpadv * PawnAdvance[63 - sq]) / 10;
      Mwpawn[sq] += PawnBonus;
      Mbpawn[sq] += PawnBonus;
      if (Mvboard[kingP[white]])
	{
	  if ((fyle < 3 || fyle > 4) && distance (sq, wking) < 3)
	    Mwpawn[sq] += PAWNSHIELD;
	}
      else if (rank < 3 && (fyle < 2 || fyle > 5))
	Mwpawn[sq] += PAWNSHIELD / 2;
      if (Mvboard[kingP[black]])
	{
	  if ((fyle < 3 || fyle > 4) && distance (sq, bking) < 3)
	    Mbpawn[sq] += PAWNSHIELD;
	}
      else if (rank > 4 && (fyle < 2 || fyle > 5))
	Mbpawn[sq] += PAWNSHIELD / 2;
      if (PawnStorm)
	{
	  if ((column (wking) < 4 && fyle > 4) || (column (wking) > 3 && fyle < 3))
	    Mwpawn[sq] += 3 * rank - 21;
	  if ((column (bking) < 4 && fyle > 4) || (column (bking) > 3 && fyle < 3))
	    Mbpawn[sq] -= 3 * rank;
	}
      Mknight[white][sq] += 5 - distance (sq, bking);
      Mknight[white][sq] += 5 - distance (sq, wking);
      Mknight[black][sq] += 5 - distance (sq, wking);
      Mknight[black][sq] += 5 - distance (sq, bking);
      Mbishop[white][sq] += BishopBonus;
      Mbishop[black][sq] += BishopBonus;
      for (i = PieceCnt[black]; i >= 0; i--)
	if (distance (sq, PieceList[black][i]) < 3)
	  Mknight[white][sq] += KNIGHTPOST;
      for (i = PieceCnt[white]; i >= 0; i--)
	if (distance (sq, PieceList[white][i]) < 3)
	  Mknight[black][sq] += KNIGHTPOST;
      if (wstrong)
	Mknight[white][sq] += KNIGHTSTRONG;
      if (bstrong)
	Mknight[black][sq] += KNIGHTSTRONG;
      if (wstrong)
	Mbishop[white][sq] += BISHOPSTRONG;
      if (bstrong)
	Mbishop[black][sq] += BISHOPSTRONG;

      if (HasBishop[white] == 2)
	Mbishop[white][sq] += 8;
      if (HasBishop[black] == 2)
	Mbishop[black][sq] += 8;
      if (HasKnight[white] == 2)
	Mknight[white][sq] += 5;
      if (HasKnight[black] == 2)
	Mknight[black][sq] += 5;

      Kfield[white][sq] = Kfield[black][sq] = 0;
      if (distance (sq, wking) == 1)
	Kfield[black][sq] = KATAK;
      if (distance (sq, bking) == 1)
	Kfield[white][sq] = KATAK;
      Pd = 0;
      for (k = 0; k <= PieceCnt[white]; k++)
	{
	  i = PieceList[white][k];
	  if (board[i] == pawn)
	    {
	      pp = true;
	      z = i + ((row (i) == 6) ? 8 : 16);
	      for (j = i + 8; j < 64; j += 8)
		if (Patak (black, j) || board[j] == pawn)
		  {
		    pp = false;
		    break;
		  }
	      Pd += ((pp) ? 5 * taxicab (sq, z) : taxicab (sq, z));
	    }
	}
      for (k = 0; k <= PieceCnt[black]; k++)
	{
	  i = PieceList[black][k];
	  if (board[i] == pawn)
	    {
	      pp = true;
	      z = i - ((row (i) == 1) ? 8 : 16);
	      for (j = i - 8; j >= 0; j -= 8)
		if (Patak (white, j) || board[j] == pawn)
		  {
		    pp = false;
		    break;
		  }
	      Pd += ((pp) ? 5 * taxicab (sq, z) : taxicab (sq, z));
	    }
	}
      if (Pd != 0)
	{
	  val = (Pd * stage2) / 10;
	  Mking[white][sq] -= val;
	  Mking[black][sq] -= val;
	}
    }
}

void
UpdateWeights (void)

/*
 * If material balance has changed, determine the values for the positional
 * evaluation terms.
 */

{
  register short s1;

  emtl[white] = mtl[white] - pmtl[white] - valueK;
  emtl[black] = mtl[black] - pmtl[black] - valueK;
  tmtl = emtl[white] + emtl[black];
  s1 = ((tmtl > 6600) ? 0 : ((tmtl < 1400) ? 10 : (6600 - tmtl) / 520));
  if (s1 != stage)
    {
      stage = s1;
      stage2 = ((tmtl > 3600) ? 0 : ((tmtl < 1400) ? 10 : (3600 - tmtl) / 220));
      PEDRNK2B = -15;		/* centre pawn on 2nd rank & blocked */
      PBLOK = -4;		/* blocked backward pawn */
      PDOUBLED = -14;		/* doubled pawn */
      PWEAKH = -4;		/* weak pawn on half open file */
      PAWNSHIELD = 10 - stage;	/* pawn near friendly king */
      PADVNCM = 10;		/* advanced pawn multiplier */
      PADVNCI = 7;		/* muliplier for isolated pawn */
      PawnBonus = stage;

      KNIGHTPOST = (stage + 2) / 3;	/* knight near enemy pieces */
      KNIGHTSTRONG = (stage + 6) / 2;	/* occupies pawn hole */

      BISHOPSTRONG = (stage + 6) / 2;	/* occupies pawn hole */
      BishopBonus = BBONUS * stage;

      RHOPN = 10;		/* rook on half open file */
      RHOPNX = 4;
      RookBonus = RBONUS * stage;

      XRAY = 8;			/* Xray attack on piece */
      PINVAL = 10;		/* Pin */

      KHOPN = (3 * stage - 30) / 2;	/* king on half open file */
      KHOPNX = KHOPN / 2;
      KCASTLD = 10 - stage;
      KMOVD = -40 / (stage + 1);/* king moved before castling */
      KATAK = (10 - stage) / 2;	/* B,R attacks near enemy king */
      KSFTY = ((stage < 8) ? KINGSAFETY - 2 * stage : 0);

      ATAKD = -6;		/* defender > attacker */
      HUNGP = -12;		/* each hung piece */
      HUNGX = -18;		/* extra for >1 hung piece */
    }
}
