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

                                 ChessV

                   COPYRIGHT (C) 2006 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 "Piece.h"
#include "Player.h"
#include "Board.h"
#include "PieceType.h"
//#include "ChessGame.h"


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


Promotion Piece::noPromotion;

extern bool testingBoolean;


int Piece::GetRank()
{
	return pBoard->ranks[playerNumber][squareNumber];
}

int Piece::GetFile()
{
	return pBoard->files[playerNumber][squareNumber];
}

int Piece::GetSignOfPlayer()
//	returns 1 for white pieces, -1 for black pieces
{
	return( playerNumber == 0 ? 1 : -1 );
}

void Piece::SetBoard( Board &board, int rank, int file )
{
	pBoard = &board;
	squareNumber = rank * board.GetNumberOfFiles() + file;
	realSquareNumber = squareNumber;

	//	allocate space for all squares on the board; this space will store
	//	information about how much strength a piece has on any given square
	//	(i.e., how many squares it attacks, and in how many directions it attacks)
	mobilityMatrix.SetSize( board.GetNumberOfSquares() );
}

int Piece::CompleteSetup()
{
	squaresVisible = 0;
	nTotalSafeChecks = 0;
	nTotalSquaresAttacked = 0;
	nTotalDirectionsAttacked = 0;
	fTotalMobility = 0.0;
	FindSquare( *pBoard, squareNumber, squaresVisible );

	aveSquaresAttacked = (float) nTotalSquaresAttacked / squaresVisible;
	aveDirectionsAttacked = (float) nTotalDirectionsAttacked / squaresVisible;
	aveSafeChecks = (float) nTotalSafeChecks / squaresVisible;
	aveMobility = fTotalMobility / squaresVisible;

	return squaresVisible;
}

void Piece::SetSquare( int rank, int file )
{
	squareNumber = rank * pBoard->GetNumberOfFiles() + file;
}

void Piece::GenerateMoves
	( MovementList &moves,
	  Board &board )
{
	pPieceType->GenerateMoves( moves, board, *this, squareNumber );
}

void Piece::GenerateCaptures
	( MovementList &moves,
	  Board &board )
{
	pPieceType->GenerateCaptures( moves, board, *this, squareNumber );
}

bool Piece::DoesAttackSquare
	( int targetRank,
	  int targetFile )
{
	int myRank = squareNumber / pBoard->GetNumberOfFiles();
	int myFile = squareNumber % pBoard->GetNumberOfFiles();
	bool doesAttack = pPieceType->DoesAttackSquare( *pPlayer, myRank, myFile, targetRank, targetFile );
	return( doesAttack );
}

int Piece::CountMoves
	( int &pseudoLegal )
{
	int myRank = squareNumber / pBoard->GetNumberOfFiles();
	int myFile = squareNumber % pBoard->GetNumberOfFiles();
	return( GetType().CountMoves( *pPlayer, myRank, myFile, pseudoLegal ) );
}

void Piece::SwitchType
	( PieceType *newType )
{
	pPieceType = newType;
}

void Piece::FindSquare( Board &board, int square, int &nSquaresSeen )
{
	nSquaresSeen++;
	float squareVal = 0.0;
	int i;

	//	iterate through each move capability (or move direction)
	for( i = 0; i < pPieceType->nMoveCapabilities; i++ )
	{
		//	initialize move vector for this movement direction
		MovementCapability &move = pPieceType->moveCapabilities[i];

		//	initialize flag to stop our movement when we hit the edge of the board
		bool onBoard = true;
		int current = square;
		int *matrix = playerNumber == 0 ?
			board.GetMovementMatrix( move.GetDirectionNumber() ) :
			board.GetOppositeMovementMatrix( move.GetDirectionNumber() );

		//	iterate through the maximum number of steps we may move in this
		//	direction, or until we leave the edge of the board
		float factor = (float) 1.0;
		for( int j = 1; j <= move.GetMaxSteps() && onBoard; j++ )
		{
			current = matrix[current];

			//	are we still on the board?
			onBoard = current >= 0;
					        
			if( onBoard )
			{
				if( move.CanCapture() || move.GetMaxSteps() != 1 )
					squareVal += factor;
				if( move.CanCapture() )
				{
					fTotalMobility += factor;
					nTotalSquaresAttacked++;
					if( j == move.GetMinSteps() )
						nTotalDirectionsAttacked++;
					if( theBoard->distance[current][square] > 1 )
						nTotalSafeChecks++;
				}
			}
			factor *= (float) 0.7;
		}
	}
	int intSquareVal = (int) (squareVal + 0.5);
	mobilityMatrix[square] = intSquareVal == 0 ? 1 : intSquareVal;
	
	//	iterate through each move capability (or move direction) again,
	//	this time recursively calling FindSquare() so that we calculate
	//	the statistics for that square as well.
	for( i = 0; i < pPieceType->nMoveCapabilities; i++ )
	{
		//	initialize move vector for this movement direction
		MovementCapability &move = pPieceType->moveCapabilities[i];

		if( move.CanMove() )
		{
			//	initialize flag to stop our movement when we hit the edge of the board
			int current = square;
			int *matrix = playerNumber == 0 ?
				board.GetMovementMatrix( move.GetDirectionNumber() ) :
				board.GetOppositeMovementMatrix( move.GetDirectionNumber() );

			current = matrix[current];

			//	are we still on the board?
			if( current >= 0 )
			{
				//	check to see if we've marked this square before
				if( mobilityMatrix[current] == 0 )
				{
					//	we haven't marked this square yet, so recursively call
					//	this function, so that we index and mark it.
					FindSquare( board, current, nSquaresSeen );
				}
			}
		}
	}
}

void Piece::Output( FILE *fi )
{
	for( int r = 0; r < pBoard->GetNumberOfRanks(); r++ )
	{
		for( int f = 0; f < pBoard->GetNumberOfFiles(); f++ )
		{
			int nSquare = r * pBoard->GetNumberOfFiles() + f;
			fprintf( fi, "%d ", mobilityMatrix[nSquare] );
		}
		fprintf( fi, "\n" );
	}
}
