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

                                 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__BOARD_H
#define FILE__BOARD_H


#include <time.h>
#include "Direction.h"
#include "Movement.h"
#include "MovementList.h"
#include "Hashtable.h"
#include "GameRec.h"
#include "PawnHashtable.h"
#include "EvalHashtable.h"
#include "Book.h"
#include "BitBoard64.h"
#include "BitBoard96.h"
#include "BitBoard128.h"


enum Symmetry
{
	Mirror,
	Rotational,
	None
};


class Board
{
  protected:
	/*	member variables  */
	Game *pGame;						/*	pointer to the Game in progress  */
	Book *pBook;						/*	pointer to opening book (if any)  */
	char *currentLine;					/*	current opening book line  */
	
	/*	board size and properties  */
	int nRanks;							/*	number of ranks on the board  */
	int nFiles;							/*	number of files on the board  */
	int nSquares;						/*	number of squares on the board  */
	int bitBoardType;					/*	type of bitboard support  */
	char namesOfFiles[MAX_FILES][3];	/*	the character(s) that identify each file  */
	char namesOfRanks[MAX_RANKS][3];	/*	the character(s) that identify each rank  */
	IntVector squareValues;				/*	array of evaluation bonuses for occupying each square  */

	/*	outpost squares  */
	bool hasOutposts;					/*	does this game have outpost squares?  */
	int *outpostSquareBonuses;			/*	map of outpost square bonuses  */
	BitBoard64 bb64OutpostNoPawnSquares[2][64];
	BitBoard96 bb96OutpostNoPawnSquares[2][96];
	BitBoard128 bb128OutpostNoPawnSquares[2][128];

	/*	edit mode  */
	bool inEditMode;					/*	are we editing the board now?  */
	int editSquare;						/*	if so, what square are we editing?  */

	/*	contents of board  */
	Piece **squareContents;				/*	array of square contents (each square is a Piece *)  */

	//	player's pieces
	Piece **pieces[2];					/*	array of pointers to all pieces (including captured ones)  */
	int nPieces[2];						/*	count of player's pieces (including captured ones)  */
	int nCapturedPieces;				/*	count of player's pieces that have been captured  */
	Piece *kings[2];					/*	pointers to the kings (for quick reference)  */
	Piece **pawns[2];					/*	pointers to the pawns (for quick reference)  */
	int nPawns[2];						/*	number of pawns per player  */
	PieceType **pieceTypes;				/*	vector of pointers to all piece types in use  */
	int nPieceTypes;					/*	number of piece types in use  */
	PieceType **playerPieceTypes[2];	/*	vector of pointers to all piece types in use by player  */
	int nPlayerPieceTypes[2];			/*	number of piece types in use by player  */
	int material[2];					/*	total base values of all uncaptured pieces (by player)  */
	int pawnMaterial[2];				/*	total base values of all uncaptured pawns (by player)  */
	int midgameEvalPST[2];				/*	the PST value of all pieces currently using midgame PST values  */

	//	info about current position
	word32 primaryHash;					/*	primary hash value of current position  */
	word32 secondaryHash;				/*	secondary hash value of current position  */
	word32 primaryPawnHash;				/*	primary hash value of current pawn formation  */
	word32 secondaryPawnHash;			/*	secondary hash value of current pawn formation  */
	int rootCurrentPlayer;				/*	current player to move at top ply (unaffected by search)  */
	word32 rootPrimaryHash;				/*	primary hash of root position (unaffected by search)  */
	word32 rootSecondaryHash;			/*	secondary hash of root position (unaffected by search)  */

	//	move generation / searching
	MovementList *movementLists;		/*	array of MovementLists (commonly called a Ply Table)  */
	int currentPlayer;					/*	current player to move (the one who moves at all odd plys)  */
	int currentDepth;					/*	current search depth  */
	int maximumDepth;					/*	maximum search depth permitted under any circumstance  */
	bool abortSearch;					/*	user has clicked "Stop Thinking"  */

