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

                                 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

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


#ifndef FILE__BITBOARD128_H
#define FILE__BITBOARD128_H


#include "Vector.h"
#include "BitBoard64.h"


class BitBoard128;


typedef Vector<int> IntVector;
typedef Vector<BitBoard128> BitBoard128Vector;


class BitBoard128
{
  protected:
	bit_data data;		//	low-order 64 bits
	bit_data hiData;	//	hi-order 64 bits

	//	helper structures
	static IntVector bitCount;
	static IntVector firstBit;


  public:
	// *** CONSTRUCTION *** //
	BitBoard128( bit_data hi_order_bits = 0ULL, bit_data bits = 0ULL )
	{	hiData = hi_order_bits;  data = bits;   }

	BitBoard128( BitBoard128 const &other )
	{	hiData = other.hiData;  data = other.data;   }

	static void InitializeData( int nRanks, int nFiles );


	// *** ATTRIBUTES *** //
	bit_data GetHiOrderBits() const
	{	return hiData;   }

	bit_data GetLowOrderBits() const
	{	return data;   }

	int GetBitCount() const
	{
		return //__popcnt64( data ) + __popcnt64( hiData );
			   bitCount.GetElement( (unsigned) (hiData >> 48) ) + 
	           bitCount.GetElement( (unsigned) (hiData >> 32) & 0xFFFFUL ) + 
	           bitCount.GetElement( (unsigned) (hiData >> 16) & 0xFFFFUL ) + 
		       bitCount.GetElement( (unsigned)  hiData & 0xFFFFUL ) + 
		       bitCount.GetElement( (unsigned) (data >> 48) ) + 
		       bitCount.GetElement( (unsigned) (data >> 32) & 0xFFFFUL ) + 
		       bitCount.GetElement( (unsigned) (data >> 16) & 0xFFFFUL ) + 
		       bitCount.GetElement( (unsigned)  data & 0xFFFFUL ); 
	}

	static BitBoard128 GetNullBitBoard()
	{	return BitBoard128();   }

	static BitBoard128 GetTrueBitBoard()
	{	return BitBoard128( 0xFFFFFFFFFFFFFFFFUL, 0xFFFFFFFFFFFFFFFFULL );   }

	static BitBoard128 GetPositionBitBoard( int nBit )
	{
		if( nBit < 64 )
			return BitBoard128( 0ULL, 1ULL << nBit );
		return BitBoard128( 1ULL << (nBit - 64), 0ULL );
	}


	// *** OPERATIONS *** //
	void Clear()
	{	hiData = 0ULL;  data = 0ULL;   }

	BitBoard128 operator ~()
	{	return BitBoard128( ~hiData, ~data );   }

	BitBoard128 operator &( BitBoard128 const &other ) const
	{	return BitBoard128( GetHiOrderBits() & other.GetHiOrderBits(), GetLowOrderBits() & other.GetLowOrderBits() );   }

	BitBoard128 operator &( int intBitMask ) const
	{	return BitBoard128( GetHiOrderBits(), GetLowOrderBits() & intBitMask );   }

	BitBoard128 operator |( BitBoard128 const &other ) const
	{	return BitBoard128( GetHiOrderBits() | other.GetHiOrderBits(), GetLowOrderBits() | other.GetLowOrderBits() );   }

	BitBoard128 operator ^( BitBoard128 const &other ) const
	{	return BitBoard128( GetHiOrderBits() ^ other.GetHiOrderBits(), GetLowOrderBits() ^ other.GetLowOrderBits() );   }

	bool operator &&( BitBoard128 const &other ) const
	{	return( (bool) (*this) && (bool) other );   }

	bool operator ||( BitBoard128 const &other ) const
	{	return( (bool) (*this) || (bool) other );   }

	word32 operator >>( int shift ) const
	{
		if( shift < 48 )
			return (word32) (GetLowOrderBits() >> shift);
		if( shift >= 64 )
			return (word32) (GetHiOrderBits() >> (shift - 64));
		return (word32) (GetLowOrderBits() >> shift) | (word32) (GetHiOrderBits() << (64 - shift));
	}

	word32 operator >>( unsigned shift ) const
	{
		if( shift < 48 )
			return (word32) (GetLowOrderBits() >> shift);
		if( shift >= 64 )
			return (word32) (GetHiOrderBits() >> (shift - 64));
		return (word32) (GetLowOrderBits() >> shift) | (word32) (GetHiOrderBits() << (64 - shift));
	}

	BitBoard128 &operator=( BitBoard128 const &other )
	{	data = other.GetLowOrderBits();  hiData = other.GetHiOrderBits();   return *this;   }

	BitBoard128 operator &=( BitBoard128 const &other ) 
	{	data &= other.GetLowOrderBits();  hiData &= other.GetHiOrderBits();  return *this;   }

	BitBoard128 operator |=( BitBoard128 const &other ) 
	{	data |= other.GetLowOrderBits();  hiData |= other.GetHiOrderBits();  return *this;   }

	BitBoard128 operator ^=( BitBoard128 const &other ) 
	{	data ^= other.GetLowOrderBits();  hiData ^= other.GetHiOrderBits();  return *this;   }

	operator bool() const 
	{	return data != 0ULL || hiData != 0ULL;   }

	operator BitBoard64() const
	{
		return BitBoard64( data );
	}

	bool GetBit( int nBit ) const
	{
		if( nBit < 64 )
			return (data & (1ULL << nBit)) != 0ULL;
		return (hiData & (1ULL << (nBit - 64))) != 0ULL;
	}

	void SetBit( int nBit )
	{
		if( nBit < 64 )
			data = data | (1ULL << nBit);
		else
			hiData = hiData | (1ULL << (nBit - 64));
	}

	void ClearBit( int nBit )
	{
		if( nBit < 64 )
			data = data & (0xFFFFFFFFFFFFFFFFULL ^ (1ULL << nBit));
		else
			hiData = hiData & (0xFFFFFFFFFFFFFFFFULL ^ (1ULL << (nBit - 64)));
	}

	void ToggleBit( int nBit )
	{
		if( nBit < 64 )
			data = data ^ (1ULL << nBit);
		else
			hiData = hiData ^ (1ULL << (nBit - 64));
	}

	int GetFirstBit()
	{
		if( hiData >> 48 )
			return firstBit[(int) (hiData >> 48)] + 112;
		if( hiData >> 32 )
			return firstBit[(int) (hiData >> 32)] + 96;
		if( hiData >> 16 )
			return firstBit[(int) (hiData >> 16)] + 80;
		if( hiData )
			return firstBit[(int) hiData] + 64;
		if( data >> 48 )
			return firstBit[(int) (data >> 48)] + 48;
		if( data >> 32 )
			return firstBit[(int) (data >> 32)] + 32;
		if( data >> 16 )
			return firstBit[(int) (data >> 16)] + 16;
		return firstBit[(int) data];
	}

	void PrintToFile
		( FILE *file, 
		  int nRanks, 
		  int nFiles );
};


#endif
