/*
 * 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"
#include "ttable.h" /* uses hashbd, hashkey and eval cache*/

int PUTVAR = false;
SHORT sscore[2];
#ifdef CACHE
struct etable *etab[2];
#endif
/* 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] =
{620, 560, 500, 440, 380, 320, 260, 240,
 560, 520, 460, 400, 340, 280, 230, 260,
 500, 460, 320, 280, 260, 220, 280, 320,
 440, 400, 280, 200, 200, 260, 340, 380,
 380, 340, 260, 200, 200, 280, 400, 440,
 320, 280, 220, 260, 280, 320, 460, 500,
 260, 230, 280, 340, 400, 460, 520, 560,
 240, 260, 320, 380, 440, 500, 560, 620};
/*
{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};

#define AHOPEN (-200)

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;
/************************* Evaluation cache code ****************************/
/* NOTE: The static evaluation cache "EETable" belongs to eval.c and cannot
/*       be moved to ttable.c */

#ifdef CACHE
struct etable *etab[2];

inline void
PutInEETable (SHORT side,int score)

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

{
    register struct etable *ptbl;
    if(!flag.cache) return;
    ptbl = &((etab[side])[hashkey % (ETABLE)]);
    ptbl->ehashbd = hashbd;
    ptbl->escore[white] = pscore[white];
    ptbl->escore[black] = pscore[black];
    ptbl->hung[white] = hung[white];
    ptbl->hung[black] = hung[black];
    ptbl->score = score;
#ifndef AMIGADOS
    memcpy ( &(ptbl->sscore), svalue, sizeof (svalue));
#else
    memcpy (ptbl->sscore, svalue, sizeof (svalue));
#endif
#if defined HASHSTATS 
    EADD++;
#endif
    return;
}

inline int
CheckEETable (SHORT side)

/* Get an evaluation from the transposition table */
{
    register struct etable *ptbl;
    if(!flag.cache)return false;
    ptbl = &((etab[side])[hashkey % (ETABLE)]);
    if (hashbd == ptbl->ehashbd) return true;
    return false;
}

inline int
ProbeEETable (SHORT side, SHORT *score)

/* Get an evaluation from the transposition table */
{
    register struct etable *ptbl;
    if(!flag.cache)return false;
    ptbl = &((etab[side])[hashkey % (ETABLE)]);
    if (hashbd == ptbl->ehashbd)
      {
	  pscore[white] = ptbl->escore[white];
	  pscore[black] = ptbl->escore[black];
#ifndef AMIGADOS
	  memcpy (svalue, &(ptbl->sscore), sizeof (svalue));
#else
	  memcpy (svalue, ptbl->sscore, sizeof (svalue));
#endif
	  *score = ptbl->score;
          hung[white] = ptbl->hung[white];
          hung[black] = ptbl->hung[black];
#if defined HASHSTATS
	  EGET++;
#endif
	  return true;
      }
    return false;

}
#else /* Define null stubs for the above procedures */
#define PutInEETable(side, score)
#define ProbeEETable(side, score) (false)
#define CheckEETable(side) (false)
#endif /* CACHE */

/* ............    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
 * PC1[column] - # of my pawns in this column
 * PC2[column] - # of opponents pawns in column
 * PieceCnt[side] - just what it says
 */
inline
int
ScoreKPK (SHORT side,
	  SHORT winner,
	  SHORT loser,
	  SHORT king1,
	  register SHORT king2,
	  register SHORT 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));
    return (s);
}
#ifndef PRE4PL67 /* this is the new 4pl68 code
// I am told it is WORSE than the #else clause which
// is based on old 4pl64 code
*/

