/* GNU Chess 5.0 - eval.c - evaluation code
   Copyright (c) 1999-2002 Free Software Foundation, Inc.

   GNU Chess is based on the two research programs 
   Cobalt by Chua Kong-Sian and Gazebo by Stuart Cracraft.

   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, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   Contact Info: 
     bug-gnu-chess@gnu.org
     cracraft@ai.mit.edu, cracraft@stanfordalumni.org, cracraft@earthlink.net
*/

/****************************************************************************
 *
 *
 *
 *****************************************************************************/


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "common.h"
#include "eval.h"

int LoneKing (int, int);
int ScoreKBNK (int, int);
int KPK (int);
int BishopTrapped (short);
int DoubleQR7 (short);

BitBoard passed[2];
BitBoard weaked[2];

static int PawnSq[2][64] = 
{
{  0,  0,  0,  0,  0,  0,  0,  0,
   5,  5,  5,-10,-10,  5,  5,  5,
  -2, -2, -2,  6,  6, -2, -2, -2,
   0,  0,  0, 25, 25,  0,  0,  0,
   2,  2, 12, 16, 16, 12,  2,  2,
   4,  8, 12, 16, 16, 12,  4,  4,
   4,  8, 12, 16, 16, 12,  4,  4,
   0,  0,  0,  0,  0,  0,  0,  0},
{  0,  0,  0,  0,  0,  0,  0,  0,
   4,  8, 12, 16, 16, 12,  4,  4,
   4,  8, 12, 16, 16, 12,  4,  4,
   2,  2, 12, 16, 16, 12,  2,  2,
   0,  0,  0, 25, 25,  0,  0,  0,
  -2, -2, -2,  6,  6, -2, -2, -2,
   5,  5,  5,-10,-10,  5,  5,  5,
   0,  0,  0,  0,  0,  0,  0,  0}
};

static const int Passed[2][8] =
{ { 0, 48, 48, 120, 144, 192, 240, 0}, {0, 240, 192, 144, 120, 48, 48, 0} };
/* Penalties for one or more isolated pawns on a given file */
static const int isolani_normal[8] = {
  -8, -10, -12, -14, -14, -12, -10, -8
};
/* Penalties if the file is half-open (i.e. no enemy pawns on it) */
static const int isolani_weaker[8] = {
  -22, -24, -26, -28, -28, -26, -24, -22
};

static const BitBoard d2e2[2] =
		 { ULL(0x0018000000000000), ULL(0x0000000000001800) };
static const BitBoard brank7[2]  = { ULL(0x000000000000FF00),
				     ULL(0x00FF000000000000) };
static const BitBoard brank8[2]  = { ULL(0x00000000000000FF),
				     ULL(0xFF00000000000000) };
static const BitBoard brank67[2] = { ULL(0x0000000000FFFF00),
				     ULL(0x00FFFF0000000000) };
static const BitBoard brank58[2] = { ULL(0x00000000FFFFFFFF),
				     ULL(0xFFFFFFFF00000000) };

