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

                                 ChessV

                   COPYRIGHT (C) 2011 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 "SpartanChessGame.h"
#include "../../Resource.h"
#include "../../ChessV.h"
#include "../../GameParameters.h"


// *** DEBUG MEMORY ALLOCATION *** //
#ifdef _DEBUG
#define new SAFE_NEW
#endif


Game *CreateSpartanChessGame( Board &brd, Player &plr0, Player &plr1 )
{
	return new SpartanChessGame( brd, plr0, plr1 );
}

SpartanChessGame::SpartanChessGame( Board &board, Player &whitePlayer, Player &blackPlayer ):
	ChessGame(board, whitePlayer, blackPlayer)
{
	// *** change settings from ChessGame that are not correct *** //

	//	disable en Passant
	enPassant = false;

	//	enable custom check testing required because of the Spartan's double kings
	//	provided by IsInCheck override
	specialCheckTesting = true;

	//	normal pawn structure valuations don't apply
	usePawnStructureEvaluation = false;
	//	NOTE - we'd like to disable for White only, but we 
	//	aren't set up to do that at present
	for( int x = 0; x < nPhases; x++ )
		phases[x].SetPawnDeficiencyFactor( 0 );
}

void SpartanChessGame::AddPlayerPieceTypes( char *gameName )
{
	//	add the piece types that each player may have
	board.AddPlayerPieceType( OrthodoxKing::orthodoxKing, 0 );
	board.AddPlayerPieceType( OrthodoxPawn::orthodoxPawn, 0 );
	board.AddPlayerPieceType( Hoplite::hoplite, 1 );
	board.AddPlayerPieceType( OrthodoxRook::orthodoxRook, 0 );
	board.AddPlayerPieceType( OrthodoxBishop::orthodoxBishop, 0 );
	board.AddPlayerPieceType( OrthodoxKnight::orthodoxKnight, 0 );
	board.AddPlayerPieceType( OrthodoxQueen::orthodoxQueen, 0 );
	board.AddPlayerPieceType( SpartanKing::spartanKing, 1 );
	board.AddPlayerPieceType( DragonKing::dragonKing, 1 );
	board.AddPlayerPieceType( Archbishop::archbishop, 1 );
	board.AddPlayerPieceType( Bowman::bowman, 1 );
	board.AddPlayerPieceType( Lieutenant::lieutenant, 1 );

	//	add piece type references to the following arrays, 
	//	minorPieceTypes, etc., used for giving bonuses and 
	//	penalties in positional evaluation
	castlingPieceTypes[0] = &OrthodoxRook::orthodoxRook;
	castlingPieceTypes[1] = &NullPieceType64::nullPieceType64;
	minorPieceTypes[0][0] = &OrthodoxKnight::orthodoxKnight;
	minorPieceTypes[1][0] = &Lieutenant::lieutenant;
	minorPieceTypes[0][1] = &OrthodoxBishop::orthodoxBishop;
	minorPieceTypes[1][1] = &Bowman::bowman;
	minorPieceTypes[0][2] = &NullPieceType64::nullPieceType64;
	minorPieceTypes[1][2] = &NullPieceType64::nullPieceType64;
	minorPieceTypes[0][3] = &NullPieceType64::nullPieceType64;
	minorPieceTypes[1][3] = &NullPieceType64::nullPieceType64;
	colorboundPieceTypes[0][0] = &OrthodoxBishop::orthodoxBishop;
	colorboundPieceTypes[1][0] = &NullPieceType64::nullPieceType64;
	colorboundPieceTypes[0][1] = &NullPieceType64::nullPieceType64;
	colorboundPieceTypes[1][1] = &NullPieceType64::nullPieceType64;
	queenPieceTypes[0] = &OrthodoxQueen::orthodoxQueen;
	queenPieceTypes[1] = &Archbishop::archbishop;
	pawnPieceTypes[0] = &OrthodoxPawn::orthodoxPawn;
	pawnPieceTypes[1] = &Hoplite::hoplite;
	castlingPiecesSlideNorth[0] = true;
	castlingPiecesSlideNorth[1] = false;
}

