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

                                 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

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


#include "StdAfx.h"
#include "../../ChessV.h"
#include "../../PieceType.h"
#include "../../Piece.h"
#include "../../Direction.h"
#include "../../Rand.h"
#include "../../GameParameters.h"
#include "UltimaGame.h"


#include "../ChessGames/Chess_Data.h"
//	this include file contains data matricies for square bonuses,
//	outpost bonuses, etc.  it also contains some macros used here.

#include "Ultima_Types.h"


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


Withdrawer Withdrawer::withdrawer;
Immobilizer Immobilizer::immobilizer;
Coordinator Coordinator::coordinator;
LongLeaper LongLeaper::longLeaper;
Chameleon Chameleon::chameleon;
UltimaKing UltimaKing::ultimaKing;
UltimaPawn UltimaPawn::ultimaPawn;


static int orthogonalDirections[4] = { DIRECTION_N, DIRECTION_S, DIRECTION_E, DIRECTION_W };


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

UltimaGame::UltimaGame( Board &board, Player &whitePlayer, Player &blackPlayer ):
	Game(board, whitePlayer, blackPlayer)
{
	// ***************************************** //
	// ***                                   *** //
	// ***  set rules and evaluation values  *** //
	// ***                                   *** //
	// ***************************************** //

	//	implement 50-move draw rule (100 half-moves)
	autoDrawPeriod = 100;

	//	turn on special Check testing.  this is necessary for 
	//	games in which the goal is to Checkmate the King, but 
	//	there are "special moves" handled by the AddSpecialMoves 
	//	function, that could attack the King.  in this case, you
	//	must set specialCheckTesting to true, and override the 
	//	IsInCheck() function.
	specialCheckTesting = true;

	//	turn off static exchange evaluation, since most 
	//	captures in this game are not generated by (and not known 
	//	to) the internal chess engine.
	useStaticExchangeEvaluation = false;

	//	no pawn structure evaluation
	usePawnStructureEvaluation = false;

	//	implement 50-move draw rule
	autoDrawPeriod = 100;

	//	turn off null-move after 24 pieces have been captured
	endgameCaptureThreshold = 24;

	//	razoring and futility pruning margins
	razorMargin = 9500;
	futilityMargin = 3000;
	extendedFutilityMargin = 6000;

	// *** PHASES *** //

	//	we have to set up the phases we wish to have in this game;
	//	we will keep it really simple and have just 2
	nPhases = 2;

	//	settings for phase 0
	phases[0].SetNumber( 0 );
	phases[0].SetMobilityFactor( 0 );
	phases[0].SetPawnDeficiencyFactor( 0 );
	phases[0].SetSquareValuesFactor( 1 );
	phases[0].SetKingSafetyFactor( 4 );
	phases[0].SetTropismFactor( 8 );

	//	settings for phase 1
	phases[0].SetNumber( 0 );
	phases[0].SetMobilityFactor( 0 );
	phases[0].SetPawnDeficiencyFactor( 0 );
	phases[0].SetSquareValuesFactor( 1 );
	phases[0].SetKingSafetyFactor( 4 );
	phases[0].SetTropismFactor( 8 );

	// *** INITIALIZATION *** //
	board.Initialize( this, BITBOARD_64 );
}

void UltimaGame::AddPlayerPieceTypes( char *gameName )
{
	//	add the piece types that each player may have
	board.AddPlayerPieceTypeBothPlayers( UltimaKing::ultimaKing );
	board.AddPlayerPieceTypeBothPlayers( Withdrawer::withdrawer );
	board.AddPlayerPieceTypeBothPlayers( Coordinator::coordinator );
	board.AddPlayerPieceTypeBothPlayers( Immobilizer::immobilizer );
	board.AddPlayerPieceTypeBothPlayers( LongLeaper::longLeaper );
	board.AddPlayerPieceTypeBothPlayers( Chameleon::chameleon );
	board.AddPlayerPieceTypeBothPlayers( UltimaPawn::ultimaPawn );
}

void UltimaGame::ChangeRulesByVariant
	( char *gameName,
	  char *&array,
	  char *&book )
{
	// *** ULTIMA *** //
	if( !strcmp( gameName, "Ultima" ) )
	{
		//	clear out all piece references
		for( int player = 0; player < 2; player++ )
		{
			withdrawers[player] = NULL;
			immobilizers[player] = NULL;
			coordinators[player] = NULL;
			for( int x = 0; x < SET_SIZE; x++ )
			{
				chameleons[player][x] = NULL;
				longLeapers[player][x] = NULL;
				pawns[player][x] = NULL;
			}
		}
		//	place pieces
		array = "clxwkxli/pppppppp/8/8/8/8/PPPPPPPP/ILXKWXLC";
		//	set name of opening book
		book = "openings\\Ultima.txt";
	}
}

