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

                                 ChessV

                   COPYRIGHT (C) 2010 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 "XiangQiGame.h"
#include "XiangQi_Types.h"

#include "XiangQi_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


//	instances of the PieceTypes
XiangQiRook XiangQiRook::xiangQiRook;
XiangQiCannon XiangQiCannon::xiangQiCannon;
XiangQiKnight XiangQiKnight::xiangQiKnight;
XiangQiElephant XiangQiElephant::xiangQiElephant;
XiangQiAdvisor XiangQiAdvisor::xiangQiAdvisor;
XiangQiPawn XiangQiPawn::xiangQiPawn;
XiangQiKing XiangQiKing::xiangQiKing;


Game *CreateXiangQiGame( Board &brd, Player &plr0, Player &plr1 )
{
	return new XiangQiGame( brd, plr0, plr1 );
}
/*
void StartXiangQiGame()
{
	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, "Xiangqi" );
}
*/

#define TOSQUARE(r, f) (((r) * 9) + (f))

XiangQiGame::XiangQiGame( 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 game we 
	//	have both cannon moves and the king-facing rule to 
	//	deal with, so we 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 pieces
	useStaticExchangeEvaluation = false;

	//	turn off use of pawn structure evaluation since we 
	//	aren't using chess-type pawns that form chains
	usePawnStructureEvaluation = false;

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

	//	futility pruning margins
	futilityMargin = 3000;
	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( 0 ); // not used in xiangqi
	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( 0 ); // not used in xiangqi
	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( 0 ); // not used in xiangqi
	phases[2].SetSquareValuesFactor( 1 );
	phases[2].SetKingSafetyFactor( 0 );
	phases[2].SetTropismFactor( 10 );


	// *** INITIALIZATION *** //

	//	basic initialization
	board.Initialize( this, BITBOARD_96 );

	//	initialize potentialPawnAttackers array (player 0)
	for( int rank = 0; rank <= 9; rank++ )
	{
		for( int file = 0; file <= 8; file++ )
		{
			int square = rank * 9 + file;
			if( rank < 9 )
				potentialPawnAttackers[0][square].SetBit( square + 9 );
			if( rank <= 4 )
			{
				if( file > 0 )
					potentialPawnAttackers[0][square].SetBit( square - 1 );
				if( file < 8 )
					potentialPawnAttackers[0][square].SetBit( square + 1 );
			}
		}
	}
	//	initialize potentialPawnAttackers array (player 1)
	for( int rank = 0; rank <= 9; rank++ )
	{
		for( int file = 0; file <= 8; file++ )
		{
			int square = rank * 9 + file;
			if( rank > 0 )
				potentialPawnAttackers[1][square].SetBit( square - 9 );
			if( rank >= 5 )
			{
				if( file > 0 )
					potentialPawnAttackers[1][square].SetBit( square - 1 );
				if( file < 8 )
					potentialPawnAttackers[1][square].SetBit( square + 1 );
			}
		}
	}
	//	initialize attacks for knights, elephants, advisors, rooks
	for( int rank = 0; rank <= 9; rank++ )
	{
		for( int file = 0; file <= 8; file++ )
		{
			int square = rank * 9 + file;

			//	knight attacks
			if( rank + 2 <= 9 && file + 1 <= 8 )
				knightAttacks[square].SetBit( TOSQUARE(rank + 2, file + 1) );
			if( rank + 1 <= 9 && file + 2 <= 8 )
				knightAttacks[square].SetBit( TOSQUARE(rank + 1, file + 2) );
			if( rank - 1 >= 0 && file + 2 <= 8 )
				knightAttacks[square].SetBit( TOSQUARE(rank - 1, file + 2) );
			if( rank - 2 >= 0 && file + 1 <= 8 )
				knightAttacks[square].SetBit( TOSQUARE(rank - 2, file + 1) );
			if( rank - 2 >= 0 && file - 1 >= 0 )
				knightAttacks[square].SetBit( TOSQUARE(rank - 2, file - 1) );
			if( rank - 1 >= 0 && file - 2 >= 0 )
				knightAttacks[square].SetBit( TOSQUARE(rank - 1, file - 2) );
			if( rank + 1 <= 9 && file - 2 >= 0 )
				knightAttacks[square].SetBit( TOSQUARE(rank + 1, file - 2) );
			if( rank + 2 <= 9 && file - 1 >= 0 )
				knightAttacks[square].SetBit( TOSQUARE(rank + 2, file - 1) );

			//	minister attacks
			if( rank + 2 <= 9 && file + 2 <= 8 )
				ministerAttacks[square].SetBit( TOSQUARE(rank + 2, file + 2) );
			if( rank - 2 >= 0 && file + 2 <= 8 )
				ministerAttacks[square].SetBit( TOSQUARE(rank - 2, file + 2) );
			if( rank - 2 >= 0 && file - 2 >= 0 )
				ministerAttacks[square].SetBit( TOSQUARE(rank - 2, file - 2) );
			if( rank + 2 <= 9 && file - 2 >= 0 )
				ministerAttacks[square].SetBit( TOSQUARE(rank + 2, file - 2) );

			//	advisor attacks
			if( rank + 1 <= 9 && file + 1 <= 8 )
				advisorAttacks[square].SetBit( TOSQUARE(rank + 1, file + 1) );
			if( rank + 1 <= 9 && file - 1 >= 0 )
				advisorAttacks[square].SetBit( TOSQUARE(rank + 1, file - 1) );
			if( rank - 1 >= 0 && file + 1 <= 8 )
				advisorAttacks[square].SetBit( TOSQUARE(rank - 1, file + 1) );
			if( rank - 1 >= 0 && file - 1 >= 0 )
				advisorAttacks[square].SetBit( TOSQUARE(rank - 1, file - 1) );

			//	rook attacks
			int newFile, newRank;
			for( newFile = file - 1; newFile >= 0; newFile-- )
				potentialRookAttackers[square].SetBit( TOSQUARE(rank, newFile) );
			for( newFile = file + 1; newFile <= 8; newFile++ )
				potentialRookAttackers[square].SetBit( TOSQUARE(rank, newFile) );
			for( newRank = rank - 1; newRank >= 0; newRank-- )
				potentialRookAttackers[square].SetBit( TOSQUARE(newRank, file) );
			for( newRank = rank + 1; newRank <= 9; newRank++ )
				potentialRookAttackers[square].SetBit( TOSQUARE(newRank, file) );
		}
	}

	//	there is no diagonal movement in Xiangqi, so update the 
	//	board "rays" array to remove the diagonal rays
	for( int square1 = 0; square1 < 90; square1++ )
	{
		int rank1 = square1 / 9;
		int file1 = square1 % 9;

		for( int square2 = 0; square2 < 90; square2++ )
		{
			int rank2 = square2 / 9;
			int file2 = square2 % 9;

			if( file1 != file2 && rank1 != rank2 )
				board.bb96_rays[square1 * 90 + square2].Clear();
		}
	}

	//	initialize palaces
	palaces[0].SetBit( 21 );   palaces[0].SetBit( 22 );   palaces[0].SetBit( 23 );
	palaces[0].SetBit( 12 );   palaces[0].SetBit( 13 );   palaces[0].SetBit( 14 );
	palaces[0].SetBit(  3 );   palaces[0].SetBit(  4 );   palaces[0].SetBit(  5 );

	palaces[1].SetBit( 66 );   palaces[1].SetBit( 67 );   palaces[1].SetBit( 68 );
	palaces[1].SetBit( 75 );   palaces[1].SetBit( 76 );   palaces[1].SetBit( 77 );
	palaces[1].SetBit( 84 );   palaces[1].SetBit( 85 );   palaces[1].SetBit( 86 );
}