static SHORT 
kpkwv_ (SHORT pf, SHORT pr, SHORT wf, SHORT wr, SHORT bf, SHORT br)
{

  /*
   *  Don Beal's routine, which was originally in Fortran.  See AICC 2
   */

  static SHORT wbdd, mbpf, nbpf, blpu;
  SHORT dist_ (SHORT, SHORT, SHORT, SHORT);
  static SHORT brpu, mwpf, wlpu, wrpu, blpuu, brpuu, wlpuu, wrpuu, md,
    bq, blpuuu, brpuuu, bsd, tbf, sgf, bpp, sdr, sgr, wsd, wsg, ppr, wpp;

  ppr = ((pr == 2)?3:pr);
  if (pf == 1)
  { if (bf == 3)
    { if (pr == 7 && wf == 1 && wr == 8 && br > 6) return(0);
      if (pr == 6 && wf < 4 && wr == 6 && br == 8) return(1);
    }

    if (bf == 1 && br > pr) return(0);
    if (pr == 7 && bf > 2) return(1);
    if (bf <= 3 && br - ppr > 1) return(0);
    if (wf == 1 && bf == 3 && wr - pr == 1 && br - pr == 1) return(0);
  }
  bq = dist_ (bf, br, pf, 8);
  if (bq > 8 - ppr) return(1);
  mbpf = bf - pf;
  if (mbpf < 0) mbpf = -mbpf;
  bpp = dist_ (bf, br, pf, ppr);
  wpp = dist_ (wf, wr, pf, ppr);
  if (bpp - wpp < -1 && br - pr != mbpf) return(0);
  if (pf == 1 && pr <= 3 && wf <= 2 && wr == 8 && bf == 4 && br >= 7) return(1);
  if (!(pf != 2 || pr != 6 || bf != 1 || br != 8))
  { if (wf <= 3 && wr == 6) return(0);
    if (wf == 4 && wr == 8) return(0);
  }
  if (pr == 7)
  { if (wr < 8 && wpp == 2 && bq == 0) return(1);
    if (wr == 6 && wf == pf && bq == 0) return(1);
    if (wr >= 6 && wpp <= 2 && bq != 0) return(1);
  }
  blpuu = dist_ (bf, br, pf - 1, pr + 2);
  wbdd = dist_ (wf, wr, bf, br - 2);
  brpuu = dist_ (bf, br, pf + 1, pr + 2);
  if (pr == 6)
  { if (dist_ (bf, br, pf + 1, pr) > 1 &&
        brpuu > dist_ (wf, wr, pf + 1, pr)) return(1);
    if (pf != 1)
    { if (blpuu > dist_ (wf, wr, pf - 1, pr)) return(1);
      if (br == 8 && mbpf == 1 && wbdd == 1) return(1);
      if (br > 6 && nbpf == 2 && dist_ (wf, wr, bf, 5) <= 1) return(1);
    }
    else
      if (wf == 1 && wr == 8 && bf == 2 && br == 6) return(0);
  }
  mwpf = wf - pf;
  if (mwpf < 0) mwpf = -mwpf;
  if (pr >= 5 && mwpf == 2 && wr == pr && bf == wf && br - pr == 2) return(1);
  brpu = dist_ (bf, br, pf + 1, pr + 1);
  wrpu = dist_ (wf, wr, pf + 1, pr + 1);
  blpu = dist_ (bf, br, pf - 1, pr + 1);
  wlpu = dist_ (wf, wr, pf - 1, pr + 1);
  if (!(pf == 1 || pr != 5))
  { if (mwpf <= 1 && wr - pr == 1) return(1);
    if (wrpu == 1 && brpu > 1) return(1);
    if (wr >= 4 && bf == wf && br - pr >= 2 && mbpf == 3) return(1);
    if (wlpu == 1 && blpu > 1) return(1);
  }
  if (pr == 2 && br == 3 && mbpf > 1 && dist_ (wf, wr, bf, br + 2) <= 1) return(1);
  if (wr - pr == 2 && br == pr && mbpf == 1 && mwpf > 1 &&
      (wf - pf) * (bf - pf) > 0) return(0);
  if (pf == 1 && wf == 1 && wr == br && bf > 3) return(1);
  sgf = pf - 1;
  if (wf >= pf) { sgf = pf + 1; }
  sgr = wr - (mwpf - 1);
  if (mwpf == 0 && wr > br) sgr = wr - 1;
  wsg = dist_ (wf, wr, sgf, sgr);
  if (wr - pr - mwpf > 0 && wr - br >= -1 && bpp - (wsg + (sgr - ppr))
      >= -1 && dist_ (bf, br, sgf, sgr) > wsg) return(1);
  md = mbpf - mwpf;
  if (!(pf != 1 || bf <= 3))
  { sdr = br + (bf - 3);
    if (sdr > 8) sdr = 8;
    if (wr > br + 1) sdr = br;
    if (sdr > ppr)
    { wsd = dist_ (wf, wr, 3, sdr);
      bsd = dist_ (bf, br, 3, sdr);
      if (bsd - wsd < -1) return(0);
      if (bsd <= wsd && md <= 0) return(0);
    }
  }
  brpuuu = dist_ (bf, br, pf + 1, pr + 3);
  if (brpu > wrpu && brpuuu > wrpu && pr - wr != pf - wf) return(1);
  if (brpuuu == 0 && wrpu == 1) return(1);
  blpuuu = dist_ (bf, br, pf - 1, pr + 3);
  if (pf != 1)
  { if (blpu > wlpu && blpuuu > wlpu && pr - wr != wf - pf) return(1);
    if (blpuuu == 0 && wlpu == 1) return(1);
  }
  wrpuu = dist_ (wf, wr, pf + 1, pr + 2);
  if (brpuu > wrpuu) return(1);
  wlpuu = dist_ (wf, wr, pf - 1, pr + 2);
  if (pf > 1 && blpuu > wlpuu) return(1);
  if (br == pr)
  { if (mwpf <= 2 && wr - pr == -1 && mbpf != 2) return(1);
    if (dist_ (wf, wr, bf - 1, br + 2) <= 1 && bf - pf > 1) return(1);
    if (dist_ (wf, wr, bf + 1, br + 2) <= 1 && bf - pf < -1) return(1);
  }
  if (pf != 1)
  { if (br == pr && mbpf > 1 && dist_ (wf, wr, pf, pr - 1) <= 1) return(1);
    if (br - pr >= 3 && wbdd == 1) return(1);
    if (wr - pr >= 2 && wr < br && md >= 0) return(1);
    if (mwpf <= 2 && wr - pr >= 3 && bf != pf && wr - br <= 1) return(1);
    if (wr >= pr && br - pr >= 5 && mbpf >= 3 && md >= -1 && ppr == 3) return(1);
    if (md >= -1 && pr == 2 && br == 8) return(1);
  }
  tbf = bf - 1;
  if (pf > bf) tbf = bf + 1;
  if (mbpf > 1 && br == ppr && dist_ (wf, wr, tbf, wr + 2) <= 1) return(1);
  if (br == pr && bf - pf == -2 && dist_ (wf, wr, pf + 2, pr - 1) <= 1) return(1);
  if (pf > 2 && br == pr && bf - pf == 2 &&
      dist_ (wf, wr, pf - 2, pr - 1) <= 1) return(1);
  return(0);
}				/* kpkwv_ */