Piece *UltimaGame::AddPiece
	( PieceType &pieceType,
	  int nPlayer,
	  int nRank,
	  int nFile )
{
	Piece *newPiece = Game::AddPiece( pieceType, nPlayer, nRank, nFile );

	if( pieceType == Withdrawer::withdrawer )
	{
		withdrawers[nPlayer] = newPiece;
	}
	else if( pieceType == Immobilizer::immobilizer )
	{
		immobilizers[nPlayer] = newPiece;
	}
	else if( pieceType == Coordinator::coordinator )
	{
		coordinators[nPlayer] = newPiece;
	}
	else if( pieceType == LongLeaper::longLeaper )
	{
		AddPieceToSet( newPiece, longLeapers, 2 );
	}
	else if( pieceType == Chameleon::chameleon )
	{
		AddPieceToSet( newPiece, chameleons, 2 );
	}
	else if( pieceType == UltimaPawn::ultimaPawn )
	{
		AddPieceToSet( newPiece, pawns, 8 );
	}
	return newPiece;
}

void UltimaGame::DeletePiece
	( Piece *piece )
{
	if( withdrawers[0] == piece )
		withdrawers[0] = NULL;
	if( withdrawers[1] == piece )
		withdrawers[1] = NULL;
	if( immobilizers[0] == piece )
		immobilizers[0] = NULL;
	if( immobilizers[1] == piece )
		immobilizers[1] = NULL;
	if( coordinators[0] == piece )
		coordinators[0] = NULL;
	if( coordinators[1] == piece )
		coordinators[1] = NULL;
	RemovePieceFromSet( piece, longLeapers, 2 );
	RemovePieceFromSet( piece, chameleons, 2 );
	RemovePieceFromSet( piece, pawns, 8 );
}

bool UltimaGame::IsImmobilized
	( Piece *piece )
{
	Piece *immobilizer = immobilizers[FLIP(piece->GetPlayerNumber())];
	if( immobilizer != NULL && 
		!immobilizer->IsCaptured() && 
		board.distance[immobilizer->GetSquareNumber()][piece->GetSquareNumber()] == 1 )
		//	yup, it's immobilized
		return true;

	//	if the piece is an immobilizer, we also need 
	//	to look to see if it's adjacent to an enemy Chameleon
	if( &(piece->GetType()) == &Immobilizer::immobilizer )
	{
		int otherPlayer = FLIP(piece->GetPlayerNumber());
		if( (chameleons[otherPlayer][0] != NULL &&
			!chameleons[otherPlayer][0]->IsCaptured() &&
			 board.distance[piece->GetSquareNumber()][chameleons[otherPlayer][0]->GetSquareNumber()] == 1) ||
			 (chameleons[otherPlayer][1] != NULL &&
			!chameleons[otherPlayer][1]->IsCaptured() &&
			 board.distance[piece->GetSquareNumber()][chameleons[otherPlayer][1]->GetSquareNumber()] == 1) )
			//	yes, this immobilizer is immobilized
			return true;
	}
	return false;
}

PieceType **UltimaGame::GetPieceTypesRequired
	( int &nPieceTypes )
{
	nPieceTypes = board.GetPieceTypeCount();
	return( board.GetPieceTypes() );
}

