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

                                 ChessV

                   COPYRIGHT (C) 2016 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 "../../GameParameters.h"
#include "CWAKGame.h"


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


void StartCWAKGame()
{
	int rtn = 0;
	if( !justLoaded )
	{
		rtn = (int) ::DialogBox( theInstance, MAKEINTRESOURCE(IDD_CWAK_SELECT_DIALOG), NULL, 
			reinterpret_cast<DLGPROC>(CWAK_SelectDlgProc) );
	}

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

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

CWAKGame::CWAKGame( Board &board, Player &whitePlayer, Player &blackPlayer ):
	ChessGame(board, whitePlayer, blackPlayer)
{
	// *** OUTPOSTS *** //

	//	we use the user variable 'gameInt1' in the PieceType class
	//	to store the 'outpost factor' for a given piece.  this value will
	//	be multiplied by the square-values stored in the 'outpost' array.
	KnightWazir::knightWazir.gameInt1 = 8;
	KnightFerz::knightFerz.gameInt1 = 8;
	KnightDabbabah::knightDabbabah.gameInt1 = 8;
	KnightAlfil::knightAlfil.gameInt1 = 8;
}

void CWAKGame::AddPlayerPieceTypes( char *gameName )
{
	//	add the piece types that each player may have
	board.AddPlayerPieceTypeBothPlayers( OrthodoxRook::orthodoxRook );
	board.AddPlayerPieceTypeBothPlayers( OrthodoxBishop::orthodoxBishop );
	board.AddPlayerPieceTypeBothPlayers( OrthodoxQueen::orthodoxQueen );
	board.AddPlayerPieceTypeBothPlayers( OrthodoxKing::orthodoxKing );
	board.AddPlayerPieceTypeBothPlayers( OrthodoxPawn::orthodoxPawn );
//	board.AddPlayerPieceTypeBothPlayers( augmentedKnight0Type );
//	board.AddPlayerPieceTypeBothPlayers( augmentedKnight1Type );
	//	initialize piece type references
	castlingPieceTypes[0] = &OrthodoxRook::orthodoxRook;
	castlingPieceTypes[1] = &OrthodoxRook::orthodoxRook;
//	minorPieceTypes[0][0] = &augmentedKnight0Type;
//	minorPieceTypes[1][0] = &augmentedKnight1Type;
	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] = &OrthodoxPawn::orthodoxPawn;
	pawnPieceTypes[1] = &OrthodoxPawn::orthodoxPawn;
	castlingPiecesSlideNorth[0] = true;
	castlingPiecesSlideNorth[1] = true;
}

static char filename[] = "openings\\CWAK_FF_v_FF.txt";

void CWAKGame::ChangeRulesByVariant
	( char *gameName,
	  char *&array,
	  char *&book )
{
	// *** CHESS with AUGMENTED KNIGHTS *** //
	if( !strcmp( gameName, "Chess with Augmented Knights" ) )
	{
		//	place pieces
		array = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR";
		//	set name of opening book
		book = filename;
	}
}