int ScoreP (short side)
/***************************************************************************
 *
 *  Pawn evaluation is based on the following factors (which is being
 *  constantly updated!).
 *
 *  1.  Pawn square tables.
 *  2.  Passed pawns.
 *  3.  Backward pawns.
 *  4.  Pawn base under attack.
 *  5.  Doubled pawns 
 *  6.  Isolated pawns 
 *  7.  Connected passed pawns on 6/7th rank.
 *  8.  Unmoved & blocked d, e pawn
 *  9.  Passed pawn which cannot be caught.
 *  10. Pawn storms.
 *
 ***************************************************************************/
{
   int xside;
   int s, sq, i, i1;
   int n1, n2, backward;
   int nfile[8];
   int EnemyKing;
   BitBoard c, t, p, blocker, *e;
   PawnSlot *ptable;

   if (board.b[side][pawn] == NULLBITBOARD)
      return (0);
   xside = 1^side;
   EnemyKing = board.king[xside];
   p = board.b[xside][pawn];
   c = t = board.b[side][pawn];
   ptable = PawnTab[side] + (PawnHashKey & PHashMask);
   TotalPawnHashCnt++;
   if (ptable->phase == phase && ptable->pkey == KEY(PawnHashKey))
   {
      GoodPawnHashCnt++;
      s = ptable->score;
      passed[side] = ptable->passed;
      weaked[side] = ptable->weaked;
      goto phase2; 
   }

   s = 0;
   passed[side] = NULLBITBOARD;
   weaked[side] = NULLBITBOARD;
   memset (nfile, 0, sizeof (nfile));
   while (t)
   {
      sq = leadz (t);
      CLEARBIT (t, sq);
      s += PawnSq[side][sq]; 

      /*  Passed pawns  */
      if ((p & PassedPawnMask[side][sq]) == NULLBITBOARD)
      {
	 if ((side == white && (FromToRay[sq][sq|56] & c) == 0) ||
	     (side == black && (FromToRay[sq][sq&7] & c) == 0)) 
         {
            passed[side] |= BitPosArray[sq];
            s += (Passed[side][RANK(sq)] * phase) / 12;
         }
      }

      /*  Backward pawns */
      backward = false;
    /*   i = sq + (side == white ? 8 : -8); */
      if ( side == white ) {
 	 i = sq + 8;  }
      else {
         i= sq - 8; }

      if (!(PassedPawnMask[xside][i] & ~FileBit[ROW(sq)] & c) &&
	  cboard[i] != pawn)
      {
         n1 = nbits (c & MoveArray[ptype[xside]][i]);
         n2 = nbits (p & MoveArray[ptype[side]][i]);
         if (n1 < n2)
            backward = true;
      }
      if (!backward && (BitPosArray[sq] & brank7[xside]))
      {
         i1 = 1;
         i = i + (side == white ? 8 : -8);
         if (!(PassedPawnMask[xside][i] & ~FileBit[ROW(i1)] & c))
         {
            n1 = nbits (c & MoveArray[ptype[xside]][i]);
            n2 = nbits (p & MoveArray[ptype[side]][i]);
            if (n1 < n2)
               backward = true;
         }
      }
      if (backward)
      {
         weaked[side] |= BitPosArray[sq];
         s += BACKWARDPAWN;
      }

      /* Pawn base under attack */
      if ((MoveArray[ptype[side]][sq] & p) && (MoveArray[ptype[side]][sq] & c))
         s += PAWNBASEATAK;
 
      /*  Increment file count for isolani & doubled pawn evaluation */
      nfile[ROW(sq)]++;
   }

   for (i = 0; i <= 7; i++)
   {
      /* Doubled pawns */
      if (nfile[i] > 1)
         s += DOUBLEDPAWN;

      /* Isolated pawns */
      if (nfile[i] && (!(c & IsolaniMask[i])))
      {
	 /* Isolated on a half-open file */
         if (!(FileBit[i] & board.b[xside][pawn]))
	   s += isolani_weaker[i] * nfile[i];
	 else /* Normal isolated pawn */
           s += isolani_normal[i] * nfile[i];
	 weaked[side] |= (c & FileBit[i]);
      }
   }


  if (computerplays == side) {

    /* Penalize having eight pawns */
    if (nbits(board.b[computerplays][pawn]) == 8)
        s += EIGHT_PAWNS;

    /* Detect stonewall formation in enemy */
    if (nbits(stonewall[xside] & board.b[xside][pawn]) == 3)
      s += STONEWALL;

    /* Locked pawns */
    n = 0;
    if (side == white)
      n = nbits((c >> 8) & board.b[xside][pawn] &
               boxes[1]);
    else
      n = nbits((c << 8) & board.b[xside][pawn] &
               boxes[1]);
    if (n > 1)
      s += n * LOCKEDPAWNS;
  }


   /* Save the score into the pawn hash table */ 
   ptable->pkey = KEY(PawnHashKey);
   ptable->passed = passed[side];
   ptable->weaked = weaked[side];
   ptable->score = s;
   ptable->phase = phase;

/***************************************************************************
 *  
 *  This section of the pawn code cannot be saved into the pawn hash as
 *  they depend on the position of other pieces.  So they have to be 
 *  calculated again.
 *
 ***************************************************************************/
phase2:

   /* Pawn on f6/c6 with Queen against castled king is very strong */
   c = board.b[side][pawn];
   sq = board.king[xside];
   if (side == white && board.b[side][queen] && 
	(BitPosArray[C6] | BitPosArray[F6]) & c)
   {
      if (c & BitPosArray[F6] && sq > H6 && distance[sq][G7]==1)
         s += PAWNNEARKING;
      if (c & BitPosArray[C6] && sq > H6 && distance[sq][B7]==1)
         s += PAWNNEARKING;
   }
   else if (side == black && board.b[side][queen] &&
	(BitPosArray[C3] | BitPosArray[F3]) & c)
   {
      if (c & BitPosArray[F3] && sq < A3 && distance[sq][G2]==1)
         s += PAWNNEARKING;
      if (c & BitPosArray[C3] && sq < A3 && distance[sq][B2]==1)
         s += PAWNNEARKING;
   }

   /* Connected passed pawns on 6th or 7th rank */
   t = passed[side] & brank67[side];
   if (t && (board.pmaterial[xside] == ValueR || 
	(board.pmaterial[xside] == ValueN &&
	pieces[xside] == board.b[xside][knight])))
   {
      n1 = ROW(board.king[xside]);
      n2 = RANK(board.king[xside]);
      for (i = 0; i <= 6; i++)
      {
	 if (t & FileBit[i] && t & FileBit[i+1] && (n1 < i-1 || n1 > i+1 ||
		(side == white && n2 < 4) || (side == black && n2 > 3)))
            s += CONNECTEDPP;
      }
   }

   /* Pawn on d2,e2/d7,e7 is blocked  */
   blocker = board.friends[side] | board.friends[xside];
   if (side == white && (((c & d2e2[white]) >> 8) & blocker))
      s += BLOCKDEPAWN;
   if (side == black && (((c & d2e2[black]) << 8) & blocker))
      s += BLOCKDEPAWN;

   /* Enemy has no pieces & King is outside of passed pawn square */
   if (passed[side] && board.pmaterial[xside]==0)
   {
      e = board.b[xside];
      i1 = board.king[xside];
      p = passed[side];
      while (p)
      {
         sq = leadz (p);
	 CLEARBIT (p, sq);
	 if (board.side == side)
         {
	    if (!(SquarePawnMask[side][sq] & board.b[xside][king]))
	       s += ValueQ * Passed[side][RANK(sq)] / PFACTOR;
         }
         else if (!(MoveArray[king][i1] & SquarePawnMask[side][sq]))
	    s += ValueQ * Passed[side][RANK(sq)] / PFACTOR;
      }
   }

  /* If both sides are castled on different sides, bonus for pawn storms */
  c = board.b[side][pawn];
  if (abs (ROW (board.king[side]) - ROW (board.king[xside])) >= 4 &&
	PHASE < 6)
  {
     n1 = ROW (board.king[xside]);
     p = (IsolaniMask[n1] | FileBit[n1]) & c;
     while (p)
     {
        sq = leadz (p);
        CLEARBIT (p, sq);
        s += 10 * (5 - distance[sq][board.king[xside]]);
     }
  }

   return (s);
}

static const int Outpost[2][64] =
{
  { 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 1, 1, 1, 1, 0, 0,
    0, 1, 1, 1, 1, 1, 1, 0,
    0, 0, 1, 1, 1, 1, 0, 0,
    0, 0, 0, 1, 1, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 1, 1, 0, 0, 0,
    0, 0, 1, 1, 1, 1, 0, 0,
    0, 1, 1, 1, 1, 1, 1, 0,
    0, 0, 1, 1, 1, 1, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0 }
};


static inline int CTL(short sq, short piece __attribute__ ((unused)), short side)
/***************************************************************************
 *
 *  Return a score corresponding to the number of squares in the bitboard
 *  target multiplied by a specified bonus for controlling each square.
 *
 *  Can be used for control of the center and attacks around the king.
 *
 ***************************************************************************/
{
  int s, n, EnemyKing, FriendlyKing;
  BitBoard controlled;

  s = 0;

  EnemyKing = board.king[1^side];
  FriendlyKing = board.king[side];

  controlled = AttackXFrom (sq, side);

  /* Center control */
  n = nbits (controlled & boxes[0]);
  s += 4*n;

  /* Attacks against enemy king */
  n = nbits (controlled & DistMap[EnemyKing][2]);
  s += n;

  /* Defenses for friendly king */
  n = nbits (controlled & DistMap[FriendlyKing][2]);
  s += n;

  /* Mobility */
  n = nbits(controlled);
  s += 4*n;

  return (s);
}

