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

                                 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 "PolymorphChessGame.h"
#include "Polymorph_Chess_Types.h"
#include "Chess_Data.h"
#include "../../Resource.h"
#include "../../ChessV.h"
#include "../../GameParameters.h"


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


PolymorphAsKnight PolymorphAsKnight::polymorphAsKnight;
PolymorphAsBishop PolymorphAsBishop::polymorphAsBishop;
PolymorphAsKnishop PolymorphAsKnishop::polymorphAsKnishop;
PolymorphAsBishight PolymorphAsBishight::polymorphAsBishight;


LRESULT CALLBACK PolymorphChess_SelectDlgProc
	( HWND hWndDlg, 
	  UINT Msg, 
	  WPARAM wParam, 
	  LPARAM lParam );


void StartPolymorphChessGame()
{
	if( !justLoaded )
		int rtn = (int) ::DialogBox( theInstance, MAKEINTRESOURCE(IDD_POLYMORPH_CHESS_DIALOG), NULL, 
			reinterpret_cast<DLGPROC>(PolymorphChess_SelectDlgProc) );

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

	strcpy( gameSelection, "Polymorph Chess" );
}

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

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


	// *** OUTPOSTS *** //
	PolymorphAsKnight::polymorphAsKnight.gameInt1 = 10;
	PolymorphAsBishop::polymorphAsBishop.gameInt1 = 8;
	PolymorphAsKnishop::polymorphAsKnishop.gameInt1 = 9;
	PolymorphAsBishight::polymorphAsBishight.gameInt1 = 9;
}

void PolymorphChessGame::AddPlayerPieceTypes( char *gameName )
{
	//	add the piece types that each player may have
	board.AddPlayerPieceTypeBothPlayers( OrthodoxRook::orthodoxRook );
	board.AddPlayerPieceTypeBothPlayers( PolymorphAsKnight::polymorphAsKnight );
	board.AddPlayerPieceTypeBothPlayers( PolymorphAsBishop::polymorphAsBishop );
	board.AddPlayerPieceTypeBothPlayers( PolymorphAsBishight::polymorphAsBishight );
	board.AddPlayerPieceTypeBothPlayers( PolymorphAsKnishop::polymorphAsKnishop );
	board.AddPlayerPieceTypeBothPlayers( OrthodoxQueen::orthodoxQueen );
	board.AddPlayerPieceTypeBothPlayers( OrthodoxKing::orthodoxKing );
	board.AddPlayerPieceTypeBothPlayers( OrthodoxPawn::orthodoxPawn );
	//	initialize piece type references
	castlingPieceTypes[0] = &OrthodoxRook::orthodoxRook;
	castlingPieceTypes[1] = &OrthodoxRook::orthodoxRook;
	minorPieceTypes[0][0] = &PolymorphAsKnight::polymorphAsKnight;
	minorPieceTypes[1][0] = &PolymorphAsKnight::polymorphAsKnight;
	minorPieceTypes[0][1] = &PolymorphAsBishop::polymorphAsBishop;
	minorPieceTypes[1][1] = &PolymorphAsBishop::polymorphAsBishop;
	minorPieceTypes[0][2] = &PolymorphAsKnishop::polymorphAsKnishop;
	minorPieceTypes[1][2] = &PolymorphAsKnishop::polymorphAsKnishop;
	minorPieceTypes[0][3] = &PolymorphAsBishight::polymorphAsBishight;
	minorPieceTypes[1][3] = &PolymorphAsBishight::polymorphAsBishight;
	colorboundPieceTypes[0][0] = &NullPieceType64::nullPieceType64;
	colorboundPieceTypes[1][0] = &NullPieceType64::nullPieceType64;
	colorboundPieceTypes[0][1] = &NullPieceType64::nullPieceType64;
	colorboundPieceTypes[1][1] = &NullPieceType64::nullPieceType64;
	queenPieceTypes[0] = &OrthodoxQueen::orthodoxQueen;
	queenPieceTypes[1] = &OrthodoxQueen::orthodoxQueen;
	pawnPieceTypes[0] = &OrthodoxPawn::orthodoxPawn;
	pawnPieceTypes[1] = &OrthodoxPawn::orthodoxPawn;
	castlingPiecesSlideNorth[0] = true;
	castlingPiecesSlideNorth[1] = true;
}