void XiangQiGame::AddPlayerPieceTypes( char *gameName )
{
	//	add the piece types that each player may have
	board.AddPlayerPieceTypeBothPlayers( XiangQiRook::xiangQiRook );
	board.AddPlayerPieceTypeBothPlayers( XiangQiCannon::xiangQiCannon );
	board.AddPlayerPieceTypeBothPlayers( XiangQiKnight::xiangQiKnight);
	board.AddPlayerPieceTypeBothPlayers( XiangQiElephant::xiangQiElephant );
	board.AddPlayerPieceTypeBothPlayers( XiangQiAdvisor::xiangQiAdvisor );
	board.AddPlayerPieceTypeBothPlayers( XiangQiPawn::xiangQiPawn );
	board.AddPlayerPieceTypeBothPlayers( XiangQiKing::xiangQiKing );
}

void XiangQiGame::ChangeRulesByVariant
	( char *gameName,
	  char *&array,
	  char *&book )
{
	//	place pieces
	array = "rneakaenr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNEAKAENR";
	//	set name of opening book
	book = "openings\\XiangQi.txt";
}

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

	return newPiece;
}

void XiangQiGame::AddSpecialMoves
	( int currentPlayer, 
	  MovementList &list, 
	  GameRec &gameRecord, 
	  bool quiescentSearch )
{
	// *** CANNON moves *** //
	BitBoard96 cannons = XiangQiCannon::xiangQiCannon.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] );
		}
	}

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

