# include "TestPositionalEvaluation.h"
# include "Game/PositionalEvaluation.h"
# include "Game/Game.h"
# include "Color.h"
# include "Moves/CapturingMove.h"
# include <Moves/SimpleMove.h>
# include <Moves/CastlingMove.h>
# include <Game/PawnStructureFeature.h>
CPPUNIT_TEST_SUITE_REGISTRATION( TestPositionalEvaluation );
using namespace Alice;
void
TestPositionalEvaluation::initialize()
{
  //CPPUNIT_ASSERT(false);
  PositionalEvaluation eval;
  Game g;
  eval.startObserving(&g);
  CPPUNIT_ASSERT_EQUAL(Evaluation::Score(0), eval.score());
};

void 
TestPositionalEvaluation::basicValue()
{
  PositionalEvaluation eval;
  eval.setBasicValue(1000);
  short value = eval.getBasicValue();
  short target = 1000;
  CPPUNIT_ASSERT_EQUAL(target, value);
};

void
TestPositionalEvaluation::evaluation()
{
  PositionalEvaluation eval;
  eval.setBasicValue(1000);
  Game g;
  g.forsytheString("7k/8/8/8/8/8/P7/K7/w");
  eval.startObserving(&g);
  //CPPUNIT_ASSERT_EQUAL(Evaluation::Score(1030), eval.score());
};

void
TestPositionalEvaluation::centralization()
{
  Square a1(0,0);
  Square h8(7,7);
  Square e4(4,3);
  //std::cerr<<PositionalEvaluation::centralization(e4)<<std::endl;
  CPPUNIT_ASSERT_EQUAL(0, PositionalEvaluation::centralization(a1));
  CPPUNIT_ASSERT_EQUAL(0, PositionalEvaluation::centralization(h8));
  
  CPPUNIT_ASSERT_EQUAL(12, PositionalEvaluation::centralization(e4));
};

void
TestPositionalEvaluation::piecePlacement()
{
  PositionalEvaluation eval;
  eval.setBasicValue(1000);
  Game g;
  g.forsytheString("7k/8/8/8/4N3/8/8/7K/w");
  eval.startObserving(&g);
  //std::cout << eval.score() << std::endl;
  CPPUNIT_ASSERT_EQUAL(Evaluation::Score(3072), eval.score());
  SmartPointer<Move> move = 
    SimpleMove::createInstance(Square(4,3), Square(6,2));
  move->makeOn(g);
  //std::cout << eval.score() << std::endl;
  CPPUNIT_ASSERT_EQUAL(Evaluation::Score(-3036),  eval.score());
  eval.stopObserving();
  g.forsytheString("7k/8/8/8/4b3/8/8/7K/w");
  eval.startObserving(&g);
  //CPPUNIT_ASSERT_EQUAL(-3072, eval.score());
};

void
TestPositionalEvaluation::passedPawns()
{
  Game g;
  g.forsytheString("k7/8/p1Pp4/1P6/8/8/8/K7/w");
  PositionalEvaluation eval;
  eval.startObserving(&g);
  //eval.countPawns();
  eval.score();
  PawnStructureFeature feature;
  feature.countPawns(&g);
  Square a6(0,5);
  Square c6(2,5);
  Square b5(1,4);
  Square d6(3,5);
  CPPUNIT_ASSERT(! feature.isPassedPawn(&g, b5));
  CPPUNIT_ASSERT(feature.isPassedPawn(&g, c6));
  CPPUNIT_ASSERT(! feature.isPassedPawn(&g, a6));
  CPPUNIT_ASSERT(feature.isPassedPawn(&g, d6));
};

void
TestPositionalEvaluation::numberOfPawnsOnFile()
{
  Game g;
  g.forsytheString("k7/pp6/1p6/P7/8/8/PP6/7k/w");
  PawnStructureFeature eval;
  const Color* white = Color::white();
  const Color* black = Color::black();
  eval.countPawns(&g);
  CPPUNIT_ASSERT(2 == eval.numberOfPawnsOnFile(0, Color::white()));
  CPPUNIT_ASSERT(1 == eval.numberOfPawnsOnFile(0, black));
  CPPUNIT_ASSERT(1 == eval.numberOfPawnsOnFile(1, white));
  CPPUNIT_ASSERT(2 == eval.numberOfPawnsOnFile(1, black));
  Square a5(0, 4);
  Square b6(1, 5);
  CapturingMove move(a5, b6);
  move.makeOn(g);
  eval.countPawns(&g);
  CPPUNIT_ASSERT(1 == eval.numberOfPawnsOnFile(0, Color::white()));
  CPPUNIT_ASSERT(1 == eval.numberOfPawnsOnFile(0, black));
  CPPUNIT_ASSERT(2 == eval.numberOfPawnsOnFile(1, white));
  CPPUNIT_ASSERT(1 == eval.numberOfPawnsOnFile(1, black));
  
};