void UltimaGame::AddSpecialMoves
	( int currentPlayer, 
	  MovementList &stack, 
	  GameRec &gameRecord,
	  bool quiescentSearch )
{
	if( board.GetCurrentPlayerNumber() == 0 )
	{
		if( coordinators[0] != NULL && 
			!coordinators[0]->IsCaptured() && 
			!board.IsImmobilized( coordinators[0]->GetSquareNumber() ) )
		{
			//	generate moves for the Coordinator
			GenerateMovesForCoordinator( coordinators[0], board.GetKing( 0 ),
				stack, gameRecord, quiescentSearch );
		}
		for( int x = 0; x < 2; x++ )
		{
			if( longLeapers[0][x] != NULL && 
				!longLeapers[0][x]->IsCaptured() && 
				!board.IsImmobilized( longLeapers[0][x]->GetSquareNumber() ) )
			{
				//	generate moves for the Long Leaper
				GenerateMovesForLongLeaper( longLeapers[0][x], 
					stack, gameRecord, quiescentSearch );
			}
			if( chameleons[0][x] != NULL && 
				!chameleons[0][x]->IsCaptured() && 
				!board.IsImmobilized( chameleons[0][x]->GetSquareNumber() ) )
			{
				//	generate moves for the Chameleon
				GenerateMovesForChameleon( chameleons[0][x], board.GetKing( 0 ),
					stack, gameRecord, quiescentSearch );
			}
		}
		for( int x = 0; x < 8; x++ )
		{
			if( pawns[0][x] != NULL && 
				!pawns[0][x]->IsCaptured() && 
				!board.IsImmobilized( pawns[0][x]->GetSquareNumber() ) )
			{
				//	generate moves for the Ultima Pawn
				GenerateMovesForUltimaPawn( pawns[0][x], 
					stack, gameRecord, quiescentSearch );
			}
		}
	}
	else
	{
		if( coordinators[1] != NULL && 
			!coordinators[1]->IsCaptured() && 
			!board.IsImmobilized( coordinators[1]->GetSquareNumber() ) )
		{
			//	generate moves for the Coordinator
			GenerateMovesForCoordinator( coordinators[1], board.GetKing( 1 ),
				stack, gameRecord, quiescentSearch );
		}
		for( int x = 0; x < 2; x++ )
		{
			if( longLeapers[1][x] != NULL && 
				!longLeapers[1][x]->IsCaptured() && 
				!board.IsImmobilized( longLeapers[1][x]->GetSquareNumber() ) )
			{
				//	generate moves for the Long Leaper
				GenerateMovesForLongLeaper( longLeapers[1][x], 
					stack, gameRecord, quiescentSearch );
			}
			if( chameleons[1][x] != NULL && 
				!chameleons[1][x]->IsCaptured() && 
				!board.IsImmobilized( chameleons[1][x]->GetSquareNumber() ) )
			{
				//	generate moves for the Chameleon
				GenerateMovesForChameleon( chameleons[1][x], board.GetKing( 1 ),
					stack, gameRecord, quiescentSearch );
			}
		}
		for( int x = 0; x < 8; x++ )
		{
			if( pawns[1][x] != NULL && 
				!pawns[1][x]->IsCaptured() && 
				!board.IsImmobilized( pawns[1][x]->GetSquareNumber() ) )
			{
				//	generate moves for the Ultima Pawns
				GenerateMovesForUltimaPawn( pawns[1][x], 
					stack, gameRecord, quiescentSearch );
			}
		}
	}
}

bool UltimaGame::MoveBeingMade
	( MoveInfo &moveInfo,
	  GameRec &gameRecord )
{
	// *** UPDATE gameInt1 *** //

	//	gameInt1 is a 'user' field in the game records that a game can use
	//	for any purpose.  we will use it to track the forward progress of 
	//	the game, so we can determine which Phase we are in ('opening', 
	//	and 'rest-of-game' in our case)

	if( gameRecord.gameInt1 < 20 )
	{
		//	we are in the opening until gameInt1 reaches 20;
		//	in the opening, we increment gameInt1 for the following moves:
		//		- any capture
		//		- the first move of any piece
		if( moveInfo.type != StandardMove || 
			(moveInfo.pPieceMoved->GetFlags() & FLAGS_HAS_MOVED_MASK) == FLAGS_HAS_MOVED )
			gameRecord.gameInt1++;
	}

	return true;
}

int UltimaGame::TranslateMove
	( MovementList &stack,
	  char *notation )
{
	//	check for suicide move - i.e., immobilized 
	//	pieces killing themselves
	if( notation[0] == '!' )
	{
		int square = board.GetFileByChar( notation[1] ) + 
			board.GetRankByChar( notation[2] ) * board.GetNumberOfFiles();
		for( int x = 0; x < stack.GetCount(); x++ )
		{
			MoveInfo &move = stack.GetMove( x );
			if( move.type == SuicideMove && 
				move.fromSquare == square )
			{
				return x;
			}
		}
		//	suicide move not found ... bad move
		return -1;
	}

	//	all other moves are handled by the default
	//	Game::TranslateMove function
	return( Game::TranslateMove( stack, notation ) );
}