static SHORT 
kpkbv_ (SHORT pf, SHORT pr, SHORT wf, SHORT wr, SHORT bf, SHORT br)
{
  static SHORT incf[8] =
    {0, 1, 1, 1, 0, -1, -1, -1};
  static SHORT incr[8] =
    {1, 1, 0, -1, -1, -1, 0, 1};

  SHORT dist_ (SHORT, SHORT, SHORT, SHORT);
  SHORT kpkwv_ (SHORT, SHORT, SHORT, SHORT, SHORT, SHORT);
  static SHORT i, nm, nbf, nbr;

  nm = 0;
  for (i = 0; i < 8; ++i)
    {
      nbf = bf + incf[i];
      if (nbf < 1 || nbf > 8) continue;
      nbr = br + incr[i];
      if (nbr < 1 || nbr > 8) continue;
      if (dist_ (nbf, nbr, wf, wr) < 2) continue;
      if (nbf == pf && nbr == pr) return(0);
      if (nbr == pr + 1 && (nbf == pf - 1 || nbf == pf + 1)) continue;
      ++nm;
      if (kpkwv_ (pf, pr, wf, wr, nbf, nbr) == 0) return(0);
    }
  if (nm > 0) return(-1);
  return(0);
}				/* kpkbv_ */

SHORT 
dist_ (SHORT f1, SHORT r1, SHORT f2, SHORT r2)
{
  static SHORT fd, rd;

  fd = f2 - f1;
  if (fd < 0) fd = -fd;

  rd = r2 - r1;
  if (rd < 0) rd = -rd;

  return(rd > fd ? rd : fd);
}				/* dist_ */

inline 
int  
ScoreK1PK (SHORT side,
           SHORT winner,
           SHORT loser,
           SHORT king1,
           register SHORT king2,
           register SHORT sq)

     /*
      *  We call Don Beal's routine with the necessary parameters and determine
      *  win/draw/loss.  Then we compute the real evaluation which is +-500 for
      *  a win/loss and 10 for a draw, plus some points to lead the computer to
      *  a decisive winning/drawing line.
      */

{
#ifdef WAY4PL64
  SHORT s;
#endif 
  SHORT win, sqc, sqr, k1c, k1r, k2c, k2r;
  const int drawn = 10, won = 500;

#ifdef WAY4PL64
#ifdef CACHE
  if (ProbeEETable(side,&s)) return s;
#endif 
#endif
  sqc = column (sq) + 1;
  sqr = row (sq) + 1;
  k1c = column (king1) + 1;
  k1r = row (king1) + 1;
  k2c = column (king2) + 1;
  k2r = row (king2) + 1;
  if (winner == black)
    {  
      sqr = 9 - sqr;
      k1r = 9 - k1r;
      k2r = 9 - k2r;
    }  
  if (sqc > 4)
    {
      sqc = 9 - sqc;
      k1c = 9 - k1c;
      k2c = 9 - k2c;
    }  
       
  if (side == winner)
    win = kpkwv_ (sqc, sqr, k1c, k1r, k2c, k2r);
  else 
    win = kpkbv_ (sqc, sqr, k1c, k1r, k2c, k2r);
     
#ifdef WAY4PL64
  if (!win)  s = drawn + 5 * distance (sq, king2) - 5*distance(king1,king2);
  else       s = won + 50 * (sqr - 2) + 10*distance(sq,king2);
#else
  if (!win)
    return drawn + 5 * distance (sq, king2);
  else
    return won + 50 * (sqr - 2);
#endif

#ifdef WAY4PL64
#ifdef CACHE
  if (PUTVAR) PutInEETable (side, s);
#endif

  return s;
#endif
}

#ifdef notdef
inline
int
ScoreK1PK (SHORT side,
	   SHORT winner,
	   SHORT loser,
	   SHORT king1,
	   register SHORT king2,
	   register SHORT sq)

     /*
      *  We call Don Beal's routine with the necessary parameters and determine
      *  win/draw/loss.  Then we compute the real evaluation which is +-500 for
      *  a win/loss and 10 for a draw, plus some points to lead the computer to
      *  a decisive winning/drawing line.
      */

