#include "win32compat.h"
#include "data.h"
#include "evaluate.h"
#include "gui.h"

// ==========================
// Pawn Hashing
// ==========================
// DATA
unsigned int WPHashSq [128];
unsigned int BPHashSq [128];
#define PAWNHASHTABLESIZE	((2 << 15) - 1)

PawnHashEntry* PawnTable = (PawnHashEntry*) malloc( sizeof (PawnHashEntry) * (PAWNHASHTABLESIZE + 1));

// --------------------------------------------------
void Clear_PawnHash ( )
{
ZeroMemory (PawnTable, sizeof (PawnHashEntry) * PAWNHASHTABLESIZE );
}

// --------------------------------------------------
//  Pawn LookUp
// --------------------------------------------------
int inline PawnHash_Lookup (PawnHashEntry &TEntry, const unsigned int nCheckSum)
{
	register int index = nCheckSum & PAWNHASHTABLESIZE;

	if (PawnTable [ index ].checksum == nCheckSum)
		{
		TEntry = PawnTable[ index ];
		return TRUE;
        }
	return FALSE;
}

// --------------------------------------------------
//  Pawn HashBoard
// --------------------------------------------------
unsigned int Pawn_HashBoard (const SBoard &Board)
{
 unsigned int sum = 0;
 int i;

	 for (i = 0; i < 8; i++)
		{
		if (Board.WPiece [i] != CAPTURED) sum += WPHashSq [ Board.WPiece [i] ];
		if (Board.BPiece [i] != CAPTURED) sum += BPHashSq [ Board.BPiece [i] ];
		}
 return sum;
}

// --------------------------------------------------
//
//  Evaluate the pawn structure on the Board
//
// --------------------------------------------------
#define ISLAND_V 5
#define WEAK_OPENFILE 6
#define BACKWARD1_V 10
const int DOUBLED_V[9]     = { 0, 0, 12, 26, 45, 65, 85, 105, 105}; // number of pawns on a file
const int PASSED_RANK[9]   = { 0, 0, 16, 22, 34, 48, 75, 112, 0 };
const int PASSEDBE_RANK[9] = { 0, 0, 16, 22, 25, 34, 60, 85,  0 };
const int CONNECTED_RANK[9]= { 0, 0,  0,  2,  5, 18, 32, 52,  0 };

int inline FreeSqCoveredByPawnB ( const SBoard &Board, const int nSq)
{
	if ((Board.Sq[ nSq ]&7) == WPAWN || Board.Sq[ nSq - 9]  == BPAWN || Board.Sq[ nSq - 11] == BPAWN) return 1;
	return 0;
}

