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

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


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


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


void StartSwitchingChessGame()
{
	if( !justLoaded )
		int rtn = (int) ::DialogBox( theInstance, MAKEINTRESOURCE(IDD_SWITCHING_CHESS_DIALOG), NULL, 
			reinterpret_cast<DLGPROC>(SwitchingChess_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, "Switching Chess" );
}

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

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

	//	the only settings that need to be changed are the value of 
	//	the pieces.  since, at this time, however, I have no idea 
	//	what the values will be, so we'll leave 'em alone for now.
}

void SwitchingChessGame::ChangeRulesByVariant
	( char *gameName,
	  char *&array,
	  char *&book )
{
	// *** SWITCHING CHESS *** //
	if( !strcmp( gameName, "Switching Chess" ) )
	{
		//	use the same handling as Orthodox Chess, except for
		//	the name of the opening book which we will change after
		ChessGame::ChangeRulesByVariant( "Orthodox Chess", array, book );
		//	set name of opening book
		book = "openings\\SwitchingChess.txt";
	}
	// *** SWITCHING SHATRANJ *** //
	else if( !strcmp( gameName, "Switching Shatranj" ) )
	{
		//	use the same handling as Shatranj, except for
		//	the name of the opening book which we will change after
		ChessGame::ChangeRulesByVariant( "Shatranj", array, book );
		//	set name of opening book
		book = "openings\\SwitchingShatranj.txt";
	}
}

void SwitchingChessGame::ChangeRulesByVariableDefinition( char *gameName )
{
	// *** SWITCHING RESTRICTION *** //
	LookupIntParameter( "restriction", restriction );

	//	process all rule changes by variable definition 
	//	of Orthodox Chess
	ChessGame::ChangeRulesByVariableDefinition( gameName );
}