{
  SHORT win, sqc, sqr, k1c, k1r, k2c, k2r;
  const int drawn = 10, won = 500;

#ifdef CACHE
   if (ProbeEETable(side,&sqc)) return sqc;
#endif /* CACHE */

  sqc = column (sq) + 1;
  sqr = row (sq) + 1;
  k1c = column (king1) + 1;
  k1r = row (king1) + 1;
  k2c = column (king2) + 1;
  k2r = row (king2) + 1;
  if (winner == black)
    {
      sqr = 9 - sqr;
      k1r = 9 - k1r;
      k2r = 9 - k2r;
    }
  if (sqc > 4)
    {
      sqc = 9 - sqc;
      k1c = 9 - k1c;
      k2c = 9 - k2c;
    }

  if (side == winner)
    win = kpkwv_ (sqc, sqr, k1c, k1r, k2c, k2r);
  else
    win = kpkbv_ (sqc, sqr, k1c, k1r, k2c, k2r);

  if (!win)
    sqc =  drawn + 5 * distance (sq, king2);
  else
    sqc = won + 50 * (sqr - 2);
#ifdef CACHE
    if (PUTVAR) PutInEETable (side, s);
#endif /* CACHE */
	return sqc;


}
#endif


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


/*
 * Score King+Bishop+Knight versus King endings.  Works fine now.
 */

{
    register SHORT s, Bsq, Nsq, KBNKsq = 0;

    if (board[PieceList[winner][1]] == bishop)
      {
        Bsq = PieceList[winner][1];
        Nsq = PieceList[winner][2];
      }
    else
      {
        Bsq = PieceList[winner][2];
        Nsq = PieceList[winner][1];
      }

    KBNKsq = (((row (Bsq) % 2) == (column (Bsq) % 2)) ? 0 : 7);

    s = emtl[winner] - 300;
    s += ((KBNKsq == 0) ? KBNK[king2] : KBNK[locn (row (king2), 7 - column (king2))]);
    s -= (8*taxicab(king1,king2) + 2*distance(Nsq,king2) + distance(Bsq,king2));
    s += KingEnding[king1];
    return (s);

}

#ifdef notdef

inline
int
ScoreKBNK (SHORT winner, SHORT king1, SHORT 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)));
    return (s);
}
#endif

inline
SHORT
ScoreLoneKing (SHORT 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;

  if (mtl[white] == valueK && mtl[black] == valueK)
    return 0;
  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)
    {
      if (emtl[winner] == valueB + valueN)
	s = ScoreKBNK (winner, king1, king2);
      else if (emtl[winner] == valueN + valueN)
	s = 0;
	else if (emtl[winner] < valueR)
       s = 0;
      else
	s = 500 + emtl[winner] - DyingKing[king2] - 2 * distance (king1, king2);
    }
  else
    {
      if (pmtl[winner] == valueP)
	s = ScoreK1PK (side, winner, loser, king1, king2, PieceList[winner][1]);
      else
	for (i = 1; i <= PieceCnt[winner]; i++)
	  s += ScoreKPK (side, winner, loser, king1, king2, PieceList[winner][i]);
    }
  return ((side == winner) ? s : -s);
}

#else /* old pre 4pl67 code */

SHORT dist_ (SHORT f1, SHORT r1, SHORT f2, SHORT r2)
{
  return distdata [ f1-9+8*r1 ][ f2-9+8*r2 ];
}

