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

                                 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 "../../boards/DecimalBoardWithRiver.h"
#include "EurasianChessGame.h"
#include "Decimal_Types.h"

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


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


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

void StartEurasianChessGame()
{
	if( !justLoaded )
		int rtn = (int) ::DialogBox( theInstance, MAKEINTRESOURCE(IDD_EURASIAN_CHESS_DIALOG), NULL, 
			reinterpret_cast<DLGPROC>(Generic_SelectDlgProc) );

	theBoard = new DecimalBoardWithRiver();
	char *player0Name = "White";
	char *player1Name = "Black";
	LookupStringParameter( "player1", player0Name );
	LookupStringParameter( "player2", player1Name );
	CreatePlayers( player0Name, player1Name, whiteComp, blackComp );

	strcpy( gameSelection, "Eurasian Chess" );
}

EurasianChessGame::EurasianChessGame( 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 the 
	//	the static exchange evaluator cannot handle the 
	//	cannon-type pieces
	useStaticExchangeEvaluation = false;

	//	turn on use of pawn structure evaluation
	usePawnStructureEvaluation = true;

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

	//	razoring and futility pruning margins
	razorMargin = 9500;
	futilityMargin = 3500;
	extendedFutilityMargin = 6750;


	// *** PHASES *** //

	//	we have to set up the phases we wish to have in this game;
	//	we will keep it simple and have 3: opening, midgame, and endgame
	nPhases = 3;

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

	//	settings for phase 1 (midgame)
	phases[1].SetNumber( 1 );
	phases[1].SetMobilityFactor( 0 );
	phases[1].SetPawnDeficiencyFactor( 10 );
	phases[1].SetSquareValuesFactor( 1 );
	phases[1].SetKingSafetyFactor( 8 );
	phases[1].SetTropismFactor( 10 );
	
	//	settings for phase 2 (endgame)
	phases[2].SetNumber( 2 );
	phases[2].SetMobilityFactor( 0 );
	phases[2].SetPawnDeficiencyFactor( 16 );
	phases[2].SetSquareValuesFactor( 1 );
	phases[2].SetKingSafetyFactor( 0 );
	phases[2].SetTropismFactor( 10 );

	// *** OUTPOSTS *** //

	//	we wish to be able to give bonuses to pieces that are 'posted'-
	//	that is, which are centrally located and cannot be reached by
	//	enemy pawns (because adjacent pawns are gone, or have advanced
	//	beyond the piece).  we also wish to be able to give different
	//	bonuses for different types of minor pieces (a posted Knight is
	//	worth more than a posted Bishop.)

	//	we will use the user variable 'gameInt1' in the PieceType class
	//	to store the 'outpost factor' for a given piece.  this value will
	//	be multiplied by the square-values stored in the 'outpost' array.
	DecimalKnight::decimalKnight.gameInt1 = 10;
	DecimalBishop::decimalBishop.gameInt1 = 7;

	// *** INITIALIZATION *** //

	//	initialize hashes
	enPassantHashMap = new HashMap( board.GetNumberOfSquares() );

	//	basic initialization
	board.Initialize( this, BITBOARD_128 );
}

void EurasianChessGame::AddPlayerPieceTypes( char *gameName )
{
	//	add the piece types that each player may have
	board.AddPlayerPieceTypeBothPlayers( DecimalRook::decimalRook );
	board.AddPlayerPieceTypeBothPlayers( DecimalBishop::decimalBishop );
	board.AddPlayerPieceTypeBothPlayers( DecimalKnight::decimalKnight);
	board.AddPlayerPieceTypeBothPlayers( DecimalQueen::decimalQueen );
	board.AddPlayerPieceTypeBothPlayers( DecimalKing::decimalKing );
	board.AddPlayerPieceTypeBothPlayers( GrandChessPawn::grandChessPawn );
	board.AddPlayerPieceTypeBothPlayers( DecimalCannon::decimalCannon );
	board.AddPlayerPieceTypeBothPlayers( DecimalVao::decimalVao );
	//	update piece values
	DecimalBishop::decimalBishop.SetBaseValue( 3500 );
	DecimalKnight::decimalKnight.SetBaseValue( 3000 );
	DecimalQueen::decimalQueen.SetBaseValue( 8600 );
	//	update piece-square-tables
	DecimalRook::decimalRook.SetSquareBonuses( 0, gcOpeningRookSquareBonuses_10x10 );
	DecimalBishop::decimalBishop.SetSquareBonuses( 0, gcOpeningBishopSquareBonuses_10x10 );
}