int ScoreN (short side)
/***************************************************************************
 *
 *  1.  central knight - distance from enemy king.
 *  2.  mobility/control/attack
 *  3.  outpost knight protected by pawn.
 *  4.  knight attacking weak pawns.
 *
 ***************************************************************************/
{
   int xside;
   int s, s1, sq;
   int EnemyKing;
   BitBoard c, t;

   if (board.b[side][knight] == NULLBITBOARD)
      return (0);
   xside = side^1;
   s = s1 = 0;
   c = board.b[side][knight];
   t = board.b[xside][pawn]; 
   EnemyKing = board.king[xside];

   if ( c & pinned )
   {
	s += PINNEDKNIGHT * nbits(c & pinned);
   }

   while (c)
   {
      sq = leadz (c);
      CLEARBIT (c, sq);

      /* Control */
      s1 = CTL(sq,knight,side);
  
      if ( (BitPosArray[sq] & rings[3]) != NULLBITBOARD)
	s1 += KNIGHTONRIM;

      if (Outpost[side][sq] && 
	  !(t & IsolaniMask[ROW(sq)] & PassedPawnMask[side][sq]) )
      {
         s1 += OUTPOSTKNIGHT;

    	 /* Knight defended by own pawn */
         if (MoveArray[ptype[xside]][sq] & board.b[side][pawn])
            s1 += OUTPOSTKNIGHT;
      }
    
      /* Attack on weak opponent pawns */
      if (MoveArray[knight][sq] & weaked[xside])
         s1 += ATAKWEAKPAWN;

      s += s1;
   }

   return (s);
}


int ScoreB (short side)
/****************************************************************************
 *
 *  1.  double bishops.
 *  2.  mobility/control/attack
 *  3.  outpost bishop
 *  4.  fianchetto bishop
 *  5.  Bishop pair
 *
 ****************************************************************************/
{
   int xside;
   int s, s1, n, sq, EnemyKing;
   BitBoard c, t;

   if (board.b[side][bishop] == NULLBITBOARD)
      return (0);
   s = s1 = 0;
   c = board.b[side][bishop];
   xside = side ^ 1;
   EnemyKing = board.king[xside];
   n = 0;
   t = board.b[xside][pawn];

   if ( c & pinned )
   {
	s += PINNEDBISHOP * nbits(c & pinned);
   }

   while (c)
   {
      sq = leadz (c);
      CLEARBIT (c, sq);
      n++;

      /* Control */
      s1 = CTL(sq,bishop,side);

      /*  Outpost bishop */
      if (Outpost[side][sq] && 
	  !(t & IsolaniMask[ROW(sq)] & PassedPawnMask[side][sq]))
      {
         s1 += OUTPOSTBISHOP;

    	 /* Bishop defended by own pawn */
	 if (MoveArray[ptype[xside]][sq] & board.b[side][pawn])
            s1 += OUTPOSTBISHOP;
      }

      /*  Fianchetto bishop */
      if (side == white)
      {
         if (board.king[side] >= F1 && board.king[side] <= H1 && sq == G2)
	    s1 += FIANCHETTO;
         if (board.king[side] >= A1 && board.king[side] <= C1 && sq == B2)
	    s1 += FIANCHETTO;
      }
      else if (side == black)
      {
         if (board.king[side] >= F8 && board.king[side] <= H8 && sq == G7)
	    s1 += FIANCHETTO;
         if (board.king[side] >= A8 && board.king[side] <= C8 && sq == B7)
	    s1 += FIANCHETTO;
      }

      /* Attack on weak opponent pawns */
      if (BishopAttack(sq) & weaked[xside])
         s1 += ATAKWEAKPAWN;

      s += s1;
   }

   /* Doubled bishops */
   if (n > 1)            
      s += DOUBLEDBISHOPS;

   return (s);

}


int BishopTrapped (short side)
/****************************************************************************
 *
 *  Check for bishops trapped at A2/H2/A7/H7
 *
 ****************************************************************************/
{
   int s = 0;

   /* Don't waste time */
   if (board.b[side][bishop] == NULLBITBOARD)
     return (0); 

   if (side == white)
   {
      if ((board.b[white][bishop] & BitPosArray[A7]) &&
	  (board.b[black][pawn] & BitPosArray[B6]) && SwapOff(MOVE(A7,B6)) < 0)
         s += BISHOPTRAPPED;
      if ((board.b[white][bishop] & BitPosArray[H7]) &&
	  (board.b[black][pawn] & BitPosArray[G6]) && SwapOff(MOVE(H7,G6)) < 0)
         s += BISHOPTRAPPED;
   }
   else
   {
      if ((board.b[black][bishop] & BitPosArray[A2]) &&
	  (board.b[white][pawn] & BitPosArray[B3]) && SwapOff(MOVE(A2,B3)) < 0)
         s += BISHOPTRAPPED;
      if ((board.b[black][bishop] & BitPosArray[H2]) &&
	  (board.b[white][pawn] & BitPosArray[G3]) && SwapOff(MOVE(H2,G3)) < 0)
         s += BISHOPTRAPPED;
   }

   return (s);
}