void
TestPositionalEvaluation::topPawn()
{
  //CPPUNIT_ASSERT(false);
  Game g;
  g.forsytheString("k7/pp6/1p6/P7/8/8/PP6/7k/w");
  PawnStructureFeature eval;
  eval.countPawns(&g);
  const Color* white = Color::white();
  const Color* black = Color::black();
  CPPUNIT_ASSERT(4 == eval.topPawn(0, white));
  CPPUNIT_ASSERT(6 == eval.topPawn(0, black));
  CPPUNIT_ASSERT(1 == eval.topPawn(1, white));
  CPPUNIT_ASSERT(6 == eval.topPawn(1, black));
  CPPUNIT_ASSERT(0 == eval.topPawn(5, white));
  CPPUNIT_ASSERT(0 == eval.topPawn(5, black));
  Square a5(0, 4);
  Square b6(1, 5);
  CapturingMove move(a5, b6);
  move.makeOn(g);
  
  eval.countPawns(&g);
  CPPUNIT_ASSERT(1 == eval.topPawn(0, white));
  CPPUNIT_ASSERT(6 == eval.topPawn(0, black));
  CPPUNIT_ASSERT(5 == eval.topPawn(1, white));
  CPPUNIT_ASSERT(6 == eval.topPawn(1, black));
  CPPUNIT_ASSERT(0 == eval.topPawn(5, white));
  CPPUNIT_ASSERT(0 == eval.topPawn(5, black));
};

void
TestPositionalEvaluation::bottomPawn()
{
  //CPPUNIT_ASSERT(false);
  Game g;
  g.forsytheString("k7/pp6/1p6/P7/8/8/PP6/7k/w");
  PawnStructureFeature eval;

  const Color* white = Color::white();
  const Color* black = Color::black();
  eval.countPawns(&g);
  CPPUNIT_ASSERT(1 == eval.bottomPawn(0, white));
  CPPUNIT_ASSERT(6 == eval.bottomPawn(0, black));
  CPPUNIT_ASSERT(1 == eval.bottomPawn(1, white));
  CPPUNIT_ASSERT(5 == eval.bottomPawn(1, black));
  CPPUNIT_ASSERT(7 == eval.bottomPawn(5, white));
  CPPUNIT_ASSERT(7 == eval.bottomPawn(5, black));
  Square a5(0, 4);
  Square b6(1, 5);
  CapturingMove move(a5, b6);
  move.makeOn(g);
  
  eval.countPawns(&g);
  CPPUNIT_ASSERT(1 == eval.bottomPawn(0, white));
  CPPUNIT_ASSERT(6 == eval.bottomPawn(0, black));
  CPPUNIT_ASSERT(1 == eval.bottomPawn(1, white));
  CPPUNIT_ASSERT(6 == eval.bottomPawn(1, black));
  CPPUNIT_ASSERT(7 == eval.bottomPawn(5, white));
  CPPUNIT_ASSERT(7 == eval.bottomPawn(5, black));
};

void
TestPositionalEvaluation::testKingSafety()
{
  {
    Game g;
    g.forsytheString("5rk1/5ppp/8/8/8/8/5PPP/5RK1/w");
    PawnStructureFeature feature;
    feature.countPawns(&g);
    CPPUNIT_ASSERT_EQUAL(0, feature.kingSafetyDeficiencies( Color::white() ) );
    CPPUNIT_ASSERT_EQUAL(0, feature.kingSafetyDeficiencies( Color::black() ) ); 
  }
  
  {
    Game g;
    g.forsytheString("5rk1/5ppp/8/8/8/6P1/5P1P/5RK1/w");
    PawnStructureFeature feature;
    feature.countPawns(&g);
    CPPUNIT_ASSERT_EQUAL(1, feature.kingSafetyDeficiencies( Color::white() ) );
    CPPUNIT_ASSERT_EQUAL(0, feature.kingSafetyDeficiencies( Color::black() ) ); 
  }
  
};