void SpartanChessGame::ChangeRulesByVariant
	( char *gameName,
	  char *&array,
	  char *&book )
{
	// *** SPARTAN CHESS *** //
	if( !strcmp( gameName, "Spartan Chess" ) )
	{
		//	give the spartan king a reasonable value
		SpartanKing::spartanKing.SetBaseValue( 3700 );
		//	change name of Archbishop to Warlord
		Archbishop::archbishop.SetFullName( "Warlord" );
		Archbishop::archbishop.SetNotation( "W" );
		//	change name of Dragon King to General
		DragonKing::dragonKing.SetFullName( "General" );
		DragonKing::dragonKing.SetNotation( "G" );
		//	change name of Bowman to Captain
		Bowman::bowman.SetFullName( "Captain" );
		Bowman::bowman.SetNotation( "C" );
		//	increase the value of the archbishop
		Archbishop::archbishop.SetArmyAdjustment( 100 );
		//	increase the value of the general a little
		DragonKing::dragonKing.SetArmyAdjustment( 50 );
		//	place pieces
		array = "lgkcckwl/hhhhhhhh/8/8/8/8/PPPPPPPP/RNBQKBNR";
		//	set name of opening book
		book = "openings\\SpartanChess.txt";
		//	activate BitBoard move and capture generation
		customMoveGeneration = true;
		customCaptureGeneration = true;
	}
}

bool SpartanChessGame::IsInCheck
	( Piece *king )
{
	if( king != NULL && king->GetPlayerNumber() == 0 )
		return IsSquareAttacked( king->GetSquareNumber(), 1 );

	BitBoard64 kings = SpartanKing::spartanKing.GetPieces( 1 );
	int sq = kings.ExtractLSB();
	if( !IsSquareAttacked( sq, 0 ) )
		return false;
	if( kings )
	{
		sq = kings.GetLSB();
		if( !IsSquareAttacked( sq, 0 ) )
			return false;
	}
	return true;
}

int SpartanChessGame::EnumeratePromotions
	( Piece *piece, 
	  int fromSquare,
	  int toSquare,
	  PieceType **promotions,
	  bool quiescentSearch )
{
	//	we need to override this function because of the potential 
	//	for the Spartans to promote to King
	if( piece->GetPlayerNumber() == 1 )
	{
		promotions[0] = &DragonKing::dragonKing;
		promotions[1] = &Archbishop::archbishop;
		promotions[2] = &Bowman::bowman;
		promotions[3] = &Lieutenant::lieutenant;
		//	promotion to king is only available if 
		//	the player is down to one king
		if( OrthodoxKing::orthodoxKing.GetPieces( 1 ).GetBitCount() == 1 )
		{
			promotions[4] = &OrthodoxKing::orthodoxKing;
			return 5;
		}
		return 4;
	}
	else
	{
		promotions[0] = &OrthodoxQueen::orthodoxQueen;
		promotions[1] = &OrthodoxRook::orthodoxRook;
		promotions[2] = &OrthodoxBishop::orthodoxBishop;
		promotions[3] = &OrthodoxKnight::orthodoxKnight;
		return 4;
	}
}

void SpartanChessGame::AddSpecialMoves
	( int currentPlayer, 
	  MovementList &stack,
	  GameRec &gameRecord,
	  bool quiescentSearch )
{
	if( currentPlayer == 0 )
	{
		// *** CASTLING *** //

		Piece *king = board.GetKing( 0 );
		if( !king->IsCaptured() && !king->HasMoved() )
		{
			//	king side
			if( board.GetSquareContents( 7 ) != NULL &&
				!board.GetSquareContents( 7 )->HasMoved() )
			{
				AddCastlingMove( stack, gameRecord, king, board.GetSquareContents( 7 ), 6, 5 );
			}
			//	queen side
			if( board.GetSquareContents( 0 ) != NULL &&
				!board.GetSquareContents( 0 )->HasMoved() )
			{
				AddCastlingMove( stack, gameRecord, king, board.GetSquareContents( 0 ), 2, 3 );
			}
		}
	}
}

word32 SpartanChessGame::AdjustPrimaryHash
	( word32 primaryHash )
{
	word32 hashCode = primaryHash;

	//	hand off to ChessGame, so hashes for Castling privledges will be added
	return( ChessGame::AdjustPrimaryHash( hashCode ) );
}