void EurasianChessGame::ChangeRulesByVariant
	( char *gameName,
	  char *&array,
	  char *&book )
{
	//	place pieces
	array = "r1c4c1r/1nbvqkvbn1/pppppppppp/40/40/40/40/PPPPPPPPPP/1NBVQKVBN1/R1C4C1R";
	//	set name of opening book
	book = "openings\\EurasianChess.txt";
}

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

	if( pieceType.IsPawn() )
	{
		if( newPiece->GetPlayerNumber() == 0 )
			newPiece->GetPromotionZone().AddToZone( 70, 99 );
		else
			newPiece->GetPromotionZone().AddToZone( 0, 29 );
	}

	return newPiece;
}

void EurasianChessGame::AddSpecialMoves
	( int currentPlayer, 
	  MovementList &list, 
	  GameRec &gameRecord, 
	  bool quiescentSearch )
{
	// *** CANNON moves *** //
	BitBoard128 cannons = DecimalCannon::decimalCannon.GetPieces( currentPlayer );
	while( cannons )
	{
		int square = cannons.GetFirstBit();
		cannons.ClearBit( square );
		int directions[4] = { DIRECTION_N, DIRECTION_S, DIRECTION_E, DIRECTION_W };
		for( int x = 0; x < 4; x++ )
		{
			GenerateMovesForCannon( square, currentPlayer, list, gameRecord, quiescentSearch, directions[x] );
		}
	}

	// *** VAO moves *** //
	BitBoard128 vaos = DecimalVao::decimalVao.GetPieces( currentPlayer );
	while( vaos )
	{
		int square = vaos.GetFirstBit();
		vaos.ClearBit( square );
		int directions[4] = { DIRECTION_NE, DIRECTION_NW, DIRECTION_SE, DIRECTION_SW };
		for( int x = 0; x < 4; x++ )
		{
			GenerateMovesForCannon( square, currentPlayer, list, gameRecord, quiescentSearch, directions[x] );
		}
	}

	//	check for en-passant
	Game::AddEnPassantMoves( list, gameRecord, quiescentSearch );
}