char *FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR";

void PolymorphChessGame::ChangeRulesByVariant
	( char *gameName,
	  char *&array,
	  char *&book )
{
	int setup;
	LookupIntParameter( "setup", setup );
	char *openingBookFilename = "openings\\PolymorphChess_StandardSetup.txt";
	if( setup == 2 )
	{
		FEN = "rnnqknnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR";
		openingBookFilename = "openings\\PolymorphChess_BlackKnightsSetup.txt";
	}
	else if( setup == 3 )
	{
		FEN = "rbbqkbbr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR";
		openingBookFilename = "openings\\PolymorphChess_BlackBishopsSetup.txt";
	}
	else if( setup == 4 )
	{
		FEN = "r_nb_bnqk_bn_nbr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR";
		openingBookFilename = "openings\\PolymorphChess_MixedSetup.txt";
	}
	array = FEN;
	book = openingBookFilename;
}

void PolymorphChessGame::AddSpecialMoves
	( int currentPlayer, 
	  MovementList &stack, 
	  GameRec &gameRecord,
	  bool quiescentSearch )
{
	if( !quiescentSearch )
	{
		BitBoard64 polymorphs = PolymorphAsKnight::polymorphAsKnight.GetPieces( currentPlayer ) | 
			                    PolymorphAsBishop::polymorphAsBishop.GetPieces( currentPlayer ) | 
								PolymorphAsKnishop::polymorphAsKnishop.GetPieces( currentPlayer ) | 
								PolymorphAsBishight::polymorphAsBishight.GetPieces( currentPlayer );
		while( polymorphs )
		{
			int square = polymorphs.ExtractLSB();
			Piece *piece = board.GetSquareContents( square );
			if( &(piece->GetType()) == &(PolymorphAsKnight::polymorphAsKnight) )
			{
				//	push conversion to Bishop
				stack.BeginMoveAdd( UserMove1, piece->GetSquareNumber(), 
					piece->GetSquareNumber(), 'B' );
				stack.AddPickUp( piece->GetSquareNumber() );
				stack.AddDrop( piece, piece->GetSquareNumber(), &PolymorphAsBishop::polymorphAsBishop );
				stack.EndMoveAdd( -2000 );
				//	push conversion to Knishop
				stack.BeginMoveAdd( UserMove1, piece->GetSquareNumber(), 
					piece->GetSquareNumber(), 'n' );
				stack.AddPickUp( piece->GetSquareNumber() );
				stack.AddDrop( piece, piece->GetSquareNumber(), &PolymorphAsKnishop::polymorphAsKnishop );
				stack.EndMoveAdd( -2000 );
				//	push conversion to Bishight
				stack.BeginMoveAdd( UserMove1, piece->GetSquareNumber(), 
					piece->GetSquareNumber(), 'b' );
				stack.AddPickUp( piece->GetSquareNumber() );
				stack.AddDrop( piece, piece->GetSquareNumber(), &PolymorphAsBishight::polymorphAsBishight );
				stack.EndMoveAdd( -2000 );
			}
			else if( &(piece->GetType()) == &(PolymorphAsBishop::polymorphAsBishop) )
			{
				//	push conversion to Knight
				stack.BeginMoveAdd( UserMove1, piece->GetSquareNumber(), 
					piece->GetSquareNumber(), 'N' );
				stack.AddPickUp( piece->GetSquareNumber() );
				stack.AddDrop( piece, piece->GetSquareNumber(), &PolymorphAsKnight::polymorphAsKnight );
				stack.EndMoveAdd( -2000 );
				//	push conversion to Knishop
				stack.BeginMoveAdd( UserMove1, piece->GetSquareNumber(), 
					piece->GetSquareNumber(), 'n' );
				stack.AddPickUp( piece->GetSquareNumber() );
				stack.AddDrop( piece, piece->GetSquareNumber(), &PolymorphAsKnishop::polymorphAsKnishop );
				stack.EndMoveAdd( -2000 );
				//	push conversion to Bishight
				stack.BeginMoveAdd( UserMove1, piece->GetSquareNumber(), 
					piece->GetSquareNumber(), 'b' );
				stack.AddPickUp( piece->GetSquareNumber() );
				stack.AddDrop( piece, piece->GetSquareNumber(), &PolymorphAsBishight::polymorphAsBishight );
				stack.EndMoveAdd( -2000 );
			}
			else if( &(piece->GetType()) == &(PolymorphAsBishight::polymorphAsBishight) )
			{
				//	push conversion to Knight
				stack.BeginMoveAdd( UserMove1, piece->GetSquareNumber(), 
					piece->GetSquareNumber(), 'N' );
				stack.AddPickUp( piece->GetSquareNumber() );
				stack.AddDrop( piece, piece->GetSquareNumber(), &PolymorphAsKnight::polymorphAsKnight );
				stack.EndMoveAdd( -2000 );
				//	push conversion to Bishop
				stack.BeginMoveAdd( UserMove1, piece->GetSquareNumber(), 
					piece->GetSquareNumber(), 'B' );
				stack.AddPickUp( piece->GetSquareNumber() );
				stack.AddDrop( piece, piece->GetSquareNumber(), &PolymorphAsBishop::polymorphAsBishop );
				stack.EndMoveAdd( -2000 );
				//	push conversion to Knishop
				stack.BeginMoveAdd( UserMove1, piece->GetSquareNumber(), 
					piece->GetSquareNumber(), 'n' );
				stack.AddPickUp( piece->GetSquareNumber() );
				stack.AddDrop( piece, piece->GetSquareNumber(), &PolymorphAsKnishop::polymorphAsKnishop );
				stack.EndMoveAdd( -2000 );
			}
			else if( &(piece->GetType()) == &(PolymorphAsKnishop::polymorphAsKnishop) )
			{
				//	push conversion to Knight
				stack.BeginMoveAdd( UserMove1, piece->GetSquareNumber(), 
					piece->GetSquareNumber(), 'N' );
				stack.AddPickUp( piece->GetSquareNumber() );
				stack.AddDrop( piece, piece->GetSquareNumber(), &PolymorphAsKnight::polymorphAsKnight );
				stack.EndMoveAdd( -2000 );
				//	push conversion to Bishop
				stack.BeginMoveAdd( UserMove1, piece->GetSquareNumber(), 
					piece->GetSquareNumber(), 'B' );
				stack.AddPickUp( piece->GetSquareNumber() );
				stack.AddDrop( piece, piece->GetSquareNumber(), &PolymorphAsBishop::polymorphAsBishop );
				stack.EndMoveAdd( -2000 );
				//	push conversion to Bishight
				stack.BeginMoveAdd( UserMove1, piece->GetSquareNumber(), 
					piece->GetSquareNumber(), 'b' );
				stack.AddPickUp( piece->GetSquareNumber() );
				stack.AddDrop( piece, piece->GetSquareNumber(), &PolymorphAsBishight::polymorphAsBishight);
				stack.EndMoveAdd( -2000 );
			}
		}
	}

	ChessGame::AddSpecialMoves( currentPlayer, stack, gameRecord, quiescentSearch );
}