//	this array is for determining the offset to the square that can block 
//	the move of a Knight
int KnightBlockDirections[] =
{
//   0      2     4     6      8           12          16          20          24
	-9, 0, -9, 0, 0, 0, 0, 0, -1, 0, 0, 0,  1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
//	26           30           34           38
	-1, 0, 0, 0,  1, 0, 0, 0,  0, 0, 9, 0,  9 
};

//	this array is for determining the offset to the square that can block 
//	the move of a Minister
int MinisterBlockDirections[] = 
{
//   0      2      4     6     8           12          16          20          24
	-10, 0, 0, 0, -8, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
//	26           30           34     36     38     40
	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  8, 0,  0, 0, 10
};

bool XiangQiGame::MoveBeingMade
	( MoveInfo &moveInfo,
	  GameRec &gameRecord )
{
	PieceType *pPieceType = &gameRecord.pieceMoved->GetType(); // the type of piece moved

	// *** ILLEGAL MOVES *** //

	//	the Kings and Counsellors can't leave their palaces
	if( pPieceType == &XiangQiKing::xiangQiKing ||
		pPieceType == &XiangQiAdvisor::xiangQiAdvisor )
		//	check the destination square to see if it is outside the palace
		if( !palaces[gameRecord.pieceMoved->GetPlayerNumber()].GetBit( moveInfo.toSquare ) )
			//	outside the palace - return false to invalidate the move
			return false;

	//	the two Kings cannot 'see' each other on an open file
	BitBoard96 ray = board.bb96_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.BB96_GetBlockers()) )
			//	nothing is blocking; move is illegal
			return false;
	}

	//	the Knight's move can be blocked
	if( pPieceType == &XiangQiKnight::xiangQiKnight && 
		board.GetSquareContents( moveInfo.fromSquare + KnightBlockDirections[moveInfo.toSquare-moveInfo.fromSquare+19] ) != NULL )
		//	blocked
		return false;

	//	the Minister's move can be blocked
	if( pPieceType == &XiangQiElephant::xiangQiElephant && 
		board.GetSquareContents( moveInfo.fromSquare + MinisterBlockDirections[moveInfo.toSquare-moveInfo.fromSquare+20] ) != NULL )
		//	blocked
		return false;

	// *** PERPETUAL CHECKING *** //

	//	in Xiangqi, perpetual checking is prohibited. specifically, it is 
	//	forbidden to keep checking the king with the same piece.
	//	(the actual rule is a great deal more complicated than this, but this  
	//	approximation is what we shall implement.)
	//	to this end, if this move gives Check to the opponent king, we shall 
	//	record the piece giving check in GameRec.pGamePiece1
	gameRecord.pGamePiece1 = NULL;

	//	check #1: does the moving piece now give check?
	Piece *pKing = board.GetKing( FLIP(gameRecord.pieceMoved->GetPlayerNumber()) );
	if( pPieceType == &XiangQiKnight::xiangQiKnight )
	{
		if( knightAttacks[moveInfo.toSquare][pKing->GetSquareNumber()] && 
			board.GetSquareContents( moveInfo.toSquare + KnightBlockDirections[pKing->GetSquareNumber()-moveInfo.toSquare+19] ) == NULL )
			//	this knight is now giving check
			gameRecord.pGamePiece1 = gameRecord.pieceMoved;
	}
	else if( pPieceType == &XiangQiRook::xiangQiRook )
	{
		BitBoard96 ray = board.bb96_rays[moveInfo.toSquare * board.GetNumberOfSquares() + pKing->GetSquareNumber()];
		if( (bool) ray && !(ray & ~BitBoard96::GetPositionBitBoard( pKing->GetSquareNumber() ) & board.BB96_GetBlockers()) )
			//	this rook is now giving check
			gameRecord.pGamePiece1 = gameRecord.pieceMoved;
	}
	else if( pPieceType == &XiangQiPawn::xiangQiPawn )
	{
		if( potentialPawnAttackers[pKing->GetPlayerNumber()][pKing->GetSquareNumber()][moveInfo.toSquare] )
			//	this pawn is now giving check
			gameRecord.pGamePiece1 = gameRecord.pieceMoved;
	}
	else if( pPieceType == &XiangQiCannon::xiangQiCannon )
	{
		BitBoard96 ray = board.bb96_rays[moveInfo.toSquare * board.GetNumberOfSquares() + pKing->GetSquareNumber()];
		if( ray )
		{
			if( (ray & ~BitBoard96::GetPositionBitBoard( pKing->GetSquareNumber() ) & board.BB96_GetBlockers()).GetBitCount() == 1 )
				//	this cannon is now giving check
				gameRecord.pGamePiece1 = gameRecord.pieceMoved;
		}
	}
	//	if we're not checking the king with the moving piece, maybe we opened up an attack
	if( gameRecord.pGamePiece1 == NULL )
	{
		BitBoard96 potentialRookAndCannonAttackers = potentialRookAttackers[pKing->GetSquareNumber()];
		BitBoard96 rooks = potentialRookAndCannonAttackers & XiangQiRook::xiangQiRook.GetPieces( FLIP(pKing->GetPlayerNumber()) );
		while( rooks )
		{
			int sq = rooks.GetFirstBit();
			rooks.ToggleBit( sq );
			BitBoard96 ray = board.bb96_rays[sq * board.GetNumberOfSquares() + pKing->GetSquareNumber()];
			if( (bool) ray && !(ray & ~BitBoard96::GetPositionBitBoard( pKing->GetSquareNumber() ) & board.BB96_GetBlockers()) )
				//	this rook is giving check
				gameRecord.pGamePiece1 = board.GetSquareContents( sq );
		}
		BitBoard96 cannons = potentialRookAndCannonAttackers & XiangQiCannon::xiangQiCannon.GetPieces( FLIP(pKing->GetPlayerNumber()) );
		while( cannons )
		{
			int sq = cannons.GetFirstBit();
			cannons.ToggleBit( sq );
			BitBoard96 ray = board.bb96_rays[sq * board.GetNumberOfSquares() + pKing->GetSquareNumber()];
			if( (ray & ~BitBoard96::GetPositionBitBoard( pKing->GetSquareNumber() ) & board.BB96_GetBlockers()).GetBitCount() == 1 )
				//	this cannon is giving check
				gameRecord.pGamePiece1 = board.GetSquareContents( sq );
		}
	}

	// *** 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 15
		//	in the opening, we increment gameInt1 for each move
		gameRecord.gameInt1++;
	}

	return true;
}

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

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

		//	in the opening we consider the following things:
		//		- penalty for knights and rooks not moving

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

		BitBoard96 bb = XiangQiKnight::xiangQiKnight.GetPieces( 0 ) | 
			XiangQiRook::xiangQiRook.GetPieces( 0 );
		while( bb )
		{
			int sq = bb.GetFirstBit();
			bb.ToggleBit( sq );
			if( !board.GetSquareContents( sq )->HasMoved() )
				eval -= factor4;
		}
		bb = XiangQiKnight::xiangQiKnight.GetPieces( 1 ) | 
			XiangQiRook::xiangQiRook.GetPieces( 1 );
		while( bb )
		{
			int sq = bb.GetFirstBit();
			bb.ToggleBit( sq );
			if( !board.GetSquareContents( sq )->HasMoved() )
				eval += factor4;
		}
	}
	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;

		// *** KING SHELTER *** //

		//	for first player, give bonuses only if the King is on e1
		Piece *pPiece = board.GetSquareContents( 4 );
		if( pPiece != NULL && &(pPiece->GetType()) == &XiangQiKing::xiangQiKing )
		{
			//	Bonus for Elephant at e3 protected by other Elephant
			Piece *pPiece = board.GetSquareContents( 22 );
			if( pPiece != NULL && &(pPiece->GetType()) == &XiangQiElephant::xiangQiElephant )
			{
				//	square has Elephant; is it protected by another?
				BitBoard96 other = ministerAttacks[22] & XiangQiElephant::xiangQiElephant.GetPieces( 0 );
				if( other )
				{
					//	make sure this potential defender is not blocked
					int square = other.GetFirstBit();
					int blockingSquare = 22 + MinisterBlockDirections[square-22+20];
					if( board.GetSquareContents( blockingSquare ) == NULL )
						eval += 250;
				}
			}

			//	Bonus for Advisor at e2 protected by other Advisor
			pPiece = board.GetSquareContents( 13 );
			if( pPiece != NULL && &(pPiece->GetType()) == &XiangQiAdvisor::xiangQiAdvisor )
			{
				if( advisorAttacks[13] & XiangQiAdvisor::xiangQiAdvisor.GetPieces( 0 ) )
					eval += 250;
			}
		}

		//	for second player, give bonus only if the king is on e10
		pPiece = board.GetSquareContents( 85 );
		if( pPiece != NULL && &(pPiece->GetType()) == &XiangQiKing::xiangQiKing )
		{
			//	Bonus for Elephant at e8 protected by other Elephant
			pPiece = board.GetSquareContents( 67 );
			if( pPiece != NULL && &(pPiece->GetType()) == &XiangQiElephant::xiangQiElephant )
			{
				//	square has Elephant; is it protected by another?
				BitBoard96 other = ministerAttacks[67] & XiangQiElephant::xiangQiElephant.GetPieces( 1 );
				if( other )
				{
					//	make sure this potential defender is not blocked
					int square = other.GetFirstBit();
					int blockingSquare = 67 + MinisterBlockDirections[square-67+20];
					if( board.GetSquareContents( blockingSquare ) == NULL )
						eval -= 250;
				}
			}


			//	Bonus for Advisor at e9 protected by other Advisor
			pPiece = board.GetSquareContents( 76 );
			if( pPiece != NULL && &(pPiece->GetType()) == &XiangQiAdvisor::xiangQiAdvisor )
			{
				if( advisorAttacks[76] & XiangQiAdvisor::xiangQiAdvisor.GetPieces( 1 ) )
					eval -= 250;
			}
		}
	}

	return *currentPhase;
}