bool EurasianChessGame::MoveBeingMade
	( MoveInfo &moveInfo,
	  GameRec &gameRecord )
{
	// *** ILLEGAL MOVES *** //

	//	the King cannot cross the river
	if( moveInfo.pPieceMoved->GetType().IsRoyal() )
		if( board.ranks[moveInfo.pPieceMoved->GetPlayerNumber()]
			[moveInfo.pPieceMoved->GetSquareNumber()] >= 5 )
			//	this King is trying to cross the river ...
			return false;

	//	the two Kings cannot 'see' each other on an open file or diagonal
	BitBoard128 ray = board.bb128_rays[board.GetKing( 0 )->GetSquareNumber() * 
		board.GetNumberOfSquares() + board.GetKing( 1 )->GetSquareNumber()];
	if( ray )
	{
		ray.ClearBit( board.GetKing( 1 )->GetSquareNumber() );
		//	the pieces are on the same file or diagonal; now check 
		//	to see if any piece is blocking them
		if( !(ray & board.BB128_GetBlockers()) )
			//	nothing is blocking; move is illegal
			return false;
	}


	// *** 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', 
	//	'midgame', or 'endgame' in our case)

	if( gameRecord.gameInt1 < 15 )
	{
		//	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
		//		- any pawn push to rank 5+ (code value of 4+)
		if( gameRecord.materialCaptured > 0 ||
			(gameRecord.pieceMoved->GetFlags() & (FLAGS_HAS_MOVED | FLAGS_HAS_MOVED_TWICE)) == FLAGS_HAS_MOVED ||
			(gameRecord.pieceMoved->IsPawn() && 
				board.ranks[gameRecord.pieceMoved->GetPlayerNumber()][gameRecord.pieceMoved->GetSquareNumber()] >= 4) )
			gameRecord.gameInt1++;
	}

	return true;
}

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

	if( board.GetCurrentGameRecord().gameInt1 < 15 )
	{
		// *** The OPENING *** //

		//	in the opening we consider the following things:
		//		- give bonus for developing the knights
		//		- penalize the queen, unicorn(s), and lions for moving early
		//		- give a bonus for castling; give a penalty for losing the ability to castle
		//		- give a penalty for moving pieces twice, and a bigger penalty for moving 3 times
		//		- penalize the blocking of center pawns

		//	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) * 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);   //   / 

		//	give a penalty for moving major pieces (queens)
		BitBoard128 majors = DecimalQueen::decimalQueen.GetPieces( 0 );
		if( majors )
		{
			int square = majors.GetFirstBit();
			if( board.GetSquareContents( square )->GetFlags() & FLAGS_HAS_MOVED )
				eval -= factor6;
		}
		majors = DecimalQueen::decimalQueen.GetPieces( 1 );
		if( majors )
		{
			int square = majors.GetFirstBit();
			if( board.GetSquareContents( square )->GetFlags() & FLAGS_HAS_MOVED )
				eval += factor6;
		}

		if( testingPosition || maxThinkTime >= 100000 )
			eval += PenalizePiecesForMovingMultipleTimes();

		// *** DON'T BLOCK CENTER PAWNS IN OPENING *** //
		if( board.GetSquareContents( 34 ) != NULL &&
			board.GetSquareContents( 24 ) != NULL &&
			!board.GetSquareContents( 24 )->HasMoved() )
			eval -= factor5;
		if( board.GetSquareContents( 35 ) != NULL &&
			board.GetSquareContents( 25 ) != NULL &&
			!board.GetSquareContents( 25 )->HasMoved() )
			eval -= factor5;
		if( board.GetSquareContents( 33 ) != NULL &&
			board.GetSquareContents( 23 ) != NULL &&
			!board.GetSquareContents( 23 )->HasMoved() )
			eval -= factor5;
		if( board.GetSquareContents( 36 ) != NULL &&
			board.GetSquareContents( 26 ) != NULL &&
			!board.GetSquareContents( 26 )->HasMoved() )
			eval -= factor5;

		if( board.GetSquareContents( 64 ) != NULL &&
			board.GetSquareContents( 74 ) != NULL &&
			!board.GetSquareContents( 74 )->HasMoved() )
			eval += factor5;
		if( board.GetSquareContents( 65 ) != NULL &&
			board.GetSquareContents( 75 ) != NULL &&
			!board.GetSquareContents( 75 )->HasMoved() )
			eval += factor5;
		if( board.GetSquareContents( 63 ) != NULL &&
			board.GetSquareContents( 73 ) != NULL &&
			!board.GetSquareContents( 73 )->HasMoved() )
			eval += factor5;
		if( board.GetSquareContents( 66 ) != NULL &&
			board.GetSquareContents( 76 ) != NULL &&
			!board.GetSquareContents( 76 )->HasMoved() )
			eval += factor5;
	}
	else if( board.GetNumberOfCapturedPieces() > 32 ||
		board.GetMaterial( 0 ) - board.GetPawnMaterial( 0 ) + 
		board.GetMaterial( 1 ) - board.GetPawnMaterial( 1 ) < 20000 )
		//	we are in the end-game
		currentPhase = phases + 2;
	else
		//	we are in the mid-game
		currentPhase = phases + 1;

	if( pPawnHash != NULL )
	{
		// *** 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.

		//	loop through all postable pieces
		BitBoard128 minors;
		minors = DecimalBishop::decimalBishop.GetPieces( 0 ) | 
			DecimalKnight::decimalKnight.GetPieces( 0 );
		while( minors )
		{
			int square = minors.GetFirstBit();
			minors.ToggleBit( square );
			Piece *piece = board.GetSquareContents( square );
			if( outpost_10x10[square] > 0 && piece->GetType().gameInt1 > 0 &&
				((int) (pPawnHash->nPawnsPerFile[1][board.files[0][square]-1]) == 0 ||
				(int) (pPawnHash->backPawnRank[1][board.files[0][square]-1]) <= board.ranks[0][square]) &&
				((int) (pPawnHash->nPawnsPerFile[1][board.files[0][square]+1]) == 0 ||
				(int) (pPawnHash->backPawnRank[1][board.files[0][square]+1]) <= board.ranks[0][square]) )
			{
				//	basic bonus for player 0's posted piece
				eval += outpost_10x10[square] * piece->GetType().gameInt1;
				int pawnSquare1 = board.GetMovementMatrix( DIRECTION_SE )[square];
				int pawnSquare2 = board.GetMovementMatrix( DIRECTION_SW )[square];
				if( board.GetSquareContents( pawnSquare1 ) != NULL &&
					board.GetSquareContents( pawnSquare1 )->GetPlayerNumber() == 0 && 
					board.GetSquareContents( pawnSquare1 )->GetType().IsPawn() )
					//	additional 50% bonus for this pawn defender
					eval += (outpost_10x10[square] * piece->GetType().gameInt1) >> 1;
				if( board.GetSquareContents( pawnSquare2 ) != NULL &&
					board.GetSquareContents( pawnSquare2 )->GetPlayerNumber() == 0 && 
					board.GetSquareContents( pawnSquare2 )->GetType().IsPawn() )
					//	additional 50% bonus for this pawn defender
					eval += (outpost_10x10[square] * piece->GetType().gameInt1) >> 1;
			}
		}
		minors = DecimalKnight::decimalKnight.GetPieces( 1 ) | 
			DecimalBishop::decimalBishop.GetPieces( 1 );
		while( minors )
		{
			int square = minors.GetFirstBit();
			minors.ToggleBit( square );
			Piece *piece = board.GetSquareContents( square );
			if( outpost_10x10[board.flipSquare[1][square]] > 0 && piece->GetType().gameInt1 > 0 &&
				((int) (pPawnHash->nPawnsPerFile[0][board.files[0][square]-1]) == 0 ||
				(int) (pPawnHash->backPawnRank[0][board.files[0][square]-1]) <= board.ranks[0][square]) &&
				((int) (pPawnHash->nPawnsPerFile[0][board.files[0][square]+1]) == 0 ||
				(int) (pPawnHash->backPawnRank[0][board.files[0][square]+1]) <= board.ranks[0][square]) )
			{
				//	basic bonus for player 1's posted piece
				eval -= outpost_10x10[square] * piece->GetType().gameInt1;
				int pawnSquare1 = board.GetMovementMatrix( DIRECTION_SE )[square];
				int pawnSquare2 = board.GetMovementMatrix( DIRECTION_SW )[square];
				if( board.GetSquareContents( pawnSquare1 ) != NULL && 
					board.GetSquareContents( pawnSquare1 )->GetPlayerNumber() == 1 && 
					board.GetSquareContents( pawnSquare1 )->GetType().IsPawn() )
					//	additional 50% bonus for this pawn defender
					eval -= (outpost_10x10[board.flipSquare[1][square]] * piece->GetType().gameInt1) >> 1;
				if( board.GetSquareContents( pawnSquare2 ) != NULL &&
					board.GetSquareContents( pawnSquare2 )->GetPlayerNumber() == 1 && 
					board.GetSquareContents( pawnSquare2 )->GetType().IsPawn() )
					//	additional 50% bonus for this pawn defender
					eval -= (outpost_10x10[board.flipSquare[1][square]] * piece->GetType().gameInt1) >> 1;
			}
		}

		// *** ROOK on OPEN and SEMI-OPEN FILE BONUS *** //
		BitBoard128 rooks;
		rooks = DecimalRook::decimalRook.GetPieces( 0 );
		while( rooks )
		{
			int square = rooks.GetFirstBit();
			rooks.ToggleBit( square );
			if( pPawnHash->nPawnsPerFile[0][board.files[0][square]] == 0 )
			{
				//	file at least semi-open
				eval += 50;
				if( pPawnHash->nPawnsPerFile[1][board.files[0][square]] == 0 )
					//	fully open file
					eval += 20;
			}
		}
		rooks = DecimalRook::decimalRook.GetPieces( 1 );
		while( rooks )
		{
			int square = rooks.GetFirstBit();
			rooks.ToggleBit( square );
			if( pPawnHash->nPawnsPerFile[1][board.files[0][square]] == 0 )
			{
				//	file at least semi-open
				eval -= 50;
				if( pPawnHash->nPawnsPerFile[0][board.files[0][square]] == 0 )
					//	fully open file
					eval -= 20;
			}
		}
	}

	//	TWO-BISHOPS BONUS
	//	give bonus for having both bishops
	//		TODO: temporarily removed

	return *currentPhase;
}