int inline FreeSqCoveredByPawnW ( const SBoard &Board, const int nSq)
{
	if ((Board.Sq[ nSq ]&7) == WPAWN || Board.Sq[ nSq + 11] == WPAWN || Board.Sq[ nSq + 9]  == WPAWN) return 1;
	return 0;
}
//
//
//
void EvalPawns ( const SBoard &Board, PawnHashEntry &TEntry)
{
int x, nFile;
int nWLeft = 8, nWRight=1, nBLeft = 9, nBRight=0;
char WFile [10], BFile [10];
char WRankMin [10], BRankMin [10];
char WRankMax [10], BRankMax [10];

memset (&TEntry, 0,  sizeof (TEntry));
memset (WFile, 0, 10 * sizeof (char) );
memset (BFile, 0, 10 * sizeof (char) );
memset (WRankMin,  20, 10 * sizeof (char) );
memset (BRankMin,  20, 10 * sizeof (char) );
memset (WRankMax, -20, 10 * sizeof (char) );
memset (BRankMax, -20, 10 * sizeof (char) );

int nLoc;

// Compute Info
for (x = 0; x < 8; x++)
	{
	nLoc = Board.WPiece[x];
	if ( nLoc != CAPTURED && Board.Sq[nLoc] == WPAWN) 
		{
		// Square Table
		TEntry.MatEnd += WPawnValueEnd [ nLoc ];
		TEntry.Mat[0] += WPawnValue [ nLoc ]; 
		TEntry.Mat[1] += WPawnValueQSOK [ nLoc ];
		TEntry.Mat[2] += WPawnValueOK [ nLoc ]; 
		TEntry.Mat[3] += WPawnValueQS [ nLoc ];

		nFile = SQFILE[ nLoc ];
		if (nFile < nWLeft)  nWLeft  = nFile;
		if (nFile > nWRight) nWRight = nFile;
		TEntry.OpenFileW |= BITMASK [ nFile ];
		WFile[ nFile ]++;
		int nRank = SQRANK [ nLoc  ];
		if ( nRank < WRankMin[ nFile ] ) WRankMin[ nFile ]= SQRANK [ nLoc  ];
		if ( nRank > WRankMax[ nFile ] ) WRankMax[ nFile ]= SQRANK [ nLoc  ];
		if ( nLoc > 82 && nLoc < 89 ) TEntry.flags |= 256;
		}
	}
for (x = 0; x < 8; x++)
	{
	nLoc = Board.BPiece[x];
	if ( nLoc != CAPTURED  && Board.Sq[nLoc] == BPAWN) 
		{
		TEntry.MatEnd += BPawnValueEnd [ nLoc ];
		TEntry.Mat[0] += BPawnValue [ nLoc ]; 
		TEntry.Mat[1] += BPawnValueOK [ nLoc ]; 
		TEntry.Mat[2] += BPawnValueQSOK [ nLoc ];
		TEntry.Mat[3] += BPawnValueQS [ nLoc ];

		nFile = SQFILE[  nLoc  ];
		if (nFile < nBLeft)  nBLeft  = nFile;
		if (nFile > nBRight) nBRight = nFile;

		TEntry.OpenFileB |= BITMASK [ nFile ];
		BFile[ nFile ]++;
		int nRank = SQRANK [ nLoc  ];
		if ( nRank < BRankMin[ nFile ] ) BRankMin[ nFile ]= SQRANK [ nLoc  ];
		if ( nRank > BRankMax[ nFile ] ) BRankMax[ nFile ]= SQRANK [ nLoc  ];
		if ( nLoc > 32 && nLoc < 39 ) TEntry.flags |= 512;
		}
	}

// For drawn rook's pawn endings
if (BFile[1] == Board.nBPawns) TEntry.flags |=1;
if (BFile[8] == Board.nBPawns) TEntry.flags |=2;
if (WFile[1] == Board.nWPawns) TEntry.flags |=4;
if (WFile[8] == Board.nWPawns) TEntry.flags |=8;
// For Outside Passed Pawns
if ( nWLeft < (nBLeft-2) || nWRight > (nBRight+2) ) TEntry.flags |=64|16;
else if ( nWLeft < (nBLeft-1) || nWRight > (nBRight+1) ) TEntry.flags |=16;
if ( nBLeft < (nWLeft-2) || nBRight > (nWRight+2) ) TEntry.flags |=128|32;
else if ( nBLeft < (nWLeft-1) || nBRight > (nWRight+1) ) TEntry.flags |=32;

TEntry.PawnFileL = (nWLeft < nBLeft ) ? nWLeft : nBLeft;
TEntry.PawnFileR = (nWRight > nBRight ) ? nWRight : nBRight;

// Doubled Pawns 
// Pawn Islands
int bStart = FALSE;
for (nFile = 1; nFile <= 8; nFile++) // WHITE
	{
	if (WFile[nFile]!= 0)
		{
		if (WFile[nFile] > 1) TEntry.eval -= DOUBLED_V [ WFile[nFile] ];
		if (bStart == FALSE)
			{
			bStart = TRUE; 
			TEntry.eval -= ISLAND_V;
			}
		}
	else bStart = FALSE;
	}

bStart = FALSE;
for (nFile = 1; nFile <= 8; nFile++) // BLACK
	{
	if (BFile[nFile]!= 0)
		{
		if (BFile[nFile] > 1) TEntry.eval += DOUBLED_V [ BFile[nFile] ];
		if (bStart == FALSE)
			{
			bStart = TRUE; 
			TEntry.eval += ISLAND_V;
			}
		}
	else bStart = FALSE;
	}

// Passed Pawns
// Isolated Pawns
// Backward Pawns  
int nWPsqs = 0, nBPsqs = 0, nRank;

for  (x = 0; x < 8; x++)
	{
	// WHITE
	nLoc = Board.WPiece[x];
	if (nLoc != CAPTURED && Board.Sq[nLoc] == WPAWN)
		{
		nFile = SQFILE [ nLoc ];
		nRank = SQRANK [ nLoc ];

		if (nRank < WRankMin [ nFile+1 ]  && nRank < WRankMin [ nFile-1 ])  
			{
			 if (WFile [ nFile-1] == 0 && WFile [ nFile +1] == 0 ) TEntry.eval -= WPawnIsolated[ nLoc ];
				 else if (FreeSqCoveredByPawnB (Board, nLoc - 10)) TEntry.eval -= BACKWARD1_V;
			 TEntry.WeakFileW |= BITMASK [nFile];
 			 if ( BFile[nFile] == 0 ) TEntry.eval -= WEAK_OPENFILE;
			}
		if (nRank >= BRankMax [ nFile+1 ]  && nRank >= BRankMax [ nFile-1 ] && nRank > BRankMax [ nFile ] && nRank == WRankMax [ nFile ])
			{
			if ( BFile[nFile] == 0) TEntry.eval += PASSED_RANK [ nRank ]; else TEntry.eval += PASSEDBE_RANK [ nRank ];
			if ( nWPsqs < 4) TEntry.WPassSqs [nWPsqs++] = nLoc;
			if ( abs(WRankMax [ nFile-1 ] - nRank) <=1 || abs(WRankMax [ nFile+1 ] - nRank) <=1) TEntry.PassedCon += (CONNECTED_RANK [ nRank ]);
			}
		}
	}
for  (x = 0; x < 8; x++)
	{
	// BLACK
	nLoc = Board.BPiece[x]; 
	if (nLoc != CAPTURED && Board.Sq[nLoc] == BPAWN) 
		{
		nFile = SQFILE [ nLoc ];
		nRank = SQRANK [ nLoc ];

		if (nRank > BRankMax [ nFile+1 ] && nRank > BRankMax [ nFile-1 ] )
			{
			  if (BFile [ nFile-1] == 0 && BFile [ nFile+1] == 0 ) TEntry.eval += BPawnIsolated[ nLoc ]; // Isolated Pawn
				else if (FreeSqCoveredByPawnW (Board, nLoc + 10) ) TEntry.eval +=BACKWARD1_V;
			  TEntry.WeakFileB |= BITMASK [nFile];
			  if ( WFile[nFile] == 0 ) TEntry.eval += WEAK_OPENFILE;
			}
		if (nRank <= WRankMin [ nFile+1 ] && nRank <= WRankMin [ nFile-1 ] && nRank < WRankMin [ nFile ] && nRank == BRankMin [ nFile ])
			{
			if ( WFile[nFile] == 0) TEntry.eval -= PASSED_RANK [ 9 - nRank ]; else TEntry.eval -= PASSEDBE_RANK [ 9 - nRank ]>>1;
			if (nBPsqs < 4) TEntry.BPassSqs [nBPsqs++] = nLoc;
			if ( abs(BRankMin [ nFile-1 ] - nRank) <=1 || abs(BRankMin [ nFile+1 ] - nRank) <=1) TEntry.PassedCon -= (CONNECTED_RANK [ 9 - nRank ]);
			}
		}
	}

// Store in Hash Table
TEntry.checksum =  Board.PawnHash;
PawnTable [ Board.PawnHash & PAWNHASHTABLESIZE ] = TEntry;
}
//
// END PAWNS
//

//
// So it can display this term in the board flags display
//
int Liquidate ( SBoard &Board )
{
return MatEval (Board, Board.nWP, Board.nBP, Board.MatVal);
}