void SpartanChessGame::GenerateMoves
	( int currentPlayer, 
	  MovementList &list )
{
	BitBoard64 pieces;

	if( currentPlayer == 0 )
	{
		// *** PAWNS *** //
		pieces = OrthodoxPawn::orthodoxPawn.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			OrthodoxPawn::orthodoxPawn.BB64_GenerateDirectCaptures( list, currentPlayer, square );
			OrthodoxPawn::orthodoxPawn.BB64_GenerateDirectMovesNoCapture( list, currentPlayer, square );
		}
		//	handle the initial 2-step pawn move
		BitBoard64 firstAndSecondRankPawns = player0PawnTwoSpaceZone & OrthodoxPawn::orthodoxPawn.GetPieces( 0 );
		while( firstAndSecondRankPawns )
		{
			int square = firstAndSecondRankPawns.ExtractLSB();
			if( board.GetSquareContents( square + 8 ) == NULL && 
				board.GetSquareContents( square + 16 ) == NULL )
				//	squares are open; add the two-step move
				list.AddMove( square, square + 16 );
		}

		// *** KNIGHTS *** //
		pieces = OrthodoxKnight::orthodoxKnight.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			OrthodoxKnight::orthodoxKnight.BB64_GenerateDirectMoves( list, currentPlayer, square );
		}

		// *** KINGS *** //
		pieces = OrthodoxKing::orthodoxKing.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			OrthodoxKing::orthodoxKing.BB64_GenerateDirectMoves( list, currentPlayer, square );
		}

		// *** ROOKS *** //
		BitBoard64 friends = board.bb64_friends[currentPlayer];
		pieces = OrthodoxRook::orthodoxRook.GetPieces( currentPlayer ) |  
				 OrthodoxQueen::orthodoxQueen.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			BitBoard64 moves;
			moves = board.bb64_rook00attack[square * board.rook00attackWidth + 
				((board.bb64_blocker >> board.shift00[square]) & board.mask00[square])] | 
				board.bb64_rook90attack[square * board.rook90attackWidth + 
				((board.bb64_blocker90 >> board.shift90[square]) & board.mask90[square])];
			moves = moves & (~friends);
			if( moves )
				list.AddBitBoard64Moves( square, moves );
		}

		// *** BISHOPS *** // 
		pieces = OrthodoxBishop::orthodoxBishop.GetPieces( currentPlayer ) | 
				 OrthodoxQueen::orthodoxQueen.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			BitBoard64 moves;
			moves = board.bb64_bishop45attack[square * board.bishop45attackWidth + 
				((board.bb64_blocker45 >> board.shift45[square]) & board.mask45[square])] | 
				board.bb64_bishop135attack[square * board.bishop135attackWidth + 
				((board.bb64_blocker135 >> board.shift135[square]) & board.mask135[square])];
			moves = moves & (~friends);
			if( moves )
				list.AddBitBoard64Moves( square, moves );
		}
	}
	else
	{
		// *** HOPLITES *** //
		pieces = Hoplite::hoplite.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			Hoplite::hoplite.BB64_GenerateDirectCaptures( list, currentPlayer, square );
			Hoplite::hoplite.BB64_GenerateDirectMovesNoCapture( list, currentPlayer, square );
		}

		// *** LIEUTENANTS *** //
		pieces = Lieutenant::lieutenant.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			Lieutenant::lieutenant.BB64_GenerateDirectMoves( list, currentPlayer, square );
			Lieutenant::lieutenant.BB64_GenerateDirectMovesNoCapture( list, currentPlayer, square );
		}

		// *** CAPTAINS *** //
		pieces = Bowman::bowman.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			Bowman::bowman.BB64_GenerateDirectMoves( list, currentPlayer, square );
		}

		// *** KINGS *** //
		pieces = SpartanKing::spartanKing.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			SpartanKing::spartanKing.BB64_GenerateDirectMoves( list, currentPlayer, square );
		}

		// *** GENERALS *** //
		BitBoard64 friends = board.bb64_friends[currentPlayer];
		pieces = DragonKing::dragonKing.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			//	handle the diagonal direct-step
			DragonKing::dragonKing.BB64_GenerateDirectMoves( list, currentPlayer, square );
			//	handle the rook slide
			BitBoard64 moves;
			moves = board.bb64_rook00attack[square * board.rook00attackWidth + 
				((board.bb64_blocker >> board.shift00[square]) & board.mask00[square])] | 
				board.bb64_rook90attack[square * board.rook90attackWidth + 
				((board.bb64_blocker90 >> board.shift90[square]) & board.mask90[square])];
			moves = moves & (~friends);
			if( moves )
				list.AddBitBoard64Moves( square, moves );
		}

		// *** WARLORDS *** // 
		pieces = Archbishop::archbishop.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			//	handle the knight leap
			Archbishop::archbishop.BB64_GenerateDirectMoves( list, currentPlayer, square );
			//	handle the bishop slide
			BitBoard64 moves;
			moves = board.bb64_bishop45attack[square * board.bishop45attackWidth + 
				((board.bb64_blocker45 >> board.shift45[square]) & board.mask45[square])] | 
				board.bb64_bishop135attack[square * board.bishop135attackWidth + 
				((board.bb64_blocker135 >> board.shift135[square]) & board.mask135[square])];
			moves = moves & (~friends);
			if( moves )
				list.AddBitBoard64Moves( square, moves );
		}
	}

	AddSpecialMoves( currentPlayer, list, board.GetCurrentGameRecord(), false );
}