void CWAKGame::Initialize()
{
	char *knight;
	if( LookupStringParameter( "white-knight", knight ) )
	{
		if( stringCompNoCase( knight, "Knight+Ferz" ) )
		{
			//	knight + ferz
			minorPieceTypes[0][0] = &KnightFerz::knightFerz;
			filename[14] = 'N';
			filename[15] = 'F';
			board.AddPlayerPieceType( KnightFerz::knightFerz, 0 );
		}
		else if( stringCompNoCase( knight, "Knight+Wazir" ) )
		{
			//	knight + wazir
			minorPieceTypes[0][0] = &KnightWazir::knightWazir;
			filename[14] = 'N';
			filename[15] = 'W';
			board.AddPlayerPieceType( KnightWazir::knightWazir, 0 );
		}
		else if( stringCompNoCase( knight, "Knight+Dabbabah" ) )
		{
			//	knight + dabbabah
			minorPieceTypes[0][0] = &KnightDabbabah::knightDabbabah;
			filename[14] = 'N';
			filename[15] = 'D';
			board.AddPlayerPieceType( KnightDabbabah::knightDabbabah, 0 );
		}
		else if( stringCompNoCase( knight, "Knight+Alfil" ) )
		{
			//	knight + alfil
			minorPieceTypes[0][0] = &KnightAlfil::knightAlfil;
			filename[14] = 'N';
			filename[15] = 'A';
			board.AddPlayerPieceType( KnightAlfil::knightAlfil, 0 );
		}
		else
		{
			//	standard knight
			minorPieceTypes[0][0] = &OrthodoxKnight::orthodoxKnight;
			filename[14] = 'K';
			filename[15] = 'N';
			board.AddPlayerPieceType( OrthodoxKnight::orthodoxKnight, 0 );
		}
	}
	if( LookupStringParameter( "black-knight", knight ) )
	{
		if( !strcmp( knight, "Knight+Ferz" ) )
		{
			//	knight + ferz
			minorPieceTypes[1][0] = &KnightFerz::knightFerz;
			filename[19] = 'N';
			filename[20] = 'F';
			board.AddPlayerPieceType( KnightFerz::knightFerz, 1 );
		}
		else if( !strcmp( knight, "Knight+Wazir" ) )
		{
			//	knight + wazir
			minorPieceTypes[1][0] = &KnightWazir::knightWazir;
			filename[19] = 'N';
			filename[20] = 'W';
			board.AddPlayerPieceType( KnightWazir::knightWazir, 1 );
		}
		else if( !strcmp( knight, "Knight+Dabbabah" ) )
		{
			//	knight + dabbabah
			minorPieceTypes[1][0] = &KnightDabbabah::knightDabbabah;
			filename[19] = 'N';
			filename[20] = 'D';
			board.AddPlayerPieceType( KnightDabbabah::knightDabbabah, 1 );
		}
		else if( !strcmp( knight, "Knight+Alfil" ) )
		{
			//	knight + alfil
			minorPieceTypes[1][0] = &KnightAlfil::knightAlfil;
			filename[19] = 'N';
			filename[20] = 'A';
			board.AddPlayerPieceType( KnightAlfil::knightAlfil, 1 );
		}
		else
		{
			//	standard knight
			minorPieceTypes[1][0] = &OrthodoxKnight::orthodoxKnight;
			filename[14] = 'K';
			filename[15] = 'N';
			board.AddPlayerPieceType( OrthodoxKnight::orthodoxKnight, 1 );
		}
	}

	//	let the base class Initialize() do its thing
	ChessGame::Initialize();
}

