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

                                 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__PIECE_TYPE_H
#define FILE__PIECE_TYPE_H


#include "PieceSquareInfo.h"
#include "MovementCapability.h"
#include "HashMap.h"
#include "Direction.h"
#include "Promotion.h"
#include "BitBoard64.h"
#include "BitBoard96.h"
#include "BitBoard128.h"
#include "Games\ChessGames\Chess_Data.h"


//	this is a helper enum which lists possible optimizations which can
//	be performed for move generation of this particular type.  this
//	defaults to NoOptimization, but the programmer can specify:

//	SimpleSingleStep IF AND ONLY IF ALL OF THE FOLLOWING:
//	1. all moves are normal moves-or-captures; no differences between
//	   movement capability and capture capability, and all captures are
//	   capture by replacement.
//	2. the piece may make no more than 1 step in any direction
//	3. the piece cannot be promoted
//	if a PieceType fits these conditions, much speed can be obtained
//	by specifying SimpleSingleStep.  See OrthodoxKnight below.

//	SimpleSlider IF AND ONLY IF ALL OF THE FOLLOWING:
//	1. all moves are normal moves-or-captures; no differences between
//	   movement capability and capture capability, and all captures are 
//	   capture by replacement.
//	2. the piece cannot be promoted
//	3. the piece can slide until it hits the edge of the board or
//	   another piece; it cannot have a range-limit on ANY of its moves.
enum MovementOptimization
{
	NoOptimization = 0,
	SimpleSingleStep = 1,
	SimpleSlider = 2
};


/************************************************************************\ 
**************************************************************************
**                                                                      **
**                            PieceType                                 **
**                                                                      **
**************************************************************************
\************************************************************************/

//	the PieceType class stores information about a type of piece, most
//	notably its material value, and its movement capabilities.
class PieceType
{
  private: 
	  virtual void Initialize() { }


  protected:
	// ********************************* //
	// ***                           *** //
	// ***        Data Members       *** //
	// ***                           *** //
	// ********************************* //


	// *** NAME of PIECE TYPE *** //

	//	current name
	char *extendedName;						//	extended name (e.g., "FIDE Rook")
	char *fullName;							//	full (regular) name (e.g., "Rook")
	char *abbrev;							//	notational abbreviation (e.g., "R")

	//	default name
	char *defaultExtendedName;				//	default extended name (e.g., "FIDE Rook")
	char *defaultFullName;					//	default full (regular) name (e.g., "Rook")
	char *defaultAbbrev;					//	default notational abbreviation (e.g., "R")

	int uniqueTypeID;						//	unique serialized ID for this type


	// *** MOVEMENT CAPABILITIES *** //
	int nMoveCapabilities;					//	number of movement capabilities
	MovementCapability *moveCapabilities;	//	array of all movement capabilities
											//	that a piece of this type has

	// *** OPTIMIZATION of MOVE GENERATION *** //
	MovementOptimization optimization;		//	optimization for non-bitboard move generation

	// *** PROMOTION *** //
	Promotion promotion;					//	promotion capabilities (if any)

	// *** MATERIAL VALUE *** //
	int baseValue;							//	midgame value of this piece in millipawns

	int perCaptureValueBonus;				//	boosts eval as the board clears out (if not 
											//	set to zero, which it is by default)

	int perCaptureBonusThreshold;			//	minimum captures before value starts changing

	int armyAdjustment;						//	normally zero, but used to adjust pieces up or 
											//	down in games with unequal armies; sometimes a piece 
											//	becomes more or less powerful because of the 
											//	particular match-up of armies

	// *** PIECE PROPERTIES *** //
	bool isRoyal;							//	is this piece Royal (like the King in Chess)

	bool isPawn;							//	is this piece a chess-pawn (move forward, 
											//	capture diagonally).  Shogi pawns don't count.

	int nRanks, nFiles;						//	size of board this piece requires

	// *** MOBILITY EVALUATION *** //
	MobilityType mobilityType;				//	type of calculation for the mobility of this piece
	int mobilityOffset;						//	adjustment to number of squares attacked
	int mobilityFactor;						//	evaluation value for each square attacked

	// *** KING TROPISM EVALUATION *** //
	TropismType tropismType;
	int tropismFactor[16];


	Board *pBoard;							//	pointer to the Board object

	HashMap hashMap[2];						//  \_ HashMaps store the Zobrist keys used
	HashMap secondaryHashMap[2];			//  /  for identifying specific board positions

	HBITMAP hBitmap[2];						//	bitmaps of this piece for each player
	char *bitmapFileNames[MAX_PIECE_SETS][2];