int ScoreR (short side)
/****************************************************************************
 *
 *  1.  rook on 7th rank and Enemy king on 8th rank or pawns on 7th rank.
 *  2.  rook on open/half-open file.
 *  3.  rook in front/behind passed pawns (pawn >= 5th rank)
 *
 ****************************************************************************/
{
   int s, s1, sq, xside, fyle, EnemyKing;
   BitBoard c;

   if (board.b[side][rook] == NULLBITBOARD)
      return (0);
   s = s1 = 0;
   c = board.b[side][rook];
   xside = side ^ 1;
   EnemyKing = board.king[xside];

   if ( c & pinned )
   {
	s += PINNEDROOK * nbits(c & pinned);
   }

   while (c)
   {
      sq = leadz (c);
      CLEARBIT (c, sq);

      /* Control */
      s1 = CTL(sq,rook,side);

      fyle = ROW(sq);
      if (PHASE < 7)
      {
         if (!(board.b[side][pawn] & FileBit[fyle]))
         {
	    if (fyle == 5 && ROW(board.king[xside])>=E_FILE)
	      s1 += ROOKLIBERATED;
            s1 += ROOKHALFFILE;
            if (!(board.b[xside][pawn] & FileBit[fyle]))
               s1 += ROOKOPENFILE;
         }
      }

      if (phase > 6 && (FileBit[fyle] & passed[white] & brank58[white]))
      {
	 if (nbits (Ray[sq][7] & passed[white]) == 1)
	    s1 += ROOKBEHINDPP;
	 else if (Ray[sq][4] & passed[white])
            s1 += ROOKINFRONTPP;
      }
      if (FileBit[fyle] & passed[black] & brank58[black])
      {
	 if (nbits (Ray[sq][4] & passed[black]) == 1)
	    s1 += ROOKBEHINDPP;
	 else if (Ray[sq][7] & passed[black])
            s1 += ROOKINFRONTPP;
      }

      /* Attack on weak opponent pawns */
      if (RookAttack(sq) & weaked[xside])
         s1 += ATAKWEAKPAWN;

      /* Rook on 7th rank */
      if (RANK (sq) == rank7[side] && (RANK (EnemyKing) == rank8[side] ||
	  board.b[xside][pawn] & RankBit[RANK(sq)]))
         s1 += ROOK7RANK;

      s += s1;
   }

   return (s);
}

int DoubleQR7 (short side)
/***************************************************************************
 *
 *  This code just check to see if there is a QQ or QR or RR combo on the
 *  7th rank.  This is very strong and given quite a big bonus.  This 
 *  routine is called by the lazy section.
 *
 ***************************************************************************/
{
   int xside;

   xside = 1^side;
   if (nbits ((board.b[side][queen]|board.b[side][rook]) & brank7[side]) > 1
      && ((board.b[xside][king] & brank8[side]) || 
	  (board.b[xside][pawn] & brank7[side])))

      return (ROOKS7RANK);
   else
      return (0);
}

int ScoreQ (short side)
/***************************************************************************
 *
 *  1. queen centralization.
 *  2. king tropism.
 *  3. Bonus if opponent king is exposed.
 *
 ***************************************************************************/
{
   int xside;
   int s, s1, sq, EnemyKing;
   BitBoard c;
   
   s = s1 = 0;

   /* Try to keep our queen on the board for attacking purposes. */
   if (board.b[side][queen] == NULLBITBOARD) {
       if (side == computer) {
         s += QUEEN_NOT_PRESENT;
       }
       return(s);
    }                                                                           

   xside = 1 ^ side;
   c = board.b[side][queen];
   EnemyKing = board.king[xside];

   if ( c & pinned )
   {
	s += PINNEDQUEEN * nbits(c & pinned);
   }

   while (c)
   {
      sq = leadz (c);
      CLEARBIT (c, sq);

      /* Control */
      s1 = CTL(sq,queen,side);

      if (distance[sq][EnemyKing] <= 2)
         s1 += QUEENNEARKING;

      /* Attack on weak opponent pawns */
      if (QueenAttack(sq) & weaked[xside])
         s1 += ATAKWEAKPAWN;

      s += s1;
   }

   return (s);
}


static const int KingSq[64] =
{
   24, 24, 24, 16, 16,  0, 32, 32,
   24, 20, 16, 12, 12, 16, 20, 24,
   16, 12,  8,  4,  4,  8, 12, 16,
   12,  8,  4,  0,  0,  4,  8, 12,
   12,  8,  4,  0,  0,  4,  8, 12,
   16, 12,  8,  4,  4,  8, 12, 16,
   24, 20, 16, 12, 12, 16, 20, 24,
   24, 24, 24, 16, 16,  0, 32, 32
};

static const int EndingKing[64] =
{
   0,  6, 12, 18, 18, 12,  6,  0,
   6, 12, 18, 24, 24, 18, 12,  6,
  12, 18, 24, 32, 32, 24, 18, 12,
  18, 24, 32, 48, 48, 32, 24, 18,
  18, 24, 32, 48, 48, 32, 24, 18,
  12, 18, 24, 32, 32, 24, 18, 12,
   6, 12, 18, 24, 24, 18, 12,  6,
   0,  6, 12, 18, 18, 12,  6,  0
};

static const int pawncover[9] = { -60, -30, 0, 5, 30, 30, 30, 30, 30 };
static const int factor[9] = { 7, 8, 8, 7, 6, 5, 4, 2, 0, };