	Hashtable hashTable;				/*	hash table for identifying previously seen positions  */
	PawnHashtable pawnHashTable;		/*	hash table for identifying pawn formations  */
	EvalHashtable *pEvalHashtable;		/*	hash table for caching evaluations  */
	int evalRandomization[16];			/*	random adjustments to evaluation for human-like personalities  */

	IntVector history[MAX_PLY];			/*	the history heuristic information  */
	char *openingBookFilename;

	
	/*	KILLER moves  */				/*	\   store up to two "killer" moves at each ply; these are  */
	Movement killer1[MAX_PLY];			/*	 >- moves to try first because they have provided cut-offs  */
	Movement killer2[MAX_PLY];			/*	/   on previous iterations.  */

//	int pvLength[PV_BUFF];				//	length of principal variation line at each ply
//	Movement pvTable[PV_BUFF][PV_BUFF];	//	principal variation table (a "triangular" table)

	GameRec gameRecords[MAX_GAME_LENGTH];
	//	the gameRecords store useful information about each move/ply; they 
	//	store positional hashes for repetition detection, and a variety of 
	//	information about the move performed at each ply for use of the 
	//	Game-derived classes when implementing "special" moves like en passant

	bool inCheck[MAX_PLY];
	//	is the side-to-move in check at any given ply?

	MovementList historicalMoves;
	//	this movement stack is unlike all other in purpose in that it doesn't contain 
	//	a set of all legal moves from a given position; rather it contains a sequence 
	//	of moves - all the moves actually performed from the start of the game to present

	MovementList legalUserMoves;
	//	this stack contains the set of all legal moves that the user may perform 
	//	from this position, including "special" moves like castling and en passant. 
	//	this MovementList filters out the illegal pseudo-legal automatically as they
	//	are pushed onto the stack.

	bool thinking;						//	computer currently searching?
	bool showStats;						//	is computer searching, or searching just completed?
	int iDepth;							//	current depth of iterative deepening
	bool timeLeft;						//	if the computer is thinking, have we run out of time?
	int rootScore;						//	current evaluation of the current position
	int rootAlpha;						//	current root alpha
	int rootBeta;						//	current root beta
	int bestRootMove;					//	index of current best move from root
	int lastRootScore;
	int gamePly;

	//	search time limit
	__time64_t startOfSearchTime;
	__time64_t endOfSearchTime;

	//	directions
	Direction *directions;				/*	array of all directions in use	*/
	int directionCount;					/*	the number of directions in use  */
	int **movementMatrix;				/*	vector field showing what square lies in each direction	 */
										/*	from every square  */
	int attackRange[2][MAX_DIRECTIONS]; /*	for each player, this specifies the maximum attack range
											in each direciton of ANY piece the player has.  that is,
											this is the sum or union of all movements a player has.  */
	bool boardWrapsAround;				/*	for cylindrical or toroidal boards this must be set to 
											true to prevent various errors from occurring  */

	//	user interface
	int squareWidth;					//	width of a square in pixels
	int squareHeight;					//	height of a square in pixels
	int borderWidth;					//	width of the board around the board in pixels
	Piece *pieceLifted;					//	if a drag-and-drop is in progress, this points to
										//	the piece being dragged; otherwise it is NULL

	int immobilizedSquares[MAX_DEPTH][MAX_SQUARES];
	//	this is all zeroes by default, but during move generation, no moves are generated for pieces 
	//	on squares who's immobilizedSquares value is non-zero.  this is used by Game-derived classes
	//	that override the AboutToGenerateMoves function.  they can set immobilizedSquares values to 
	//	"freeze" pieces, such as the Immobilizer piece in Ultima does.


	//	statistics and debugging
	MovementList positionTestList;
	FILE *outfile;