Phase &UltimaGame::AdjustEvaluation
	( int &eval,
	  PawnHash *pPawnHash )
{
	Phase *currentPhase = phases;
	if( board.GetCurrentGameRecord().gameInt1 < 20 )
	{
		// *** The OPENING *** //

		//	in the opening, we give a bonus for the first move of any piece, 
		//	and a penalty for moving any piece twice, and an even larger penalty 
		//	for moving a piece three times.

		//	use this "factor" to scale down the adjustments to be applied here, 
		//	so that the adjustments become smaller and smaller as we leave the 
		//	opening and enter the mid-game
		int factor = MAX(board.GetCurrentGameRecord().gameInt1 - 10, 0);
		int factor6 = 640 - (factor << 6);
		int factor5 = 320 - (factor << 5);

		for( int x = 0; x < board.GetNumberOfPieces( 0 ); x++ )
		{
			Piece *piece = board.GetPiece( 0, x );
			if( !piece->IsCaptured() )
			{
				switch( piece->GetFlags() & FLAGS_HAS_MOVED_MASK )
				{
				  case FLAGS_HAS_MOVED:
					eval += factor5;
					break;
				  case FLAGS_HAS_MOVED | FLAGS_HAS_MOVED_TWICE:
					eval -= factor5;
					break;
				  case FLAGS_HAS_MOVED | FLAGS_HAS_MOVED_TWICE | FLAGS_HAS_MOVED_THREE_TIMES:
					eval -= factor6;
				}
			}
		}
		for( int x = 0; x < board.GetNumberOfPieces( 1 ); x++ )
		{
			Piece *piece = board.GetPiece( 1, x );
			if( !piece->IsCaptured() )
			{
				switch( piece->GetFlags() & FLAGS_HAS_MOVED_MASK )
				{
				  case FLAGS_HAS_MOVED:
					eval -= factor5;
					break;
				  case FLAGS_HAS_MOVED | FLAGS_HAS_MOVED_TWICE:
					eval += factor5;
					break;
				  case FLAGS_HAS_MOVED | FLAGS_HAS_MOVED_TWICE | FLAGS_HAS_MOVED_THREE_TIMES:
					eval += factor6;
				}
			}
		}
	}
	else
		currentPhase = phases + 1;


	// *** The IMMOBILIZER *** //

	//	we need to adjust the values for all immobilized pieces.
	//	all immobilized pieces lose 25% of their value, and Kings 
	//	are assessed a flat penalty of -2500.

	Piece *immobilizer = immobilizers[0];
	if( immobilizer != NULL && 
		!immobilizer->IsCaptured() )
	{
		for( int x = 0; x < 8; x++ )
		{
			int square = board.GetMovementMatrix( x )[immobilizer->GetSquareNumber()];
			if( square >= 0 &&
				board.GetSquareContents( square ) != NULL )
			{
				Piece *pieceOnSquare = board.GetSquareContents( square );
				if( pieceOnSquare->GetPlayerNumber() == 1 )
				{
					eval += pieceOnSquare->GetBaseValue() >> 2;
					if( &(pieceOnSquare->GetType()) == &Chameleon::chameleon )
						eval -= immobilizer->GetBaseValue() >> 2;
				}
			}
		}
	}
	immobilizer = immobilizers[1];
	if( immobilizer != NULL && 
		!immobilizer->IsCaptured() )
	{
		for( int x = 0; x < 8; x++ )
		{
			int square = board.GetMovementMatrix( x )[immobilizer->GetSquareNumber()];
			if( square >= 0 &&
				board.GetSquareContents( square ) != NULL )
			{
				Piece *pieceOnSquare = board.GetSquareContents( square );
				if( pieceOnSquare->GetPlayerNumber() == 0 )
				{
					eval -= pieceOnSquare->GetBaseValue() >> 2;
					if( &(pieceOnSquare->GetType()) == &Chameleon::chameleon )
						eval += immobilizer->GetBaseValue() >> 2;
				}
			}
		}
	}


	// *** The WITHDRAWER *** //

	//	give the withdrawer a bonus proportional to the value of 
	//	the most powerful enemy piece it stands adjacent to, provided 
	//	that there is at least one square in the opposite direction
	//	for the withdrawer to (eventually) move to.

	//	also, penalize the withdrawer if a Chameleon stands next to it,
	//	and there is at least one square away for it to move it.

	Piece *piece = withdrawers[0];
	int nSquare = piece->GetSquareNumber();
	if( piece != NULL && !piece->IsCaptured() )
	{
		int maxEnemyValue = 0;
		int nEnemyChameleons = 0;
		for( int x = 0; x < 8; x++ )
		{
			Direction &direction = board.GetDirection( x );
			int oppositeDirection = direction.GetOppositeDirectionNumber();
			int *movementMatrix = board.GetMovementMatrix( x );

			if( movementMatrix[nSquare] != -1 && 
				board.GetSquareContents( movementMatrix[nSquare] ) != NULL && 
				board.GetSquareContents( movementMatrix[nSquare] )->GetPlayerNumber() == 1 && 
				board.GetSquareContents( movementMatrix[nSquare] )->GetBaseValue() > maxEnemyValue &&
				board.GetMovementMatrix( oppositeDirection )[nSquare] != -1 )
				//	this is the most valuable adjacent enemy found so far
				maxEnemyValue = board.GetSquareContents( movementMatrix[nSquare] )->GetBaseValue();

			if( movementMatrix[nSquare] != -1 && 
				board.GetSquareContents( movementMatrix[nSquare] ) != NULL && 
				board.GetSquareContents( movementMatrix[nSquare] )->GetPlayerNumber() == 1 && 
				&(board.GetSquareContents( movementMatrix[nSquare] )->GetType()) == &Chameleon::chameleon &&
				movementMatrix[movementMatrix[nSquare]] != -1 )
				//	adjacent enemy Chameleon with room to move away
				nEnemyChameleons++;
		}
		eval += maxEnemyValue >> 4;
		eval -= nEnemyChameleons << 8;
	}
	piece = withdrawers[1];
	nSquare = piece->GetSquareNumber();
	if( piece != NULL && !piece->IsCaptured() )
	{
		int maxEnemyValue = 0;
		int nEnemyChameleons = 0;
		for( int x = 0; x < 8; x++ )
		{
			Direction &direction = board.GetDirection( x );
			int oppositeDirection = direction.GetOppositeDirectionNumber();
			int *movementMatrix = board.GetMovementMatrix( x );

			if( movementMatrix[nSquare] != -1 && 
				board.GetSquareContents( movementMatrix[nSquare] ) != NULL && 
				board.GetSquareContents( movementMatrix[nSquare] )->GetPlayerNumber() == 0 && 
				board.GetSquareContents( movementMatrix[nSquare] )->GetBaseValue() > maxEnemyValue && 
				board.GetMovementMatrix( oppositeDirection )[nSquare] != -1 )
				//	this is the most valuable adjacent enemy found so far
				maxEnemyValue = board.GetSquareContents( movementMatrix[nSquare] )->GetBaseValue();

			if( movementMatrix[nSquare] != -1 && 
				board.GetSquareContents( movementMatrix[nSquare] ) != NULL && 
				board.GetSquareContents( movementMatrix[nSquare] )->GetPlayerNumber() == 0 && 
				&(board.GetSquareContents( movementMatrix[nSquare] )->GetType()) == &Chameleon::chameleon &&
				movementMatrix[movementMatrix[nSquare]] != -1 )
				//	adjacent enemy Chameleon with room to move away
				nEnemyChameleons++;
		}
		eval -= maxEnemyValue >> 4;
		eval += nEnemyChameleons << 8;
	}


	// *** The COORDINATOR *** //

	//	the coordinator gets a bonus proportional to the number of  
	//	enemy pieces on the same rank or file as the coordinator's King

	if( coordinators[0] != NULL && !coordinators[0]->IsCaptured() )
	{
		piece = board.GetKing( 0 );
		int nEnemies = 0;
		for( int x = 0; x < 4; x++ )
		{
			int *movementMatrix = board.GetMovementMatrix( orthogonalDirections[x] );
			int nSquare = movementMatrix[piece->GetSquareNumber()];

			while( nSquare >= 0 )
			{
				if( board.GetSquareContents( nSquare ) != NULL && 
					board.GetSquareContents( nSquare )->GetPlayerNumber() == 1 )
					//	another coordinatable enemy piece
					nEnemies++;
				nSquare = movementMatrix[nSquare];
			}
		}
		eval += nEnemies << 6;
	}
	if( coordinators[1] != NULL && !coordinators[1]->IsCaptured() )
	{
		piece = board.GetKing( 1 );
		int nEnemies = 0;
		for( int x = 0; x < 4; x++ )
		{
			int *movementMatrix = board.GetMovementMatrix( orthogonalDirections[x] );
			int nSquare = movementMatrix[piece->GetSquareNumber()];

			while( nSquare >= 0 )
			{
				if( board.GetSquareContents( nSquare ) != NULL && 
					board.GetSquareContents( nSquare )->GetPlayerNumber() == 0 )
					//	another coordinatable enemy piece
					nEnemies++;
				nSquare = movementMatrix[nSquare];
			}
		}
		eval -= nEnemies << 6;
	}


	// *** The CHAMELEON *** //

	//	the chameleon gets a number of different (small) bonuses.  it gets
	//	a bonus for being adjacent to an enemy Withdrawer, with at least 
	//	one square in the opposite direction (not necessarily empty.)  this 
	//	bonus is already assessed above, in the Withdrawer loop.

	//	the chameleon also gets a bonus when the enemy coordinator is on 
	//	the same rank or file as the friendly king, making it coordinat-able.

	if( coordinators[1] != NULL && !coordinators[1]->IsCaptured() && 
		(board.files[0][coordinators[1]->GetSquareNumber()] == board.files[0][board.GetKing( 0 )->GetSquareNumber()] ||
		 board.ranks[0][coordinators[1]->GetSquareNumber()] == board.ranks[0][board.GetKing( 0 )->GetSquareNumber()]) )
	{
		if( chameleons[0][0] != NULL && !chameleons[0][0]->IsCaptured() )
			eval += 50;
		if( chameleons[0][1] != NULL && !chameleons[0][1]->IsCaptured() )
			eval += 50;
	}
	if( coordinators[0] != NULL && !coordinators[0]->IsCaptured() && 
		(board.files[0][coordinators[0]->GetSquareNumber()] == board.files[0][board.GetKing( 1 )->GetSquareNumber()] ||
		 board.ranks[0][coordinators[0]->GetSquareNumber()] == board.ranks[0][board.GetKing( 1 )->GetSquareNumber()]) )
	{
		if( chameleons[1][0] != NULL && !chameleons[1][0]->IsCaptured() )
			eval -= 50;
		if( chameleons[1][1] != NULL && !chameleons[1][1]->IsCaptured() )
			eval -= 50;
	}


	// *** The KING *** //

	//	we need to give the King a big penalty for being immobilized. 
	//	we don't need to do this for other pieces, because they all 
	//	lose 25% of their value when immobilized.  the King, however, 
	//	has a value of zero, so it loses nothing.  we will correct this 
	//	here, by giving it a flat -2500 penalty for being immobilized.

	if( IsImmobilized( board.GetKing( 0 ) ) )
		eval -= 2500;
	if( IsImmobilized( board.GetKing( 1 ) ) )
		eval += 2500;


	return *currentPhase;
}