	bool hasBeenInitialized;

	bool useSquareBonuses;					//	use a piece-square-value table? (overrides default PST)
	int *squareBonuses[MAX_PHASES];			//	if so, these are the bonuses

	int attackRange[2][MAX_DIRECTIONS];		//	max striking range in each direction
	int minAttackRange[2][MAX_DIRECTIONS];	//	min striking range in each direction (for lame movers)

	PieceSquareInfo *squareValues;			//	info about this piece's power on each square
	float fTotalSquaresAttacked;			//	statistical info (currently unused)
	float fTotalCenterSquaresAttacked;		//	statistical info (currently unused)
	int nTotalSafeChecks;					//	statistical info (currently unused)
	int nTotalDirectionsAttacked;			//	statistical info (currently unused)
	int nSquaresSeen;						//	statistical info (currently unused)
	float aveDirectionsAttacked;			//	statistical info (currently unused)
	float aveSquaresAttacked;				//	statistical info (currently unused)
	float aveSafeChecks;					//	statistical info (currently unused)
	bool statsInitialized;


	// *** linked list of piece types *** //
	static PieceType *pFirstType;
	PieceType *pNextType;


	//	helper functions
	void FindSquare( Board &board, Player &player, int rank, int file, int &nSquaresSeen );

	word32 GetPrimaryHash( int playerNumber, int squareNumber )
	{	return( hashMap[playerNumber].GetHash( squareNumber ) );   }

	word32 GetSecondaryHash( int playerNumber, int squareNumber )
	{	return( secondaryHashMap[playerNumber].GetHash( squareNumber ) );  }

	void GenerateMoves
		( MovementList &moves,
		  Board &board,
		  Piece &piece,
		  int squareNumber );

	void GenerateAreaMoves
		( MovementList &moves,
		  Board &board,
		  Piece &piece,
		  int squareNumber,
		  int maxSteps );

	void GenerateCaptures
		( MovementList &moves,
		  Board &board,
		  Piece &piece,
		  int squareNumber );

  public:
	// *** INITIALIZATION *** //
	PieceType( const char *extended_name, const char *name, const char *abbreviation, int ranks, int files );

	virtual void Initialize( int personality );

	virtual void SetBoard( Board *pBoard );

	virtual void SetPieceDefaults( Piece *piece );


	// *** DESTRUCTION *** //
	virtual ~PieceType();


	// *** ATTRIBUTES *** //
	Board *GetBoard() const
	{	return( pBoard );   }

	char *GetNotation() const
	{	return( abbrev );   }

	char *GetFullName() const
	{	return( fullName );   }

	char *GetExtendedName() const
	{	return( extendedName );   }

	int GetTypeID() const
	{	return( uniqueTypeID );   }

	bool IsRoyal() const
	{	return isRoyal;   }

	bool IsPawn() const
	{	return isPawn;   }

	int GetNumberOfRanks() const
	{	return nRanks;   }

	int GetNumberOfFiles() const
	{	return nFiles;   }

	MobilityType GetMobilityType()
	{	return mobilityType;   }

	MovementOptimization GetMovementOptimization() const 
	{	return optimization;   }

	TropismType GetTropismType()
	{	return tropismType;   }

	int GetTropism( int distance )
	{	return tropismFactor[distance];   }

	int GetBaseValue() const
	{	return baseValue;  }

	int GetArmyAdjustment() const 
	{	return armyAdjustment;   }

	void SetBaseValue( int value )
	{	baseValue = value;  }

	void SetPerCaptureValueBonus( int value )
	{	perCaptureValueBonus = value;   }

	void SetPerCaptureBonusThreshold( int value )
	{	perCaptureBonusThreshold = value;   }

	void SetArmyAdjustment( int value )
	{	armyAdjustment = value;   }

	void SetExtendedName( char *exName );

	void SetFullName( char *name );

	void SetNotation( char *notation );

	void SetTypeID( int typeID )
	{	uniqueTypeID = typeID;   }

	void SetMovementOptimization( MovementOptimization newOptimization ) 
	{	optimization = newOptimization;   }

	void SetBitmapFileName( int pieceSet, int playerNumber, char *filename )
	{	bitmapFileNames[pieceSet][playerNumber] = filename;   }

	bool UsingSquareBonusTables()
	{	return useSquareBonuses;   }

	int *GetSquareBonusTable( int phaseNumber )
	{	return squareBonuses[phaseNumber];   }

	HBITMAP GetBitmap( int playerNumber ) const
	{	return hBitmap[playerNumber];  }

	int GetMoveCapabilityCount() const
	{	return nMoveCapabilities;  }