void SpartanChessGame::GenerateCaptures
	( int currentPlayer, 
	  MovementList &list )
{
	BitBoard64 pieces;

	if( currentPlayer == 0 )
	{
		// *** PAWNS *** //
		pieces = OrthodoxPawn::orthodoxPawn.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			OrthodoxPawn::orthodoxPawn.BB64_GenerateDirectCaptures( list, currentPlayer, square );
		}

		// *** KNIGHTS *** //
		pieces = OrthodoxKnight::orthodoxKnight.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			OrthodoxKnight::orthodoxKnight.BB64_GenerateDirectCaptures( list, currentPlayer, square );
		}

		// *** KINGS *** //
		pieces = OrthodoxKing::orthodoxKing.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			OrthodoxKing::orthodoxKing.BB64_GenerateDirectCaptures( list, currentPlayer, square );
		}

		// *** ROOKS *** //
		BitBoard64 enemies = board.bb64_friends[FLIP(currentPlayer)];
		pieces = OrthodoxRook::orthodoxRook.GetPieces( currentPlayer ) |  
				 OrthodoxQueen::orthodoxQueen.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			BitBoard64 moves;
			moves = board.bb64_rook00attack[square * board.rook00attackWidth + 
				((board.bb64_blocker >> board.shift00[square]) & board.mask00[square])] | 
				board.bb64_rook90attack[square * board.rook90attackWidth + 
				((board.bb64_blocker90 >> board.shift90[square]) & board.mask90[square])];
			moves = moves & enemies;
			if( moves )
				list.AddBitBoard64Captures( square, moves );
		}

		// *** BISHOPS *** // 
		pieces = OrthodoxBishop::orthodoxBishop.GetPieces( currentPlayer ) | 
				 OrthodoxQueen::orthodoxQueen.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			BitBoard64 moves;
			moves = board.bb64_bishop45attack[square * board.bishop45attackWidth + 
				((board.bb64_blocker45 >> board.shift45[square]) & board.mask45[square])] | 
				board.bb64_bishop135attack[square * board.bishop135attackWidth + 
				((board.bb64_blocker135 >> board.shift135[square]) & board.mask135[square])];
			moves = moves & enemies;
			if( moves )
				list.AddBitBoard64Captures( square, moves );
		}
	}
	else
	{
		// *** HOPLITES *** //
		pieces = Hoplite::hoplite.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			Hoplite::hoplite.BB64_GenerateDirectCaptures( list, currentPlayer, square );
		}

		// *** LIEUTENANTS *** //
		pieces = Lieutenant::lieutenant.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			Lieutenant::lieutenant.BB64_GenerateDirectCaptures( list, currentPlayer, square );
		}

		// *** CAPTAINS *** //
		pieces = Bowman::bowman.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			Bowman::bowman.BB64_GenerateDirectCaptures( list, currentPlayer, square );
		}

		// *** KINGS *** //
		pieces = SpartanKing::spartanKing.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			SpartanKing::spartanKing.BB64_GenerateDirectCaptures( list, currentPlayer, square );
		}

		// *** GENERALS *** //
		BitBoard64 enemies = board.bb64_friends[FLIP(currentPlayer)];
		pieces = DragonKing::dragonKing.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			//	handle the diagonal direct-step
			DragonKing::dragonKing.BB64_GenerateDirectCaptures( list, currentPlayer, square );
			//	handle the rook slide
			BitBoard64 moves;
			moves = board.bb64_rook00attack[square * board.rook00attackWidth + 
				((board.bb64_blocker >> board.shift00[square]) & board.mask00[square])] | 
				board.bb64_rook90attack[square * board.rook90attackWidth + 
				((board.bb64_blocker90 >> board.shift90[square]) & board.mask90[square])];
			moves = moves & enemies;
			if( moves )
				list.AddBitBoard64Captures( square, moves );
		}

		// *** WARLORDS *** // 
		pieces = Archbishop::archbishop.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			//	handle the knight leap
			Archbishop::archbishop.BB64_GenerateDirectMoves( list, currentPlayer, square );
			//	handle the bishop slide
			BitBoard64 moves;
			moves = board.bb64_bishop45attack[square * board.bishop45attackWidth + 
				((board.bb64_blocker45 >> board.shift45[square]) & board.mask45[square])] | 
				board.bb64_bishop135attack[square * board.bishop135attackWidth + 
				((board.bb64_blocker135 >> board.shift135[square]) & board.mask135[square])];
			moves = moves & enemies;
			if( moves )
				list.AddBitBoard64Captures( square, moves );
		}
	}
}

