# include "Game/Game.h"
# include "TranspositionTableTestCase.h"
# include "TestHeader.h"
# include "Color.h"
# include "Square.h"
# include "Pieces/Piece.h"
# include "Moves/SimpleMove.h"
# include "Moves/CapturingMove.h"
# include "Moves/PromotingMove.h"
# include "Moves/PromotingCapture.h"
# include "Moves/DoubleStep.h"
# include "Directions/Direction.h"
# include <sstream>

using namespace Alice;
void
TranspositionTableTestCase::initializing()
{
  Game g;
  TranspositionTable ttable;
  ttable.startObserving(&g);
};


void
TranspositionTableTestCase::basicMove()
{
  Game g;
  
  TranspositionTable ttable;
  ttable.startObserving(&g);
  HashCode before(ttable.getCurrentCode());
  Square e2(4, 1);
  Square e4(4, 3);
  SmartPointer<Move> move = SimpleMove::createInstance(e2, e4);
  move->makeOn(g);
  HashCode after(ttable.getCurrentCode());
  CPPUNIT_ASSERT(before != after);
  move->takeBackOn(g);
  after = ttable.getCurrentCode();
  CPPUNIT_ASSERT(before == after);
};
void
TranspositionTableTestCase::capture()
{
  Game g;
  g.forsytheString("r4k2/p3nppp/3q4/2Np1b2/1r1P3P/5QP1/P4PB1/2R1R1K1");
  TranspositionTable ttable;
  ttable.startObserving(&g);
  HashCode before(ttable.getCurrentCode());
  Square e1(4, 0);
  Square e7(4, 6);
  CapturingMove move(e1, e7);
  move.makeOn(g);
  HashCode after(ttable.getCurrentCode());
  CPPUNIT_ASSERT(before != after);
  move.takeBackOn(g);
  after = ttable.getCurrentCode();
  CPPUNIT_ASSERT(before == after);
  
};

void
TranspositionTableTestCase::promotion()
{
  Game g;
  g.forsytheString("8/P7/K7/8/k7/8/8/8/");
  TranspositionTable ttable;
  ttable.startObserving(&g);
  HashCode before(ttable.getCurrentCode());
  Square a7(0, 6);
  Square a8(0, 7);
  PromotingMove move(a7, a8, Piece::newQueen(Color::white()));
  move.makeOn(g);
  HashCode afterQueen(ttable.getCurrentCode());
  CPPUNIT_ASSERT(before != afterQueen);
  move.takeBackOn(g);
  CPPUNIT_ASSERT(before == ttable.getCurrentCode());
  PromotingMove move2(a7, a8, Piece::newRook(Color::white()));
  move2.makeOn(g);
  HashCode afterRook(ttable.getCurrentCode());
  CPPUNIT_ASSERT(before != afterRook);
  CPPUNIT_ASSERT(afterQueen != afterRook);
  move2.takeBackOn(g);
  CPPUNIT_ASSERT(before == ttable.getCurrentCode());
  
};

void
TranspositionTableTestCase::promotionCapture()
{
  Game g;
  g.forsytheString("r7/1P6/K7/8/k7/8/8/8/");
  TranspositionTable ttable;
  ttable.startObserving(&g);
  HashCode before(ttable.getCurrentCode());
  Square b7(1, 6);
  Square a8(0, 7);
  PromotingCapture move(b7, a8, Piece::newQueen(Color::white()));
  move.makeOn(g);
  HashCode afterQueen(ttable.getCurrentCode());
  CPPUNIT_ASSERT(before != afterQueen);
  move.takeBackOn(g);
  CPPUNIT_ASSERT(before == ttable.getCurrentCode());
  PromotingCapture move2(b7, a8, Piece::newRook(Color::white()));
  move2.makeOn(g);
  HashCode afterRook(ttable.getCurrentCode());
  CPPUNIT_ASSERT(before != afterRook);
  CPPUNIT_ASSERT(afterQueen != afterRook);
  move2.takeBackOn(g);
  CPPUNIT_ASSERT(before == ttable.getCurrentCode());
  
};

void
TranspositionTableTestCase::enPassant()
{
  Game g;
  g.forsytheString("k7/8/8/8/8/8/PP6/K7/w");
  TranspositionTable ttable;
  ttable.startObserving(&g);
  Square a2(0, 1);
  Square a4(0, 3);
  Square a3(0, 2);
  Square b2(1, 1);
  Square b3(1, 2);
  Square b4(1, 3);
  Square a8(0, 7);
  Square a7(0, 6);
  
  DoubleStep* a2a4 = DoubleStep::createInstance(a2, a4, a3);
  DoubleStep* b2b4 = DoubleStep::createInstance(b2, b4, b3);
  SmartPointer<Move> a8a7 = SimpleMove::createInstance(a8, a7);
  //std::cerr<<"ep test";
  HashCode before(ttable.getCurrentCode());
  
  a2a4->makeOn(g);
  a8a7->makeOn(g);
  b2b4->makeOn(g);
  
  HashCode after_b3(ttable.getCurrentCode());
  
  b2b4->takeBackOn(g);
  a8a7->takeBackOn(g);
  a2a4->takeBackOn(g);
  CPPUNIT_ASSERT(ttable.getCurrentCode() == before);
  
  b2b4->makeOn(g);
  a8a7->makeOn(g);
  a2a4->makeOn(g);
  
  HashCode after_a3(ttable.getCurrentCode());
  
  a2a4->takeBackOn(g);
  a8a7->takeBackOn(g);
  b2b4->takeBackOn(g);
  CPPUNIT_ASSERT(ttable.getCurrentCode() == before);
  CPPUNIT_ASSERT(after_a3 != after_b3);
  delete a2a4;
  delete b2b4;
};

void
TranspositionTableTestCase::changeGame()
{
  Game game1;
  TranspositionTable ttable;
  ttable.startObserving(&game1);
  Game game2;
  ttable.stopObserving();
  ttable.stopObserving();
  ttable.startObserving(&game2);
  ttable.stopObserving();
};

Test*
TranspositionTableTestCase::suite()
{
  TestSuite* testSuite = new TestSuite("TranspositionTableTestCase");
  AddTest(testSuite, TranspositionTableTestCase, initializing);
  AddTest(testSuite, TranspositionTableTestCase, basicMove);
  AddTest(testSuite, TranspositionTableTestCase, capture);
  AddTest(testSuite, TranspositionTableTestCase, promotion);
  AddTest(testSuite, TranspositionTableTestCase, promotionCapture);
  AddTest(testSuite, TranspositionTableTestCase, enPassant);
  AddTest(testSuite, TranspositionTableTestCase, changeGame);
  return testSuite;
};
