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

                                 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 "DiamondChessGame.h"
#include "../../Resource.h"
#include "../../ChessV.h"
#include "../../GameParameters.h"
#include "../../boards/DiamondBoard.h"


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


DiamondPawn DiamondPawn::diamondPawn;


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

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

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

	if( stringCompNoCase( selectedVariant->name, "Legan's Game" ) || 
		stringCompNoCase( selectedVariant->baseGameName, "Legan's Game" ) )
		strcpy( gameSelection, "Legan's Game" );
	if( stringCompNoCase( selectedVariant->name, "Diamond Chess" ) || 
		stringCompNoCase( selectedVariant->baseGameName, "Diamond Chess" ) )
		strcpy( gameSelection, "Diamond Chess" );
	if( stringCompNoCase( selectedVariant->name, "Diagonal Chess" ) || 
		stringCompNoCase( selectedVariant->baseGameName, "Diagonal Chess" ) )
		strcpy( gameSelection, "Diagonal Chess" );
}

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

	//	turn off ChessGame's en Passant; diamond pawns have no 2-space move
	enPassant = false;

	//	no castling by default
	castlingType = CASTLING_TYPE_NONE;

	//	normal pawn structure valuations don't apply
	usePawnStructureEvaluation = false;
	for( int x = 0; x < nPhases; x++ )
		phases[x].SetPawnDeficiencyFactor( 0 );
}

void DiamondChessGame::AddPlayerPieceTypes( char *gameName )
{
	//	add the piece types that each player may have
	board.AddPlayerPieceTypeBothPlayers( OrthodoxRook::orthodoxRook );
	board.AddPlayerPieceTypeBothPlayers( OrthodoxBishop::orthodoxBishop );
	board.AddPlayerPieceTypeBothPlayers( OrthodoxKnight::orthodoxKnight );
	board.AddPlayerPieceTypeBothPlayers( OrthodoxQueen::orthodoxQueen );
	board.AddPlayerPieceTypeBothPlayers( OrthodoxKing::orthodoxKing );
	board.AddPlayerPieceTypeBothPlayers( DiamondPawn::diamondPawn );
	//	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] = &OrthodoxRook::orthodoxRook;
	minorPieceTypes[0][0] = &OrthodoxKnight::orthodoxKnight;
	minorPieceTypes[1][0] = &OrthodoxKnight::orthodoxKnight;
	minorPieceTypes[0][1] = &OrthodoxBishop::orthodoxBishop;
	minorPieceTypes[1][1] = &OrthodoxBishop::orthodoxBishop;
	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] = &OrthodoxBishop::orthodoxBishop;
	colorboundPieceTypes[0][1] = &NullPieceType64::nullPieceType64;
	colorboundPieceTypes[1][1] = &NullPieceType64::nullPieceType64;
	queenPieceTypes[0] = &OrthodoxQueen::orthodoxQueen;
	queenPieceTypes[1] = &OrthodoxQueen::orthodoxQueen;
	pawnPieceTypes[0] = &DiamondPawn::diamondPawn;
	pawnPieceTypes[1] = &DiamondPawn::diamondPawn;
	castlingPiecesSlideNorth[0] = true;
	castlingPiecesSlideNorth[1] = true;
}

void DiamondChessGame::ChangeRulesByVariant
	( char *gameName,
	  char *&array,
	  char *&book )
{
	// *** LEGAN'S GAME *** //
	if( stringCompNoCase( gameName, "Legan's Game" ) )
	{
		//	castling
		castlingType = CASTLING_TYPE_USER_CASTLING_1;
		//	place pieces
		array = "knbrp3/bqpp4/npp5/rp1p3P/p3P1PR/5PPN/4PPQB/3PRBNK";
		//	set name of opening book
		book = "openings\\LegansGame.txt";
	}
	// *** DIAMOND CHESS *** //
	else if( stringCompNoCase( gameName, "Diamond Chess" ) )
	{
		//	place pieces
		array = "krbp4/rqnp4/nbpp4/pppp4/4PPPP/4PPBN/4PNQR/4PBRK";
		//	set name of opening book
		book = "openings\\DiamondChess.txt";
	}
	// *** DIAGONAL CHESS *** //
	else if( stringCompNoCase( gameName, "Diagonal Chess" ) )
	{
		//	place pieces
		array = "krnp4/rpqp4/nbbp4/pppp4/4PPPP/4PBBN/4PQPR/4PNRK";
		//	set name of opening book
		book = "openings\\DiagonalChess.txt";
	}
}

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

	//	if Pawn, set the promotion zone
	if( &pieceType == pawnPieceTypes[nPlayer] )
	{
		if( newPiece->GetPlayerNumber() == 0 )
		{
			newPiece->GetPromotionZone().AddToZone( 56, 63 );
			newPiece->GetPromotionZone().AddToZone( 48, 48 );
			newPiece->GetPromotionZone().AddToZone( 40, 40 );
			newPiece->GetPromotionZone().AddToZone( 32, 32 );
			newPiece->GetPromotionZone().AddToZone( 24, 24 );
			newPiece->GetPromotionZone().AddToZone( 16, 16 );
			newPiece->GetPromotionZone().AddToZone(  8,  8 );
			newPiece->GetPromotionZone().AddToZone(  0,  0 );
		}
		else
		{
			newPiece->GetPromotionZone().AddToZone(  0,  7 );
			newPiece->GetPromotionZone().AddToZone( 15, 15 );
			newPiece->GetPromotionZone().AddToZone( 23, 23 );
			newPiece->GetPromotionZone().AddToZone( 31, 31 );
			newPiece->GetPromotionZone().AddToZone( 39, 39 );
			newPiece->GetPromotionZone().AddToZone( 47, 47 );
			newPiece->GetPromotionZone().AddToZone( 63, 63 );
		}
	}

	return newPiece;
}