SHORT 
kpkwv_ (SHORT pf, SHORT pr, SHORT wf, SHORT wr, SHORT bf, SHORT br)
{

  /*
   *  Don Beal's routine, which was originally in Fortran.  See AICC 2
   */


  const SHORT drawn=0, win=1;
  
  SHORT wbdd, mbpf, blpu;
  SHORT brpu, mwpf, wlpu, wrpu, blpuu, brpuu, wlpuu, wrpuu, md,
    bq, blpuuu, brpuuu, bsd, tbf, sgf, bpp, sdr, sgr, wsd, wsg, ppr, wpp;


  ppr = pr;
  if (pr == 2) { ppr = 3; }
  if (pf != 1) { goto L2; }
  if (bf != 3) { goto L1; }
  if (pr == 7 && wf == 1 && wr == 8 && br > 6) return drawn;
  if (pr == 6 && wf < 4 && wr == 6 && br == 8) return win;
L1:
  if (bf == 1 && br > pr) return drawn;
  if (pr == 7 && bf > 2) return win;
  if (bf <= 3 && br - ppr > 1) return drawn;
  if (wf == 1 && bf == 3 && wr - pr == 1 && br - pr == 1) return drawn;
L2:
  bq = dist_ (bf, br, pf, 8);
  if (bq > 8 - ppr) return win;
  mbpf = bf - pf;
  if (mbpf < 0) { mbpf = -mbpf; }
  bpp = dist_ (bf, br, pf, ppr);
  wpp = dist_ (wf, wr, pf, ppr);
  if (bpp - wpp < -1 && br - pr != mbpf) return drawn;
  if (pf == 1 && pr <= 3 && wf <= 2 && wr == 8 && bf == 4 && br >= 7) return win;
  if (pf != 2 || pr != 6 || bf != 1 || br != 8) { goto L3; }
  if (wf <= 3 && wr == 6) return drawn;
  if (wf == 4 && wr == 8) return drawn;
L3:
  if (pr != 7) { goto L4; }
  if (wr < 8 && wpp == 2 && bq == 0) return win;
  if (wr == 6 && wf == pf && bq == 0) return win;
  if (wr >= 6 && wpp <= 2 && bq != 0) return win;
L4:
  blpuu = dist_ (bf, br, pf-1, pr+2);
  wbdd = dist_ (wf, wr, bf, br-2);
  brpuu = dist_ (bf, br, pf+1, pr+2);
  if (pr != 6) { goto L6; }
  if (dist_ (bf, br, pf+1, pr) > 1 && brpuu > dist_ (wf, wr, pf+1, pr)) return win;
  if (pf == 1) { goto L5; }
  if (blpuu > dist_ (wf, wr, pf-1, pr)) return win;
  if (br == 8 && mbpf == 1 && wbdd == 1) return win;
  if (br > 6 && mbpf == 2 && dist_ (wf, wr, bf, 5) <= 1) return win;
  goto L6;
L5:
  if (wf == 1 && wr == 8 && bf == 2 && br == 6) return drawn;
L6:
  mwpf = wf - pf;
  if (mwpf < 0) { mwpf = -mwpf; }
  if (pr >= 5 && mwpf == 2 && wr == pr && bf == wf && br - pr == 2) return win;
  brpu = dist_ (bf, br, pf+1, pr+1);
  wrpu = dist_ (wf, wr, pf+1, pr+1);
  blpu = dist_ (bf, br, pf-1, pr+1);
  wlpu = dist_ (wf, wr, pf-1, pr+1);
  if (pf == 1 || pr != 5) { goto L7; }
  if (mwpf <= 1 && wr - pr == 1) return win;
  if (wrpu == 1 && brpu > 1) return win;
  if (wr >= 4 && bf == wf && br - pr >= 2 && mbpf == 3) return win;
  if (wlpu == 1 && blpu > 1) return win;
L7:
  if (pr == 2 && br == 3 && mbpf > 1 && dist_ (wf, wr, bf, br+2) <= 1) return win;
  if (wr - pr == 2 && br == pr && mbpf == 1 && mwpf > 1 && (wf - pf) *
      (bf - pf) > 0) return drawn;
  if (pf == 1 && wf == 1 && wr == br && bf > 3) return win;
  sgf = pf - 1;
  if (wf >= pf) { sgf = pf + 1; }
  sgr = wr - (mwpf - 1);
  if (mwpf == 0 && wr > br) { sgr = wr - 1; }
  wsg = dist_ (wf, wr, sgf, sgr);
  if (wr - pr - mwpf > 0 && wr - br >= -1 && bpp - (wsg + (sgr - ppr))
      >= -1 && dist_ (bf, br, sgf, sgr) > wsg) return win;
  md = mbpf - mwpf;
  if (pf != 1 || bf <= 3) { goto L8; }
  sdr = br + (bf - 3);
  if (sdr > 8) { sdr = 8; }
  if (wr > br + 1) { sdr = br; }
  if (sdr <= ppr) { goto L8; }
  wsd = dist_ (wf, wr, 3, sdr);
  bsd = dist_ (bf, br, 3, sdr);
  if (bsd - wsd < -1) return drawn;
  if (bsd <= wsd && md <= 0) return drawn;
L8:
  brpuuu = dist_ (bf, br, pf+1, pr+3);
  if (brpu > wrpu && brpuuu > wrpu && pr - wr != pf - wf) return win;
  if (brpuuu == 0 && wrpu == 1) return win;
  blpuuu = dist_ (bf, br, pf-1, pr+3);
  if (pf == 1) { goto L9; }
  if (blpu > wlpu && blpuuu > wlpu && pr - wr != wf - pf) return win;
  if (blpuuu == 0 && wlpu == 1) return win;
L9:
  wrpuu = dist_ (wf, wr, pf+1, pr+2);
  if (brpuu > wrpuu) return win;
  wlpuu = dist_ (wf, wr, pf-1, pr+2);
  if (pf > 1 && blpuu > wlpuu) return win;
  if (br != pr) { goto L10; }
  if (mwpf <= 2 && wr - pr == -1 && mbpf != 2) return win;
  if (dist_ (wf, wr, bf-1, br+2) <= 1 && bf - pf > 1) return win;
  if (dist_ (wf, wr, bf+1, br+2) <= 1 && bf - pf < -1) return win;
L10:
  if (pf == 1) { goto L11; }
  if (br == pr && mbpf > 1 && dist_ (wf, wr, pf, pr-1) <= 1) return win;
  if (br - pr >= 3 && wbdd == 1) return win;
  if (wr - pr >= 2 && wr < br && md >= 0) return win;
  if (mwpf <= 2 && wr - pr >= 3 && bf != pf && wr - br <= 1) return win;
  if (wr >= pr && br - pr >= 5 && mbpf >= 3 && md >= -1 && ppr == 3) return win;
  if (md >= -1 && pr == 2 && br == 8) return win;
L11:
  tbf = bf - 1;
  if (pf > bf) { tbf = bf + 1; }
  if (mbpf > 1 && br == ppr && dist_ (wf, wr, tbf, wr+2) <= 1) return win;
  if (br == pr && bf - pf == -2 && dist_ (wf, wr, pf+2, pr-1) <= 1) return win;
  if (pf > 2 && br == pr && bf - pf == 2 && dist_ (wf, wr, pf-2, pr-1) <= 1) return win;

  return drawn;
}				/* kpkwv_ */