static int CannonAttackDirections[] = { DIRECTION_N, DIRECTION_E, DIRECTION_S, DIRECTION_W };
static int KnightAttackStepDirections[][2] = { { DIRECTION_NE, DIRECTION_NW }, { DIRECTION_NE, DIRECTION_SE }, { DIRECTION_SE, DIRECTION_SW }, { DIRECTION_SW, DIRECTION_NW } };

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

	//	check for pawn attacks
	if( (bool) (potentialPawnAttackers[FLIP(playerNumber)][squareNumber] & XiangQiPawn::xiangQiPawn.GetPieces( playerNumber )) )
		return true;

	//	check for knight attacks
	BitBoard96 knightAttackers = (knightAttacks[squareNumber] & XiangQiKnight::xiangQiKnight.GetPieces( playerNumber ));
	while( knightAttackers )
	{
		int sq = knightAttackers.GetFirstBit();
		knightAttackers.ToggleBit( sq );
		if( board.GetSquareContents( sq + KnightBlockDirections[squareNumber-sq+19] ) == NULL )
			return true;
	}

	for( x = 0; x < 4; x++ )
	{
		int *movementMatrix = board.GetMovementMatrix( CannonAttackDirections[x] );
		int square = movementMatrix[squareNumber];
		int steps = 1;
		bool screenFound = false;

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

		//	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()) == &XiangQiRook::xiangQiRook )
					return true;
			}
			steps++;
		}

		//	blocker counts as a 'screen' for cannon-movers; now we continue 
		//	stepping looking for an attack from a cannon
		while( square >= 0 )
		{
			Piece *piece = board.GetSquareContents( square );
			square = movementMatrix[square];
			if( piece != NULL )
			{
				square = -1;
				if( piece->GetPlayerNumber() == playerNumber &&
					&(piece->GetType()) == &XiangQiCannon::xiangQiCannon )
					return true;
			}
			steps++;
		}
	}
	return false;
}

bool XiangQiGame::TestForWinLossDraw
	( int &eval )
{
//	if( board.IsDraw() )
//	{
		//	we have a draw by repetition, so we need to see if this 
		//	has been a case of perpetual checking and adjucate accordingly
		
//	}

	return Game::TestForWinLossDraw( eval );
}

void XiangQiGame::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_STANDARD;
}


void XiangQiGame::AboutToStartThinking
	( int currentPlayer )
{
}