	MovementCapability &GetMoveCapability( int index ) const
	{	return moveCapabilities[index];  }

	int GetAttackRange( int playerNumber, int directionNumber )
	{	return( attackRange[playerNumber][directionNumber] );  }

	int GetMinAttackRange( int playerNumber, int directionNumber )
	{	return( minAttackRange[playerNumber][directionNumber] );  }

	Promotion &GetPromotion()
	{	return promotion;   }

	void SetPromotionType( PromotionCapability capability )
	{	promotion.SetPromotionCapability( capability );   }

	void SetTypeToPromoteTo( PieceType &promotionType )
	{	promotion.SetTypeToPromoteTo( promotionType );   }

	int GetPerCaptureValueBonus()
	{	return perCaptureValueBonus;   }

	int GetPerCaptureBonusThreshold()
	{	return perCaptureBonusThreshold;   }

	void SetRoyal( bool royal )
	{	isRoyal = royal;   }

	void SetPawn( bool pawn )
	{	isPawn = pawn;   }

	bool DoesSupportPieceSet( int nPieceSet )
	{	return bitmapFileNames[nPieceSet][0] != NULL && 
		       bitmapFileNames[nPieceSet][1] != NULL;   }


	// *** OPERATIONS *** //
	bool operator==( PieceType &other );

	bool operator!=( PieceType &other )
	{	return this != &other;   }

	MovementCapability &AddMovementCapability( MovementCapability const &move )
	{	return( moveCapabilities[nMoveCapabilities++] = move );  }

	void ClearMovementCapabilities()
	{	nMoveCapabilities = 0;   }