	//	helper functions
	void InitializeBitBoard64Data();
	void InitializeBitBoard96Data();
	void InitializeBitBoard128Data();
	void CompleteUICreation();
	void Bookkeeping();
	void RecalculateHashes();
	bool IsDraw();
	void UpdatePieceRealSquareNumbers();
	void ParseOpeningLine( char *buffer, int cursor );
	void Move( int moveNumber );
	void CheckAllMoveLists();
	void SetCurrentDepth( int newDepth )
	{	currentDepth = newDepth;   }
	void BuildAttackerList
		( int squareNumber,
		  AttackVector *playerAttackers[2], 
		  int playerAttackerCount[2],
		  Piece *pieceToIgnore = NULL );


  public:
	//	construction and setup
	Board( int ranks, int files );

	virtual void Initialize( Game *game, int bitboardType );

	virtual void PostInitialize();

	virtual void PrepareGame();

	void AddPieceType( PieceType &pieceType );

	void AddPlayerPieceType( PieceType &pieceType, int player );

	void AddPlayerPieceTypeBothPlayers( PieceType &pieceType );

	void AddPieceTypeIfNecessary( PieceType &pieceType );

	bool RemovePieceType( PieceType &pieceType );

	virtual void AddPieceToBoard( Piece &piece, int rank, int file );

	virtual void InitializeOutpost( int *squareBonuses );


	//	destruction
	virtual ~Board();


	// ********************** //
	// ***                *** //
	// ***   ATTRIBUTES   *** //
	// ***                *** //
	// ********************** //

	Game &GetGame()
	{	return *pGame;   }

	int GetNumberOfRanks()
	{	return nRanks;   }

	int GetNumberOfFiles()
	{	return nFiles;   }

	int GetNumberOfSquares()
	{	return nSquares;   }

	int GetBitBoardType()
	{	return bitBoardType;   }

	bool IsInEditMode()
	{	return inEditMode;   }

	int GetEditSquare()
	{	return editSquare;   }

	void SetEditSquare( int square )
	{	editSquare = square;   }

	int GetSquareWidth()
	{	return squareWidth;   }

	int GetSquareHeight()
	{	return squareHeight;   }

	void SetSquareWidth( int value )
	{	squareWidth = value;   }

	void SetSquareHeight( int value )
	{	squareHeight = value;   }

	void SetBorderWidth( int value )
	{	borderWidth = value;   }

	int GetNumberOfPieces( int player )
	{	return nPieces[player];   }

	Piece *GetPiece( int player, int piece )
	{	return pieces[player][piece];   }

	int GetNumberOfPawns( int player )
	{	return nPawns[player];   }

	Piece *GetPawn( int player, int pawn )
	{	return pawns[player][pawn];   }

	MovementList &GetCurrentMovementList();

	MovementList &GetLegalUserMovementList()
	{	return legalUserMoves;   }

	MovementList &GetHistoricalMovementList()
	{	return historicalMoves;   }

	MovementList &GetPositionTestList()
	{	return positionTestList;   }

	MovementList &GetMovementList( int depth )
	{	return movementLists[depth];   }

	Piece *GetPieceBeingLifted()
	{	return pieceLifted;   }

	int GetCurrentPlayerNumber()
	{	return currentPlayer;   }

	int GetRootCurrentPlayerNumber()
	{	return rootCurrentPlayer;   }

	int GetMaterial()
	{	return material[currentPlayer] - 
	           material[FLIP(currentPlayer)];   }

	int GetMaterial( int playerNumber )
	{	return material[playerNumber];   }

	int GetPawnMaterial( int playerNumber )
	{	return pawnMaterial[playerNumber];   }

	word32 GetPrimaryHash();

	word32 GetSecondaryHash()
	{	return secondaryHash;   }

	word32 GetPrimaryPawnHash()
	{	return primaryPawnHash;   }

	word32 GetSecondaryPawnHash()
	{	return secondaryPawnHash;   }

	bool DoesBoardWrapAround() const
	{	return boardWrapsAround;   }

	int GetGamePly()
	{	return gamePly;   }