int ScoreK (short side)
/***************************************************************************
 *
 *  1.  king in the corner. ?? SRW 2002-08-02 Unclear if implemented
 *  2.  pawns around king.
 *  3.  king on open file.
 *  4.  Uncastled king.
 *  5.  Open rook file via Ng5 or Bxh7 sac.
 *  6.  No major or minor piece in the king's quadrant.
 *
 ***************************************************************************/
{
   int xside;
   int s, sq, sq1, n, n1, n2, file, fsq, rank;
   BitBoard b, x;

   s = 0;
   xside = 1^side;
   sq = board.king[side];
   file = ROW (sq);
   rank = RANK (sq);
   KingSafety[side] = 0;
   if (!ENDING)
   { 

      s += ((6 - phase) * KingSq[sq] + phase * EndingKing[sq]) / 6;

      /* After castling kingside, reward having all 3 pawns in front but not if
	 there is a threatening pawn. This permits the freeing move F3/F6. */
	 
      if (side == white)
        n = nbits (MoveArray[king][sq] & board.b[side][pawn] & RankBit[rank+1]);
      else
        n = nbits (MoveArray[king][sq] & board.b[side][pawn] & RankBit[rank-1]);
      s += pawncover[n];

      /* Penalize compromised wing pawn formations prior to castle. */
      if (!board.castled[side]) {
        n = -1;
        if (side == white) {
          /* King on original square and unmoved */
	  if (sq == 4 && Mvboard[sq] == 0) {
	    /* Kingside - rook on original square and unmoved. */
	    if ( (board.b[side][rook] & BitPosArray[H1])!=NULLBITBOARD &&
		 Mvboard[H1] == 0)
                   n = nbits (MoveArray[king][G1] & 
			      board.b[side][pawn] & RankBit[rank+1]);
	    /* Queenside */
	    if ( (board.b[side][rook] & BitPosArray[A1])!=NULLBITBOARD &&
		 Mvboard[A1] == 0)
                   n = nbits (MoveArray[king][C1] & 
			      board.b[side][pawn] & RankBit[rank+1]);
          }
   	} else {
	  if (sq == 60 && Mvboard[sq] == 0) {
	    /* Kingside */
	    if ( (board.b[side][rook] & BitPosArray[H8])!=NULLBITBOARD &&
		 Mvboard[H8] == 0)
                   n = nbits (MoveArray[king][G8] & 
			      board.b[side][pawn] & RankBit[rank-1]);
	    /* Queenside */
	    if ( (board.b[side][rook] & BitPosArray[A8])!=NULLBITBOARD &&
		 Mvboard[A8] == 0)
                   n = nbits (MoveArray[king][C8] & 
			      board.b[side][pawn] & RankBit[rank-1]);
          }
	}
        
	/* Penalize breaking the wing pawn formations prior to castle */
	if (n != -1) s += pawncover[n];
      }

      if (side == computer && file >= F_FILE && 
		!(FileBit[G_FILE] & board.b[side][pawn]))
      {
         if (side == white && cboard[F2] == pawn)
            s += GOPEN;
         else if (side == black && cboard[F7] == pawn)
            s += GOPEN;
      }

      /* No friendly pawns on this king file */
      if (!(FileBit[file] & board.b[side][pawn]))
         s += KINGOPENFILE;

      /* No enemy pawns on this king file */
      if (!(FileBit[file] & board.b[xside][pawn]))
         s += KINGOPENFILE1;

      switch (file)
      {
         case A_FILE :
         case E_FILE :
         case F_FILE :
	 case G_FILE : if (!(FileBit[file+1] & board.b[side][pawn]))
		          s += KINGOPENFILE;
		       if (!(FileBit[file+1] & board.b[xside][pawn]))
		          s += KINGOPENFILE1;
	               break;
         case H_FILE :
         case D_FILE :
         case C_FILE :
	 case B_FILE : if (!(FileBit[file-1] & board.b[side][pawn]))
		          s += KINGOPENFILE;
		       if (!(FileBit[file-1] & board.b[xside][pawn]))
		          s += KINGOPENFILE1;
	               break;
	 default :
	               break;
      }

      if (board.castled[side]) {
        if (side == white) {
          if (file > E_FILE) {
            if (!(BitPosArray[F2] & board.b[side][pawn]) ||
                !(BitPosArray[G2] & board.b[side][pawn]) ||
                !(BitPosArray[H2] & board.b[side][pawn]) )
                s += RUPTURE;
          } else if (file < E_FILE) {
            if (!(BitPosArray[A2] & board.b[side][pawn]) ||
                !(BitPosArray[B2] & board.b[side][pawn]) ||
                !(BitPosArray[C2] & board.b[side][pawn]) )
                s += RUPTURE;
          }
        } else {
          if (file > E_FILE) {
            if (!(BitPosArray[F7] & board.b[side][pawn]) ||
                !(BitPosArray[G7] & board.b[side][pawn]) ||
                !(BitPosArray[H7] & board.b[side][pawn]) )
                s += RUPTURE;
          } else if (file < E_FILE) {
            if (!(BitPosArray[A7] & board.b[side][pawn]) ||
                !(BitPosArray[B7] & board.b[side][pawn]) ||
                !(BitPosArray[C7] & board.b[side][pawn]) )
                s += RUPTURE;
	  }
	}
      }
      if (side == computer) {

	/* Stock piece sacrifice on h file */

	if (file >= E_FILE && board.b[xside][queen] && board.b[xside][rook] &&
	    !((board.b[side][pawn]|board.b[xside][pawn]) & FileBit[7]))
         s += HOPEN;
	
	/* King trapping rook */
        if (side == white) {
	  if (file > E_FILE) {
	    if (board.b[side][rook]&mask_kr_trapped_w[H_FILE-file]) {
		s += ROOKTRAPPED;
	    }
	  } else if (file < D_FILE) {
	    if (board.b[side][rook]&mask_qr_trapped_w[file]) {
		s += ROOKTRAPPED;
	    }
	  }
	} else {
	  if (file > E_FILE) {
	    if (board.b[side][rook]&mask_kr_trapped_b[H_FILE-file]) {
		s += ROOKTRAPPED;
	    }
	  } else if (file < D_FILE) {
	    if (board.b[side][rook]&mask_qr_trapped_b[file]) {
		s += ROOKTRAPPED;
	    }
	  }
	}
      }

      /* Don't give fianchetto target for advanced pawns */
      if (file > E_FILE && ROW(board.king[xside]) < D_FILE) {
         if (side == white) fsq = G3; else fsq = G6;
	 if ((BitPosArray[fsq] & board.b[side][pawn]) != NULLBITBOARD)
            if (((BitPosArray[F4]|BitPosArray[H4]|
	         BitPosArray[F5]|BitPosArray[H5])
	      & board.b[xside][pawn]) != NULLBITBOARD) 
	        s += FIANCHETTO_TARGET;	
      }
      if (file < E_FILE && ROW(board.king[xside]) > E_FILE) {
         if (side == white) fsq = B3; else fsq = B6;
	 if ((BitPosArray[fsq] & board.b[side][pawn]) != NULLBITBOARD)
            if (((BitPosArray[A4]|BitPosArray[C4]|
	         BitPosArray[A5]|BitPosArray[C5])
	      & board.b[xside][pawn]) != NULLBITBOARD) 
	        s += FIANCHETTO_TARGET;	
      }

      /* No major/minor piece in king's quadrant */
      /* First identify the quadrant */
      x = boardhalf[side] & boardside[file<=D_FILE];
      /* Now identify the number of non-pawn enemy in quadrant */
      n1 = nbits(x & (board.friends[xside]));
      if (n1 > 0) {
        /* Now identify the number of non-pawn friends in quadrant */
        n2 = nbits(x & (board.friends[side] & ~board.b[side][pawn] & 
	 	~board.b[side][king]));
        if (n1 > n2)
	  s += (n1 - n2) * KING_DEFENDER_DEFICIT;
      }
      
      KingSafety[side] = s;
      s = (s * factor[phase]) / 8;
   }
   else
   {
      s += EndingKing[sq];
      s += CTL(sq,king,side);
      b = (board.b[white][pawn] | board.b[black][pawn]);
      while (b)
      {
         sq1 = leadz (b);
         CLEARBIT (b, sq1);
	 if (BitPosArray[sq1] & board.b[white][pawn])
            s -= distance[sq][sq1+8] * 10 - 5;
	 else if (BitPosArray[sq1] & board.b[white][pawn])
            s -= distance[sq][sq1-8] * 10 - 5;
         else
	    s -= distance[sq][sq1] - 5;
      }

      /* Attack on weak opponent pawns */
      if (MoveArray[king][sq] & weaked[xside])
         s += ATAKWEAKPAWN * 2;

   }

    if (phase >= 4) {
      /* Weak back rank */
      if (side == white) {
        if (sq < A2) 
	  if (!(MoveArray[king][sq] & (~board.b[side][pawn] & RankBit[1]))) 
	    s += KING_BACK_RANK_WEAK;
      } else {
	if (sq > H7) 
	  if (!(MoveArray[king][sq] & (~board.b[side][pawn] & RankBit[6]))) 
	    s += KING_BACK_RANK_WEAK;
      }
   }

   return (s);
}