SHORT 
kpkbv_ (SHORT pf, SHORT pr, SHORT wf, SHORT wr, SHORT bf, SHORT br)
{
  /* Initialized data */

  static SHORT incf[8] =
  {0, 1, 1, 1, 0, -1, -1, -1};
  static SHORT incr[8] =
  {1, 1, 0, -1, -1, -1, 0, 1};

  /* System generated locals */
  SHORT ret_val;

  /* Local variables */
  static SHORT i;
  static SHORT nm, nbf, nbr;

  ret_val = 0;
  nm = 0;
  for (i = 1; i <= 8; ++i)
    {
      nbf = bf + incf[i - 1];
      if (nbf < 1 || nbf > 8) { goto L1; }
      nbr = br + incr[i - 1];
      if (nbr < 1 || nbr > 8) { goto L1; }
      if (dist_ (nbf, nbr, wf, wr) < 2) { goto L1; }
      if (nbf == pf && nbr == pr) { goto L2; }
      if (nbr == pr + 1 && (nbf == pf - 1 || nbf == pf + 1)) { goto L1; }
      ++nm;
      if (kpkwv_ (pf, pr, wf, wr, nbf, nbr) == 0) { goto L2; }
    L1:
      ;
    }
  if (nm > 0) { ret_val = -1; }
L2:
  return ret_val;
}				/* kpkbv_ */


inline
int
ScoreK1PK (SHORT int side,
	   SHORT int winner,
	   SHORT int loser,
	   SHORT int king1,
	   register SHORT int king2,
	   register SHORT int sq)

     /*
      *  We call Don Beal's routine with the necessary parameters and determine
      *  win/draw/loss.  Then we compute the real evaluation which is +-500 for
      *  a win/loss and 10 for a draw, plus some points to lead the computer to
      *  a decisive winning/drawing line.
      */

{
  SHORT s, win, sqc, sqr, k1c, k1r, k2c, k2r;
  const int drawn = 10, won = 500;

#ifdef CACHE
  if (ProbeEETable(side,&s)) return s;
#endif

  sqc = column (sq) + 1;
  sqr = row (sq) + 1;
  k1c = column (king1) + 1;
  k1r = row (king1) + 1;
  k2c = column (king2) + 1;
  k2r = row (king2) + 1;
  if (winner == black)
    {
      sqr = 9 - sqr;
      k1r = 9 - k1r;
      k2r = 9 - k2r;
    }
  if (sqc > 4)
    {
      sqc = 9 - sqc;
      k1c = 9 - k1c;
      k2c = 9 - k2c;
    }

  if (side == winner) win = kpkwv_ (sqc, sqr, k1c, k1r, k2c, k2r);
  else                win = kpkbv_ (sqc, sqr, k1c, k1r, k2c, k2r);

  if (!win)  s = drawn + 5 * distance (sq, king2) - 5*distance(king1,king2);
  else       s = won + 50 * (sqr - 2) + 10*distance(sq,king2);
/*  if (!win)  s = drawn + 5 * distance (sq, king2); // old 2.50 way
//  else       s = won + 50 * (sqr - 2); // old 2.50 way */

#ifdef CACHE 
  if (PUTVAR) PutInEETable (side, s); 
#endif 

  return s;
}


inline
SHORT int
ScoreLoneKing (ARGSZ 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;

  if (mtl[white] == valueK && mtl[black] == valueK)
    return 0;
    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)
    {
    if (emtl[winner] == valueB + valueN)
      s = ScoreKBNK (winner, king1, king2);
      else if (emtl[winner] == valueN + valueN || 
               emtl[winner] == valueN || emtl[winner] == valueB)
	s = 0; 
      else
	s = 500 + emtl[winner] - DyingKing[king2] - 2 * distance (king1, king2);
    }
  else {
    if (pmtl[winner] == valueP)
        s = ScoreK1PK (side, winner, loser, king1, king2, PieceList[winner][1]);
      else for (i = 1; i <= PieceCnt[winner]; i++)
        s += ScoreKPK (side, winner, loser, king1, king2, PieceList[winner][i]);
    }

    if (side != winner)
     s = 0 - s;
    return(s);
