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

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


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


BerolinaPawn BerolinaPawn::berolinaPawn;


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

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

	//	turn off ChessGame's en Passant; we have our own
	derivedClassEP = true;
	enPassant = true;

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

void BerolinaChessGame::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( BerolinaPawn::berolinaPawn );
	//	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] = &BerolinaPawn::berolinaPawn;
	pawnPieceTypes[1] = &BerolinaPawn::berolinaPawn;
	castlingPiecesSlideNorth[0] = true;
	castlingPiecesSlideNorth[1] = true;
}

void BerolinaChessGame::ChangeRulesByVariant
	( char *gameName,
	  char *&array,
	  char *&book )
{
	// *** BEROLINA CHESS *** //
	if( !strcmp( gameName, "Berolina Chess" ) )
	{
		//	place pieces
		array = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR";
		//	set name of opening book
		book = "openings\\BerolinaChess.txt";
	}
}

void BerolinaChessGame::AddSpecialMoves
	( int currentPlayer, 
	  MovementList &stack, 
	  GameRec &gameRecord,
	  bool quiescentSearch )
{
	//	check for special "berolina" en-passant
	if( enPassant && 
		gameRecord.pieceMoved != NULL &&
		gameRecord.pieceMoved->IsPawn() &&
		gameRecord.pieceMoved->HasMoved() &&
		!gameRecord.pieceMoved->HasMovedTwice() &&
		gameRecord.pieceMoved->GetSquareNumber() >= 24 &&
		gameRecord.pieceMoved->GetSquareNumber() < 32 )
	{
		//	white pawn just moved twice; see if there's
		//	a black pawn that can take it en passant
		int square1 = gameRecord.pieceMoved->GetSquareNumber() - 1;
		int square2 = gameRecord.pieceMoved->GetSquareNumber() + 1;
		if( square2 == 32 )
			square2 = -1;
		else if( square1 == 23 )
			square1 = -1;
		if( square1 != -1 && board.GetSquareContents( square1 ) != NULL &&
			gameRecord.pieceMoved->GetSquareNumber() > gameRecord.oldSquareNumber + 16 )
		{
			Piece *piece = board.GetSquareContents( square1 );
			if( piece->IsPawn() && piece->GetPlayerNumber() == 1 )
			{
				int captureSquare = gameRecord.pieceMoved->GetSquareNumber();
				stack.BeginMoveAdd( EnPassant, square1, captureSquare - 9 );
				stack.AddPickUp( square1 );
				stack.AddPickUp( captureSquare );
				stack.AddDrop( piece, captureSquare - 9 );
				stack.EndMoveAdd();
			}
		}
		if( square2 != -1 && board.GetSquareContents( square2 ) != NULL &&
			gameRecord.pieceMoved->GetSquareNumber() < gameRecord.oldSquareNumber + 16 )
		{
			Piece *piece = board.GetSquareContents( square2 );
			if( piece->IsPawn() && piece->GetPlayerNumber() == 1 )
			{
				int captureSquare = gameRecord.pieceMoved->GetSquareNumber();
				stack.BeginMoveAdd( EnPassant, square2, captureSquare - 7 );
				stack.AddPickUp( square2 );
				stack.AddPickUp( captureSquare );
				stack.AddDrop( piece, captureSquare - 7 );
				stack.EndMoveAdd();
			}
		}
	}
	if( enPassant && 
		gameRecord.pieceMoved != NULL &&
		gameRecord.pieceMoved->IsPawn() &&
		gameRecord.pieceMoved->HasMoved() &&
		!gameRecord.pieceMoved->HasMovedTwice() &&
		gameRecord.pieceMoved->GetSquareNumber() >= 32 &&
		gameRecord.pieceMoved->GetSquareNumber() < 40 )
	{
		//	black pawn just moved twice; see if there's
		//	a white pawn that can take it en passant 
		int square1 = gameRecord.pieceMoved->GetSquareNumber() - 1;
		int square2 = gameRecord.pieceMoved->GetSquareNumber() + 1;
		if( square2 == 40 )
			square2 = -1;
		else if( square1 == 31 )
			square1 = -1;
		if( square1 != -1 && board.GetSquareContents( square1 ) != NULL && 
			gameRecord.pieceMoved->GetSquareNumber() > gameRecord.oldSquareNumber - 16 )
		{
			Piece *piece = board.GetSquareContents( square1 );
			if( piece->IsPawn() && piece->GetPlayerNumber() == 0 )
			{
				int captureSquare = gameRecord.pieceMoved->GetSquareNumber();
				stack.BeginMoveAdd( EnPassant, square1, captureSquare + 7 );
				stack.AddPickUp( square1 );
				stack.AddPickUp( captureSquare );
				stack.AddDrop( piece, captureSquare + 7 );
				stack.EndMoveAdd();
			}
		}
		if( square2 != -1 && board.GetSquareContents( square2 ) != NULL && 
			gameRecord.pieceMoved->GetSquareNumber() < gameRecord.oldSquareNumber - 16 )
		{
			Piece *piece = board.GetSquareContents( square2 );
			if( piece->IsPawn() && piece->GetPlayerNumber() == 0 )
			{
				int captureSquare = gameRecord.pieceMoved->GetSquareNumber();
				stack.BeginMoveAdd( EnPassant, square2, captureSquare + 9 );
				stack.AddPickUp( square2 );
				stack.AddPickUp( captureSquare );
				stack.AddDrop( piece, captureSquare + 9 );
				stack.EndMoveAdd();
			}
		}
	}

	//	hand off to ChessGame, so Castling moves will be added
	ChessGame::AddSpecialMoves( currentPlayer, stack, gameRecord, quiescentSearch );
}

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

	//	include hash value for en-Passant square (if any)
	if( enPassant )
		return primaryHash ^ GetBerolinaEnPassantHash( board.GetGameRecord( board.GetGamePly() - 1 ), enPassantHashMap );

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