int EurasianChessGame::EnumeratePromotions
	( Piece *piece, 
	  int fromSquare,
	  int toSquare,
	  Piece **pieces,
	  bool quiescentSearch )
{
	int count = 0;

	//	in Opulent Chess, we may only promote to the type of a friendly 
	//	piece that has been captured (for which it is exchanged.)
	
	if( toSquare >= 10 && toSquare < 90 )
		//	promotion is optional, so push "exchange" to same piece
		pieces[count++] = piece;

	bool rookFound = false;
	bool knightFound = false;
	bool bishopFound = false;
	bool queenFound = false;
	bool cannonFound = false;
	bool vaoFound = false;

	for( int x = 0; x < board.GetNumberOfPieces( piece->GetPlayerNumber() ); x++ )
	{
		Piece *currentPiece = board.GetPiece( piece->GetPlayerNumber(), x );
		if( currentPiece->IsCaptured() )
		{
			if( currentPiece->GetType() == DecimalRook::decimalRook && !rookFound )
			{
				rookFound = true;
				pieces[count++] = currentPiece;
			}
			else if( currentPiece->GetType() == DecimalKnight::decimalKnight && !knightFound )
			{
				knightFound = true;
				pieces[count++] = currentPiece;
			}
			else if( currentPiece->GetType() == DecimalBishop::decimalBishop && !bishopFound )
			{
				bishopFound = true;
				pieces[count++] = currentPiece;
			}
			else if( currentPiece->GetType() == DecimalQueen::decimalQueen && !queenFound )
			{
				queenFound = true;
				pieces[count++] = currentPiece;
			}
			else if( currentPiece->GetType() == DecimalCannon::decimalCannon && !cannonFound )
			{
				cannonFound = true;
				pieces[count++] = currentPiece;
			}
			else if( currentPiece->GetType() == DecimalVao::decimalVao && !vaoFound )
			{
				vaoFound = true;
				pieces[count++] = currentPiece;
			}
		}
	}

	return count;
}