void PolymorphChessGame::DescribeMove
	( MoveInfo &move,
	  char *queryDescription,
	  char *description,
	  char *notation )
{
	if( move.tag == 'B' || move.tag == 'b' || 
		move.tag == 'N' || move.tag == 'n' )
	{
		if( move.tag == 'B' && queryDescription != NULL )
			sprintf( queryDescription, "convert to Bishop" );
		else if( move.tag == 'N' && queryDescription != NULL )
			sprintf( queryDescription, "convert to Knight" );
		else if( move.tag == 'b' && queryDescription != NULL )
			sprintf( queryDescription, "convert to Bishight" );
		else if( move.tag == 'n' && queryDescription != NULL )
			sprintf( queryDescription, "convert to Knishop" );

		int fromRank = move.fromSquare / board.GetNumberOfFiles();
		int fromFile = move.fromSquare % board.GetNumberOfFiles();
		int toRank = move.toSquare / board.GetNumberOfFiles();
		int toFile = move.toSquare % board.GetNumberOfFiles();

		if( move.tag == 'B' && description != NULL )
			sprintf( description, "%s %c%c = Bishop", 
				move.originalType->GetFullName(),
				'a' + fromFile,
				'1' + fromRank );
		else if( move.tag == 'b' && description != NULL )
			sprintf( description, "%s %c%c = Bishight", 
				move.originalType->GetFullName(),
				'a' + fromFile,
				'1' + fromRank );
		else if( move.tag == 'N' && description != NULL )
			sprintf( description, "%s %c%c = Knight", 
				move.originalType->GetFullName(),
				'a' + fromFile,
				'1' + fromRank );
		else if( move.tag == 'n' && description != NULL )
			sprintf( description, "%s %c%c = Knishop", 
				move.originalType->GetFullName(),
				'a' + fromFile,
				'1' + fromRank );

		if( move.tag == 'B' && notation != NULL )
			sprintf( notation, "%c%c=B", 
				'a' + fromFile, '1' + fromRank );
		else if( move.tag == 'b' && notation != NULL )
			sprintf( notation, "%c%c=BI", 
				'a' + fromFile, '1' + fromRank );
		else if( move.tag == 'N' && notation != NULL )
			sprintf( notation, "%c%c=N", 
				'a' + fromFile, '1' + fromRank );
		else if( move.tag == 'n' && notation != NULL )
			sprintf( notation, "%c%c=NI", 
				'a' + fromFile, '1' + fromRank );
	}
	else
		ChessGame::DescribeMove( move, queryDescription, description, notation );
}