int LoneKing (int side, int loser)
/**************************************************************************
 *
 *  One side has a lonely king and the other has no pawns, but enough
 *  mating material.  We give an additional bonus of 150 points for the 
 *  winning side to attract the search to such positions.
 *
 **************************************************************************/
{
   int s, winer, sq1, sq2;

   winer = 1^loser;
   if (board.material[winer] == ValueB+ValueN && 
	nbits(board.b[winer][bishop]) == 1 &&
	nbits(board.b[winer][knight]) == 1)
      return (ScoreKBNK (side, loser));

   sq1 = board.king[winer];
   sq2 = board.king[loser];
   s = 150 - 6 * taxicab[sq1][sq2] - EndingKing[sq2];
   if (side == loser)
      s = -s;
   s += MATERIAL;

   return (s);
}


int KPK (int side)
/**************************************************************************
 *
 *  A KPK endgame evaluator.  Side is the one on the move.
 *  This is not a perfect evaluator, it merely identifies SOME positions
 *  as wins or draw.  Some WON positions could be seen as draws; the search
 *  will be able to use the knowledge here to identify more positions.
 *
 **************************************************************************/
{
   int winer, loser, sq, sqw, sql;
   int s;

   winer = (board.b[white][pawn] ? white : black);
   loser = 1 ^ winer;
   sq  = leadz (board.b[winer][pawn]);
   sqw = board.king[winer];
   sql = board.king[loser];
   s = ValueP + (ValueQ * Passed[winer][RANK(sq)] / PFACTOR) + 
	 4 * (winer == white ? RANK(sqw) : 7-RANK(sqw));

/**************************************************************************
 *
 * Pawn is outside the square of the king 
 *
 **************************************************************************/
   if (~SquarePawnMask[winer][sq] & board.b[loser][king])
   {
      if (!(MoveArray[king][sql] & SquarePawnMask[winer][sq]))
         return (winer == side ? s : -s);
      if (winer == side)
         return (s);
   }

/**************************************************************************
 *
 *  Friendly king is on same or adjacent file to the pawn, and the pawn is 
 *  on a file other than a rook file and ...
 *
 **************************************************************************/
   if (ROW(sq) != 0 && ROW(sq) != 7 &&
        ((IsolaniMask[ROW(sq)] | FileBit[ROW(sq)]) & board.b[winer][king]))
   {

/**************************************************************************
 *
 * a. friendly king is 2 ranks more advanced than the pawn 
 * b. friendly king is 1 rank more advanced than the pawn 
 *    i.  The friendly king is on the sixth rank.
 *    ii. The enemy king does not have direct opposition by being 2 ranks
 *        in front of the friendly king and on the same file.
 * c. friendly king is same rank as pawn
 *    i.  The enemy king is not 2-4 ranks more advanced that the pawn.
 *    ii. The pawn is on the sixth rank and the enemy king does not have
 *        direct opposition.
 * d. pawn is on the 7th rank, friendly king is on sixth rank and
 *    i.  The enemy king is not on the queening square.
 *    ii. The enemy is on the queening square but both kings are in the same
 *        file.
 * 
 **************************************************************************/
      if (winer == white)
      {
         if (RANK(sqw) == RANK(sq) + 2)
            return (winer == side ? s : -s);
         if (RANK(sqw) == RANK(sq) + 1)
         {
	    if (RANK(sqw) == 5)
               return (winer == side ? s : -s);
            if (sqw < A6) 
	    {
	       if (sqw+16 == sql && winer == side)
		  return (0);
	       else
                  return (winer == side ? s : -s);
	    }
         }
         if (RANK(sqw) == RANK(sq))
         {
            if ((RANK(sql) - RANK(sq) < 2 || RANK(sql) - RANK(sq) > 4) &&
		 winer == side)
	       return (s);
            if ((RANK(sql) - RANK(sq) < 1 || RANK(sql) - RANK(sq) > 5) &&
		 loser == side)
               return (-s);
	    if (RANK(sq) == 5 && sqw+16 != sql)
               return (winer == side ? s : 0);
	 }
	 if (RANK(sq) == 6 && RANK(sqw) == 5)
         {
	    if (sql != sq+8)
               return (winer == side ? s : 0);
	    if (sql == sq+8 && sql == sqw+16)
               return (winer == side ? s : 0);
	 }
      } 
      else
      {
         if (RANK(sqw) == RANK(sq) - 2)
            return (winer == side ? s : -s);
         if (RANK(sqw) == RANK(sq) - 1)
         {
	    if (RANK(sqw) == 2)
               return (winer == side ? s : -s);
	    if (sqw > H3)
	    {
	       if (sqw-16 == sql && winer == side)
	          return (0);
	       else
                  return (winer == side ? s : -s);
	    }	
	 }
         if (RANK(sqw) == RANK(sq))
         {
            if ((RANK(sq) - RANK(sql) < 2 || RANK(sq) - RANK(sql) > 4) &&
		 winer == side)
	       return (s);
            if ((RANK(sq) - RANK(sql) < 1 || RANK(sq) - RANK(sql) > 5) &&
		 loser == side)
	       return (-s);
	    if (RANK(sq) == 5 && sqw+16 != sql)
               return (winer == side ? s : 0);
	 }
	 if (RANK(sq) == 1 && RANK(sqw) == 2)
         {
	    if (sql != sq-8)
               return (winer == side ? s : 0);
	    if (sql == sq-8 && sql == sqw-16)
               return (winer == side ? s : 0);
	 }
      } 
   }  

   return (0);
}


