
/***************************************************************************

                                 ChessV

                   COPYRIGHT (C) 2005 BY GREGORY STRONG

This file is part of ChessV.  ChessV 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 of the License, 
or (at your option) any later version.

ChessV 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; the file 'COPYING' contains the License text, but if for
some reason you need a copy, please write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

****************************************************************************/


#include "StdAfx.h"
#include "Board.h"
#include "Game.h"
#include "Piece.h"
#include "Personality.h"


// *** DEBUG MEMORY ALLOCATION *** //
#ifdef _DEBUG
#define new SAFE_NEW
#endif


int Board::Evaluate( int alpha, int beta )
{
	//	if we are looking for a mate score, then
	//	just return the material balance
	if( alpha > MATE - MAX_DEPTH )
		return GetMaterial();
	if( beta < -MATE + MAX_DEPTH )
		return GetMaterial();


	// *** lookup in EVALUATION CACHE *** //
	int eval = 0;
	if( pEvalHashtable != NULL )
	{
		if( pEvalHashtable->Lookup( eval ) )
		//	we found the entry in the cache
			if( currentPlayer == 1 )
				return -eval;
			else
				return eval;
	}


	// *** MATERIAL *** //
	eval = material[0] - material[1];


	// *** PAWN STRUCTURE EVALUATION *** //
	PawnHash *pPawnHash = NULL;
	int pawnStructureEval;
	if( pGame->UsePawnStructureEvaluation() )
		pawnStructureEval = pawnHashTable.Lookup( &pPawnHash );


	//	pass the evaluation to the Game class so each derived Game class
	//	can do any specific evaluation that they wish to.  this also allows
	//	them to specify the current phase of the game (opening, midgame, ...)
	Phase &phase = pGame->AdjustEvaluation( eval, pPawnHash );


	//	adjust the evaluation based on pawn structure
	if( pGame->UsePawnStructureEvaluation() )
		eval += phase.GetPawnDeficiencyFactor() * pawnStructureEval;

	//	adjust material values based on the per-capture adjustments 
	//	for the various piece types, and the bonuses from the piece-square-tables
	for( int x = 0; x < nPieces[0]; x++ )
	{
		if( !pieces[0][x]->IsCaptured() )
		{
			//	add army adjustment (if any)
			eval += pieces[0][x]->GetType().GetArmyAdjustment();

			//	add per-capture bonus if necessary
			if( GetNumberOfCapturedPieces() > pieces[0][x]->GetType().GetPerCaptureBonusThreshold() )
				eval += (GetNumberOfCapturedPieces() - pieces[0][x]->GetType().GetPerCaptureBonusThreshold()) *
					pieces[0][x]->GetType().GetPerCaptureValueBonus();

			//	add square value if necessary
			if( phase.GetSquareValuesFactor() > 0 )
			{
				if( pieces[0][x]->GetType().UsingSquareBonusTables() && !pieces[0][x]->IsPromoted() )
					//	add square bonuses from piece-square-tables
					eval += (pieces[0][x]->GetType().GetSquareBonusTable( phase.GetNumber() ))[pieces[0][x]->GetSquareNumber()];
				else
					//	add default square bonuses
					eval += GetSquareValue( pieces[0][x]->GetSquareNumber() );
			}

			//	add tropism value if necessary
			if( phase.GetTropismFactor() > 0 )
			{
				if( pieces[0][x]->GetType().GetTropismType() == DistanceTropism )
					eval += pieces[0][x]->GetType().GetTropism( 
						distance[pieces[0][x]->GetSquareNumber()][kings[1]->GetSquareNumber()] ) *
						phase.GetTropismFactor();
				else if( pieces[0][x]->GetType().GetTropismType() == HVDistanceTropism )
					eval += pieces[0][x]->GetType().GetTropism( 
						hv_distance[pieces[0][x]->GetSquareNumber()][kings[1]->GetSquareNumber()] ) *
						phase.GetTropismFactor();
			}
		}
	}
	for( int y = 0; y < nPieces[1]; y++ )
	{
		if( !pieces[1][y]->IsCaptured() )
		{
			//	add army adjustment (if any)
			eval -= pieces[1][y]->GetType().GetArmyAdjustment();

			//	add per-capture bonus if necessary
			if( GetNumberOfCapturedPieces() > pieces[1][y]->GetType().GetPerCaptureBonusThreshold() )
				eval -= (GetNumberOfCapturedPieces() - pieces[1][y]->GetType().GetPerCaptureBonusThreshold()) *
					pieces[1][y]->GetType().GetPerCaptureValueBonus();

			//	add square value if necessary
			if( phase.GetSquareValuesFactor() > 0 )
			{
				if( pieces[1][y]->GetType().UsingSquareBonusTables() && !pieces[1][y]->IsPromoted() )
					//	add square bonuses from piece-square-tables
					eval -= (pieces[1][y]->GetType().GetSquareBonusTable( phase.GetNumber() ))[mirrorSquare[1][pieces[1][y]->GetSquareNumber()]];
				else
					//	add default square bonuses
					eval -= GetSquareValue( pieces[1][y]->GetSquareNumber() );
			}

			//	add tropism value if necessary
			if( phase.GetTropismFactor() > 0 )
			{
				if( !pieces[1][y]->IsCaptured() )
				{
					if( pieces[1][y]->GetType().GetTropismType() == DistanceTropism )
						eval -= pieces[1][y]->GetType().GetTropism( 
							distance[pieces[1][y]->GetSquareNumber()][kings[0]->GetSquareNumber()] ) *
							phase.GetTropismFactor();
					else if( pieces[1][y]->GetType().GetTropismType() == HVDistanceTropism )
						eval -= pieces[1][y]->GetType().GetTropism( 
							hv_distance[pieces[1][y]->GetSquareNumber()][kings[0]->GetSquareNumber()] ) *
							phase.GetTropismFactor();
				}
			}
		}
	}

	// *** KING SAFETY *** //

	if( phase.GetKingSafetyFactor() > 0 )
	{
		//	evaluate king safety for player 0
		int p0safety = 0;
		for( int i = 0; i < 3; i++ )
		{
			int square = movementMatrix[i][kings[0]->GetSquareNumber()];
			if( square >= 0 )
			{
				if( squareContents[square] == NULL )
					//	penalise this open space around the king
					p0safety -= 3;
				else if( squareContents[square]->GetPlayerNumber() == 0 )
					//	bonus for a friendly piece in this spot
					p0safety += 5;
				else
					//	big penalty for enemy piece here
					p0safety -= 4;
			}
		}
		//	evaluate king safety for player 1
		int p1safety = 0;
		for( int i = 3; i < 6; i++ )
		{
			int square = movementMatrix[i][kings[1]->GetSquareNumber()];
			if( square >= 0 )
			{
				if( squareContents[square] == NULL )
					//	penalise this open space around the king
					p1safety -= 3;
				else if( squareContents[square]->GetPlayerNumber() == 1 )
					//	bonus for a friendly piece in this spot
					p1safety += 5;
				else
					//	big penalty for enemy piece here
					p1safety -= 4;
			}
		}
		//	add in king safety values
		eval += phase.GetKingSafetyFactor() * p0safety;
		eval -= phase.GetKingSafetyFactor() * p1safety;
	}

	if( personality == PERSONALITY_D )
	{
		//	randomization
		eval += evalRandomization[GetSecondaryHash() & 0x0000000F];
	}

	// *** EVALUATION CACHE *** //
	if( pEvalHashtable != NULL )
	{
		//	store this evaluation for later reference
		pEvalHashtable->Store( eval );
	}

	if( currentPlayer == 1 )
		eval = -eval;

	return eval;
}