	int GetCurrentDepth()
	{	return currentDepth;   }

	int GetIterDepth()
	{	return iDepth;  }

	bool IsThinking()
	{	return thinking;   }

	bool ShowStats()
	{	return showStats;   }

	bool FastCheckTest()
	{	return inCheck[currentDepth];   }

	int GetRootScore()
	{	return rootScore;   }

	int GetDirectionCount()
	{	return directionCount;   }

	Direction &GetDirection( int directionNumber )
	{	return directions[directionNumber];  }

	int *GetMovementMatrix( int directionNumber )
	{	return movementMatrix[directionNumber];  }

	int *GetOppositeMovementMatrix( int directionNumber )
	{	return movementMatrix[directions[directionNumber].GetOppositeDirectionNumber()];  }

	int GetAttackRange( int nPlayer, int nDirection )
	{	return attackRange[nPlayer][nDirection];    }

	int GetNumberOfCapturedPieces()
	{	return nCapturedPieces;   }

	GameRec &GetGameRecord( int nRecord )
	{	return gameRecords[nRecord];   }

	char *GetCurrentLine()
	{	return currentLine;   }

	PieceType **GetPieceTypes()
	{	return pieceTypes;    }

	int GetPieceTypeCount()
	{	return nPieceTypes;   }

	PieceType **GetPlayerPieceTypes( int nPlayer )
	{	return playerPieceTypes[nPlayer];    }

	int GetPlayerPieceTypeCount( int nPlayer )
	{	return nPlayerPieceTypes[nPlayer];   }

	bool IsImmobilized( int nSquare )
	{	return immobilizedSquares[currentDepth][nSquare] != 0;   }

	void GetImmobilizedMatrix( int (**immobilizedMatrix)[MAX_DEPTH][MAX_SQUARES] )
	{	*immobilizedMatrix = &immobilizedSquares;   }


	//	accessing squares on the board
	int GetSquareValue( int square_number )
	{	return squareValues[square_number];   }

	Piece *GetSquareContents( int square_number )
	{	return( squareContents[square_number] );   }

	Piece *GetSquareContents( int rank, int file )
	{	return( squareContents[(rank * nFiles) + file] );   }

	void SetSquareContents( int square_number, Piece *piece )
	{	squareContents[square_number] = piece;   }

	void SetSquareContents( int rank, int file, Piece *piece )
	{	squareContents[(rank * nFiles) + file] = piece;  }

	void ClearSquare( int square_number )
	{	squareContents[square_number] = NULL;   }

	void ClearSquare( int rank, int file )
	{	squareContents[rank * nFiles + file] = NULL;   }

	Piece **GetSquareReference( int square_number )
	{	return &squareContents[square_number];   }

	Piece **GetSquareReference( int rank, int file )
	{	return &squareContents[(rank * nFiles) + file];   }

	int CanMoveToSquare( int nSquare, bool updateUI = false );

	//	names of ranks and files
	int GetRankByName( char *rankName );
	int GetRankByChar( char rankName );
	int GetRankByCharPair( char rankName1, char rankName2 );

	int GetFileByName( char *fileName );
	int GetFileByChar( char fileName );
	int GetFileByCharPair( char fileName1, char fileName2 );

	char *GetNameOfFile( int nFile )
	{	return namesOfFiles[nFile];   }

	char *GetNameOfRank( int nRank )
	{	return namesOfRanks[nRank];   }

	//	accessing pieces
	Piece *GetKing( int player )
	{	return( kings[player] );  }

	void SetKing( int player, Piece *king )
	{	kings[player] = king;   }

	//	accessing bitboards
	int GetRook00AttackWidth()
	{	return rook00attackWidth;   }

	int GetRook90AttackWidth()
	{	return rook90attackWidth;   }

	int GetBishop45AttackWidth()
	{	return bishop45attackWidth;   }

	int GetBishop135AttackWidth()
	{	return bishop135attackWidth;   }