bool UltimaGame::IsInCheck
	( Piece *king )
{
	int squareNumber = king->GetSquareNumber();
	int playerNumber = FLIP(king->GetPlayerNumber());

	for( int x = 0; x < 8; x++ )
	{
		int square = board.GetMovementMatrix( x )[squareNumber];
		Direction &direction = board.GetDirection( x );
		int oppositeDirection = direction.GetOppositeDirectionNumber();

		if( square >= 0 )
		{
			Piece *piece = board.GetSquareContents( square );
			square = board.GetMovementMatrix( x )[square];
			if( piece != NULL )
			{
				if( piece->GetPlayerNumber() == playerNumber )
				{
					if( &(piece->GetType()) == &Chameleon::chameleon || 
						&(piece->GetType()) == &UltimaKing::ultimaKing )
					{
						if( !IsImmobilized( piece ) )
							//	king is in check
							return true;
					}
					else if( &(piece->GetType()) == &Withdrawer::withdrawer )
					{
						//	king is in check, but only if the withdrawer can
						//	move at least one square in this direction
						if( square != -1 && board.GetSquareContents( square ) == NULL && 
							!IsImmobilized( piece ) )
							//	king is in check
							return true;
					}
					else if( &(piece->GetType()) == &LongLeaper::longLeaper )
					{
						if( board.GetMovementMatrix( oppositeDirection )[squareNumber] != -1 && 
							board.GetSquareContents( board.GetMovementMatrix( oppositeDirection )[squareNumber] ) == NULL && 
							!IsImmobilized( piece ) )
							//	attacked by this Long Leaper
							return true;
					}
					//	extra detection for pincer pawns in orthogonal directions...
					if( x == DIRECTION_N || x == DIRECTION_S || x == DIRECTION_E || x == DIRECTION_W )
					{
						//	since an enemy piece occupies an orthogonally adjacent 
						//	square to the king, we need to see if an enemy pincer pawn 
						//	can move to the opposite square; if one can, then we are 
						//	in check, becuase we can be "pinched".
						int oppositeSquareNumber = board.GetMovementMatrix( oppositeDirection )[squareNumber];
						if( oppositeSquareNumber != -1 && board.GetSquareContents( oppositeSquareNumber  ) == NULL )
						{
							for( int y = 0; y < 4; y++ )
							{
								int *newMovementMatrix = board.GetMovementMatrix( orthogonalDirections[y] );
								int searchSquareNumber = newMovementMatrix[oppositeSquareNumber];

								while( searchSquareNumber != -1 )
								{
									if( board.GetSquareContents( searchSquareNumber ) != NULL )
									{
										if( &(board.GetSquareContents( searchSquareNumber )->GetType()) == &UltimaPawn::ultimaPawn &&
											board.GetSquareContents( searchSquareNumber )->GetPlayerNumber() == playerNumber && 
											!IsImmobilized( board.GetSquareContents( searchSquareNumber ) ) )
											//	king is in check
											return true;
										else
											//	hit obstacle; search no further in this direction
											searchSquareNumber = -1;
									}
									else
										searchSquareNumber = newMovementMatrix[searchSquareNumber];
								}
							}
						}
					}
				}
				square = -1;
			}
		}

		//	now that we are past the first "step" (which is the trickiest), 
		//	we need to keep stepping, but we only need to look for attacks 
		//	from Long Leapers at this point.  the only other thing that we 
		//	could be attacked by is a Coordinator, and we will look for that 
		//	attack later (seperately.)
		//	also, before we keep stepping, looking for a Long Leaper attack,
		//	we should check the square on the opposite of the King first; if 
		//	it is not vacant, then the King cannot be threatened by any Long 
		//	Leaper in this direction, as the Leaper cannot jump adjacent pieces
		if( board.GetMovementMatrix( oppositeDirection )[squareNumber] != -1 && 
			board.GetSquareContents( board.GetMovementMatrix( oppositeDirection )[squareNumber] ) == NULL )
		{
			while( square >= 0 )
			{
				Piece *piece = board.GetSquareContents( square );
				square = board.GetMovementMatrix( x )[square];
				if( piece != NULL )
				{
					if( piece->GetPlayerNumber() == playerNumber )
					{
						if( &(piece->GetType()) == &LongLeaper::longLeaper )
						{
							if( !IsImmobilized( piece ) )
								//	the King is in Check, because it's under
								//	attack from this Long Leaper
								return true;
							else
								//	we need look no further in this direction, as 
								//	the Long Leaper can't jump a piece of the same color
								square = -1;
						}
						else
							//	we need look no further in this direction, as 
							//	the Long Leaper can't jump a piece of the same color
							square = -1;
					}
					else
					{
						//	take a peek beyond; if that square is occupied, we need 
						//	look no further, because the Long Leaper cannot ever jump 
						//	two adjacent pieces
						if( square != -1 && board.GetSquareContents( square ) != NULL )
						{
							Piece *pieceOnSquare = board.GetSquareContents( square );
							if( &(pieceOnSquare->GetType()) == &LongLeaper::longLeaper &&
								pieceOnSquare->GetPlayerNumber() == playerNumber )
								//	we are attacked by this Long Leaper
								return true;
							else
								//	adjacent pieces; look no further
								square = -1;
						}
					}
				}
			}
		}
	}

	//	now, we look for attacks from the Coordinator; we do this seperately 
	//	because it is the most efficient way.  Check-testing for Coordinator 
	//	attacks is particularly expensive.  

	if( board.ranks[0][board.GetKing( 0 )->GetSquareNumber()] == 
		board.ranks[0][board.GetKing( 1 )->GetSquareNumber()] )
	{
		//	if the kings are on the same rank, then the king is in check if a coordinator 
		//	of the opposite color can move to the same file
		int targetFile = board.files[0][king->GetSquareNumber()];
		Piece *coordinator = coordinators[playerNumber];
		int nDirections = 3;
		if( coordinator != NULL && !coordinator->IsCaptured() && 
			!IsImmobilized( coordinator ) )
		{
			//	potential attacker - see if it can get there
			int directions[3];
			//	assume move to left, correct later if to right
			directions[0] = DIRECTION_NW;
			directions[1] = DIRECTION_W;
			directions[2] = DIRECTION_SW;
			if( targetFile > board.files[0][coordinator->GetSquareNumber()] )
			{
				//	need to move right to reach target file
				directions[0] = DIRECTION_NE;
				directions[1] = DIRECTION_E;
				directions[2] = DIRECTION_SE;
			}
			else if( targetFile == board.files[0][coordinator->GetSquareNumber()] )
			{
				directions[0] = DIRECTION_N;
				directions[1] = DIRECTION_S;
				nDirections = 2;
			}

			//	now step in each direction until we reach target file, 
			//	or until we hit an obstacle
			for( int y = 0; y < nDirections; y++ )
			{
				int nSquare = board.GetMovementMatrix( directions[y] )[coordinator->GetSquareNumber()];
				while( board.GetSquareContents( nSquare ) == NULL )
				{
					if( board.files[0][nSquare] == targetFile )
						//	yup, we are in check!
						return true;
					nSquare = board.GetMovementMatrix( directions[y] )[nSquare];
				}
			}
		}
	}
	if( board.files[0][board.GetKing( 0 )->GetSquareNumber()] == 
		board.files[0][board.GetKing( 1 )->GetSquareNumber()] )
	{
		//	if the kings are on the same file, then the king is in check if a coordinator 
		//	of the opposite color can move to the same rank
		int targetRank = board.ranks[0][king->GetSquareNumber()];
		Piece *coordinator = coordinators[playerNumber];
		int nDirections = 3;
		if( coordinator != NULL && !coordinator->IsCaptured() && 
			!IsImmobilized( coordinator ) )
		{
			//	potential attacker - see if it can get there
			int directions[3];
			//	assume move to north, correct later if to south
			directions[0] = DIRECTION_NE;
			directions[1] = DIRECTION_N;
			directions[2] = DIRECTION_NW;
			if( targetRank < board.ranks[0][coordinator->GetSquareNumber()] )
			{
				//	need to move right to reach target file
				directions[0] = DIRECTION_SE;
				directions[1] = DIRECTION_S;
				directions[2] = DIRECTION_SW;
			}
			else if( targetRank == board.ranks[0][coordinator->GetSquareNumber()] )
			{
				directions[0] = DIRECTION_E;
				directions[1] = DIRECTION_W;
				nDirections = 2;
			}
			//	now step in each direction until we reach target file, 
			//	or until we hit an obstacle
			for( int y = 0; y < nDirections; y++ )
			{
				int nSquare = board.GetMovementMatrix( directions[y] )[coordinator->GetSquareNumber()];
				while( board.GetSquareContents( nSquare ) == NULL )
				{
					if( board.ranks[0][nSquare] == targetRank )
						//	yup, we are in check!
						return true;
					nSquare = board.GetMovementMatrix( directions[y] )[nSquare];
				}
			}
		}
	}

	//	King not under attack
	return false;
}