/*    return ((side == winner) ? s : -s);*/
}

#endif /* old eval pre 4pl67 way */


int
evaluate (register SHORT side,
	  register SHORT ply,
	  register SHORT depth,
          register SHORT ext,
	  register SHORT alpha,
	  register SHORT beta,
	  SHORT INCscore,
	  SHORT *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 xside;
    register SHORT slk;
    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)));

	      /* should we use the estimete or score the position */
	if ( !slk && (ply == 1 ||
#ifdef CACHE
    	(CheckEETable (side)) ||
#endif
        (flag.neweval ? ((
        (ply==Sdepth || (!ext && depth == 0 && s>=alpha-30 && s<=beta+30)) ||
        (ext && (s >= (alpha - 30) && s <= (beta + 30)) )) )
        :
        ((Sdepth ==  ply) ||
        (ply > Sdepth && (s >= (alpha - 30) && s <= (beta + 30)) )) )
        ))
      {
	  /* score the position */
	  ataks (side, atak[side]);
	  if (Anyatak (side, PieceList[xside][0])){
	  ataks (xside, atak[xside]);
	  ChkFlag[ply-1] = *InChk = (Anyatak (xside, PieceList[side][0]))?(Pindex[TOsquare]+1):0;
	      return (10001 - ply);
	  }
	  ataks (xside, atak[xside]);
	  ChkFlag[ply-1] = *InChk = (Anyatak (xside, PieceList[side][0]))?(Pindex[TOsquare]+1):0;

#ifndef BAREBONES 
	  EvalNodes++;
#endif
	if(ply>4)PUTVAR=true;
	      s = ScorePosition (side);
	PUTVAR=false;
      }
    else
      {
	  /* use the estimate but look at check and slk */
       *InChk = SqAtakd (PieceList[side][0], xside);
       ChkFlag[ply - 1] = ((*InChk) ? Pindex[TOsquare] + 1 : 0);
       if (SqAtakd (PieceList[xside][0], side)){ return (10001 - ply); }
#ifdef DEBUG 
       if(debuglevel & 4096){
      printf("%lx %lx %d %d\n",hashbd,hashkey,ply,s);
      }
#endif
	  if (slk){
		if(ply>4)PUTVAR=true;
	      	s = ScoreLoneKing (side);
		PUTVAR=false;}
      }

    Pscore[ply] = s - mtl[side] + mtl[xside];
    ChkFlag[ply - 1] = ((*InChk) ? Pindex[TOsquare] + 1 : 0);
    QueenCheck[ply - 1] =       /* tom@izf.tno.nl */
          ((*InChk) && board[TOsquare] == queen) ? TOsquare : 0;
#ifdef DEBUG 
       if(debuglevel & 4096){
	printf("%lx %lx %d %d\n",hashbd,hashkey,ply,s);
	}
#endif
    return (s);
}

inline
int
BRscan (register SHORT sq, SHORT *mob)

/*
 * Find Bishop and Rook mobility, XRAY attacks, and pins. Increment the
 * hung[] array if a pin is found.
 */
{
    register UCHAR *ppos, *pdir;
    register SHORT s, mobx;
    register SHORT u, pin;
    SHORT piece, *Kf;
    mobx = s = 0;
    Kf = Kfield[c1];
    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)
	    {
		mobx++;
		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);
    *mob = mobx;
    return s;
}

inline
SHORT
KingScan (register SHORT 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 cnt;
    register UCHAR *ppos, *pdir;
    register SHORT s;
    register SHORT u;
    SHORT 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);
    return (s);
}