	BitBoard64 BB64_GetFriends( int nPlayer )
	{	return bb64_friends[nPlayer];   }

	BitBoard64 BB64_GetBlockers()
	{	return bb64_blocker;   }

	BitBoard64 BB64_GetBlockers90()
	{	return bb64_blocker90;   }

	BitBoard64 BB64_GetBlockers45()
	{	return bb64_blocker45;   }

	BitBoard64 BB64_GetBlockers135()
	{	return bb64_blocker135;   }

	BitBoard96 BB96_GetFriends( int nPlayer )
	{	return bb96_friends[nPlayer];   }

	BitBoard96 BB96_GetBlockers()
	{	return bb96_blocker;   }

	BitBoard96 BB96_GetBlockers90()
	{	return bb96_blocker90;   }

	BitBoard96 BB96_GetBlockers45()
	{	return bb96_blocker45;   }

	BitBoard96 BB96_GetBlockers135()
	{	return bb96_blocker135;   }

	BitBoard128 BB128_GetFriends( int nPlayer )
	{	return bb128_friends[nPlayer];   }

	BitBoard128 BB128_GetBlockers()
	{	return bb128_blocker;   }

	BitBoard128 BB128_GetBlockers90()
	{	return bb128_blocker90;   }

	BitBoard128 BB128_GetBlockers45()
	{	return bb128_blocker45;   }

	BitBoard128 BB128_GetBlockers135()
	{	return bb128_blocker135;   }

	//	accessing game records
	GameRec &GetCurrentGameRecord()
	{	return gameRecords[gamePly-1];   }


	// ********************** //
	// ***                *** //
	// ***   OPERATIONS   *** //
	// ***                *** //
	// ********************** //

	//	User Interface Operations
	void ToggleEditMode()
	{	inEditMode = !inEditMode;   }

	void ForceWindowRedraw();

	void RecalculateMaterial();

	void ClearAnyExtraCaptures();


	//	Game Operations
	void Think();

	void TestPosition();

	bool IsMoveLegal( int fromSquareNumber, int toSquareNumber );

	void PerformMove( int selectedMoveIndex );

	void LiftPiece( Piece *pieceToLift )
	{	pieceLifted = pieceToLift;  }

	void DropPiece( int squareNumber );

	void TakeBackMove();

	void TakeBackAllMoves();

	void PlayLine( char *line );

	void AbortSearch()
	{	abortSearch = true;   }

	void GetPV( char *line );

	int GetPiecePostedBonus( int playerNumber, int squareNumber, PieceType &pawnType );


	//	Setup Operations
	void PlacePiecesByFEN( char *notation );

	void StartGame();

	void SetOpeningBook( Book *openingBook, const char *filename );

	void ClearTranspositionTables()
	{	hashTable.ClearAll();    }

	void SetSizeOfTranspositionTables( int newSize )
	{	hashTable.SetSize( newSize );   }

	void SetEvaluationCacheSize( int newSize )
	{	if( pEvalHashtable != NULL ) pEvalHashtable->SetSize( newSize );   }


	// ************************ //
	// ***                  *** //
	// ***   OVERRIDABLES   *** //
	// ***                  *** //
	// ************************ //

	//	board geometry
	virtual int GetSquareRank( int squareNumber )
	{	return squareNumber / nFiles;   }

	virtual int GetSquareFile( int squareNumber )
	{	return squareNumber % nFiles;   }

	//	drawing
	virtual void DrawBoard( HWND hwnd, HDC hdc, LPPAINTSTRUCT ps );
	virtual void DrawPiecesOnBoard( HWND hwnd, HDC hdc, LPPAINTSTRUCT ps );
	virtual void InvalidateSquare( int nSquare );
	virtual int SquareHitTest( int x, int y );
	virtual int GetBoardRightEdge();
	virtual int GetBoardBottomEdge();