void SwitchingChessGame::AddSpecialMoves
	( int currentPlayer, 
	  MovementList &stack, 
	  GameRec &gameRecord,
	  bool quiescentSearch )
{
	//	any two adjacent friendly pieces can switch places.
	//	so, add these switching moves, and then call
	//	ChessGame::AddSpecialMoves to handle castling and 
	//	en passant as usual

	if( !quiescentSearch && (restriction == 0 || !board.IsInCheck()) )
	{
		int player = board.GetCurrentPlayerNumber();
		for( int x = 0; x < board.GetNumberOfPieces( player ); x++ )
		{
			Piece *piece = board.GetPiece( player, x );
			if( !piece->IsCaptured() && 
				(restriction != 2 || !piece->GetType().IsRoyal()) )
			{
				for( int y = x + 1; y < board.GetNumberOfPieces( player ); y++ )
				{
					Piece *otherPiece = board.GetPiece( player, y );
					if( !otherPiece->IsCaptured() && 
						(restriction != 2 || !otherPiece->GetType().IsRoyal()) )
					{
						//	are they adjacent?
						if( board.distance[piece->GetSquareNumber()][otherPiece->GetSquareNumber()] == 1 )
						{
							//	make sure they're not the same type;
							//	it wouldn't make any sense to switch them
							if( &(piece->GetType()) != &(otherPiece->GetType()) )
							{
								//	check for pawn promotion
								if( (piece->IsPawn() && piece->GetPlayerNumber() == 0 && otherPiece->GetSquareNumber() >= A8 && otherPiece->GetSquareNumber() <= H8) ||
									(piece->IsPawn() && piece->GetPlayerNumber() == 1 && otherPiece->GetSquareNumber() >= A1 && otherPiece->GetSquareNumber() <= H1) ||
									(otherPiece->IsPawn() && otherPiece->GetPlayerNumber() == 0 && piece->GetSquareNumber() >= A8 && piece->GetSquareNumber() <= H8) || 
									(otherPiece->IsPawn() && otherPiece->GetPlayerNumber() == 1 && piece->GetSquareNumber() >= A1 && piece->GetSquareNumber() <= H1) )
								{
									//	ok, a pawn is being promoted.  make sure it's 
									//	"piece" and not "otherPiece"
									if( otherPiece->IsPawn() )
									{
										Piece *temp = piece;
										piece = otherPiece;
										otherPiece = temp;
									}
									int pieceSquare = piece->GetSquareNumber();
									int otherPieceSquare = otherPiece->GetSquareNumber();
									//	push move with promotion to Queen
									stack.BeginMoveAdd( UserMove1, pieceSquare, otherPieceSquare, 'Q' );
									stack.AddPickUp( pieceSquare );
									stack.AddPickUp( otherPieceSquare );
									stack.AddDrop( piece, otherPieceSquare, &OrthodoxQueen::orthodoxQueen );
									stack.AddDrop( otherPiece, pieceSquare );
									stack.EndMoveAdd( 0 );
									//	push same move with promotion to Knight
									stack.BeginMoveAdd( UserMove1, pieceSquare, otherPieceSquare, 'N' );
									stack.AddPickUp( pieceSquare );
									stack.AddPickUp( otherPieceSquare );
									stack.AddDrop( piece, otherPieceSquare, &OrthodoxKnight::orthodoxKnight );
									stack.AddDrop( otherPiece, pieceSquare );
									stack.EndMoveAdd( 0 );
									//	push same move with promotion to Bishop
									stack.BeginMoveAdd( UserMove1, pieceSquare, otherPieceSquare, 'B' );
									stack.AddPickUp( pieceSquare );
									stack.AddPickUp( otherPieceSquare );
									stack.AddDrop( piece, otherPieceSquare, &OrthodoxBishop::orthodoxBishop );
									stack.AddDrop( otherPiece, pieceSquare );
									stack.EndMoveAdd( 0 );
									//	push same move with promotion to Rook
									stack.BeginMoveAdd( UserMove1, pieceSquare, otherPieceSquare, 'R' );
									stack.AddPickUp( pieceSquare );
									stack.AddPickUp( otherPieceSquare );
									stack.AddDrop( piece, otherPieceSquare, &OrthodoxRook::orthodoxRook );
									stack.AddDrop( otherPiece, pieceSquare );
									stack.EndMoveAdd( 0 );

									//	if we are adding moves to the legalUserMoves stack, we also 
									//	want to add the "opposite" of the move we just added.  it is 
									//	really the same move, it just has the to and from squares 
									//	reversed.  we do this so that the user can drag either piece 
									//	on top of the other.
									if( &stack == &(board.GetLegalUserMovementList()) )
									{
										stack.BeginMoveAdd( UserMove1, otherPieceSquare, pieceSquare, 'Q' );
										stack.AddPickUp( pieceSquare );
										stack.AddPickUp( otherPieceSquare );
										stack.AddDrop( piece, otherPieceSquare, &OrthodoxQueen::orthodoxQueen );
										stack.AddDrop( otherPiece, pieceSquare );
										stack.EndMoveAdd( 0 );
										//	push same move with promotion to Knight
										stack.BeginMoveAdd( UserMove1, otherPieceSquare, pieceSquare, 'N' );
										stack.AddPickUp( pieceSquare );
										stack.AddPickUp( otherPieceSquare );
										stack.AddDrop( piece, otherPieceSquare, &OrthodoxKnight::orthodoxKnight );
										stack.AddDrop( otherPiece, pieceSquare );
										stack.EndMoveAdd( 0 );
										//	push same move with promotion to Bishop
										stack.BeginMoveAdd( UserMove1, otherPieceSquare, pieceSquare, 'B' );
										stack.AddPickUp( pieceSquare );
										stack.AddPickUp( otherPieceSquare );
										stack.AddDrop( piece, otherPieceSquare, &OrthodoxBishop::orthodoxBishop );
										stack.AddDrop( otherPiece, pieceSquare );
										stack.EndMoveAdd( 0 );
										//	push same move with promotion to Rook
										stack.BeginMoveAdd( UserMove1, otherPieceSquare, pieceSquare, 'R' );
										stack.AddPickUp( pieceSquare );
										stack.AddPickUp( otherPieceSquare );
										stack.AddDrop( piece, otherPieceSquare, &OrthodoxRook::orthodoxRook );
										stack.AddDrop( otherPiece, pieceSquare );
										stack.EndMoveAdd( 0 );
									}
								}
								else
								{
									//	add the switching move
									int pieceSquare = piece->GetSquareNumber();
									int otherPieceSquare = otherPiece->GetSquareNumber();
									stack.BeginMoveAdd( UserMove1, pieceSquare, otherPieceSquare );
									stack.AddPickUp( pieceSquare );
									stack.AddPickUp( otherPieceSquare );
									stack.AddDrop( piece, otherPieceSquare );
									stack.AddDrop( otherPiece, pieceSquare );
									stack.EndMoveAdd( 0 );

									//	if we are adding moves to the legalUserMoves stack, we also 
									//	want to add the "opposite" of the move we just added.  it is 
									//	really the same move, it just has the to and from squares 
									//	reversed.  we do this so that the user can drag either piece 
									//	on top of the other.
									if( &stack == &(board.GetLegalUserMovementList()) )
									{
										stack.BeginMoveAdd( UserMove1, otherPieceSquare, pieceSquare );
										stack.AddPickUp( pieceSquare );
										stack.AddPickUp( otherPieceSquare );
										stack.AddDrop( piece, otherPieceSquare );
										stack.AddDrop( otherPiece, pieceSquare );
										stack.EndMoveAdd( 0 );
									}
								}
							}
						}
					}
				}
			}
		}
	}

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

void SwitchingChessGame::DescribeMove
	( MoveInfo &move,
	  char *queryDescription,
	  char *description,
	  char *notation )
{
	if( move.tag == 'Q' && queryDescription != NULL )
		sprintf( queryDescription, "promote to Queen" );
	else if( move.tag == 'R' && queryDescription != NULL )
		sprintf( queryDescription, "promote to Rook" );
	else if( move.tag == 'N' && queryDescription != NULL )
		sprintf( queryDescription, "promote to Knight" );
	else if( move.tag == 'B' && queryDescription != NULL )
		sprintf( queryDescription, "promote to Bishop" );
	else
		ChessGame::DescribeMove( move, queryDescription, description, notation );
}
