/***************************************************************************
                          Evaluation.cpp  -  description
                             -------------------
    begin                : Tue May 22 2001
    copyright            : (C) 2001 by Sven Reichard
    email                : reichard@math.udel.edu
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program 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.                                   *
 *                                                                         *
 ***************************************************************************/
# include "Game/Evaluation.h"
# include "Moves/CapturingMove.h"
# include "Moves/PromotingMove.h"
# include "Moves/PromotingCapture.h"
# include "Moves/EnPassantMove.h"
# include "Game/Game.h"
# include "Pieces/Piece.h"
# include "Color.h"
# include <math.h>

using namespace Alice;
Evaluation::Evaluation()
  :_basicValue(1)
{
  
};

Evaluation::~Evaluation()
{};

void
Evaluation::startObserving(Game* game)
{
  GameObserver::startObserving(game);
  while (! mScoreStack.empty())
    mScoreStack.pop();
  mScoreStack.push(stalemate());
  Color* c = ((Game*)game)->colorToMove();
  for (int i = 0; i < 8; i++)
    for (int j = 0; j < 8; j++)
      {
	const Piece* p = ((Game*)game)->board().at(Square(i, j));
	if (! p->isNull())
	  {
	    if (p->color() == c)
	      mScoreStack.top() += pieceValue(p);
	    else
	      mScoreStack.top() -= pieceValue(p);
	  }
      }

};

Evaluation::Score
Evaluation::score() const
{
  return boundedScore(mate(), -mate());
}


Evaluation::Score
Evaluation::boundedScore(Score alpha, Score beta) const
{
  verify();
  assert(mScoreStack.size());
  return mScoreStack.top();
};

void
Evaluation::basicDoMove(Move& move)
{
  mScoreStack.push(propagate(mScoreStack.top()));
};

void Evaluation::basicTakeBack(Move& move)
{
  mScoreStack.pop();
};
void
Evaluation::doNullMove()
{
  mScoreStack.top()= propagate(mScoreStack.top());
};

void 
Evaluation::takeBackNullMove()
{
  mScoreStack.top() = backPropagate(mScoreStack.top());
};

void
Evaluation::doCapturingMove(CapturingMove& move)
{
  basicDoMove(move);
  Square sq(move.destination());
  const Piece* p=observedGame->board().at(sq);
  mScoreStack.top() -= pieceValue(p);
  ;
};

void
Evaluation::doPromotingMove(PromotingMove& move)
{
  basicDoMove(move);
  Square sq(move.source());
  const Piece* p=observedGame->board().at(sq);
  mScoreStack.top() += pieceValue(p);
  mScoreStack.top() -= pieceValue(move.promotedPiece());
  ;
};
void
Evaluation::doPromotingCapture(PromotingCapture& move)
{
  basicDoMove(move);
  Square sq(move.source());
  const Piece* p=observedGame->board().at(sq);
  mScoreStack.top() += pieceValue(p);
  mScoreStack.top() -= pieceValue(move.promotedPiece());
  Square dest(move.destination());
  const Piece* victim=observedGame->board().at(dest);
  mScoreStack.top() -= pieceValue(victim);
  ;
};

void
Evaluation::doEnPassantMove(EnPassantMove& move)
{
  basicDoMove(move);
  const Piece* p = observedGame->board().at(move.capturedSquare());
  mScoreStack.top() -= pieceValue(p);
  ;
};
/*
std::ostream&
operator << (std::ostream& out, const Evaluation::Score& score)
{
	short s = score.getValue();
	short c = -30000;
	if (score.getValue() > 30000)
		return out<<"#"<<31001-score.getValue();
	if (s < c)
		return out<<"-#"<<score.getValue() + 31001;
	return out<<score.getValue();
};
*/
Evaluation::Score
Evaluation::pieceValue(const Piece* p) const
{
  assert(p != 0);
  return Score(p->basicValue()*_basicValue);
};

void
Evaluation::setBasicValue(short int value)
{
  _basicValue = value;
};

void
Evaluation::verify() const
{
  Game* game = (Game*) observedGame;
  Color* c = game->colorToMove();
  Score score = 0;
  for (int i = 0; i < 8; i++)
    for (int j = 0; j < 8; j++)
      {
	const Piece* p = ((Game*)game)->board().at(Square(i, j));
	if (! p->isNull())
	  {
	    if (p->color() == c)
	      score  += pieceValue(p);
	    else
	      score -= pieceValue(p);
	  }
      }
  if (fabs(score - mScoreStack.top()) > 500 )
    {
      std::cerr<<"score: "<<score<<std::endl;
      std::cerr<<"stack: "<<mScoreStack.top()<<std::endl;
      game->board().displayOn(std::cerr);
      assert(false);
    }
  
};