	// *** CALCULATIONS *** //
	int Evaluate( int alpha, int beta );
	bool IsInCheck();
	bool IsInCheck( int fromSquare, int toSquare = -1 );
	bool IsOtherPlayerInCheck();
	bool IsSquareAttacked( int squareNumber, int playerNumber );
	bool IsSquareAttacked( int squareNumber, int playerNumber, int dirSquare1, int dirSquare2 );



	// *** SEARCH FUNCTIONS *** //
	int SearchRoot( int alpha, int beta, int depth, int &evaluation );
	int Search( int alpha, int beta, int depth, bool do_null, NodeType nodeType, Movement &bestMoveFound );
	int QuiescentSearch( int alpha,  int beta, int qdepth, NodeType nodeType );


	// *** LOOKUP TABLES *** //
	int files[2][MAX_SQUARES];
	int ranks[2][MAX_SQUARES];
	int flipSquare[2][MAX_SQUARES];
	int mirrorSquare[2][MAX_SQUARES];
	int distance[MAX_SQUARES][MAX_SQUARES];
	int hv_distance[MAX_SQUARES][MAX_SQUARES];
	int directionLookup[MAX_SQUARES][MAX_SQUARES][4];
	int openingMoveEvalForPawnBasedOnFile[MAX_FILES];

	// *********************************
	// **                             **
	// **          BitBoards          **
	// **                             **
	// *********************************

	//	BitBoards - general
	int rook00attackWidth;
	int rook90attackWidth;
	int bishop45attackWidth;
	int bishop135attackWidth;

	int rotate90[MAX_SQUARES];
	int rotate45[MAX_SQUARES];
	int rotate135[MAX_SQUARES];
	int shift00[MAX_SQUARES];
	int shift90[MAX_SQUARES];
	int shift45[MAX_SQUARES];
	int shift135[MAX_SQUARES];
	int mask00[MAX_SQUARES];
	int mask90[MAX_SQUARES];
	int mask45[MAX_SQUARES];
	int mask135[MAX_SQUARES];

	//	bitboards - 64 bit
	BitBoard64 bb64_blocker;
	BitBoard64 bb64_blocker90;
	BitBoard64 bb64_blocker45;
	BitBoard64 bb64_blocker135;
	BitBoard64 bb64_friends[2];
	BitBoard64 bb64_files[MAX_FILES];
	BitBoard64Vector bb64_rays;
	BitBoard64Vector bb64_rook00attack;
	BitBoard64Vector bb64_rook90attack;
	BitBoard64Vector bb64_bishop45attack;
	BitBoard64Vector bb64_bishop135attack;

	//	BitBoards - 96 bit
	BitBoard96 bb96_blocker;
	BitBoard96 bb96_blocker90;
	BitBoard96 bb96_blocker45;
	BitBoard96 bb96_blocker135;
	BitBoard96 bb96_friends[2];
	BitBoard96Vector bb96_rays;
	BitBoard96Vector bb96_rook00attack;
	BitBoard96Vector bb96_rook90attack;
	BitBoard96Vector bb96_bishop45attack;
	BitBoard96Vector bb96_bishop135attack;

	//	BitBoards - 128 bit
	BitBoard128 bb128_blocker;
	BitBoard128 bb128_blocker90;
	BitBoard128 bb128_blocker45;
	BitBoard128 bb128_blocker135;
	BitBoard128 bb128_friends[2];
	BitBoard128Vector bb128_rays;
	BitBoard128Vector bb128_rook00attack;
	BitBoard128Vector bb128_rook90attack;
	BitBoard128Vector bb128_bishop45attack;
	BitBoard128Vector bb128_bishop135attack;


	// *** DEBUGGING *** //
	void AssertValid();
	void AssertValidSetup();
	void Output( FILE *fi );


	// *** FRIENDS *** //
	friend class Piece;
	friend class Game;
	friend class ChessGame;
	friend class MovementList;
	friend class PawnHashtable;
	friend class EvalHashtable;
	friend void LoadGame( char *filename );
};


#endif
