/***************************************************************************
                          CastlingTestCase.cpp  -  description
                             -------------------
    begin                : Sun Sep 2 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 <iostream>
#include "CastlingTestCase.h"
# include "TestHeader.h"
# include "Game/Game.h"
# include "Game/CastlingSentry.h"
# include "Moves/SimpleMove.h"
# include "Color.h"
# include "Moves/CastlingMove.h"
using namespace Alice;
//CastlingTestCase::CastlingTestCase(){
//}
CastlingTestCase::~CastlingTestCase(){
}

void
CastlingTestCase::basic()
{
  Game g;

  g.forsytheString("k7/8/8/8/8/8/8/4K2R/w");
  CastlingSentry sentry;
  sentry.startObserving(&g);
  CPPUNIT_ASSERT(sentry.canCastleShort());

  sentry.stopObserving();
  g.forsytheString("k7/8/8/8/8/8/8/R3K3/w");
  sentry.startObserving(&g);
  CPPUNIT_ASSERT(sentry.canCastleLong());
};

Test*
CastlingTestCase::suite()
{
  TestSuite* testSuite = new TestSuite("CastlingTestCase");
  AddTest(testSuite, CastlingTestCase, basic);
  AddTest(testSuite, CastlingTestCase, obstructed);
  AddTest(testSuite, CastlingTestCase, inCheck);
  AddTest(testSuite, CastlingTestCase, attacked);
  AddTest(testSuite, CastlingTestCase, moved);
  AddTest(testSuite, CastlingTestCase, generate);
  AddTest(testSuite, CastlingTestCase, testHasCastled);
  return testSuite;
};
/** make sure we can't castle if any pieces
are between the king and the rook. */
void CastlingTestCase::obstructed()
{
  
  Game g;
  g.forsytheString("k7/8/8/8/8/8/8/4K1NR/w");
  CastlingSentry sentry;
  sentry.startObserving(&g);
  CPPUNIT_ASSERT(!sentry.canCastleShort());
  sentry.stopObserving();
  g.forsytheString("k7/8/8/8/8/8/8/4Kb1R/w");
  sentry.startObserving(&g);
  CPPUNIT_ASSERT(!sentry.canCastleShort());
  sentry.stopObserving();
  g.forsytheString("k7/8/8/8/8/8/8/R1B1K3/w");
  sentry.startObserving(&g);
  CPPUNIT_ASSERT(!sentry.canCastleLong());
  sentry.stopObserving();
  g.forsytheString("k7/8/8/8/8/8/8/RN2K3/w");
  sentry.startObserving(&g);
  CPPUNIT_ASSERT(!sentry.canCastleLong());
};
/** don't allow castling when in check */
void CastlingTestCase::inCheck(){
  Game g;
  g.forsytheString("k7/8/8/b7/8/8/8/R3K2R/w");
  CastlingSentry sentry;
  sentry.startObserving(&g);
  CPPUNIT_ASSERT(!sentry.canCastleShort());
  CPPUNIT_ASSERT(!sentry.canCastleLong());
  sentry.stopObserving();
}
/** don't  castle across an attacked square */
void CastlingTestCase::attacked(){
  Game g;
  g.forsytheString("k7/8/b7/8/8/8/8/R3K2R/w");
  CastlingSentry sentry;
  sentry.startObserving(&g);
  CPPUNIT_ASSERT(!sentry.canCastleShort());
  CPPUNIT_ASSERT(sentry.canCastleLong());
  sentry.stopObserving();
  
  g.forsytheString("k7/8/8/8/b7/8/8/R3K2R/w");
  sentry.startObserving(&g);
  CPPUNIT_ASSERT(sentry.canCastleShort());
  CPPUNIT_ASSERT(!sentry.canCastleLong());
  sentry.stopObserving();
  
}
/** check that castling isn't allowed if any
    of the involved pieces have moved. */
void CastlingTestCase::moved(){
  Game g;
  g.forsytheString("r3k2r/8/8/8/8/8/8/R3K2R/w");
  CastlingSentry sentry;
  sentry.startObserving(&g);
  CPPUNIT_ASSERT(sentry.canCastleShort());
  CPPUNIT_ASSERT(sentry.canCastleLong());
  Square e1(4, 0),
    e2(4,1),
    e7(4,6),
    e8(4,7);
  SmartPointer<Move> e1e2 = SimpleMove::createInstance(e1, e2);
  SmartPointer<Move> e2e1= SimpleMove::createInstance(e2, e1);
  SmartPointer<Move> e8e7= SimpleMove::createInstance(e8, e7);
  SmartPointer<Move> e7e8= SimpleMove::createInstance(e7, e8);
  e1e2->makeOn(g);
  e8e7->makeOn(g);
  e2e1->makeOn(g);
  e7e8->makeOn(g);
  CPPUNIT_ASSERT(!sentry.canCastleShort());
  CPPUNIT_ASSERT(!sentry.canCastleLong());
  e7e8->takeBackOn(g);
  e2e1->takeBackOn(g);
  e8e7->takeBackOn(g);
  e1e2->takeBackOn(g);
  CPPUNIT_ASSERT(sentry.canCastleShort());
  CPPUNIT_ASSERT(sentry.canCastleLong());
};
/** see if castling is properly generated */
void CastlingTestCase::generate()
{
  Game g;
  g.forsytheString("r3k2r/8/8/8/8/8/8/R3K2R/w");
  
  //g.forsytheString("3k4/8/8/8/8/8/1r6/R3K3/w");
  CastlingSentry sentry;
  sentry.startObserving(&g);
  {
    MoveList moves;
    sentry.generateMoves(moves);
    CPPUNIT_ASSERT(moves.size() == 2);
    return;
    for (MoveList::iterator it = moves.begin();
	 it != moves.end(); ++ it){
      (*it)->printOn(std::cout);
      std::cout<<", ";
    }
    std::cout<<std::endl;
  }
  
};

void
CastlingTestCase::testHasCastled()
{
  Game g;
  g.forsytheString("r3k2r/8/8/8/8/8/8/R3K2R/w");
  CastlingSentry sentry;
  sentry.startObserving(&g);
  CPPUNIT_ASSERT(!sentry.hasCastled(Color::white()));
  CPPUNIT_ASSERT_EQUAL( std::string("KQkq"), sentry.getEPDString());
  Square e1(4,0);
  Square f1(5,0);
  Square g1(6,0);
  Square h1(7,0);
  CastlingMove whiteShortCastle(e1, g1, h1, f1);
  whiteShortCastle.makeOn(g);
  CPPUNIT_ASSERT(g.hasCastled(Color::white()));
  CPPUNIT_ASSERT(!g.hasCastled(Color::black()));
  CPPUNIT_ASSERT_EQUAL( std::string( "kq"),sentry.getEPDString());
  whiteShortCastle.takeBackOn(g);
  CPPUNIT_ASSERT( ! g.hasCastled(Color::white()) );
}