bool SpartanChessGame::IsSquareAttacked
	( int squareNumber, 
	  int playerNumber )
{
	BitBoard64 pieces;
	int otherPlayer = FLIP(playerNumber);

	if( playerNumber == 0 )
	{
		// *** PAWNS *** //
		if( OrthodoxPawn::orthodoxPawn.bb64_attack[otherPlayer][squareNumber] &
			OrthodoxPawn::orthodoxPawn.GetPieces( playerNumber ) )
			return true;

		// *** KNIGHTS *** //
		if( OrthodoxKnight::orthodoxKnight.bb64_attack[otherPlayer][squareNumber] &
			OrthodoxKnight::orthodoxKnight.GetPieces( playerNumber ) )
			return true;

		// *** KINGS *** //
		if( OrthodoxKing::orthodoxKing.bb64_attack[otherPlayer][squareNumber] &
			OrthodoxKing::orthodoxKing.GetPieces( playerNumber ) )
			return true;

		// *** ROOKS *** //
		pieces = OrthodoxRook::orthodoxRook.bb64_attack[otherPlayer][squareNumber] & 
			(OrthodoxRook::orthodoxRook.GetPieces( playerNumber ) | 
			 OrthodoxQueen::orthodoxQueen.GetPieces( playerNumber ));
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			if( ! ((bool) (board.bb64_rays[(squareNumber * board.GetNumberOfSquares()) + square] & 
				  board.bb64_blocker & ~BitBoard64::GetPositionBitBoard( square ))) )
				return true;
		}

		// *** BISHOPS *** //
		pieces = OrthodoxBishop::orthodoxBishop.bb64_attack[otherPlayer][squareNumber] & 
			(OrthodoxBishop::orthodoxBishop.GetPieces( playerNumber ) | 
			 OrthodoxQueen::orthodoxQueen.GetPieces( playerNumber ));
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			if( ! ((bool) (board.bb64_rays[(squareNumber * board.GetNumberOfSquares()) + square] & 
				  board.bb64_blocker & ~BitBoard64::GetPositionBitBoard( square ))) )
				return true;
		}
	}
	else
	{
		// *** HOPLITES *** //
		if( Hoplite::hoplite.bb64_attack[otherPlayer][squareNumber] &
			Hoplite::hoplite.GetPieces( playerNumber ) )
			return true;

		// *** LIEUTENANTS *** //
		if( Lieutenant::lieutenant.bb64_attack[otherPlayer][squareNumber] &
			Lieutenant::lieutenant.GetPieces( playerNumber ) )
			return true;

		// *** CAPTAINS *** //
		if( Bowman::bowman.bb64_attack[otherPlayer][squareNumber] &
			Bowman::bowman.GetPieces( playerNumber ) )
			return true;

		// *** KINGS *** //
		if( SpartanKing::spartanKing.bb64_attack[otherPlayer][squareNumber] &
			SpartanKing::spartanKing.GetPieces( playerNumber ) )
			return true;

		// *** GENERALS *** //
		pieces = DragonKing::dragonKing.bb64_attack[otherPlayer][squareNumber] & 
			DragonKing::dragonKing.GetPieces( playerNumber );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			if( ! ((bool) (board.bb64_rays[(squareNumber * board.GetNumberOfSquares()) + square] & 
				  board.bb64_blocker & ~BitBoard64::GetPositionBitBoard( square ))) )
				return true;
		}

		// *** WARLORDS *** //
		pieces = Archbishop::archbishop.bb64_attack[otherPlayer][squareNumber] & 
			Archbishop::archbishop.GetPieces( playerNumber );
		while( pieces )
		{
			int square = pieces.ExtractLSB();
			if( ! ((bool) (board.bb64_rays[(squareNumber * board.GetNumberOfSquares()) + square] & 
				  board.bb64_blocker & ~BitBoard64::GetPositionBitBoard( square ))) )
				return true;
		}
	}

	return false;
}

