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

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


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

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

void AlternateMoveHashtable::SetSize
	( unsigned sizeInMB )
{
	unsigned long int element_size = sizeof(AlternateMoveHash);
	tableSize = 1;
	int i = 1;

	if( table != NULL )
		delete[] table;

	if( sizeInMB == 0 )
		table = NULL;
	else
	{
		/*	compute the maximum hash element, based upon size desired  */
		while( tableSize * element_size <= sizeInMB << 19 )
			tableSize = 1 << i++;

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

		/*	allocate our hash table's memory, and report on the allocation  */
		table = new AlternateMoveHash[tableSize];
		if( table == NULL )
		{
			ASSERT(false);
			//	TO DO: exit on failure
		}
	}
}

void AlternateMoveHashtable::Store
	( Movement move )
{
	if( table == NULL )
		return;

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

	//	look for the correct place to put the hash
	pHash = &(table[hashMask & board.GetPrimaryHash()]);

	//	store our hash info
	pHash->primaryHash = board.GetPrimaryHash();
	pHash->secondaryHash = board.GetSecondaryHash();
	pHash->move = move;
}

bool AlternateMoveHashtable::Lookup
	( Movement &move )
{
	if( table != NULL )
	{
		//	look-up our hash
		AlternateMoveHash *pHash = &(table[hashMask & board.GetPrimaryHash()]);

		if( pHash->GetPrimaryHash() == board.GetPrimaryHash() &&
			pHash->GetSecondaryHash() == board.GetSecondaryHash() )
		{
			move = pHash->GetMove();
			return true;
		}
	}
	move = Movement();
	return false;
}

void AlternateMoveHashtable::ClearAll()
{
	for( unsigned long l = 0; l < tableSize; l++ )
		table[l].move = Movement();
}