inline
int
trapped (register SHORT 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;
    register UCHAR *ppos, *pdir;
    register SHORT piece;

    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 int
PawnValue (register SHORT sq, SHORT side)
/*
 * Calculate the positional value for a pawn on 'sq'.
 */

{
    register SHORT fyle, rank;
    register SHORT j, 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(rank != 7 && color[sq+8] == black && board[sq+8] == pawn) s -= PCRASH;
	  if (PC2[fyle] == 0)
	    {
		r = rank - ((side == black)?1:0);
		in_square = (row (bking) >= r && distance (sq, bking) < 8 - r);
		e = (a2 == 0 || side == white)? 0: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(rank != 0 && color[sq+8] == white && board[sq+8] == pawn) s -= PCRASH;
	  if (PC2[fyle] == 0)
	    {
		r = rank + ((side == white)?1:0);
		in_square = (row (wking) <= r && distance (sq, wking) < r + 1);
		e = (a2 == 0 || side == black)?0: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((rank >2 && rank < 6) && (fyle > 2 && fyle < 5)) s += PCENTER;
    if (a2 > 0)
      {
	  if (a1 == 0 || a2 > ctlP + 1)
	    {
		s += HUNGP;
		if (trapped (sq)) hung[c1] += 2;
		hung[c1]++;
	    }
	  else if (a2 > a1) s += ATAKD;
      }
    return (s);
}

inline
int
KnightValue (register SHORT sq)

/*
 * 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;
		if (trapped (sq))
		    hung[c1] += 2;
		hung[c1]++;
	    }
	  else if (a2 >= ctlBN || a1 < ctlP)
	      s += ATAKD;
      }
    return (s);
}

inline
int
BishopValue (register SHORT sq)

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

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

    s = Mbishop[c1][sq];
    s += BRscan (sq, &mob);
    s += BMBLTY[mob];
    a2 = (atk2[sq] & 0x4FFF);
    if (a2 > 0)
      {
	  a1 = (atk1[sq] & 0x4FFF);
	  if (a1 == 0 || a2 > ctlBN + 1)
	    {
		s += HUNGP;
		if (trapped (sq))
		    hung[c1] += 2;
		hung[c1]++;
	    }
	  else if (a2 >= ctlBN || a1 < ctlP)
	      s += ATAKD;
      }
    return (s);
}

inline
int
RookValue (register SHORT sq)

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

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

    s = RookBonus;
/*
    if(stage < 3 && !castld[c1] ){
	if(sq == qrook[c1]  && sq == krook[c1]) s += 99;
    }
*/
    s += BRscan (sq, &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;
		if (trapped (sq))
		    hung[c1] += 2;
		hung[c1]++;
	    }
	  else if (a2 >= ctlR || a1 < ctlP)
	      s += ATAKD;
      }
    return (s);
}

inline
int
QueenValue (register SHORT sq)

/*
 * 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;
		if (trapped (sq))
		    hung[c1] += 2;
		hung[c1]++;
	    }
	  else if (a2 >= ctlQ || a1 < ctlP)
	      s += ATAKD;
      }
    return (s);
}

inline
int
KingValue (register SHORT sq)

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

{
    register SHORT s;
    register SHORT fyle;
    SHORT a2, a1;
    s = (emtl[c2] > 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;
/*
    if(!castld[c1] && sq == kingP[c1])s += 50;
*/

    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 6:
	  if(HasQueen[c2])if (PC1[7] == 0) s += AHOPEN;
      case 4:
      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 1:
	  if(HasQueen[c2])if (PC1[0] == 0) s += AHOPEN;
      case 3:
      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;
      }
    return (s);
}




SHORT
ScorePosition (register SHORT 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 score;
    register SHORT sq, i, xside;
    SHORT s;

    xside = side ^ 1;
    hung[white] = hung[black] = pscore[white] = pscore[black] = 0;
#ifdef CACHE
    if (!(hashkey+hashbd) || !ProbeEETable (side, &s))
      {
#endif
          UpdateWeights ();
	  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);
			    break;
			case bishop:
			    s = BishopValue (sq);
			    break;
			case rook:
			    s = RookValue (sq);
			    break;
			case queen:
			    s = QueenValue (sq);
			    break;
			case king:
			    s = KingValue (sq);
			    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;
#ifndef NODITHER
    if (dither)
      {
	  if (flag.hash)
	      gsrand (starttime + (unsigned int) hashbd);
	  score += urand () % dither;
      }
#endif
    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;
#ifdef CACHE
    if(PUTVAR)PutInEETable(side,score);
#endif
    return (score);
#ifdef CACHE
}
else {
return s;
}
#endif
}
static inline void
BlendBoard (const SHORT a[64], const SHORT b[64], SHORT 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 a[64], SHORT b[64])
{
    register const SHORT *sqa;
    register SHORT *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;
    register SHORT fyle;
    SHORT wpadv, bpadv, wstrong, bstrong, z, side, pp, j, k, val, Pd, rank;
    static SHORT PawnStorm = false;
/* update ataks arrays */
    ataks (white, atak[white]);
    ataks (black, atak[black]);
/*	*/
    UpdateWeights ();
/* initialize Hasxxx */
    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;
	      }
/* Developed if has moved knights and bishops */
    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);
/* Pawn Storm */
    if (!PawnStorm && stage < 5)
	PawnStorm = ((column (wking) < 3 && column (bking) > 4) ||
		     (column (wking) > 4 && column (bking) < 3));
/* setup base tables */
    memcpy(Mknight[white],pknight,sizeof(pknight));
    memcpy(Mknight[black],pknight,sizeof(pknight));
    memcpy(Mbishop[white],pbishop,sizeof(pbishop));
    memcpy(Mbishop[black],pbishop,sizeof(pbishop));
#ifdef notdef
    CopyBoard (pknight, Mknight[white]);
    CopyBoard (pknight, Mknight[black]);
    CopyBoard (pbishop, Mbishop[white]);
    CopyBoard (pbishop, Mbishop[black]);
#endif
/* linear interpolate on stage	*/
/* Mking = (KingOpening * (10 - stage) + KingEnding * srage) /10  */
    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;
/* does a black pawn attack to squares in this col from sq to end */
	  for (i = sq; i < 64; i += 8)
	      if (Patak (black, i)) { wstrong = false; break; }
/* does a white pawn attack to squares in this col from sq to end */
	  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 - 4 * stage) : 0);

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