word32 EurasianChessGame::AdjustPrimaryHash
	( word32 primaryHash )
{
	return primaryHash ^ GetEnPassantHash( board.GetCurrentGameRecord(), enPassantHashMap );
}

static bool CannonAttackDirections[] = { true, false, false, true, false, false, true, true };
static bool VaoAttackDirections[] = { false, true, true, false, true, true, false, false, false };

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

	for( x = 0; x < 8; x++ )
	{
		Direction &direction = board.GetDirection( x );
		int oppositeDirection = direction.GetOppositeDirectionNumber();
		int steps = 1;
		int *movementMatrix = board.GetMovementMatrix( oppositeDirection );
		int square = movementMatrix[squareNumber];
			
		bool screenFound = false;

		//	first step unrolled ...
		if( square >= 0 )
		{
			Piece *piece = board.GetSquareContents( square );
			square = movementMatrix[square];
			if( piece != NULL )
			{
				screenFound = true;
				if( piece->GetPlayerNumber() == playerNumber &&
					piece->GetType().GetAttackRange( piece->GetPlayerNumber(), x ) >= steps )
					return true;
			}
			steps++;
		}

		//	continue stepping until we find an attacker or a blocker
		while( square >= 0 && !screenFound )
		{
			Piece *piece = board.GetSquareContents( square );
			square = movementMatrix[square];
			if( piece != NULL )
			{
				screenFound = true;
				if( piece->GetPlayerNumber() == playerNumber &&
					piece->GetType().GetAttackRange( piece->GetPlayerNumber(), x ) >= steps )
					return true;
			}
			steps++;
		}

		//	blocker counts as a 'screen' for cannon-movers; now we continue 
		//	stepping looking for an attack from a cannon-mover
		while( square >= 0 )
		{
			Piece *piece = board.GetSquareContents( square );
			square = movementMatrix[square];
			if( piece != NULL )
			{
				square = -1;
				if( piece->GetPlayerNumber() == playerNumber &&
					((&(piece->GetType()) == &DecimalCannon::decimalCannon && 
					  CannonAttackDirections[x]) ||
				     (&(piece->GetType()) == &DecimalVao::decimalVao && 
					  VaoAttackDirections[x])) )
					return true;
			}
			steps++;
		}
	}
	for( ; x < board.GetDirectionCount(); x++ )
	{
		Direction &direction = board.GetDirection( x );
		int oppositeDirection = direction.GetOppositeDirectionNumber();
		int *movementMatrix = board.GetMovementMatrix( oppositeDirection );
		int square = movementMatrix[squareNumber];
		int steps = 1;

		//	unrolled ...
		if( square >= 0 )
		{
			Piece *piece = board.GetSquareContents( square );
			square = movementMatrix[square];
			if( piece != NULL )
			{
				square = -1;
				if( piece->GetPlayerNumber() == playerNumber &&
					piece->GetType().GetAttackRange( piece->GetPlayerNumber(), x ) > 0 )
					return true;
			}
			steps++;
		}

		while( square >= 0 )
		{
			Piece *piece = board.GetSquareContents( square );
			square = movementMatrix[square];
			if( piece != NULL )
			{
				square = -1;
				if( piece->GetPlayerNumber() == playerNumber &&
					piece->GetType().GetAttackRange( piece->GetPlayerNumber(), x ) >= steps )
					return true;
			}
			steps++;
		}
	}
	return false;
}

void EurasianChessGame::DefaultSettings()
{
	squareColor1 = RGB(255, 255, 204);
	squareColor2 = RGB(93, 126, 126);
	pieceColor1 = RGB(255, 255, 255);
	pieceColor2 = RGB(89, 132, 189);
	borderColor = RGB(128, 70, 70);
	boardDisplayType = BOARD_IS_CHECKERED;
	selectedPieceSet = PIECE_SET_EURASIAN;
}


void EurasianChessGame::AboutToStartThinking
	( int currentPlayer )
{
/*	board.ClearTranspositionTable();
	if( currentPlayer == 0 )
	{
		razorMargin = 4000;
		futilityMargin = 1800;
		extendedFutilityMargin = 2500;
	}
	else
	{
		razorMargin = 4000;
		futilityMargin = 2000;
		extendedFutilityMargin = 2900;
	}*/
}