void UltimaGame::AboutToGenerateMoves
	( int currentPlayer, 
	  int currentDepth )
{
	//	we need to setup the immobilizedSquares Matrix, 
	//	so that  move generation will not occur for 
	//	pieces on immobilized squares

	int (*immobilizedSquares)[MAX_DEPTH][MAX_SQUARES];
	board.GetImmobilizedMatrix( &immobilizedSquares );

	//	first, clear out the immobilizedSquares
	memset( (*immobilizedSquares)[currentDepth], 0, 64 * sizeof(int) );

	//	find the enemy immobilizer
	Piece *piece = immobilizers[FLIP(currentPlayer)];
	if( !piece->IsCaptured() )
	{
		for( int dir = 0; dir < 8; dir++ )
		{
			int square = board.GetMovementMatrix( dir )[piece->GetSquareNumber()];
			if( square >= 0 )
			{
				//	adjacent to enemy immobilizer - immobilize square
				(*immobilizedSquares)[currentDepth][square] += 1;
			}
		}
	}

	//	we also need to look at the squares adjacent to our own 
	//	immobilizer, to see if they contain an enemy Chameleon.  
	//	if it does, then we need to immobilize the Immobilizer as well.
	piece = immobilizers[currentPlayer];
	if( !piece->IsCaptured() )
	{
		for( int dir = 0; dir < 8; dir++ )
		{
			int square = board.GetMovementMatrix( dir )[piece->GetSquareNumber()];
			if( square >= 0 )
			{
				if( board.GetSquareContents( square ) != NULL && 
					board.GetSquareContents( square )->GetPlayerNumber() != currentPlayer &&
					&(board.GetSquareContents( square )->GetType()) == &Chameleon::chameleon )
				{
					//	adjacent to enemy Chameleon - immobilize Immobilizer
					(*immobilizedSquares)[currentDepth][piece->GetSquareNumber()] += 1;
				}
			}
		}
	}
}

void UltimaGame::AboutToStartThinking
	( int currentPlayer )
{
/*	board.ClearTranspositionTable();
	board.RecalculateMaterial();
	useQuiescentSearch = true;
	useStaticExchangeEvaluation = false;
	if( currentPlayer == 0 )
	{
		UltimaPawn::ultimaPawn.SetBaseValue( 1250 );
	}
	else
	{
		UltimaPawn::ultimaPawn.SetBaseValue( 1000 );
	}*/
}