	void LoadBitmap
		( char *whiteImage,
		  char *blackImage )
	{
		if( hBitmap[0] != NULL )
			::DeleteObject( hBitmap[0] );
		if( hBitmap[1] != NULL )
			::DeleteObject( hBitmap[1] );
		hBitmap[0] = (HBITMAP) ::LoadImage( NULL, whiteImage, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
		hBitmap[1] = (HBITMAP) ::LoadImage( NULL, blackImage, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
	}

	void LoadPieceSet( int nPieceSet )
	{
		LoadBitmap( bitmapFileNames[nPieceSet][0], bitmapFileNames[nPieceSet][1] );
	}

	void ReduceBoardSize( int newRanks, int newFiles );

	int PlaceOnBoard( Board &board, Player &player, int rank, int file );

	bool DoesAttackSquare
		( Player &player,
		  int myRank,
		  int myFile,
		  int targetRank,
		  int targetFile );

	bool DoesAttackSquare
		( Player &player,
		  int mySquare,
		  int targetSquare );

	int CountMoves
		( const Player &player,
		  int myRank,
		  int myFile,
		  int &pseudoLegal );

	void SetMobility( MobilityType type, int offset, int factor )
	{	mobilityType = type; mobilityOffset = offset; mobilityFactor = factor;   }

	void SetTropismType( TropismType type )
	{	tropismType = type;   }

	void SetTropism( int distance, int factor )
	{	tropismFactor[distance] = factor;   }

	void SetSquareBonuses
		( int phaseNumber, int *bonuses );

	int CalculateMobility( int playerNumber, int squareNumber );

	int CalculateMobilityEvaluation( int numberOfMoves )
	{	return (numberOfMoves + mobilityOffset) * mobilityFactor;   }

	void Output( FILE *f );


	// *** OVERRIDES *** //
	virtual void PostPaintMoveDiagram( LPPAINTSTRUCT ps, HDC hdc );


	// *** LIST of PIECE TYPES *** //
	static PieceType *GetFirstType()
	{	return pFirstType;   }

	PieceType *GetNextType()
	{	return pNextType;  }


	// *** USER VARIABLES *** //

	//	these are for the use of Game-derived classes to use
	//	for whatever purpose that their game might require
	int gameInt1;
	int gameInt2;


	//	friends
	friend class Piece;
	friend LRESULT CALLBACK PiecePropertiesWndProc
		( HWND hWnd, 
		UINT message, 
		WPARAM wParam, 
		LPARAM lParam );
};

class PieceType64:
	public PieceType
{
  public:
	//	construction
	PieceType64( const char *extended_name, const char *name, const char *abbreviation, int ranks, int files ):
		PieceType( extended_name, name, abbreviation, ranks, files )  {  }

	virtual void Initialize( int personality )
	{
		if( !hasBeenInitialized )
		{
			bb64_pieces[0].Clear();
			bb64_pieces[1].Clear();
			int nSquares = nRanks * nFiles;
			bb64_attack[0].SetSize( nSquares );
			bb64_attack[1].SetSize( nSquares );
			bb64_direct_move[0].SetSize( nSquares );
			bb64_direct_move[1].SetSize( nSquares );
			bb64_direct_move_no_capture[0].SetSize( nSquares );
			bb64_direct_move_no_capture[1].SetSize( nSquares );
			bb64_direct_move_capture_only[0].SetSize( nSquares );
			bb64_direct_move_capture_only[1].SetSize( nSquares );
			for( int player = 0; player < 2; player++ )
			{
				for( int sq = 0; sq < nSquares; sq++ )
				{
					bb64_attack[player][sq].Clear();
					bb64_direct_move[player][sq].Clear();
					bb64_direct_move_no_capture[player][sq].Clear();
					bb64_direct_move_capture_only[player][sq].Clear();
				}
			}
			PieceType::Initialize( personality );
		}
	}

	virtual void BB64_Initialize();


	//	attributes
	BitBoard64 GetPieces( int nPlayer ) const
	{	return bb64_pieces[nPlayer];   }

	BitBoard64 GetAttackMatrix( int nPlayer, int nSquare )
	{	return bb64_attack[nPlayer][nSquare];   }


	//	operations
	void SetPiece( int nPlayer, int nSquare )
	{	bb64_pieces[nPlayer].SetBit( nSquare );  }

	void ClearPiece( int nPlayer, int nSquare )
	{	bb64_pieces[nPlayer].ClearBit( nSquare );  }


	//	move generation
	void BB64_GenerateDirectMoves( MovementList &stack, int nPlayer, int nSquare );
	void BB64_GenerateDirectCaptures( MovementList &stack, int nPlayer, int nSquare );
	void BB64_GenerateDirectMovesNoCapture( MovementList &stack, int nPlayer, int nSquare );
	void BB64_GenerateDirectMovesCaptureOnly( MovementList &stack, int nPlayer, int nSquare );

	//	public look-up tables
//	static BitBoard64Vector bb64_rook_attack;
//	static BitBoard64Vector bb64_bishop_attack;
//	static BitBoard64Vector bb64_queen_attack;
//	static BitBoard64Vector bb64_pawn_attack[2];
//	static BitBoard64Vector bb64_king_attack;
//	static BitBoard64Vector bb64_knight_attack;

	// ********************************* //
	// ***                           *** //
	// ***        Data Members       *** //
	// ***                           *** //
	// ********************************* //

	BitBoard64 bb64_pieces[2];
	BitBoard64Vector bb64_attack[2];
	BitBoard64Vector bb64_direct_move[2];
	BitBoard64Vector bb64_direct_move_no_capture[2];
	BitBoard64Vector bb64_direct_move_capture_only[2];
};

class NullPieceType64:
	public PieceType64
{
  private:
	NullPieceType64():
		PieceType64("Null 64", "Null", " ", 0, 0)
	{
	}

  public:
	static NullPieceType64 nullPieceType64;
};

class PieceType96:
	public PieceType
{
  public:
	//	construction
	PieceType96( const char *extended_name, const char *name, const char *abbreviation, int ranks, int files ):
		PieceType( extended_name, name, abbreviation, ranks, files )  {  }

	virtual void Initialize( int personality )
	{
		if( !hasBeenInitialized )
		{
			bb96_pieces[0].Clear();
			bb96_pieces[1].Clear();
			int nSquares = nRanks * nFiles;
			bb96_attack[0].SetSize( nSquares );
			bb96_attack[1].SetSize( nSquares );
			bb96_direct_move[0].SetSize( nSquares );
			bb96_direct_move[1].SetSize( nSquares );
			bb96_direct_move_no_capture[0].SetSize( nSquares );
			bb96_direct_move_no_capture[1].SetSize( nSquares );
			bb96_direct_move_capture_only[0].SetSize( nSquares );
			bb96_direct_move_capture_only[1].SetSize( nSquares );
			for( int player = 0; player < 2; player++ )
			{
				for( int sq = 0; sq < nSquares; sq++ )
				{
					bb96_attack[player][sq].Clear();
					bb96_direct_move[player][sq].Clear();
					bb96_direct_move_no_capture[player][sq].Clear();
					bb96_direct_move_capture_only[player][sq].Clear();
				}
			}
			PieceType::Initialize( personality );
		}
	}

	virtual void BB96_Initialize();


	//	attributes
	BitBoard96 GetPieces( int nPlayer ) const
	{	return bb96_pieces[nPlayer];   }

	BitBoard96 GetAttackMatrix( int nPlayer, int nSquare )
	{	return bb96_attack[nPlayer][nSquare];   }


	//	operations
	void SetPiece( int nPlayer, int nSquare )
	{	bb96_pieces[nPlayer].SetBit( nSquare );  }

	void ClearPiece( int nPlayer, int nSquare )
	{	bb96_pieces[nPlayer].ClearBit( nSquare );  }


	//	move generation
	void BB96_GenerateDirectMoves( MovementList &stack, int nPlayer, int nSquare );
	void BB96_GenerateDirectCaptures( MovementList &stack, int nPlayer, int nSquare );
	void BB96_GenerateDirectMovesNoCapture( MovementList &stack, int nPlayer, int nSquare );
	void BB96_GenerateDirectMovesCaptureOnly( MovementList &stack, int nPlayer, int nSquare );


	// ********************************* //
	// ***                           *** //
	// ***        Data Members       *** //
	// ***                           *** //
	// ********************************* //

	BitBoard96 bb96_pieces[2];
	BitBoard96Vector bb96_attack[2];
	BitBoard96Vector bb96_direct_move[2];
	BitBoard96Vector bb96_direct_move_no_capture[2];
	BitBoard96Vector bb96_direct_move_capture_only[2];
};

class NullPieceType96:
	public PieceType96
{
  private:
	NullPieceType96():
		PieceType96("Null 96", "Null", " ", 0, 0)
	{
	}

  public:
	static NullPieceType96 nullPieceType96;
};

class PieceType128:
	public PieceType
{
  protected:
	// ********************************* //
	// ***                           *** //
	// ***        Data Members       *** //
	// ***                           *** //
	// ********************************* //

	BitBoard128 bb128_pieces[2];
	BitBoard128Vector bb128_attack[2];
	BitBoard128Vector bb128_direct_move[2];
	BitBoard128Vector bb128_direct_move_no_capture[2];
	BitBoard128Vector bb128_direct_move_capture_only[2];


  public:
	//	construction
	PieceType128( const char *extended_name, const char *name, const char *abbreviation, int ranks, int files ):
		PieceType( extended_name, name, abbreviation, ranks, files )  {  }

	virtual void Initialize( int personality )
	{
		if( !hasBeenInitialized )
		{
			bb128_pieces[0].Clear();
			bb128_pieces[1].Clear();
			int nSquares = nRanks * nFiles;
			bb128_attack[0].SetSize( nSquares );
			bb128_attack[1].SetSize( nSquares );
			bb128_direct_move[0].SetSize( nSquares );
			bb128_direct_move[1].SetSize( nSquares );
			bb128_direct_move_no_capture[0].SetSize( nSquares );
			bb128_direct_move_no_capture[1].SetSize( nSquares );
			bb128_direct_move_capture_only[0].SetSize( nSquares );
			bb128_direct_move_capture_only[1].SetSize( nSquares );
			for( int player = 0; player < 2; player++ )
			{
				for( int sq = 0; sq < nSquares; sq++ )
				{
					bb128_attack[player][sq].Clear();
					bb128_direct_move[player][sq].Clear();
					bb128_direct_move_no_capture[player][sq].Clear();
					bb128_direct_move_capture_only[player][sq].Clear();
				}
			}
			PieceType::Initialize( personality );
		}
	}

	virtual void BB128_Initialize();


	//	attributes
	BitBoard128 GetPieces( int nPlayer ) const
	{	return bb128_pieces[nPlayer];   }

	BitBoard128 GetAttackMatrix( int nPlayer, int nSquare )
	{	return bb128_attack[nPlayer][nSquare];   }


	//	operations
	void SetPiece( int nPlayer, int nSquare )
	{	bb128_pieces[nPlayer].SetBit( nSquare );  }

	void ClearPiece( int nPlayer, int nSquare )
	{	bb128_pieces[nPlayer].ClearBit( nSquare );  }


	//	move generation - NOT IMPLEMENTED YET
//	void BB128_GenerateDirectMoves( MovementList &stack, int nPlayer, int nSquare );
//	void BB128_GenerateDirectCaptures( MovementList &stack, int nPlayer, int nSquare );
//	void BB128_GenerateDirectMovesNoCapture( MovementList &stack, int nPlayer, int nSquare );
//	void BB128_GenerateDirectMovesCaptureOnly( MovementList &stack, int nPlayer, int nSquare );
};

class NullPieceType128:
	public PieceType128
{
  private:
	NullPieceType128():
		PieceType128("Null 128", "Null", " ", 0, 0)
	{
	}

  public:
	static NullPieceType128 nullPieceType128;
};


#endif