//
// ROOKS
//
const int RPAWNSUPPORT [ 12 ] = { 0, 20, 15, 9, 0, 0, 9, 15, 20 };
const int R_Tropism[16]     = { 11, 6, 2,  1, 0, 0, 0, 0 }; // Half open file
const int R_TropismOpen[16] = { 22, 12, 6,  3, 0, 0, 0, 0 }; // Open File
#define ROOK_HALF 10
#define ROOK_FULL 21 // Rook on open file
#define KINGTRAPSROOK 29
#define ROOKS_7 10
#define ROOKS_8 18
#define ROOKS_7K8 52 // ENDR7_K8 is in addition, as well as the piece square tables
#define QR7_K8 70
#define ENDR7_K8 34
const int BRMOVE[16] = {  1, 0, 0, 0, 0, 1, 1, 1,  0, 0, 0, 0, 0, 0, 0, 0  };  
const int WRMOVE[16] = {  1, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 1, 1, 1  };
const int R_MovesValOpen[16]   = { -16, -6,  0, 2, 4, 6, 8, 6, 7, 8, 9, 10, 11, 12, 13, 14};
const int R_MovesValClosed[16] = { -16, -14, -2, 0, 2, 4, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14};

int inline EvalRookBlack (const SBoard &Board, const int &nRookSq, const int &nKingSqO, const unsigned char &cOpenW, const unsigned char &cOpenB, const unsigned char &cWeakW , int &nTropism )
	{
	 int HMoves = 0;
	 int eval = 0;
	 int nFile = SQFILE[nRookSq];

	 if ( BRMOVE [ Board.Sq [ nRookSq+1 ] ] ) {HMoves++;if ( Board.Sq [ nRookSq+2 ] == EMPTY) {HMoves++; if (Board.Sq [nRookSq+3] == EMPTY) HMoves++;} }
	 if ( BRMOVE [ Board.Sq [ nRookSq-1 ] ] ) {HMoves++;if ( Board.Sq [ nRookSq-2 ] == EMPTY) {HMoves++; if (Board.Sq [nRookSq-3] == EMPTY) HMoves++;} }

	 if (SQRANK[nRookSq] <= 3 ) 
		{
		 if (Board.Sq [ nRookSq-9 ] == BPAWN || Board.Sq [ nRookSq-11 ] == BPAWN) eval+= RPAWNSUPPORT [ SQRANK[nRookSq] ];
		}

	 if ( (cOpenB & BITMASK[ nFile ]) == 0)
		{
		 if ( (cOpenW & BITMASK[ nFile ]) == 0 || (cWeakW & BITMASK[nFile ]) != 0) 
			{eval += ROOK_FULL;
		     nTropism += R_TropismOpen [ abs( nFile - SQFILE [ nKingSqO ] ) ];
			}
			else 
			{eval += ROOK_HALF;		 
			 nTropism += R_Tropism [ abs( nFile - SQFILE [ nKingSqO ] ) ];
			}
		 if ( SQFILE[Board.BPiece[14]] == nFile ) nTropism+=R_Tropism [ abs( nFile - SQFILE [ nKingSqO ] ) ];

		 eval += R_MovesValOpen [ HMoves ];
		}
	 else 
		{
		 eval += R_MovesValClosed [ HMoves ];
		}
	 if ( ((cOpenW | cOpenB) & BITMASK[ nFile ]) !=0 && RookTrappedB[nRookSq] !=0 )
			{if (RookTrappedB [nRookSq]==2) 
				{if (Board.BPiece[15] == 28 || Board.BPiece[15] == 27 ) eval-=KINGTRAPSROOK;}
			else if (Board.BPiece[15] == 23 || Board.BPiece[15] == 24 ) eval-=KINGTRAPSROOK;
			}			

	 return eval;
	}

int inline EvalRookWhite (const SBoard &Board, const int &nRookSq, const int &nKingSqO,  const unsigned char &cOpenW, const unsigned char &cOpenB, const unsigned char &cWeakB, int &nTropism)
	{
	 int HMoves = 0;
	 int eval = 0;
	 int nFile = SQFILE[nRookSq];

	 if ( WRMOVE [ Board.Sq [ nRookSq+1 ] ] ) {HMoves++;if ( Board.Sq [ nRookSq+2 ] == EMPTY) {HMoves++; if (Board.Sq [nRookSq+3] == EMPTY) HMoves++;} }
	 if ( WRMOVE [ Board.Sq [ nRookSq-1 ] ] ) {HMoves++;if ( Board.Sq [ nRookSq-2 ] == EMPTY) {HMoves++; if (Board.Sq [nRookSq-3] == EMPTY) HMoves++;} }

	 if (SQRANK[nRookSq] >=6 ) 
		{
		 if (Board.Sq [ nRookSq+9 ] == WPAWN || Board.Sq [ nRookSq+11 ] == WPAWN) eval+= RPAWNSUPPORT [ SQRANK[nRookSq] ];
		}

	 if ( (cOpenW & BITMASK[ nFile ]) == 0)
		{
		 if ( (cOpenB & BITMASK[ nFile ]) == 0 || (cWeakB & BITMASK[ nFile ]) != 0)
			{eval += ROOK_FULL;
		     nTropism += R_TropismOpen [ abs( nFile - SQFILE [nKingSqO] ) ];
			}
			else 
			{eval += ROOK_HALF;
			 nTropism += R_Tropism [ abs( nFile - SQFILE [nKingSqO] ) ];
			}
		 if ( SQFILE[Board.WPiece[14]] == nFile ) nTropism+=R_Tropism [ abs( nFile - SQFILE [nKingSqO] ) ];

		 eval += R_MovesValOpen [ HMoves ];
		}
	 else 
		{
		 eval += R_MovesValClosed [ HMoves ];
		}		 
	 if ( ((cOpenW | cOpenB) & BITMASK[ nFile ]) !=0 && RookTrappedW [nRookSq]!=0)
			{if ( RookTrappedW [nRookSq]==2) 
				{if (Board.WPiece[15] == 98 || Board.WPiece[15] == 97 ) eval-=KINGTRAPSROOK;}
			else if (Board.WPiece[15] == 93 || Board.WPiece[15] == 94 ) eval-=KINGTRAPSROOK;
			}			

	 return eval;
	}