Phase &SpartanChessGame::AdjustEvaluation
	( int &eval,
	  PawnHash *pPawnHash )
{
	Phase *currentPhase = phases;

	if( board.GetCurrentGameRecord().gameInt1 < 15 )
	{
		// *** The OPENING *** //
		int factor = MAX(board.GetCurrentGameRecord().gameInt1 - 10, 0) * 2;
		int factor6 = 640 - (factor << 6);  //   \    
		int factor5 = 320 - (factor << 5);  //    \_  different adjustments
		int factor4 = 160 - (factor << 4);  //    /   from large to small
		int factor3 = 80 - (factor << 3);   //   / 

		// *** CASTLING *** //
		if( board.GetKing( 0 )->GetFlags() & FLAGS_HAS_CASTLED )
			eval += (personality <= PERSONALITY_B ? factor5 : factor6);
		else
		{
			if( board.GetKing( 0 )->HasMoved() || 
				((board.GetSquareContents( 7 ) == NULL ||
				board.GetSquareContents( 7 )->HasMoved()) &&
				(board.GetSquareContents( 0 ) == NULL ||
				board.GetSquareContents( 0 )->HasMoved())) )
				eval -= (personality <= PERSONALITY_B ? factor4 : factor5);
		}

		//	penalty for moving the same piece twice
		BitBoard64 bb = board.BB64_GetFriends( 0 );
		while( bb )
		{
			int square = bb.ExtractLSB();
			if( board.GetSquareContents( square )->HasMovedTwice() )
				eval -= factor6;
		}
		bb = board.BB64_GetFriends( 1 );
		while( bb )
		{
			int square = bb.ExtractLSB();
			if( board.GetSquareContents( square )->HasMovedTwice() )
				eval += factor6;
		}

		//	don't block the king or queen's pawns in the opening (Persians Only)
		if( personality == PERSONALITY_A )
		{
			if( board.GetSquareContents( D3 ) != NULL &&
				board.GetSquareContents( D2 ) != NULL &&
				!board.GetSquareContents( D2 )->HasMoved() )
				eval -= factor5;
			if( board.GetSquareContents( E3 ) != NULL &&
				board.GetSquareContents( E2 ) != NULL &&
				!board.GetSquareContents( E2 )->HasMoved() )
				eval -= factor5;
		}
		else
		{
			if( board.GetSquareContents( D3 ) != NULL &&
				board.GetSquareContents( D2 ) != NULL &&
				!board.GetSquareContents( D2 )->HasMoved() )
				eval -= factor6;
			if( board.GetSquareContents( E3 ) != NULL &&
				board.GetSquareContents( E2 ) != NULL &&
				!board.GetSquareContents( E2 )->HasMoved() )
				eval -= factor6;
		}
	}
	else if( board.GetNumberOfCapturedPieces() > 24 ||
		board.GetMaterial( 0 ) - board.GetPawnMaterial( 0 ) + 
		board.GetMaterial( 1 ) - board.GetPawnMaterial( 1 ) < 18000 )
		//	we are in the end-game
		currentPhase = phases + 2;
	else
		//	we are in the mid-game
		currentPhase = phases + 1;


	// *** OUTPOSTS *** //

	//	outposts are minor pieces in central squares that cannot be driven off by enemy pawns.
	//	the basic output bonus is the value of the piece's square in the 'outpost' array, times
	//	the value of the piece type's 'outpost factor' (stored in 'gameInt1'.)

	//	a posted piece that is protected by one of its own pawns is extra good, so
	//	it gets 150% of the above bonus.  a posted piece protected by two of its
	//	own pawns is really, really good, because if the posted piece is captured,
	//	the player will have a protected, passed pawn.  a posted piece that is thus
	//	protected by 2 pawns gets double the standard output bonus.

	BitBoard64 bb64 = OrthodoxKnight::orthodoxKnight.GetPieces( 0 );

	//	loop through all Persian (player 0's) Knights
	while( bb64 )
	{
		int square = bb64.ExtractLSB();
		Piece *knight = board.GetSquareContents( square );

		int outpostBonus = board.GetPiecePostedBonus( 0, square, Hoplite::hoplite );
		if( outpostBonus )
		{
			//	basic bonus for player 0's posted piece
			eval += outpostBonus * knight->GetType().gameInt1;
			//	additional bonus if defended by pawn
			if( OrthodoxPawn::orthodoxPawn.GetAttackMatrix( 1, square ) & OrthodoxPawn::orthodoxPawn.GetPieces( 0 ) )
				eval += outpostBonus * knight->GetType().gameInt1;
		}
	}

	// *** Rook AND General ON OPEN FILE BONUS *** //

	BitBoard64 castlingPieces = castlingPieceTypes[0]->GetPieces( 0 );
	while( castlingPieces )
	{
		int square = castlingPieces.ExtractLSB();
		if( !(board.bb64_files[square % board.GetNumberOfFiles()] & OrthodoxPawn::orthodoxPawn.GetPieces( 0 )) )
		{
			//	file at least semi-open
			eval += 200;
			if( !(board.bb64_files[square % board.GetNumberOfFiles()] & Hoplite::hoplite.GetPieces( 1 )) )
				//	fully open file
				eval += 50;
		}
	}

	BitBoard64 generals = DragonKing::dragonKing.GetPieces( 1 );
	while( generals )
	{
		int square = generals.ExtractLSB();
		if( !(board.bb64_files[square % board.GetNumberOfFiles()] & OrthodoxPawn::orthodoxPawn.GetPieces( 0 )) )
		{
			//	file at least semi-open
			eval -= 200;
			if( !(board.bb64_files[square % board.GetNumberOfFiles()] & Hoplite::hoplite.GetPieces( 0 )) )
				//	fully open file
				eval -= 50;
		}
	}

	//	TWO-BISHOPS BONUS
	BitBoard64 colorboundPieces = OrthodoxBishop::orthodoxBishop.GetPieces( 0 );
	if( (colorboundPieces & whiteSquares) && (colorboundPieces & blackSquares) )
		eval += 500;

	//	try to keep our queens, for their viscious attack value! (ASYMMETRY)
	//	THIS HAS BEEN REMOVED.

	//	Fianchetto bishop bonus
	if( personality >= PERSONALITY_B )
	{
		if( board.GetKing( 0 )->GetSquareNumber() >= F1 &&
			board.GetKing( 0 )->GetSquareNumber() <= H1 &&
			board.GetSquareContents( G2 ) != NULL &&
			board.GetSquareContents( G2 )->GetType() == OrthodoxBishop::orthodoxBishop )
			eval += 200;
		else if( board.GetKing( 0 )->GetSquareNumber() >= A1 &&
			board.GetKing( 0 )->GetSquareNumber() <= C1 &&
			board.GetSquareContents( B2 ) != NULL &&
			board.GetSquareContents( B2 )->GetType() == OrthodoxBishop::orthodoxBishop )
			eval += 200;
	}

	return *currentPhase;
}