/*
void CWAKGame::GenerateMoves
	( int currentPlayer, 
	  MovementList &list )
{
	BitBoard64 pieces;

	// *** PAWNS *** //
	pieces = OrthodoxPawn::orthodoxPawn.GetPieces( currentPlayer );
	while( pieces )
	{
		int square = pieces.GetFirstBit();
		pieces.ClearBit( square );
		OrthodoxPawn::orthodoxPawn.BB64_GenerateDirectCaptures( list, currentPlayer, square );
		OrthodoxPawn::orthodoxPawn.BB64_GenerateDirectMovesNoCapture( list, currentPlayer, square );
	}
	//	handle the initial 2-step pawn move
	if( currentPlayer == 0 )
	{
		BitBoard64 secondRankPawns = player0PawnTwoSpaceZone & 
			OrthodoxPawn::orthodoxPawn.GetPieces( 0 );
		while( secondRankPawns )
		{
			int square = secondRankPawns.GetFirstBit();
			secondRankPawns.ClearBit( square );
			if( board.GetSquareContents( square + 8 ) == NULL && 
				board.GetSquareContents( square + 16 ) == NULL )
				//	squares are open; add the two-step move
				list.AddMove( square, square + 16 );
		}
	}
	else
	{
		BitBoard64 seventhRankPawns = player1PawnTwoSpaceZone & 
			OrthodoxPawn::orthodoxPawn.GetPieces( 1 );
		while( seventhRankPawns )
		{
			int square = seventhRankPawns.GetFirstBit();
			seventhRankPawns.ClearBit( square );
			if( board.GetSquareContents( square - 8 ) == NULL && 
				board.GetSquareContents( square - 16 ) == NULL )
				//	squares are open; add the two-step move
				list.AddMove( square, square - 16 );
		}
	}

	// *** KNIGHTS *** //
	if( currentPlayer == 0 )
	{
		pieces = augmentedKnight0Type.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.GetFirstBit();
			pieces.ClearBit( square );
			augmentedKnight0Type.BB64_GenerateDirectMoves( list, currentPlayer, square );
		}
	}
	else
	{
		pieces = augmentedKnight1Type.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.GetFirstBit();
			pieces.ClearBit( square );
			augmentedKnight1Type.BB64_GenerateDirectMoves( list, currentPlayer, square );
		}
	}

	// *** KING *** //
	Piece *king = board.GetKing( currentPlayer );
	OrthodoxKing::orthodoxKing.BB64_GenerateDirectMoves( list, currentPlayer, king->GetSquareNumber() );

	// *** ROOK sliders *** //
	BitBoard64 friends = board.bb64_friends[currentPlayer];
	pieces = OrthodoxRook::orthodoxRook.GetPieces( currentPlayer ) |  
		OrthodoxQueen::orthodoxQueen.GetPieces( currentPlayer );
	while( pieces )
	{
		int square = pieces.GetFirstBit();
		pieces.ToggleBit( square );

		BitBoard64 moves;
		moves = board.bb64_rook00attack[square * board.rook00attackWidth + 
			((board.bb64_blocker >> board.shift00[square]) & board.mask00[square])] | 
			board.bb64_rook90attack[square * board.rook90attackWidth + 
			((board.bb64_blocker90 >> board.shift90[square]) & board.mask90[square])];
		moves = moves & (~friends);
		if( moves )
			list.AddBitBoard64Moves( square, moves );
	}

	// *** BISHOP sliders *** // 
	pieces = OrthodoxBishop::orthodoxBishop.GetPieces( currentPlayer ) | 
		OrthodoxQueen::orthodoxQueen.GetPieces( currentPlayer );
	while( pieces )
	{
		int square = pieces.GetFirstBit();
		pieces.ToggleBit( square );

		BitBoard64 moves;
		moves = board.bb64_bishop45attack[square * board.bishop45attackWidth + 
			((board.bb64_blocker45 >> board.shift45[square]) & board.mask45[square])] | 
			board.bb64_bishop135attack[square * board.bishop135attackWidth + 
			((board.bb64_blocker135 >> board.shift135[square]) & board.mask135[square])];
		moves = moves & (~friends);
		if( moves )
			list.AddBitBoard64Moves( square, moves );
	}

	//	check for en-passant
	AddSpecialMoves( currentPlayer, list, board.GetCurrentGameRecord(), false );
}

void CWAKGame::GenerateCaptures
	( int currentPlayer, 
	  MovementList &list )
{
	BitBoard64 pieces;

	// *** PAWNS *** //
	pieces = OrthodoxPawn::orthodoxPawn.GetPieces( currentPlayer );
	while( pieces )
	{
		int square = pieces.GetFirstBit();
		pieces.ClearBit( square );
		OrthodoxPawn::orthodoxPawn.BB64_GenerateDirectCaptures( list, currentPlayer, square );
	}

	// *** KNIGHTS *** //
	if( currentPlayer == 0 )
	{
		pieces = augmentedKnight0Type.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.GetFirstBit();
			pieces.ClearBit( square );
			augmentedKnight0Type.BB64_GenerateDirectCaptures( list, currentPlayer, square );
		}
	}
	else
	{
		pieces = augmentedKnight1Type.GetPieces( currentPlayer );
		while( pieces )
		{
			int square = pieces.GetFirstBit();
			pieces.ClearBit( square );
			augmentedKnight1Type.BB64_GenerateDirectCaptures( list, currentPlayer, square );
		}
	}

	// *** KING *** //
	Piece *king = board.GetKing( currentPlayer );
	OrthodoxKing::orthodoxKing.BB64_GenerateDirectCaptures( list, currentPlayer, king->GetSquareNumber() );

	// *** ROOK sliders *** //
	BitBoard64 enemies = board.bb64_friends[FLIP(currentPlayer)];
	pieces = OrthodoxRook::orthodoxRook.GetPieces( currentPlayer ) |  
		OrthodoxQueen::orthodoxQueen.GetPieces( currentPlayer );
	while( pieces )
	{
		int square = pieces.GetFirstBit();
		pieces.ToggleBit( square );

		BitBoard64 moves;
		moves = board.bb64_rook00attack[square * board.rook00attackWidth + 
			((board.bb64_blocker >> board.shift00[square]) & board.mask00[square])] | 
			board.bb64_rook90attack[square * board.rook90attackWidth + 
			((board.bb64_blocker90 >> board.shift90[square]) & board.mask90[square])];
		moves = moves & enemies;
		if( moves )
			list.AddBitBoard64Captures( square, moves );
	}

	// *** BISHOP sliders *** // 
	pieces = OrthodoxBishop::orthodoxBishop.GetPieces( currentPlayer ) | 
		OrthodoxQueen::orthodoxQueen.GetPieces( currentPlayer );
	while( pieces )
	{
		int square = pieces.GetFirstBit();
		pieces.ToggleBit( square );

		BitBoard64 moves;
		moves = board.bb64_bishop45attack[square * board.bishop45attackWidth + 
			((board.bb64_blocker45 >> board.shift45[square]) & board.mask45[square])] | 
			board.bb64_bishop135attack[square * board.bishop135attackWidth + 
			((board.bb64_blocker135 >> board.shift135[square]) & board.mask135[square])];
		moves = moves & enemies;
		if( moves )
			list.AddBitBoard64Captures( square, moves );
	}

	//	check for en-passant
	if( enPassant )
		Game::AddEnPassantMoves( list, board.GetCurrentGameRecord(), true );
}

bool CWAKGame::IsSquareAttacked
	( int squareNumber, 
	  int playerNumber )
{
	BitBoard64 pieces;
	int otherPlayer = FLIP(playerNumber);

	// *** PAWNS *** //
	if( OrthodoxPawn::orthodoxPawn.bb64_attack[otherPlayer][squareNumber] &
		OrthodoxPawn::orthodoxPawn.GetPieces( playerNumber ) )
		return true;

	// *** AUGMENTED KNIGHTS *** //
	if( playerNumber == 0 )
	{
		if( augmentedKnight0Type.bb64_attack[otherPlayer][squareNumber] & 
			augmentedKnight0Type.GetPieces( playerNumber ) )
			return true;
	}
	else
	{
		if( augmentedKnight1Type.bb64_attack[otherPlayer][squareNumber] & 
			augmentedKnight1Type.GetPieces( playerNumber ) )
			return true;
	}

	// *** KINGS *** //
	if( OrthodoxKing::orthodoxKing.bb64_attack[otherPlayer][squareNumber] &
		OrthodoxKing::orthodoxKing.GetPieces( playerNumber ) )
		return true;

	// *** ROOKS *** //
	pieces = OrthodoxRook::orthodoxRook.bb64_attack[otherPlayer][squareNumber] & 
		(OrthodoxRook::orthodoxRook.GetPieces( playerNumber ) | 
		 OrthodoxQueen::orthodoxQueen.GetPieces( playerNumber ));
	while( pieces )
	{
		int square = pieces.GetFirstBit();
		if( ! ((bool) (board.bb64_rays[(squareNumber * board.GetNumberOfSquares()) + square] & 
			  board.bb64_blocker & ~BitBoard64::GetPositionBitBoard( square ))) )
			return true;
		pieces.ClearBit( square );
	}

	// *** BISHOPS *** //
	pieces = OrthodoxBishop::orthodoxBishop.bb64_attack[otherPlayer][squareNumber] & 
		(OrthodoxBishop::orthodoxBishop.GetPieces( playerNumber ) | 
		 OrthodoxQueen::orthodoxQueen.GetPieces( playerNumber ));
	while( pieces )
	{
		int square = pieces.GetFirstBit();
		if( ! ((bool) (board.bb64_rays[(squareNumber * board.GetNumberOfSquares()) + square] & 
			  board.bb64_blocker & ~BitBoard64::GetPositionBitBoard( square ))) )
			return true;
		pieces.ClearBit( square );
	}

	return false;
}
*/