//
// BISHOPS
//
const int BISHOP_PAIR = 20;
const int BISHOP_PAIRENDGAME = 35;
const int BISHOP_BEHINDPAWN= -6;
const int BISHOP_PROTECTED= 6;
const int BISHOP_BLOCKSPAWN = -8;
const int BISHOP_TRAPPED= -150;

const int B_Tropism[16] = { 9, 6, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 
const int B_Tropism2[16]= { 7, 10, 10, 8, 4 , 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
const int B_MovesVal[16] = { -12, -6, -2, 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};

int inline EvalBishopWhite (const SBoard &Board, const int &nSq, const int &nBKingSq, int &nTropism)
{
int nEval = 0;
int Moves = 0;
if (nSq == 75 || nSq == 76) if (Board.Sq[nSq+10] == WPAWN) nEval += BISHOP_BLOCKSPAWN;
if ((Board.Sq [nSq-11]&7) == WPAWN) nEval += BISHOP_BEHINDPAWN;
else {
	 nTropism += B_Tropism [ abs(SQDIAG1[nSq] - SQDIAG1 [nBKingSq]) ]; 
	 if (Board.Sq [nSq-11]==EMPTY) 
		{Moves++; 
		 if (Board.Sq [nSq-22] == EMPTY) Moves++;
		 else if ((Board.Sq [nSq-22]&7)== WPAWN) nEval += BISHOP_BEHINDPAWN;
		}		 
	}
if ((Board.Sq [nSq-9]&7)== WPAWN) nEval += BISHOP_BEHINDPAWN;
else
	{
	nTropism += B_Tropism [ abs(SQDIAG2[nSq] - SQDIAG2 [nBKingSq]) ];
	if (Board.Sq [nSq-9] ==EMPTY) 
		{Moves++; 
		 if (Board.Sq [nSq-18] == EMPTY) Moves++;
		 else if ((Board.Sq [nSq-18]&7)== WPAWN) nEval += BISHOP_BEHINDPAWN;
		}
	}
nTropism += B_Tropism2 [ ChessDist ( nSq, nBKingSq ) ];

if (Board.Sq [nSq+11]==EMPTY ) Moves++;
if (Board.Sq [nSq+9] ==EMPTY ) Moves++;

if (Moves == 0) 
	{
	 if (Board.Sq [nSq-9]  == BPAWN && (Board.Sq [ nSq - 20] == BPAWN || Board.Sq [ nSq - 18] == BPAWN) ) nEval+=BISHOP_TRAPPED;
 	 if (Board.Sq [nSq-11] == BPAWN && (Board.Sq [ nSq - 22] == BPAWN || Board.Sq [ nSq - 20] == BPAWN) ) nEval+=BISHOP_TRAPPED;
	}
nEval += B_MovesVal [Moves];

return nEval;
}

//
int inline EvalBishopBlack (const SBoard &Board, const int &nSq, const int &nWKingSq, int &nTropism)
{
int nEval = 0;
int Moves = 0;
if (nSq == 45 || nSq == 46) if (Board.Sq[nSq-10] == BPAWN) nEval += BISHOP_BLOCKSPAWN;

if ((Board.Sq [nSq+11]&7)== WPAWN) nEval += BISHOP_BEHINDPAWN;
else 
	{
	nTropism += B_Tropism [ abs(SQDIAG1[nSq] - SQDIAG1 [nWKingSq]) ] ;
	if (Board.Sq [nSq+11] == EMPTY) 
		{Moves++; 
		 if (Board.Sq [nSq+22] == EMPTY) Moves++;
		 else if ((Board.Sq [nSq+22]&7)== WPAWN) nEval += BISHOP_BEHINDPAWN;
		}
	}
if ((Board.Sq [nSq+9]&7) == WPAWN) nEval += BISHOP_BEHINDPAWN;
else
	{
	nTropism +=B_Tropism [ abs(SQDIAG2[nSq] - SQDIAG2 [nWKingSq]) ]; 
	if (Board.Sq [nSq+9] == EMPTY) 
		{Moves++; 
		 if (Board.Sq [nSq+18] == EMPTY) Moves++;
		 else if ((Board.Sq [nSq+18]&7)== WPAWN) nEval += BISHOP_BEHINDPAWN;
		}
	} 

nTropism += B_Tropism2 [ ChessDist ( nSq, nWKingSq ) ];

if (Board.Sq [nSq-11]==EMPTY) Moves++;
if (Board.Sq [nSq-9] ==EMPTY) Moves++;

if (Moves == 0) 
	{
	 if (Board.Sq [nSq+9]  == WPAWN && (Board.Sq [ nSq + 18] == WPAWN || Board.Sq [ nSq + 20] == WPAWN) ) nEval+=BISHOP_TRAPPED;
 	 if (Board.Sq [nSq+11] == WPAWN && (Board.Sq [ nSq + 20] == WPAWN || Board.Sq [ nSq + 22] == WPAWN) ) nEval+=BISHOP_TRAPPED;
	}
nEval += B_MovesVal [Moves];

return nEval;
}

//
//
void inline BishopTrapped ( const SBoard &Board,  int &eval )
{
	int nSq;
	nSq = Board.WPiece[10];
	if ( BishopTrappedW [ nSq ] == 0 ) nSq = Board.WPiece[11];
	if ( BishopTrappedW [ nSq ] )
		{
		if (nSq == 32)
			{if (Board.Sq[43] == BPAWN && Board.Sq[34] == BPAWN) eval += BISHOP_TRAPPED;
		     else if (Board.Sq[43] == BPAWN) eval += (BISHOP_TRAPPED>>1);
			}
		else if (nSq == 23 && Board.Sq[43] == BPAWN && Board.Sq[34] == BPAWN) eval += (BISHOP_TRAPPED>>1);
		else if (nSq == 39) 
			{if (Board.Sq[48] == BPAWN && Board.Sq[37] == BPAWN) eval += BISHOP_TRAPPED;
			 else if (Board.Sq[48] == BPAWN) eval += (BISHOP_TRAPPED>>1);
			}
		else if (nSq == 28 && Board.Sq[48] == BPAWN && Board.Sq[37] == BPAWN) eval += (BISHOP_TRAPPED>>1);
		}
	nSq = Board.BPiece[10];
	if ( BishopTrappedB [ nSq ] == 0 ) nSq = Board.BPiece[11];
	if ( BishopTrappedB [ nSq ] )
		{
		if (nSq == 82)
			{if (Board.Sq [73] == WPAWN && Board.Sq [84] == WPAWN) eval -= BISHOP_TRAPPED;
			 else if (Board.Sq[73] == WPAWN) eval -= (BISHOP_TRAPPED>>1);
			}
		else if (nSq == 93 && Board.Sq [73] == WPAWN && Board.Sq [84] == WPAWN)  eval -= (BISHOP_TRAPPED>>1);
		if (nSq == 89)
			{if (Board.Sq [78] == WPAWN && Board.Sq [87] == WPAWN ) eval -= BISHOP_TRAPPED;
			 else if (Board.Sq[78] == WPAWN) eval -= (BISHOP_TRAPPED>>1);
			}
		else if (nSq == 98 && Board.Sq [78] == WPAWN && Board.Sq [87] == WPAWN )  eval -= (BISHOP_TRAPPED>>1);
		}
}

//
// KNIGHTS
//
const int N_Tropism[16] = { 12, 11, 11, 14, 12, 10, 7, 6, 4, 2, 0, 0, 0, 0, 0, 0 }; 
#define KNIGHT_UNSAFE -22;
#define KNIGHT_NOFORWARD -8;

int inline EvalKnightWhite (const SBoard &Board, const int &nSq, const int &nBKingSq, int &nTropism )
{
	int eval =0;
	if (Board.Sq [ nSq - 11 ] == BPAWN || Board.Sq [ nSq - 9] == BPAWN) eval+= KNIGHT_UNSAFE;
	if (Board.Sq [ nSq + 9 ] == WPAWN || Board.Sq [ nSq + 11] == WPAWN) eval+= WKnightPost [ nSq ];
	if (SQRANK[nSq] <= 4 && Board.Sq[ nSq - 30] == BPAWN) eval+= KNIGHT_NOFORWARD;
	nTropism+=N_Tropism [ abs ( SQFILE [nBKingSq] - SQFILE [nSq] ) + abs ( SQRANK [nBKingSq] - SQRANK [nSq]) ];
	return eval;
}

int inline EvalKnightBlack (const SBoard &Board, const int &nSq, const int &nWKingSq, int &nTropism )
{
	int eval =0;
	if (Board.Sq [ nSq - 11] == BPAWN || Board.Sq [ nSq - 9] == BPAWN) eval+= BKnightPost [ nSq ];
	if (Board.Sq [ nSq + 9 ] == WPAWN || Board.Sq [ nSq + 11] == WPAWN) eval+= KNIGHT_UNSAFE;
	if (SQRANK[nSq] >= 5 && Board.Sq[ nSq + 30] == WPAWN) eval+= KNIGHT_NOFORWARD;
	nTropism+=N_Tropism [ abs ( SQFILE [nWKingSq] - SQFILE [nSq] ) + abs ( SQRANK [nWKingSq] - SQRANK [nSq]) ];
	return eval;
}

//
// Passed Pawns supported by the king get a bonus
//
// Passed Pawns blocked by a knight a bishop or a king or rook get a penalty since they aren't as dangerous blocked.
//
void inline PassedPawnEval ( const SBoard &Board, int &eval, const int &nWKingSq, const int &nBKingSq,  const PawnHashEntry &SPawns)
{
int nSq, i;
int nR1 = Board.BPiece[12], nR2 = Board.BPiece[13];
 for (i = 0; i < 4; i++) // BLACK PASSED PAWNS
	{
	nSq=SPawns.BPassSqs[i];
	if (nSq==0) break;
	if (SQRANK[nSq] <=4 && SQRANK[nBKingSq] <= (SQRANK[nSq]+1) && abs (SQFILE[nSq] - SQFILE[nBKingSq]) <=1)
		{if ((ChessDistB (nWKingSq, nSq)) >=2) eval -= KINGBYPAWN [ 9-SQRANK[nSq] ];
			else eval -= (KINGBYPAWN [ 9-SQRANK[nSq] ]>>1);
		}
	else eval-= (KINGPAWNDIST[ ChessDistB (nWKingSq, nSq) ]>>1);
	if (WBLOCKER[ Board.Sq [nSq + 10] ] ) eval+=BLOCKEDPASSPAWN [ 9-SQRANK[nSq] ];
	if (nR1 != CAPTURED) eval+= ROOK_PP[ acDirec[ nR1 + (nSq<<7) ] + 12 ];
	if (nR2 != CAPTURED) eval+= ROOK_PP[ acDirec[ nR2 + (nSq<<7) ] + 12 ];
	}

 nR1 = Board.WPiece[12]; nR2 = Board.WPiece[13];
 for (i = 0; i < 4; i++) // WHITE PASSED PAWNS
	{
	nSq=SPawns.WPassSqs[i];
	if (nSq==0) break;
	if (SQRANK[nSq] >=5 && SQRANK[nWKingSq] >= (SQRANK[nSq]-1) && abs (SQFILE[nSq] - SQFILE[nWKingSq]) <= 1)
		{if ((ChessDistW (nBKingSq, nSq)) >=2) eval += KINGBYPAWN [ SQRANK[nSq] ];
			else eval += (KINGBYPAWN [ SQRANK[nSq] ]>>1);
		}
	else eval+= (KINGPAWNDIST[ ChessDistW (nBKingSq, nSq) ]>>1);
	if (BBLOCKER[Board.Sq [ nSq - 10 ] ]) eval-=BLOCKEDPASSPAWN [ SQRANK[nSq] ];
	if (nR1 != CAPTURED) eval+= ROOK_PP[ acDirec[ nR1 + (nSq<<7) ] + 12 ];
	if (nR2 != CAPTURED) eval+= ROOK_PP[ acDirec[ nR2 + (nSq<<7) ] + 12 ];
	}
}

//
// (Don't do king support in midgame)
//
void inline MidgamePassedPawnEval ( const SBoard &Board, int &eval, const int &nWKingSq, const int &nBKingSq,  const PawnHashEntry &SPawns)
{
int nSq, i;
 for (i = 0; i < 4; i++) // BLACK PASSED PAWNS
	{
	nSq=SPawns.BPassSqs[i];
	if (nSq==0) break;
	if (WBLOCKER[ Board.Sq [nSq + 10] ] ) eval+=BLOCKEDPASSPAWN [ 9-SQRANK[nSq] ];
	if (acDirec[ Board.BPiece[12] + (nSq<<7) ] == 10) eval-=ROOK_BEHIND_PP;
	if (acDirec[ Board.BPiece[13] + (nSq<<7) ] == 10) eval-=ROOK_BEHIND_PP;
	}

 for (i = 0; i < 4; i++) // WHITE PASSED PAWNS
	{
	nSq=SPawns.WPassSqs[i];
	if (nSq==0) break;
	if (BBLOCKER[Board.Sq [ nSq - 10 ] ]) eval-=BLOCKEDPASSPAWN [ SQRANK[nSq] ];
	if (acDirec[ Board.WPiece[12] + (nSq<<7) ] == -10) eval+=ROOK_BEHIND_PP;
	if (acDirec[ Board.WPiece[13] + (nSq<<7) ] == -10) eval+=ROOK_BEHIND_PP;
	}
}

#define KING_PAWNCOVERFRONT 14
#define KING_PAWNCOVERFRONT2 10
#define KING_PAWNCOVER 11
#define KING_PAWNCOVER2 8
#define MAX_PAWNCOVER 18

// 
// Don't return good evals for a side if it can't win (or is very unlikely to win.)
// Called when no pawns are on the board for the side in the funtion name, and the eval favors that side
//
int inline WhiteCantWin (const SBoard &Board, int &eval)
{
	if (Board.WMat < 400 ) 
		{eval = -Board.nBPawns; return TRUE;}
	if (Board.WMat == 2*PieceValues [ WKNIGHT ])
		{eval = (eval>>3); return TRUE; }

	if (Board.nWP == (Board.nBP+1) && Board.nWMinors == (Board.nBMinors+1) && (Board.MatVal+Board.nBPawns*100) < 400 ) 
		{	 
		if (Board.nWP > 2) eval = (eval>>1);
					else 
					{if (Board.WMat == PieceValues[ WROOK ] + PieceValues[ WBISHOP ]) eval = (eval>>2);
						else eval = (eval>>3); 
					}
		return TRUE;
		}
	return FALSE;
}

int inline BlackCantWin (const SBoard &Board, int &eval )
{
	if (Board.BMat < 400 ) 
		{eval = Board.nWPawns; return TRUE;}
	if (Board.BMat == 2*PieceValues [ WKNIGHT ])
		{eval = (eval>>3); return TRUE; }

	if (Board.nBP == (Board.nWP+1) && Board.nBMinors == (Board.nWMinors+1) && (Board.MatVal-Board.nWPawns*100) > -400 ) 
		{
		if (Board.nBP > 2) eval = (eval>>1); 
			else 
				{if (Board.BMat == PieceValues[ WROOK ] + PieceValues[ WBISHOP ]) eval = (eval>>2);
				else eval = (eval>>3); 
				}
		return TRUE;}
	return FALSE;
}



const int Q_Tropism[16] = { 22, 26, 23, 21, 17, 14, 12, 9, 7, 5, 4, 2, 1, 0, 0, 0 }; 
#define QUEENATTACKER 24
#define OUTSIDE_PAWN_END 32
const int BISH_ROOK = PieceValues[ WROOK ]+PieceValues[ WBISHOP ];

int WTropism, BTropism;
int WPawnCover, BPawnCover;
// ==========================
//
//  BOARD EVALUATION
//
// (This isn't the full Eval Function, some parts are elsewhere and some is updated incrementally )
// 1 Pawn = 100
// ==========================
short EvaluateBoard (const SBoard &Board, int alpha, int beta)
     {
     int eval = 0, nSq;
	 int nWKingSq = Board.WPiece [ 15 ];
	 int nBKingSq = Board.BPiece [ 15 ];
		//return Board.MatVal; // Mat only?

	    // piece count  ( incrementally updated by domove )
        eval += Board.MatVal;

		// More Pieces/ Number of pieces left
		eval += MatEval (Board, Board.nWP, Board.nBP, Board.MatVal);

		// No Pawn Endgame or pieces, so low ply can mate with KRK and KQK
		if ((Board.nBPawns+Board.nWPawns) == 0)
			{
			return (short)MatingEval ( Board, nWKingSq, nBKingSq, eval );
			}

		// Check for position in pawn table
		PawnHashEntry SPawns;
		if ( !PawnHash_Lookup ( SPawns, Board.PawnHash ) ) EvalPawns ( Board, SPawns);

		// No Piece Endgame
		if ((Board.nWP + Board.nBP) == 0) return KingAndPawns ( Board, eval, nWKingSq, nBKingSq, SPawns );

		eval += SPawns.eval;

		// Bishop Trapped?
		BishopTrapped (Board, eval);

		// Piece Square Values
		eval += Board.TempValue; 

		int WMat = Board.WMat - Board.nWPawns*100;
		int BMat = Board.BMat - Board.nBPawns*100;

		// Early exit on the eval for fail high or low
		// I adjust to be safer because for fail lows I get a value,
		// then don't call eval from the quiescence if the capture isn't good enough
		if ( (WMat > 1000 || BMat > 1000) )
			{
			if ((eval+LAZY_MARGIN) < alpha ) return eval + 200;
			if ((eval-LAZY_MARGIN) > beta  ) return eval - 200;
			}

		nSq = SQRANK[ Board.WPiece [12]  ];
		int nRank2 = SQRANK[ Board.WPiece[13] ];
		// Queen and Rook on open 7th rank
		if ((nSq == 7 || nRank2 ==7)  && (SPawns.flags&512)==0)
			{
			if (SQRANK[ Board.WPiece [14] ] == 7 && SQRANK [ nBKingSq ] > 5) eval+=QR7_K8;
			else if ( BMat < 1470 && SQRANK [ nBKingSq ] == 8) eval+=ENDR7_K8;
			}
		// 1 Rook 7 King 8 in endgame.
		if ( nSq == nRank2) 
			{
			if (nSq == 7)
				{if (SQRANK [ nBKingSq ] == 8) eval+= ROOKS_7K8;}
			else if (nSq == 8) 
				{eval+= ROOKS_8;}						
			}
		nSq = SQRANK[ Board.BPiece [12]  ];
		nRank2 = SQRANK[ Board.BPiece[13] ];
		if ( (nSq == 2 || nRank2 ==2)  && (SPawns.flags&256)==0) 
			{
			if (SQRANK[ Board.BPiece [14] ] == 2 && SQRANK [ nWKingSq ] < 4) eval-=QR7_K8;
			else if (WMat < 1470 && SQRANK [ nWKingSq ] == 1) eval-=ENDR7_K8;
			}
		if ( nSq == nRank2 ) 
			{
			if (nSq == 2)
				{if (SQRANK [ nWKingSq ] == 1) eval-= ROOKS_7K8;}
			else if (nSq == 1) 
				{eval-= ROOKS_8;}	
			}

		// One piece endgame instead of rest of eval
		if (Board.nWP <= 1 && Board.nBP <=1)
			{
			return OnePieceEndgame ( Board, eval, nWKingSq, nBKingSq, SPawns, WMat, BMat);
			}

		if (WMat <= 1470 && BMat <= 1470) 
			{ 
			PassedPawnEval ( Board,  eval, nWKingSq, nBKingSq, SPawns);
			}
		eval += SPawns.PassedCon;

		// Maybe one side has only pawns but the other only has 1 minor piece which can't mate (Or is only up 1 minor)
		// (If both sides had no pawns mating eval was called and the function exited before this)
		if (Board.nWPawns == 0 && eval >=0)
			{
			if (WhiteCantWin (Board, eval)) return eval;
			}
		if (Board.nBPawns == 0 && eval <=0)
			{
			if (BlackCantWin (Board, eval)) return eval;
			}

		// Lazy eval exit 2 
		if ( (eval+LAZY_MARGIN2) < alpha ) return eval + 60;
		if ( (eval-LAZY_MARGIN2) > beta  ) return eval - 60;
	

		if (WMat > 1470 || BMat > 1470) // Blocked Passers in midgame
			{
			MidgamePassedPawnEval ( Board,  eval, nWKingSq, nBKingSq, SPawns);
			}

		// Endgame
	    if ( WMat <= 1460 && BMat <= 1460) 
				{
				BPawnCover = KING_PAWNCOVERFRONT;
				WPawnCover = KING_PAWNCOVERFRONT;
				// Pawn sq vals end
				eval += SPawns.MatEnd; 
				eval += WKingValueEnd [ nWKingSq ] - WKingValueEnd [ nBKingSq ];
				if ( (SPawns.flags&64) && (SPawns.flags&32) == 0 && Board.nWPawns > 1)  eval+= OUTSIDE_PAWN_END; 
				if ( (SPawns.flags&128) && (SPawns.flags&16) == 0 && Board.nBPawns > 1)  eval-= OUTSIDE_PAWN_END; 
				}
		else
			{
			WPawnCover = 1;
			BPawnCover = 1;
			// Pawn sq vals opening/mid
			int nKingSides = 0;
			if (SQFILE [ nWKingSq ] < 5) nKingSides|=1;
			if (SQFILE [ nBKingSq ] < 5) nKingSides|=2;
			if (WMat > 1840 || BMat > 1840) eval+= SPawns.Mat[nKingSides]; 
				else eval+= ((SPawns.MatEnd + SPawns.Mat[nKingSides]) >> 1);
			
			// King behind pawns in opening & midgame
			if (Board.WCastle >= 3)
				{
				WPawnCover-=KING_PAWNCOVERFRONT+1;
				if (Board.Sq [ nWKingSq - 10 ] == WPAWN) WPawnCover+=KING_PAWNCOVERFRONT;
				else if (Board.Sq [ nWKingSq - 20 ] == WPAWN) WPawnCover+=KING_PAWNCOVERFRONT2;
				if (Board.Sq [ nWKingSq - 11 ] == WPAWN) WPawnCover+=KING_PAWNCOVER;
				else if (Board.Sq [ nWKingSq - 21 ] == WPAWN || Board.Sq [ nWKingSq - 1 ] == WPAWN) WPawnCover+=KING_PAWNCOVER2;
				if (Board.Sq [ nWKingSq - 9 ] == WPAWN ) WPawnCover+=KING_PAWNCOVER;
				else if (Board.Sq [ nWKingSq - 19 ] == WPAWN || Board.Sq [ nWKingSq + 1 ] == WPAWN) WPawnCover+=KING_PAWNCOVER2;

				if (WPawnCover > MAX_PAWNCOVER) WPawnCover = MAX_PAWNCOVER;
				if (SQRANK[ nWKingSq ] > 2) {WPawnCover-=KING_PAWNCOVERFRONT2; }
				if (BMat > 2350  && SQRANK[ nWKingSq ] == 1) eval+= WPawnCover + (WPawnCover>>2);
				else if (BMat > 1850)  eval+= WPawnCover;
				else  eval+= (WPawnCover>>1);
				}

			// Now for Black
			if (Board.BCastle >= 3)
				{
				BPawnCover-=KING_PAWNCOVERFRONT+1;
				if (Board.Sq [ nBKingSq + 10 ] == BPAWN) BPawnCover+=KING_PAWNCOVERFRONT;
				else if (Board.Sq [ nBKingSq + 20 ] == BPAWN) BPawnCover+=KING_PAWNCOVERFRONT2;
				if (Board.Sq [ nBKingSq + 11 ] == BPAWN) BPawnCover+=KING_PAWNCOVER;
				else if (Board.Sq [ nBKingSq + 21 ] == BPAWN || Board.Sq [ nBKingSq + 1 ] == BPAWN) BPawnCover+=KING_PAWNCOVER2;
				if (Board.Sq [ nBKingSq + 9 ] == BPAWN ) BPawnCover+=KING_PAWNCOVER;
				else if (Board.Sq [ nBKingSq + 19 ] == BPAWN || Board.Sq [ nBKingSq - 1 ] == BPAWN) BPawnCover+=KING_PAWNCOVER2;

				if (BPawnCover > MAX_PAWNCOVER) BPawnCover = MAX_PAWNCOVER;
				if (SQRANK[ nBKingSq ] <  7) {BPawnCover-=KING_PAWNCOVERFRONT2; }
				if (WMat > 2350 && SQRANK[ nBKingSq ] == 8) eval-= BPawnCover + (BPawnCover>>2);
				else if (WMat > 1850)  eval-= BPawnCover;
				else  eval-= (BPawnCover>>1);
				}
			}

		WTropism = 0;
		BTropism = 0;

		// Rooks 
		nSq = Board.WPiece [12];
		if (nSq != CAPTURED) eval+= EvalRookWhite ( Board, nSq, nBKingSq, SPawns.OpenFileW, SPawns.OpenFileB,  SPawns.WeakFileB, WTropism );

		nSq = Board.WPiece [13];
		if (nSq != CAPTURED) eval+= EvalRookWhite ( Board, nSq, nBKingSq, SPawns.OpenFileW, SPawns.OpenFileB,  SPawns.WeakFileB, WTropism );

		nSq = Board.BPiece [12];
		if (nSq != CAPTURED) eval-= EvalRookBlack ( Board, nSq, nWKingSq, SPawns.OpenFileW, SPawns.OpenFileB, SPawns.WeakFileW, BTropism );

		nSq = Board.BPiece [13];
		if (nSq != CAPTURED) eval-= EvalRookBlack ( Board, nSq, nWKingSq, SPawns.OpenFileW, SPawns.OpenFileB,  SPawns.WeakFileW, BTropism);

		// Queen
		nSq = Board.WPiece[14];
		if (nSq != CAPTURED) 
			{
			if (BPawnCover <= 0 && WMat > 1440) eval+=QUEENATTACKER;
			WTropism+=Q_Tropism [ abs ( SQFILE [nBKingSq] - SQFILE [nSq] ) + abs ( SQRANK [nBKingSq] - SQRANK [nSq]) ];
			}

		nSq = Board.BPiece[14];
		if (nSq != CAPTURED) 
			{
			if (WPawnCover <= 0 && BMat > 1440) eval-=QUEENATTACKER;
			BTropism+=Q_Tropism [  abs ( SQFILE [nWKingSq] - SQFILE [nSq] ) + abs ( SQRANK [nWKingSq] - SQRANK [nSq]) ];
			}

 		// Knights
		nSq = Board.WPiece[8];
		if (nSq != CAPTURED) eval+= EvalKnightWhite ( Board, nSq, nBKingSq, WTropism );

		nSq = Board.WPiece[9];
		if (nSq != CAPTURED) eval+= EvalKnightWhite ( Board, nSq, nBKingSq, WTropism );

		nSq = Board.BPiece[8];
		if (nSq != CAPTURED) eval-= EvalKnightBlack ( Board, nSq, nWKingSq, BTropism );

		nSq = Board.BPiece[9];
		if (nSq != CAPTURED) eval-= EvalKnightBlack ( Board, nSq, nWKingSq, BTropism );


		// Bishops
		int nBish = 0;
		nSq = Board.WPiece[10];
		if (nSq != CAPTURED) {eval += EvalBishopWhite ( Board, nSq, nBKingSq, WTropism);
							  nBish++;
							 }
		nSq = Board.WPiece[11];
		if (nSq != CAPTURED) {eval += EvalBishopWhite ( Board, nSq, nBKingSq, WTropism);
							  nBish++;
							 }
		if (nBish == 2) 
			{if (WMat > 1460 || BMat > 1460) eval += BISHOP_PAIR; else eval += BISHOP_PAIRENDGAME;}

		nBish = 0;
		nSq = Board.BPiece[10];
		if (nSq != CAPTURED) {eval -= EvalBishopBlack ( Board, nSq, nWKingSq, BTropism);
							  nBish++;
							 }
		nSq = Board.BPiece[11];
		if (nSq != CAPTURED) {eval -= EvalBishopBlack ( Board, nSq, nWKingSq, BTropism);
							  nBish++;
							 }
		if (nBish == 2)
				{if (WMat > 1460 || BMat > 1460) eval -= BISHOP_PAIR; else eval -= BISHOP_PAIRENDGAME;}


		// Endgame 
		if (WMat <= 1050 && BMat <= 1050) 
			{
			// opposite bishops with rooks?
			if (WMat == BISH_ROOK && WMat == BMat)
				{
				nSq = Board.WPiece[10]; if (nSq == CAPTURED) nSq = Board.WPiece[11];
				int nbSq = Board.BPiece[10]; if (nbSq == CAPTURED) nbSq = Board.BPiece[11]; 
				if (SQCOLOR [nSq] != SQCOLOR [nbSq]) eval = (eval>>1) + (eval>>2);
				}
			}
		else
			{
			//
			// King Safety
			//
			if (WMat > 2000 && BPawnCover <= 0) eval += (WTropism+(WTropism>>1));
				else if (WMat > 1050) eval += WTropism;
			if (BMat > 2000 && WPawnCover <= 0) eval -= (BTropism+(BTropism>>1));
				else if (BMat > 1050) eval -= BTropism;
			if (BMat > 2600) eval += SquareVals [ (WKING<<7) + nWKingSq ];// Keep King back in opening
				else if (BMat > 1800) eval += (SquareVals [ (WKING<<7) + nWKingSq ] >>1);
			if (WMat > 2600) eval += SquareVals [ (BKING<<7) + nBKingSq ];
				else if (WMat > 1800) eval += (SquareVals [ (BKING<<7) + nBKingSq ]>>1);
			}

		// quantize evaluation, since it isn't that accurate anyway
		if (abs(eval)>4) eval&=0xFFFC;
		return (short)eval;
	}