/* 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 "piece.h"
#include "util.h"
#include "eval.h"
#include "bitboard.h"
#include "move.h"
#include "material.h"
#include "square.h"
#include "ptable.h"
#include "searchparams.h"
#include "searchdata.h"
#include "searchstats.h"
#include "atak.h"
#include "swap.h"
#include "hung.h"

int LoneKing (board_t *board, int side, int loser);
int ScoreKBNK (board_t *board, int side, int loser);
int KPK (board_t *board, int side);
int BishopTrapped (board_t *board, short side);
int DoubleQR7 (board_t *board, short side);
int ScoreKBPK(board_t *board, uint32_t *flags);

// TODO Make these less global

BitBoard passed[2];
BitBoard weaked[2];
BitBoard pieces[2];

// TODO Make this nonglobal

BitBoard pinned;

int Value[7] = { 0, ValueP, ValueN, ValueB, ValueR, ValueQ, ValueK};


/* Example: a material count of 9199 or lower corresponds to phase >=1. 
   Currently the initial material count is 8800 so the initial phase
   is 1. 
 */



int Phase[10]={INFIN /*0*/, 
	       9199 /*1*/, 
	       8049 /*2*/, 
	       6899 /*3 (6900 is opening lower bound)*/, 
	       5749 /*4*/, 
	       4599 /*5*/, 
	       3449 /*6 (3449 is endgame upper bound) */, 
	       2299 /*7*/, 
	       1149 /*8*/, 
	       -INFIN};

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 (board_t *board, searchparams_t *searchparams, 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;
   int n;
   int ph;

   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];
   if(PTableGet(PTable, 
		board,
		side,
		&(passed[side]), 
		&(weaked[side]), 
		&s, 
		&ph)){
       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 & bitboards.PassedPawnMask[side][sq]) == NULLBITBOARD)
      {
	 if ((side == white && (bitboards.FromToRay[sq][sq|56] & c) == 0) ||
	     (side == black && (bitboards.FromToRay[sq][sq&7] & c) == 0)) 
         {
            passed[side] |= bitboards.BitPosArray[sq];
	    s += (Passed[side][RANK(sq)] * board->phase) / 12;
         }
      }

      /*  Backward pawns */
      backward = false;
    /*   i = sq + (side == white ? 8 : -8); */
      if ( side == white ) {
 	 i = sq + 8;  }
      else {
         i= sq - 8; }

      if (!(bitboards.PassedPawnMask[xside][i] & ~bitboards.FileBit[FILE_(sq)] & c) &&
	  board->cboard[i] != pawn)
      {
         n1 = nbits (c & bitboards.MoveArray[ptype[xside]][i]);
         n2 = nbits (p & bitboards.MoveArray[ptype[side]][i]);
         if (n1 < n2)
            backward = true;
      }
      if (!backward && (bitboards.BitPosArray[sq] & brank7[xside]))
      {
         i1 = 1;
         i = i + (side == white ? 8 : -8);
         if (!(bitboards.PassedPawnMask[xside][i] & ~bitboards.FileBit[FILE_(i1)] & c))
         {
            n1 = nbits (c & bitboards.MoveArray[ptype[xside]][i]);
            n2 = nbits (p & bitboards.MoveArray[ptype[side]][i]);
            if (n1 < n2)
               backward = true;
         }
      }
      if (backward)
      {
         weaked[side] |= bitboards.BitPosArray[sq];
         s += BACKWARDPAWN(board);
      }

      /* Pawn base under attack */
      if ((bitboards.MoveArray[ptype[side]][sq] & p) && (bitboards.MoveArray[ptype[side]][sq] & c))
         s += PAWNBASEATAK;
 
      /*  Increment file count for isolani & doubled pawn evaluation */
      nfile[FILE_(sq)]++;
   }

   for (i = 0; i <= 7; i++)
   {
      /* Doubled pawns */
       if (nfile[i] > 1){
	   s += DOUBLEDPAWN(board);
       }
       /* Isolated pawns */
       if (nfile[i] && (!(c & bitboards.IsolaniMask[i]))){
	   /* Isolated on a half-open file */
	   if (!(bitboards.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 & bitboards.FileBit[i]);
      }
   }


    /* Penalize having eight pawns */
   if (nbits(board->b[side][pawn]) == 8){
        s += EIGHT_PAWNS;
   }

    /* Detect stonewall formation in enemy */
   if (nbits(bitboards.stonewall[xside] & board->b[xside][pawn]) == 3){
      s += STONEWALL;
   }
    /* Locked pawns */
    n = 0;
    if (side == white){
      n = nbits((c >> 8) & board->b[xside][pawn] &
               bitboards.boxes[1]);
    }else{
      n = nbits((c << 8) & board->b[xside][pawn] &
               bitboards.boxes[1]);
    }
    if (n > 1){
	s += n * LOCKEDPAWNS;
    }


   /* Save the score into the pawn hash table */ 

    PTablePut(PTable, 	      
	      board, 
	      side,
	      passed[side], 
	      weaked[side], 
	      s, 
	      board->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] && 
	(bitboards.BitPosArray[C6] | bitboards.BitPosArray[F6]) & c)
   {
      if (c & bitboards.BitPosArray[F6] && sq > H6 && distance[sq][G7]==1)
         s += PAWNNEARKING;
      if (c & bitboards.BitPosArray[C6] && sq > H6 && distance[sq][B7]==1)
         s += PAWNNEARKING;
   }
   else if (side == black && board->b[side][queen] &&
	(bitboards.BitPosArray[C3] | bitboards.BitPosArray[F3]) & c)
   {
      if (c & bitboards.BitPosArray[F3] && sq < A3 && distance[sq][G2]==1)
         s += PAWNNEARKING;
      if (c & bitboards.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 = FILE_(board->king[xside]);
      n2 = RANK(board->king[xside]);
      for (i = 0; i <= 6; i++)
      {
	 if (t & bitboards.FileBit[i] && t & bitboards.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 (!(bitboards.SquarePawnMask[side][sq] & board->b[xside][king]))
	       s += ValueQ * Passed[side][RANK(sq)] / PFACTOR;
         }
         else if (!(bitboards.MoveArray[king][i1] & bitboards.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 (FILE_ (board->king[side]) - FILE_ (board->king[xside])) >= 4 &&
           board->phase < 6)
  {
     n1 = FILE_ (board->king[xside]);
     p = (bitboards.IsolaniMask[n1] | bitboards.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(board_t *board, 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 (board, sq, side);

  /* Center control */
  n = nbits (controlled & bitboards.boxes[0]);
  s += 4*n;

  /* Attacks against enemy king */
  n = nbits (controlled & bitboards.DistMap[EnemyKing][2]);
  s += n;

  /* Defenses for friendly king */
  n = nbits (controlled & bitboards.DistMap[FriendlyKing][2]);
  s += n;

  /* Mobility */
  n = nbits(controlled);
  s += 4*n;

  return (s);
}

int ScoreN (board_t *board, searchparams_t *searchparams, 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(board, sq,knight,side);
  
      if ( (bitboards.BitPosArray[sq] & bitboards.rings[3]) != NULLBITBOARD)
	s1 += KNIGHTONRIM;

      if (Outpost[side][sq] && 
	  !(t & bitboards.IsolaniMask[FILE_(sq)] & bitboards.PassedPawnMask[side][sq]) )
      {
         s1 += OUTPOSTKNIGHT;
    	 /* Knight defended by own pawn */
         if (bitboards.MoveArray[ptype[xside]][sq] & board->b[side][pawn])
            s1 += OUTPOSTKNIGHT;
      }
    
      /* Attack on weak opponent pawns */
      if (bitboards.MoveArray[knight][sq] & weaked[xside])
         s1 += ATAKWEAKPAWN;

      s += s1;
   }

   return (s);
}


int ScoreB (board_t *board, searchparams_t *searchparams, 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(board, sq,bishop,side);

      /*  Outpost bishop */
      if (Outpost[side][sq] && 
	  !(t & bitboards.IsolaniMask[FILE_(sq)] & bitboards.PassedPawnMask[side][sq]))
      {
         s1 += OUTPOSTBISHOP;

    	 /* Bishop defended by own pawn */
	 if (bitboards.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 (MagicBishopAttack(board,sq) & weaked[xside])
         s1 += ATAKWEAKPAWN;

      s += s1;
   }

   /* Doubled bishops */
   if (n > 1)            
      s += DOUBLEDBISHOPS;

   return (s);

}


int BishopTrapped (board_t *board, 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] & bitboards.BitPosArray[A7]) &&
	  (board->b[black][pawn] & bitboards.BitPosArray[B6]) && SwapOff(board,MOVE(A7,B6)) < 0)
         s += BISHOPTRAPPED;
      if ((board->b[white][bishop] & bitboards.BitPosArray[H7]) &&
	  (board->b[black][pawn] & bitboards.BitPosArray[G6]) && SwapOff(board,MOVE(H7,G6)) < 0)
         s += BISHOPTRAPPED;
   }
   else
   {
      if ((board->b[black][bishop] & bitboards.BitPosArray[A2]) &&
	  (board->b[white][pawn] & bitboards.BitPosArray[B3]) && SwapOff(board,MOVE(A2,B3)) < 0)
         s += BISHOPTRAPPED;
      if ((board->b[black][bishop] & bitboards.BitPosArray[H2]) &&
	  (board->b[white][pawn] & bitboards.BitPosArray[G3]) && SwapOff(board,MOVE(H2,G3)) < 0)
         s += BISHOPTRAPPED;
   }

   return (s);
}

int ScoreR (board_t *board, searchparams_t *searchparams, 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(board, sq,rook,side);

      fyle = FILE_(sq);
      if (board->phase < 7)
      {
         if (!(board->b[side][pawn] & bitboards.FileBit[fyle]))
         {
	    if (fyle == 5 && FILE_(board->king[xside])>=E_FILE)
	      s1 += ROOKLIBERATED;
            s1 += ROOKHALFFILE;
            if (!(board->b[xside][pawn] & bitboards.FileBit[fyle]))
               s1 += ROOKOPENFILE;
         }
      }

      if (board->phase > 6 && (bitboards.FileBit[fyle] & passed[white] & brank58[white]))
      {
	 if (nbits (bitboards.Ray[sq][7] & passed[white]) == 1)
	    s1 += ROOKBEHINDPP;
	 else if (bitboards.Ray[sq][4] & passed[white])
            s1 += ROOKINFRONTPP;
      }
      if (bitboards.FileBit[fyle] & passed[black] & brank58[black])
      {
	 if (nbits (bitboards.Ray[sq][4] & passed[black]) == 1)
	    s1 += ROOKBEHINDPP;
	 else if (bitboards.Ray[sq][7] & passed[black])
            s1 += ROOKINFRONTPP;
      }

      /* Attack on weak opponent pawns */
      if (MagicRookAttack(board,sq) & weaked[xside])
         s1 += ATAKWEAKPAWN;

      /* Rook on 7th rank */
      if (RANK (sq) == rank7[side] && (RANK (EnemyKing) == rank8[side] ||
	  board->b[xside][pawn] & bitboards.RankBit[RANK(sq)]))
         s1 += ROOK7RANK;

      s += s1;
   }

   return (s);
}

int DoubleQR7 (board_t *board, 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 (board_t *board, searchparams_t *searchparams, 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) {
         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(board, sq,queen,side);

      if (distance[sq][EnemyKing] <= 2)
         s1 += QUEENNEARKING;

      /* Attack on weak opponent pawns */
      if (MagicQueenAttack(board,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 (board_t *board, searchparams_t *searchparams, 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;
   short KingSafety[2];

   
   s = 0;
   xside = 1^side;
   sq = board->king[side];
   file = FILE_ (sq);
   rank = RANK (sq);
   KingSafety[side] = 0;
   if (!ENDING(board))
   { 

      s += ((6 - board->phase) * KingSq[sq] + board->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 (bitboards.MoveArray[king][sq] & board->b[side][pawn] & bitboards.RankBit[rank+1]);
      else
        n = nbits (bitboards.MoveArray[king][sq] & board->b[side][pawn] & bitboards.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 && board->Mvboard[sq] == 0) {
	    /* Kingside - rook on original square and unmoved. */
	    if ( (board->b[side][rook] & bitboards.BitPosArray[H1])!=NULLBITBOARD &&
		 board->Mvboard[H1] == 0)
                   n = nbits (bitboards.MoveArray[king][G1] & 
			      board->b[side][pawn] & bitboards.RankBit[rank+1]);
	    /* Queenside */
	    if ( (board->b[side][rook] & bitboards.BitPosArray[A1])!=NULLBITBOARD &&
		 board->Mvboard[A1] == 0)
                   n = nbits (bitboards.MoveArray[king][C1] & 
			      board->b[side][pawn] & bitboards.RankBit[rank+1]);
          }
   	} else {
	  if (sq == 60 && board->Mvboard[sq] == 0) {
	    /* Kingside */
	    if ( (board->b[side][rook] & bitboards.BitPosArray[H8])!=NULLBITBOARD &&
		 board->Mvboard[H8] == 0)
	                 n = nbits (bitboards.MoveArray[king][G8] & 
			      board->b[side][pawn] & bitboards.RankBit[rank-1]);
	    /* Queenside */
	    if ( (board->b[side][rook] & bitboards.BitPosArray[A8])!=NULLBITBOARD &&
		 board->Mvboard[A8] == 0)
                   n = nbits (bitboards.MoveArray[king][C8] & 
			      board->b[side][pawn] & bitboards.RankBit[rank-1]);
          }
	}
        
	/* Penalize breaking the wing pawn formations prior to castle */
	if (n != -1) s += pawncover[n];
      }

      if (/*side == searchparams->computer &&*/ file >= F_FILE && 
		!(bitboards.FileBit[G_FILE] & board->b[side][pawn])){
	  if (side == white && board->cboard[F2] == pawn){
	      s += GOPEN;
	  }else if (side == black && board->cboard[F7] == pawn){
	      s += GOPEN;
	  }
      }

      /* No friendly pawns on this king file */
      if (!(bitboards.FileBit[file] & board->b[side][pawn]))
         s += KINGOPENFILE;

      /* No enemy pawns on this king file */
      if (!(bitboards.FileBit[file] & board->b[xside][pawn]))
         s += KINGOPENFILE1;

      switch (file)
      {
         case A_FILE :
         case E_FILE :
         case F_FILE :
	 case G_FILE : if (!(bitboards.FileBit[file+1] & board->b[side][pawn]))
		          s += KINGOPENFILE;
		       if (!(bitboards.FileBit[file+1] & board->b[xside][pawn]))
		          s += KINGOPENFILE1;
	               break;
         case H_FILE :
         case D_FILE :
         case C_FILE :
	 case B_FILE : if (!(bitboards.FileBit[file-1] & board->b[side][pawn]))
		          s += KINGOPENFILE;
		       if (!(bitboards.FileBit[file-1] & board->b[xside][pawn]))
		          s += KINGOPENFILE1;
	               break;
	 default :
	               break;
      }

      if (board->castled[side]) {
        if (side == white) {
          if (file > E_FILE) {
            if (!(bitboards.BitPosArray[F2] & board->b[side][pawn]) ||
                !(bitboards.BitPosArray[G2] & board->b[side][pawn]) ||
                !(bitboards.BitPosArray[H2] & board->b[side][pawn]) )
                s += RUPTURE;
          } else if (file < E_FILE) {
            if (!(bitboards.BitPosArray[A2] & board->b[side][pawn]) ||
                !(bitboards.BitPosArray[B2] & board->b[side][pawn]) ||
                !(bitboards.BitPosArray[C2] & board->b[side][pawn]) )
                s += RUPTURE;
          }
        } else {
          if (file > E_FILE) {
            if (!(bitboards.BitPosArray[F7] & board->b[side][pawn]) ||
                !(bitboards.BitPosArray[G7] & board->b[side][pawn]) ||
                !(bitboards.BitPosArray[H7] & board->b[side][pawn]) )
                s += RUPTURE;
          } else if (file < E_FILE) {
            if (!(bitboards.BitPosArray[A7] & board->b[side][pawn]) ||
                !(bitboards.BitPosArray[B7] & board->b[side][pawn]) ||
                !(bitboards.BitPosArray[C7] & board->b[side][pawn]) )
                s += RUPTURE;
	  }
	}
      }

	/* 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]) & bitboards.FileBit[7])){
         s += HOPEN;
	}
	/* King trapping rook */
        if (side == white) {
	  if (file > E_FILE) {
	    if (board->b[side][rook]&bitboards.mask_kr_trapped_w[H_FILE-file]) {
		s += ROOKTRAPPED;
	    }
	  } else if (file < D_FILE) {
	    if (board->b[side][rook]&bitboards.mask_qr_trapped_w[file]) {
		s += ROOKTRAPPED;
	    }
	  }
	} else {
	  if (file > E_FILE) {
	    if (board->b[side][rook]&bitboards.mask_kr_trapped_b[H_FILE-file]) {
		s += ROOKTRAPPED;
	    }
	  } else if (file < D_FILE) {
	    if (board->b[side][rook]&bitboards.mask_qr_trapped_b[file]) {
		s += ROOKTRAPPED;
	    }
	  }
	}

      /* Don't give fianchetto target for advanced pawns */
      if (file > E_FILE && FILE_(board->king[xside]) < D_FILE) {
         if (side == white) fsq = G3; else fsq = G6;
	 if ((bitboards.BitPosArray[fsq] & board->b[side][pawn]) != NULLBITBOARD)
            if (((bitboards.BitPosArray[F4]|bitboards.BitPosArray[H4]|
	         bitboards.BitPosArray[F5]|bitboards.BitPosArray[H5])
	      & board->b[xside][pawn]) != NULLBITBOARD) 
	        s += FIANCHETTO_TARGET;	
      }
      if (file < E_FILE && FILE_(board->king[xside]) > E_FILE) {
         if (side == white) fsq = B3; else fsq = B6;
	 if ((bitboards.BitPosArray[fsq] & board->b[side][pawn]) != NULLBITBOARD)
            if (((bitboards.BitPosArray[A4]|bitboards.BitPosArray[C4]|
	         bitboards.BitPosArray[A5]|bitboards.BitPosArray[C5])
	      & board->b[xside][pawn]) != NULLBITBOARD) 
	        s += FIANCHETTO_TARGET;	
      }

      /* No major/minor piece in king's quadrant */
      /* First identify the quadrant */
      x = bitboards.boardhalf[side] & bitboards.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[board->phase]) / 8;
   }
   else
   {
      s += EndingKing[sq];
      s += CTL(board, sq,king,side);
      b = (board->b[white][pawn] | board->b[black][pawn]);
      while (b)
      {
         sq1 = leadz (b);
         CLEARBIT (b, sq1);
	 if (bitboards.BitPosArray[sq1] & board->b[white][pawn])
            s -= distance[sq][sq1+8] * 10 - 5;
	 else if (bitboards.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 (bitboards.MoveArray[king][sq] & weaked[xside])
         s += ATAKWEAKPAWN * 2;

   }

    if (board->phase >= 4) {
      /* Weak back rank */
      if (side == white) {
        if (sq < A2) 
	  if (!(bitboards.MoveArray[king][sq] & (~board->b[side][pawn] & bitboards.RankBit[1]))) 
	    s += KING_BACK_RANK_WEAK;
      } else {
	if (sq > H7) 
	  if (!(bitboards.MoveArray[king][sq] & (~board->b[side][pawn] & bitboards.RankBit[6]))) 
	    s += KING_BACK_RANK_WEAK;
      }
   }

   return (s);
}


int LoneKing (board_t *board, 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.
 *
 **************************************************************************/
{
   // We must have a hard look at this routine..

   int s, winner, sq1, sq2;

   winner = 1^loser;
   if (board->material[winner] == ValueB+ValueN && 
	nbits(board->b[winner][bishop]) == 1 &&
       nbits(board->b[winner][knight]) == 1){
     return (ScoreKBNK (board, side, loser));
   }

   
   if(board->material[winner]<ValueR){
       return DRAWSCORE;
   }

   if(nbits(board->b[winner][knight])==2 && board->material[winner]==2*ValueN){
       return DRAWSCORE;
   }

   sq1 = board->king[winner];
   sq2 = board->king[loser];
   s = 150 - 6 * taxicab[sq1][sq2] - EndingKing[sq2];
   if (side == loser)
      s = -s;
   s += MATERIAL(board,side);

   return (s);
}


int KPK (board_t *board, int side)

// TODO: the evaluation of rookpawns is wildy off.
// This seems to be only fixable using a bitbase.

/**************************************************************************
 *
 *  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 pawn_file, winner, loser, sq, sqw, sql;
   int s;

   winner = (board->b[white][pawn] ? white : black);
   loser = 1 ^ winner;
   sq  = leadz (board->b[winner][pawn]);
   sqw = board->king[winner];
   sql = board->king[loser];
   s = ValueP + (ValueQ * Passed[winner][RANK(sq)] / PFACTOR) + 
	 4 * (winner == white ? RANK(sqw) : 7-RANK(sqw));

   pawn_file=FILE_(sq);

/**************************************************************************
 *
 * Pawn is outside the square of the king 
 *
 **************************************************************************/
   if (~bitboards.SquarePawnMask[winner][sq] & board->b[loser][king])
   {
      if (!(bitboards.MoveArray[king][sql] & bitboards.SquarePawnMask[winner][sq]))
         return (winner == side ? s : -s);
      if (winner == 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 (FILE_(sq) != 0 && FILE_(sq) != 7 &&
        ((bitboards.IsolaniMask[FILE_(sq)] | bitboards.FileBit[FILE_(sq)]) & board->b[winner][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 (winner == white)
      {
         if (RANK(sqw) == RANK(sq) + 2)
            return (winner == side ? s : -s);
         if (RANK(sqw) == RANK(sq) + 1)
         {
	    if (RANK(sqw) == 5)
               return (winner == side ? s : -s);
            if (sqw < A6) 
	    {
	       if (sqw+16 == sql && winner == side)
		  return (0);
	       else
                  return (winner == side ? s : -s);
	    }
         }
         if (RANK(sqw) == RANK(sq))
         {
            if ((RANK(sql) - RANK(sq) < 2 || RANK(sql) - RANK(sq) > 4) &&
		 winner == 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 (winner == side ? s : 0);
	 }
	 if (RANK(sq) == 6 && RANK(sqw) == 5)
         {
	    if (sql != sq+8)
               return (winner == side ? s : 0);
	    if (sql == sq+8 && sql == sqw+16)
               return (winner == side ? s : 0);
	 }
      } 
      else
      {
         if (RANK(sqw) == RANK(sq) - 2)
            return (winner == side ? s : -s);
         if (RANK(sqw) == RANK(sq) - 1)
         {
	    if (RANK(sqw) == 2)
               return (winner == side ? s : -s);
	    if (sqw > H3)
	    {
	       if (sqw-16 == sql && winner == side)
	          return (0);
	       else
                  return (winner == side ? s : -s);
	    }	
	 }
         if (RANK(sqw) == RANK(sq))
         {
            if ((RANK(sq) - RANK(sql) < 2 || RANK(sq) - RANK(sql) > 4) &&
		 winner == 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 (winner == side ? s : 0);
	 }
	 if (RANK(sq) == 1 && RANK(sqw) == 2)
         {
	    if (sql != sq-8)
               return (winner == side ? s : 0);
	    if (sql == sq-8 && sql == sqw-16)
               return (winner == 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 (board_t *board, int side, int loser)
/****************************************************************************
 *
 *  My very own KBNK routine!
 *
 ****************************************************************************/
{
   int s, winner, sq1, sq2, sqB;

   winner = 1^loser;
   sqB = board->king[loser];
   if (board->b[winner][bishop] & bitboards.WhiteSquares)
      sqB = RANK(sqB)*8 + 7 - FILE_(sqB);
   sq1 = board->king[winner];
   sq2 = board->king[loser];
   s = 300 - 6 * taxicab[sq1][sq2];
   s -= KBNK[sqB];
   s -= EndingKing[sq2];
   s -= taxicab[leadz(board->b[winner][knight])][sq2];
   s -= taxicab[leadz(board->b[winner][bishop])][sq2];

   /*  King in the central 4x4 region is good! */
   if (board->b[winner][king] & ULL(0x00003C3C3C3C0000))
      s += 20;
   if (side == loser)
      s = -s;
   s += MATERIAL(board,side);

   return (s); 
}


static const BitBoard nn[2] = { ULL(0x4200000000000000), ULL(0x0000000000000042) };
static const BitBoard bb[2] = { ULL(0x2400000000000000), ULL(0x0000000000000024) };

int ScoreDev (board_t *board, searchparams_t *searchparams, 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] || board->GameCnt >= 38)
      return (s);

   s += NOTCASTLED;

   /* If the king is moved, nail it, otherwise check rooks */
   if (board->Mvboard[board->king[side]] > 0) 
      s += KINGMOVED;

   /* Discourage rook moves */
   c = board->b[side][rook];
   while (c) {
     sq = leadz(c);
     CLEARBIT(c, sq);
     if (board->Mvboard[sq] > 0)
       s += ROOKMOVED;
   }

   /* Penalize a queen that moves at all */
   if (board->b[side][queen])
   {
      sq = leadz (board->b[side][queen]);
      if (board->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 (board->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 (board->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 (board->Mvboard[sq] > 1) 
	s += EARLYCENTERPREPEAT;
   }

   return (s);
}


/*  Array of pointer to functions  */
static int (*ScorePiece[7]) (board_t *, searchparams_t *, short) =
{ NULL, ScoreP, ScoreN, ScoreB, ScoreR, ScoreQ, ScoreK };


#define NOT_RECOGNIZED -INFIN-1
#define KBPK_NOTRECOGNIZED 0x0001
#define KBPK_LOWERBOUND    0x0002
#define KBPK_UPPERBOUND    0x0004
#define KBPK_EXACTSCORE    0x0008



int Evaluate (board_t *board, 
	      searchparams_t *searchparams,
	      searchdata_t *searchdata, 
	      searchstats_t *searchstats, 
	      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 score;
   int piece;
   int npiece[2];
   BitBoard *b;
   int ending, recog;
   uint32_t KBPK_flags;
   int KBPK_score;
   int no_lazy_eval=false;
   int side_has_no_mating_material;
   int xside_has_no_mating_material;
   int side_has_no_pawns;
   int xside_has_no_pawns;

   searchstats->EvalCnt++;
   ending=ENDING(board);
   
   recog=Material[board->material_index].recog;

   side = board->side;
   xside = 1 ^ side;
   // printf("Evaluate 1\n");

   /*  If we are looking for a MATE, just return the material */
   if (alpha > MATE-255 || beta < -MATE+255){
       return (MATERIAL(board,side)); 
   }
   //   printf("Evaluate 2\n");

   /*  A KPK endgame. */
   if (ending && board->material[white]+board->material[black] == ValueP){
     return (KPK (board,side));  
   }

   //   printf("Evaluate 3\n");

   /*  One side has a lone king and other side has no pawns */
   if (ending && board->material[xside] == 0 && board->b[side][pawn] == NULLBITBOARD){
     return LoneKing (board, side, xside);
   }
   if (ending && board->material[side] == 0 && board->b[xside][pawn] == NULLBITBOARD){
     return LoneKing (board, side, side);
   }

   //   printf("Evaluate 4\n");

   KBPK_flags=KBPK_NOTRECOGNIZED;
   if(ending && recog==MATERIAL_KBPK){
       no_lazy_eval=true;
       KBPK_score=ScoreKBPK(board,&KBPK_flags);
       if(KBPK_flags==KBPK_EXACTSCORE){
	   
	   return KBPK_score;
       }
   }

   //   printf("Evaluate 5\n");



   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]);


   // Hacky and inefficient. Clean up later using material tables.

   side_has_no_mating_material=ending && !board->b[side][pawn] 
       && (board->material[side] < ValueR || (pieces[side] == board->b[side][knight] && nbits(pieces[side])<=2));
	   
   xside_has_no_mating_material=ending &&  !board->b[xside][pawn] 
       && (board->material[xside] < ValueR || (pieces[xside] == board->b[xside][knight]  && nbits(pieces[xside])<=2));
	   
   side_has_no_pawns=ending && !board->b[side][pawn]; 
   
   xside_has_no_pawns=ending &&	!board->b[xside][pawn]; 

   if(ending && (side_has_no_mating_material || 
      xside_has_no_mating_material || 
      side_has_no_pawns || 
		 xside_has_no_pawns)){
       no_lazy_eval=true;
   }

/****************************************************************************
 *
 *  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.
 *
 ****************************************************************************/
   int lazy_material, lazy_eval, lazy_pos, slow_pos;
   lazy_material=MATERIAL(board,side);

   if (!no_lazy_eval && lazy_material + searchdata->posdiff[side]/*+150*/ <= alpha 
        &&  board->phase <= 6 )   {
       searchstats->EvalMatCnt++;
       //       printf("Evaluate 6\n");
       return lazy_material+searchdata->posdiff[side]/2 ;
    }
   if (!no_lazy_eval && lazy_material - searchdata->posdiff[xside]/* -150*/>= beta 
        &&  board->phase <= 6 )   {
       searchstats->EvalMatCnt++;
       //       printf("Evaluate 7\n");
       return lazy_material-searchdata->posdiff[xside]/2;
    }
   lazy_pos = 0;
   lazy_pos  += ScoreDev (board, searchparams, side) - ScoreDev (board, searchparams, xside);
   lazy_pos += ScoreP (board, searchparams, side) - ScoreP (board, searchparams, xside);
   lazy_pos += ScoreK (board, searchparams, side) - ScoreK (board, searchparams, xside);
   lazy_pos += BishopTrapped (board,side) - BishopTrapped (board,xside);
   lazy_pos += DoubleQR7 (board, side) - DoubleQR7 (board, xside);
/***************************************************************************
 *
 *  Add adjustments from material table
 *
 ***************************************************************************/
   if(side==white){
       lazy_pos+=Material[board->material_index].score;
   }else{
       lazy_pos-=Material[board->material_index].score;
   }


   lazy_eval=lazy_pos + lazy_material;

/**************************************************************************
 *
 *  See if we can have a lazy evaluation cut.  Otherwise its a slow eval.
 * 
 **************************************************************************/

   if (!no_lazy_eval && lazy_eval + searchdata->lazydiff[side] /*+50*/ <= alpha)
   {
       searchstats->EvalLazyCnt++;
       //       printf("Evaluate 8\n");
       return lazy_eval + searchdata->lazydiff[side]/2;
   }
   else if (!no_lazy_eval && lazy_eval - searchdata->lazydiff[xside] /*-50*/ >= beta)
   {
       searchstats->EvalLazyCnt++;
       //       printf("Evaluate 9\n");
       return lazy_eval- searchdata->lazydiff[xside]/2 ;
   }

   searchstats->EvalFullCnt++;

   GenAtaks(board);
   slow_pos = HUNGPENALTY * ( EvalHung(board,side) - EvalHung(board,xside) );
   FindPins(board, &pinned);
   
   for (piece = knight; piece < king; piece++) {
       slow_pos += (*ScorePiece[piece]) (board, searchparams, side) 
	   - (*ScorePiece[piece]) (board, searchparams, xside);
   }
   score = lazy_eval + slow_pos;


/***************************************************************************
 *
 *  Opposite color bishops is drawish.
 *
 ***************************************************************************/
   if (ending && pieces[white] == board->b[white][bishop] && 
       pieces[black] == board->b[black][bishop] &&
       ((pieces[white] & bitboards.WhiteSquares && pieces[black] & bitboards.BlackSquares) ||
	(pieces[white] & bitboards.BlackSquares && pieces[black] & bitboards.WhiteSquares))) {
       score /= 2;
   }

    
/***************************************************************************
 *
 *  When one side has no mating material, then his score can never be > 0.
 *
 ***************************************************************************/
   if (score > 0 && side_has_no_mating_material){
       //       printf("Evaluate 9.1\n");
      score = 0;
   }
   if (score < 0 && xside_has_no_mating_material){
       //       printf("Evaluate 9.2\n");
      score = 0;
   }
/***************************************************************************
 *
 *  If we have no pawns then we need more than the value of a Bishop extra to win
 *
 ***************************************************************************/
   if (score > 0 && side_has_no_pawns 
       && (MATERIAL(board,side)+nbits(board->b[xside][pawn])*ValueP<=ValueB)){
       score = MIN(score,48-EndingKing[board->king[xside]]); 
   }
   
   if (score < 0 && xside_has_no_pawns
       && (MATERIAL(board,xside)+nbits(board->b[side][pawn])*ValueP<=ValueB)){
       score = MAX(score,-48+EndingKing[board->king[side]]); 
   }

   if(ending && KBPK_flags==KBPK_LOWERBOUND){
       score=MAX(score,KBPK_score);
   }
   if(ending && KBPK_flags==KBPK_UPPERBOUND){
       score=MIN(score,KBPK_score);
   }



   slow_pos=score-lazy_eval;
   
   searchdata->posdiff[side]=MAX(searchdata->posdiff[side],lazy_pos+slow_pos);
   searchdata->lazydiff[side]=MAX(searchdata->lazydiff[side],slow_pos);
   searchdata->posdiff[xside]=MAX(searchdata->posdiff[xside],-lazy_pos-slow_pos);
   searchdata->lazydiff[xside]=MAX(searchdata->lazydiff[xside],-slow_pos);

   //   printf("Evaluate 10\n");
   
   return (score);
}



int ScoreKBPK(board_t *board, uint32_t *flags){

    // This is a mess. Needs endgame framework.
    // TODO: 
    // Replace file check with bitboard mask.
    // Make heuristic draw conditions more precise. 

    int side, xside, winner, loser;
    int KBPK;
    int file, t, new_file, prom_rank, prom_color, prom_square, first_pawn, first_blocker_pawn, blocked;
    BitBoard c, blocker_pawns;
    int s;
    int loser_king_distance, winner_king_distance, side_bonus, winner_pawn_distance;
    

    side=board->side;
    xside=1^side;

    KBPK=false;
    if((nbits(board->friends[side])==nbits(board->b[side][pawn])+nbits(board->b[side][bishop])+1)
       && (nbits(board->b[side][bishop])==1)
       && (nbits(board->b[side][pawn])>=1)
       && nbits(board->friends[xside])==nbits(board->b[xside][pawn])+1
       ){
	*flags=KBPK_UPPERBOUND; // flags for side: the winner gets at most an upperbound
	winner=side;
	loser=xside;
	KBPK=true;
    }else if((nbits(board->friends[xside])==nbits(board->b[xside][pawn])+nbits(board->b[xside][bishop])+1)
	     && (nbits(board->b[xside][bishop])==1)
	     && (nbits(board->b[xside][pawn])>=1)
	     && nbits(board->friends[side])==nbits(board->b[side][pawn])+1
	     ){
	*flags=KBPK_LOWERBOUND; // flags for side: the winner gets at most an upperbound
	winner=xside;
	loser=side;
	KBPK=true;
    }
    if(KBPK){
	if 	(nbits(board->friends[loser])==1){
	    *flags=KBPK_EXACTSCORE;
	} // bound flags have already been set
	file=-1;
	c=board->b[winner][pawn];
	while(c){
	    t = leadz (c);
	    CLEARBIT (c, t);  
	    // replace by masking!
	    new_file=FILE_(t);
	    if((file!=-1 && new_file!=file)|| (new_file!=0 && new_file!=7)){
		*flags=KBPK_NOTRECOGNIZED;
		return NOT_RECOGNIZED;
	    }else{
		file=new_file;
	    }
	}
	if(winner==white){
	    prom_rank=7;
	}else{
	    prom_rank=0;
	}
	prom_color=1^((prom_rank+file)&1);
	if(prom_color==white && (board->b[winner][bishop]&bitboards.WhiteSquares)!=NULLBITBOARD){
	    *flags=KBPK_NOTRECOGNIZED;
	    return NOT_RECOGNIZED;
	}
	if(prom_color==black && (board->b[winner][bishop]&bitboards.BlackSquares)!=NULLBITBOARD){
	    *flags=KBPK_NOTRECOGNIZED;
	    return NOT_RECOGNIZED;
	}
	prom_square=SQUARE(file,prom_rank);
	loser_king_distance=distance[prom_square][board->king[loser]];
	if(loser_king_distance<= 1){
	    return DRAWSCORE;
	}
	// heuristic scores for winner
	side_bonus=(winner==side?1:0);
	first_pawn=(winner==white?trailz(board->b[winner][pawn]):leadz(board->b[winner][pawn]));
	winner_pawn_distance=distance[prom_square][first_pawn];
	winner_king_distance=distance[prom_square][board->king[winner]];
	
	blocker_pawns=bitboards.FileBit[file] & board->b[loser][pawn];
	blocked=false;
	if(blocker_pawns){
	    first_blocker_pawn=(winner==white?trailz(blocker_pawns):leadz(blocker_pawns));
	    blocked=(winner==white?first_blocker_pawn>first_pawn:first_blocker_pawn<first_pawn);
	}
	if (!blocked && loser_king_distance>winner_pawn_distance-side_bonus+1){
	    s=MATERIAL(board,winner)-10*winner_pawn_distance+70;
	}else if(!blocked){
	    if (loser_king_distance>winner_king_distance-side_bonus+1){
		s=MATERIAL(board,winner)-10*winner_pawn_distance;
	    }else{
		s=5*loser_king_distance;
	    }
	}else{ // blocked
	    if (loser_king_distance>winner_king_distance-side_bonus+1){
                /* the /3 works best because KPK is mis evaluated */
		s=(MATERIAL(board,winner)/3+loser_king_distance) ;
		if((blocker_pawns&bitboards.WhiteSquares)!=NULLBITBOARD && (board->b[winner][bishop]&bitboards.WhiteSquares)!=NULLBITBOARD){
		    s+=20;
		}else
		if((blocker_pawns&bitboards.BlackSquares)!=NULLBITBOARD && (board->b[winner][bishop]&bitboards.BlackSquares)!=NULLBITBOARD){
		    s+=20;
		}else
		if(abs(first_blocker_pawn-first_pawn)>8){
	           s+=15;
		}
	    }else{
		s=5*loser_king_distance;
	    }
	    
	}
	if(side!=winner){
	    s=-s;
	}
	return s;
    }
    *flags=KBPK_NOTRECOGNIZED;
    return NOT_RECOGNIZED;
	
}



short EvaluateDraw (board_t *board)

{
/***************************************************************************
 *
 *  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;
   uint32_t KBPK_flags;
   int recog;

   recog=Material[board->material_index].recog;
   

   if(!ENDING(board)){
       return  false;
   }


   w = board->b[white];
   b = board->b[black];



   if(recog==MATERIAL_KBPK && (ScoreKBPK(board,&KBPK_flags)==DRAWSCORE) && (KBPK_flags==KBPK_EXACTSCORE)){
       return true;
   }

   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] & bitboards.WhiteSquares) == 2 ||
           nbits(board->b[black][bishop] & bitboards.BlackSquares) == 2 )){
	  return (true);
      }
   }
   if (bm < ValueR)
   {
      if (wm == 2*ValueB && 
         ( nbits(board->b[white][bishop] & bitboards.WhiteSquares) == 2 ||
           nbits(board->b[white][bishop] & bitboards.BlackSquares) == 2 )){
	  return (true);
      }
   }


   return (false);
}