void PolymorphChessGame::DescribeMove
	( Movement &movement,
	  char *description )
{
	int fromRank = movement.GetFromSquare() / board.GetNumberOfFiles();
	int fromFile = movement.GetFromSquare() % board.GetNumberOfFiles();
	if( movement.GetTag() == 'B' )
		sprintf( description, "%c%c=B", 'a' + fromFile, '1' + fromRank );
	else if( movement.GetTag() == 'N' )
		sprintf( description, "%c%c=N", 'a' + fromFile, '1' + fromRank );
	else if( movement.GetTag() == 'b' )
		sprintf( description, "%c%c=BI", 'a' + fromFile, '1' + fromRank );
	else if( movement.GetTag() == 'n' )
		sprintf( description, "%c%c=NI", 'a' + fromFile, '1' + fromRank );
	else
		ChessGame::DescribeMove( movement, description );
}

int PolymorphChessGame::TranslateMove
	( MovementList &stack,
	  char *notation )
{
	if( notation[2] == '=' )
	{
		int fromSquare = board.GetFileByChar( notation[0] ) + board.GetRankByChar( notation[1] ) * board.GetNumberOfFiles();
		for( int x = 0; x < stack.GetCount(); x++ )
		{
			MoveInfo &move = stack.GetMove( x );
			if( move.fromSquare == fromSquare )
			{
				if( move.tag == 'b' && notation[3] == 'B' && notation[4] == 'I' )
					return x;
				else if( move.tag == 'B' && notation[3] == 'B' && notation[4] != 'I' )
					return x;
				else if( move.tag == 'n' && notation[3] == 'N' && notation[4] == 'I' )
					return x;
				else if( move.tag == 'N' && notation[3] == 'N' && notation[4] != 'I' )
					return x;
			}
		}
		//	move not found
		return -1;
	}
	return ChessGame::TranslateMove( stack, notation );
}

