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

                                 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__BITBOARD64_H
#define FILE__BITBOARD64_H


#include <intrin.h>
#include "Vector.h"

class BitBoard64;


typedef Vector<int> IntVector;
typedef Vector<BitBoard64> BitBoard64Vector;

extern const int index64[64];

class BitBoard64
{
  protected:
	bit_data data;	//	must be first data-memeber

	static const uint64 debruijn64 = 0x07EDD5E59A4E28C2ULL;

  public:
	// *** CONSTRUCTION *** //
	BitBoard64( bit_data bits = 0ULL )
	{	data = bits;   }

	BitBoard64( BitBoard64 const &other )
	{	data = other.data;   }

	static void InitializeData( int nRanks, int nFiles );


	// *** ATTRIBUTES *** //
	bit_data GetBits() const
	{	return data;   }

	int GetBitCount() const
	{	
		#ifdef HAS_POPCOUNT_INSTRUCTION
			return __popcnt64( data );
		#else
			uint64 x = data;
			const uint64 k1 = 0x5555555555555555UL;
			const uint64 k2 = 0x3333333333333333UL;
			const uint64 k4 = 0x0f0f0f0f0f0f0f0fUL;
			const uint64 kf = 0x0101010101010101UL;
			x =  x       - ((x >> 1)  & k1); //put count of each 2 bits into those 2 bits
			x = (x & k2) + ((x >> 2)  & k2); //put count of each 4 bits into those 4 bits
			x = (x       +  (x >> 4)) & k4 ; //put count of each 8 bits into those 8 bits
			x = (x * kf) >> 56; //returns 8 most significant bits of x + (x<<8) + (x<<16) + (x<<24) + ...
			return (int) x;
		#endif
	}

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

	static BitBoard64 GetTrueBitBoard()
	{	return BitBoard64( 0xFFFFFFFFFFFFFFFFULL );   }

	static BitBoard64 GetPositionBitBoard( int nBit )
	{	return BitBoard64( 1ULL << nBit );   }


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

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

	BitBoard64 operator &( BitBoard64 const &other ) const
	{	return BitBoard64( GetBits() & other.GetBits() );   }

	BitBoard64 operator &( int intBitMask ) const
	{	return BitBoard64( GetBits() & intBitMask );   }

	BitBoard64 operator |( BitBoard64 const &other ) const
	{	return BitBoard64( GetBits() | other.GetBits() );   }

	BitBoard64 operator ^( BitBoard64 const &other ) const
	{	return BitBoard64( GetBits() ^ other.GetBits() );   }

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

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

	word32 operator >>( int shift ) const
	{	return (word32) (GetBits() >> shift);   }

	word32 operator >>( unsigned shift ) const
	{	return (word32) (GetBits() >> shift);   }

	BitBoard64 &operator=( BitBoard64 const &other )
	{	data = other.GetBits();  return *this;   }

	BitBoard64 &operator=( bit_data new_data )
	{	data = new_data;  return *this;   }

	BitBoard64 &operator=( int new_data )
	{	data = (bit_data) new_data;  return *this;   }

	BitBoard64 operator &=( BitBoard64 const &other ) 
	{	data &= other.GetBits();  return *this;   }

	BitBoard64 operator |=( BitBoard64 const &other ) 
	{	data |= other.GetBits();  return *this;   }

	BitBoard64 operator ^=( BitBoard64 const &other ) 
	{	data ^= other.GetBits();  return *this;   }

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

	bool operator ==( bit_data value )
	{	return data == value;   }

	bool operator ==( int value )
	{	return data == (bit_data) value;   }

	operator bit_data() const
	{	return data;   }

	bool operator[]( int nBit ) const
	{	return (data & (1ULL << nBit)) != 0ULL;   }

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

	void SetBit( int nBit )
	{	data = data | (1ULL << nBit);   }

	void ClearBit( int nBit )
	{	data = data & (0xFFFFFFFFFFFFFFFFULL ^ (1ULL << nBit));   }

	void ToggleBit( int nBit )
	{	data = data ^ (1ULL << nBit);   }

	int ExtractLSB()
	{
		#ifdef __X64
			unsigned long rtn;
			_BitScanForward64( &rtn, data );
			data &= data - 1;
			return rtn;
		#else
			int index = index64[((data & -data) * debruijn64) >> 58];
			data &= data - 1;
			return index;
		#endif
	}

	int GetLSB()
	{
		#ifdef __X64
			unsigned long rtn;
			_BitScanForward64( &rtn, data );
			return rtn;
		#else
			return index64[((data & -data) * debruijn64) >> 58];
		#endif
	}

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


#endif