int KBNK[64] = 
{
   0, 10, 20, 30, 40, 50, 60, 70,
  10, 20, 30, 40, 50, 60, 70, 60,
  20, 30, 40, 50, 60, 70, 60, 50,
  30, 40, 50, 60, 70, 60, 50, 40,
  40, 50, 60, 70, 60, 50, 40, 30,
  50, 60, 70, 60, 50, 40, 30, 20,
  60, 70, 60, 50, 40, 30, 20, 10,
  70, 60, 50, 40, 30, 20, 10,  0
};

int ScoreKBNK (int side, int loser)
/****************************************************************************
 *
 *  My very own KBNK routine!
 *
 ****************************************************************************/
{
   int s, winer, sq1, sq2, sqB;

   winer = 1^loser;
   sqB = board.king[loser];
   if (board.b[winer][bishop] & WHITESQUARES)
      sqB = RANK(sqB)*8 + 7 - ROW(sqB);
   sq1 = board.king[winer];
   sq2 = board.king[loser];
   s = 300 - 6 * taxicab[sq1][sq2];
   s -= KBNK[sqB];
   s -= EndingKing[sq2];
   s -= taxicab[leadz(board.b[winer][knight])][sq2];
   s -= taxicab[leadz(board.b[winer][bishop])][sq2];

   /*  King in the central 4x4 region is good! */
   if (board.b[winer][king] & ULL(0x00003C3C3C3C0000))
      s += 20;
   if (side == loser)
      s = -s;
   s += MATERIAL;

   return (s); 
}


static const BitBoard nn[2] = { ULL(0x4200000000000000), ULL(0x0000000000000042) };
static const BitBoard bb[2] = { ULL(0x2400000000000000), ULL(0x0000000000000024) };

int ScoreDev (short side)
/***************************************************************************
 *
 *  Calculate the development score for side (for opening only).
 *  Penalize the following.
 *  .  Uncastled and cannot castled
 *  .  Undeveloped knights and bishops
 *  .  Early queen move.
 *
 ***************************************************************************/
{
   int s;
   int sq;
   BitBoard c;

   /* Calculate whether we are developed */
   c = (board.b[side][knight] & nn[side]) | (board.b[side][bishop] & bb[side]);
   s = nbits(c) * -8;

   /* If we are castled or beyond the 20th move, no more ScoreDev */
   if (board.castled[side] || GameCnt >= 38)
      return (s);

   s += NOTCASTLED;

   /* If the king is moved, nail it, otherwise check rooks */
   if (Mvboard[board.king[side]] > 0) 
      s += KINGMOVED;

   /* Discourage rook moves */
   c = board.b[side][rook];
   while (c) {
     sq = leadz(c);
     CLEARBIT(c, sq);
     if (Mvboard[sq] > 0)
       s += ROOKMOVED;
   }

   /* Penalize a queen that moves at all */
   if (board.b[side][queen])
   {
      sq = leadz (board.b[side][queen]);
      if (Mvboard[sq] > 0)
         s += EARLYQUEENMOVE;
         /* s += Mvboard[sq] * EARLYQUEENMOVE; */
   }

   /* Discourage repeat minor piece moves */
   c = board.b[side][knight] | board.b[side][bishop];
   while (c) {
     sq = leadz(c);
     CLEARBIT(c, sq);
     if (Mvboard[sq] > 1)
	s += EARLYMINORREPEAT;
	/* s += Mvboard[sq] * EARLYMINORREPEAT; */
   }

   /* Discourage any wing pawn moves */
/*   c = board.b[side][pawn] & (FileBit[0]|FileBit[1]|FileBit[6]|FileBit[7]); */
   c = board.b[side][pawn] & ULL(0xc3c3c3c3c3c3c3c3);
   while (c) {
     sq = leadz(c);
     CLEARBIT(c, sq);
     if (Mvboard[sq] > 0) 
	s += EARLYWINGPAWNMOVE;
   }

   /* Discourage any repeat center pawn moves */
/*   c = board.b[side][pawn] & (FileBit[2]|FileBit[3]|FileBit[4]|FileBit[5]); */
   c = board.b[side][pawn] & ULL(0x3c3c3c3c3c3c3c3c);
   while (c) {
     sq = leadz(c);
     CLEARBIT(c, sq);
     if (Mvboard[sq] > 1) 
	s += EARLYCENTERPREPEAT;
   }

   return (s);
}


/*  Array of pointer to functions  */
static int (*ScorePiece[7]) (short) =
{ NULL, ScoreP, ScoreN, ScoreB, ScoreR, ScoreQ, ScoreK };