void DiamondChessGame::AddSpecialMoves
	( int currentPlayer, 
	  MovementList &stack, 
	  GameRec &gameRecord,
	  bool quiescentSearch )
{
	if( quiescentSearch || castlingType == CASTLING_TYPE_NONE || 
		(board.FastCheckTest() && goalIsCheckmate) )
		return;

	// *** CASTLING *** //

	if( castlingType == CASTLING_TYPE_USER_CASTLING_1 )
	{
		if( board.GetCurrentPlayerNumber() == 0 )
		{
			//	white to move
			Piece *king = board.GetKing( 0 );
			if( !king->IsCaptured() && !king->HasMoved() && king->GetSquareNumber() == 7 )
			{
				if( board.GetSquareContents( 4 ) != NULL &&
					!board.GetSquareContents( 4 )->HasMoved() )
				{
					if( board.GetSquareContents( 6 ) == NULL && 
						board.GetSquareContents( 5 ) == NULL && 
						!board.IsSquareAttacked( 6, 1 ) && 
						!board.IsSquareAttacked( 5, 1 ) )
					{
						stack.BeginMoveAdd( Castling, 7, 5 );
						stack.AddPickUp( 7 );
						stack.AddPickUp( 4 );
						stack.AddDrop( king, 5 );
						stack.AddDrop( board.GetSquareContents( 4 ), 6 );
						stack.EndMoveAdd( 1000 );
					}
				}
				if( board.GetSquareContents( 31 ) != NULL &&
					!board.GetSquareContents( 31 )->HasMoved() )
				{
					if( board.GetSquareContents( 15 ) == NULL && 
						board.GetSquareContents( 23 ) == NULL && 
						!board.IsSquareAttacked( 15, 1 ) && 
						!board.IsSquareAttacked( 23, 1 ) )
					{
						stack.BeginMoveAdd( Castling, 7, 23 );
						stack.AddPickUp( 7 );
						stack.AddPickUp( 31 );
						stack.AddDrop( king, 23 );
						stack.AddDrop( board.GetSquareContents( 31 ), 15 );
						stack.EndMoveAdd( 1000 );
					}
				}
			}
		}
		else
		{
			//	black to move
			Piece *king = board.GetKing( 1 );
			if( !king->IsCaptured() && !king->HasMoved() && king->GetSquareNumber() == 56 )
			{
				if( board.GetSquareContents( 59 ) != NULL &&
					!board.GetSquareContents( 59 )->HasMoved() )
				{
					if( board.GetSquareContents( 58 ) == NULL && 
						board.GetSquareContents( 57 ) == NULL && 
						!board.IsSquareAttacked( 58, 0 ) && 
						!board.IsSquareAttacked( 57, 0 ) )
					{
						stack.BeginMoveAdd( Castling, 56, 58 );
						stack.AddPickUp( 56 );
						stack.AddPickUp( 59 );
						stack.AddDrop( king, 58 );
						stack.AddDrop( board.GetSquareContents( 59 ), 57 );
						stack.EndMoveAdd( 1000 );
					}
				}
				if( board.GetSquareContents( 32 ) != NULL &&
					!board.GetSquareContents( 32 )->HasMoved() )
				{
					if( board.GetSquareContents( 40 ) == NULL && 
						board.GetSquareContents( 48 ) == NULL && 
						!board.IsSquareAttacked( 40, 0 ) && 
						!board.IsSquareAttacked( 48, 0 ) )
					{
						stack.BeginMoveAdd( Castling, 56, 40 );
						stack.AddPickUp( 56 );
						stack.AddPickUp( 32 );
						stack.AddDrop( king, 40 );
						stack.AddDrop( board.GetSquareContents( 32 ), 48 );
						stack.EndMoveAdd( 1000 );
					}
				}
			}
		}
	}
}

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

	//	TODO: adjust hash for Legan's Game castling privledge

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

void DiamondChessGame::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_SMALL;
}
