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

                                 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 "Statistics.h"
#include "EvalHashtable.h"


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


EvalHashtable::EvalHashtable
	( Board &theBoard, 
	  unsigned sizeInMB ):
		board(theBoard)
{
	table = NULL;
	SetSize( sizeInMB );
}

EvalHashtable::~EvalHashtable()
{
	if( table != NULL )
		delete[] table;
}

void EvalHashtable::SetSize
	( unsigned long int newSize )
{
	if( table != NULL )
		delete[] table;

	if( newSize <= 0 )
		table = NULL;
	else
	{
		int i = 1;
		unsigned long int max_hash = 1;
		unsigned long int element_size = sizeof(EvalHash);

		//	compute the maximum hash element, based upon size desired
		while( max_hash * element_size <= newSize << 19 )
			max_hash = 1 << i++;

		//	compute the hash mask, for computing hash table indices
		hashMask = max_hash - 1;

		//	allocate hash table memory, and report on the allocation
		table = new EvalHash[max_hash];
		if( table == NULL )
		{
			ASSERT(false);
			//	TO DO: exit on failure
		}
	}
}

void EvalHashtable::Store
	( int evaluation )
{
	if( table == NULL )
		return;

	/*	store a position into the hash table  */
	EvalHash *pHash;

	/*	look for the correct place to put the hash  */
	pHash = table + (hashMask & board.GetSecondaryHash());

	/*	store our hash info  */
	pHash->hash = board.GetSecondaryHash();
	pHash->score = evaluation;
}

bool EvalHashtable::Lookup( int &evaluation )
{
	if( table == NULL )
		return false;

	/*	look-up our hash  */
	STAT_INCREMENT(ecLookupCount);
	EvalHash *pHash = table + (hashMask & board.GetSecondaryHash());
	
	if( pHash->GetHash() == board.GetSecondaryHash() )
	{
		STAT_INCREMENT(ecMatchCount);
		evaluation = pHash->GetEvaluation();
		return true;
	}
	return false;
}

void EvalHashtable::ClearAll()
{
	for( unsigned long int x = 0; x <= hashMask; x++ )
		table[x].hash = 0UL;
}