int Evaluate (int alpha, int beta)
/****************************************************************************
 *
 *  First check to see if this position can be specially dealt with.
 *  E.g. if our bounds indicate that we are looking for a mate score,
 *  then just return the material score.  Nothing else is important.
 *  If its a KPK endgame, call our KPK routine.
 *  If one side has a lone king & the winning side has no pawns then call
 *  the LoneKing() mating driver routine.  Note that there is enough
 *  mating material as we have already check for insufficient mating material
 *  in the call to EvaluateDraw() in search()/quiesce().
 *
 ****************************************************************************/
{
   int side, xside;
   int piece, s, s1, score;
   int npiece[2];
   BitBoard *b;

   side = board.side;
   xside = 1 ^ side;

   /*  If we are looking for a MATE, just return the material */
   if (alpha > MATE-255 || beta < -MATE+255)
      return (MATERIAL); 

   /*  A KPK endgame. */
   if (board.material[white]+board.material[black] == ValueP)
      return (KPK (side));  

   /*  One side has a lone king and other side has no pawns */
   if (board.material[xside] == 0 && board.b[side][pawn] == NULLBITBOARD)
      return LoneKing (side, xside);
   if (board.material[side] == 0 && board.b[xside][pawn] == NULLBITBOARD)
      return LoneKing (side, side);

/****************************************************************************
 *
 *  Lets try a lazy evaluation.  In this stage, we should evaluate all those
 *  features that gives big bonus/penalties.  E.g. squares around king is
 *  attacked by enemy pieces, 2 rooks on 7th rank, runaway passed pawns etc.
 *  This will be the direction, so things will continue to change in this
 *  section.
 *
 ****************************************************************************/
   EvalCall++;
   phase = PHASE;
   b = board.b[white];
   pieces[white] = b[knight] | b[bishop] | b[rook] | b[queen];
   npiece[white] = nbits (pieces[white]);
   b = board.b[black];
   pieces[black] = b[knight] | b[bishop] | b[rook] | b[queen];
   npiece[black] = nbits (pieces[black]);
   s1 = MATERIAL;

   if ((s1 + maxposnscore[side] < alpha || s1 - maxposnscore[xside] > beta) &&
	phase <= 6)
   {
      score = s1;
      goto next;
   }
   s = 0;
   s += ScoreDev (side) - ScoreDev (xside);
   s += ScoreP (side) - ScoreP (xside);
   s += ScoreK (side) - ScoreK (xside);
   s += BishopTrapped (side) - BishopTrapped (xside);
   s += DoubleQR7 (side) - DoubleQR7 (xside);

   s1 = s + MATERIAL;

/**************************************************************************
 *
 *  See if we can have a lazy evaluation cut.  Otherwise its a slow eval.
 * 
 **************************************************************************/

   if (s1 + lazyscore[side] < alpha || s1 - lazyscore[side] > beta)
   {
      score = s1;
   }
   else
   {
      EvalCnt++;

	GenAtaks();
	s1 = HUNGPENALTY * ( EvalHung(side) - EvalHung(xside) );
	FindPins(&pinned);

      for (piece = knight; piece < king; piece++)
      {
         s1 += (*ScorePiece[piece]) (side) - (*ScorePiece[piece]) (xside);
      }
      lazyscore[side] = MAX (s1, lazyscore[side]);
      maxposnscore[side] = MAX (maxposnscore[side], s + s1);
      score = s + s1 + MATERIAL;
   }

/***************************************************************************
 *
 *  Trade down bonus code.  When ahead, trade pieces & not pawns;
 *
 ***************************************************************************/
next:
   if (MATERIAL >= 200)
   {
      score += (RootPieces - nbits(pieces[white] | pieces[black])) * TRADEPIECE;
      score -= (RootPawns - nbits(board.b[white][pawn] | board.b[black][pawn])) 
			* TRADEPAWNS;
   }
   else if (MATERIAL <= -200)
   {
      score -= (RootPieces - nbits(pieces[white] | pieces[black])) * TRADEPIECE;
      score += (RootPawns - nbits(board.b[white][pawn] | board.b[black][pawn]))
			 * TRADEPAWNS;
   }
      
/***************************************************************************
 *
 *  Opposite color bishops is drawish.
 *
 ***************************************************************************/
   if (ENDING && pieces[white] == board.b[white][bishop] && 
                 pieces[black] == board.b[black][bishop] &&
       ((pieces[white] & WHITESQUARES && pieces[black] & BLACKSQUARES) ||
	(pieces[white] & BLACKSQUARES && pieces[black] & WHITESQUARES)))
   {
      score /= 2;
   }
    
/***************************************************************************
 *
 *  When one side has no mating material, then his score can never be > 0.
 *
 ***************************************************************************/
   if (score > 0 && !board.b[side][pawn] && (board.material[side] < ValueR
        || pieces[side] == board.b[side][knight]))
      score = 0;
   if (score < 0 && !board.b[xside][pawn] && (board.material[xside] < ValueR
        || pieces[xside] == board.b[xside][knight]))
      score = 0;
   
   return (score);
}


short EvaluateDraw (void)
/***************************************************************************
 *
 *  This routine is called by search() and quiesce() before anything else
 *  is done.  Its purpose it to check if the current position is a draw.
 *  0.  50-move draw.
 *  1.  If there are any pawns, it is not.
 *  2.  If both sides has anything less than a rook, draw.
 *  3.  If both sides has <= 2 knights only, draw.
 *  4.  If its a KBBK and bishops of same color, draw.
 *
 ***************************************************************************/
{
   BitBoard *w, *b;
   int wm, bm, wn, bn;

   /* 
    * Exception - if we are close to a pawn move, promotion 
    * or capture it is possible a forced mate will follow.
    * So we assume not drawn for 2 moves.
    */

   if ( (GameCnt-Game50) < 5 )
     return (false);

   /* 50 move rule */
   if ( (GameCnt-Game50) > 100 )
     return (true);

   w = board.b[white];
   b = board.b[black];
   if (w[pawn] != 0 || b[pawn] != 0)
      return (false);

   wm = board.material[white];
   bm = board.material[black];
   wn = nbits (w[knight]);
   bn = nbits (b[knight]);
   if  ((wm<ValueR || (wm==2*ValueN && wn==2)) &&
        (bm<ValueR || (bm==2*ValueN && bn==2)))
      return (true); 

   if (wm < ValueR)
   {
      if (bm == 2*ValueB && 
         ( nbits(board.b[black][bishop] & WHITESQUARES) == 2 ||
           nbits(board.b[black][bishop] & BLACKSQUARES) == 2 ))
      return (true);
   }
   if (bm < ValueR)
   {
      if (wm == 2*ValueB && 
         ( nbits(board.b[white][bishop] & WHITESQUARES) == 2 ||
           nbits(board.b[white][bishop] & BLACKSQUARES) == 2 ))
      return (true);
   }

   return (false);
}
