/***************************************************************************
                          TranspositionTable.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 "TranspositionTable/TranspositionTable.h"
# include "Square.h"
# include "Moves/Move.h"
# include "Moves/CapturingMove.h"
# include "Moves/PromotingMove.h"
# include "Moves/EnPassantMove.h"
# include "Moves/DoubleStep.h"
# include "Pieces/Piece.h"
# include "Game/Game.h"
# include <assert.h>
using namespace Alice;
TranspositionTable::TranspositionTable(int bits)
  : HashTable(bits),
    entries(1<<bits),
    requests(0),
    successes(0)
{
  assert(mCurrentCode.primary() < entries.size());
  currentEntry = &firstEntry();
};

TranspositionTable::~TranspositionTable()
{
};

TableEntry&
TranspositionTable::firstEntry()
{
  int index = currentCode().primary();
  return entries[index].first;
};

TableEntry&
TranspositionTable::secondEntry()
{
  int index = currentCode().primary();
  return entries[index].second;
};
const TableEntry&
TranspositionTable::firstEntry() const
{
  int index = getCurrentCode().primary();
  return entries[index].first;
};

const TableEntry&
TranspositionTable::secondEntry() const
{
  int index = getCurrentCode().primary();
  return entries[index].second;
};

void
TranspositionTable::storeExactScore(Evaluation::Score score, int depth, 
				    SmartPointer<Move> bestMove)
{
  isValid();
  /*if (depth == 4)
    {
      std::cout<<"storing ";
      bestMove->printOn(std::cout);
      std::cout<<std::endl;
      assert(false);
    };
  */
  TableEntry& entry = firstEntry();
  if (entry.store(TableEntry::EXACT,
		  isMate(score)? depth+20: depth, depth,
		  score, bestMove,
		  currentCode().secondary()))
    return;
  
  TableEntry& second = secondEntry();
  second.store(TableEntry::EXACT,
	       0, depth,
	       score, bestMove,
	       currentCode().secondary());
};
void
TranspositionTable::storeUpperBound(Evaluation::Score score, int depth, 
				    SmartPointer<Move> bestMove)
{
  isValid();
  TableEntry& entry = firstEntry();
  if (entry.store(TableEntry::UPPER,
		  isMate(score)? depth+20:depth, depth,
		  score, bestMove,
		  currentCode().secondary()))
    return;
  TableEntry& second = secondEntry();
  second.store(TableEntry::UPPER,
	       0, depth,
	       score, bestMove,
	       currentCode().secondary());
};
void
TranspositionTable::storeLowerBound(Evaluation::Score score, int depth, 
				    SmartPointer<Move> bestMove)
{
  isValid();
  TableEntry& entry = firstEntry();
  if (entry.store(TableEntry::LOWER,
		  isMate(score)? depth+20:depth, depth,
		  score, bestMove,
		  currentCode().secondary()))
    return;
  TableEntry& second = secondEntry();
  second.store(TableEntry::LOWER,
	       0, depth,
	       score, bestMove,
	       currentCode().secondary());
};
bool 
TranspositionTable::cutsOff(int depth, Evaluation::Score alpha,
			    Evaluation::Score beta, Evaluation::Score& result) const
{
  if (!isValid())
    return false;
  return currentEntry->cutsOff(depth, alpha, beta, result);
  
};
Evaluation::Score 
TranspositionTable::score() const
{
  assert(isValid());
  return currentEntry->score();
};

bool
TranspositionTable::isValid() const
{
  requests ++;
  const TableEntry& entry = firstEntry();
  if (getCurrentCode().secondary() == entry.identifier()){
    if (!entry.bestMove()){
      return false;
    }
    currentEntry = &entry;
    successes ++;
    return true;
  }
  const TableEntry& secondEntry = this->secondEntry();
  if (getCurrentCode().secondary() == secondEntry.identifier()){
    if (!secondEntry.bestMove()){
      return false;
    }
    currentEntry = &secondEntry;
    successes ++;
    return true;
  }
  return false;
};

SmartPointer<Move>
TranspositionTable::bestMove() const
{
  assert(isValid());
 return currentEntry->bestMove();
};
void
TranspositionTable::print(std::ostream& out)
{
  std::cout<<"current code: "<<currentCode().primary()<<", "<<
    currentCode().secondary()<<std::endl;
};

void
TranspositionTable::clear()
{
  for (std::vector<std::pair<TableEntry,TableEntry> >::iterator it(entries.begin());
       it != entries.end(); ++it)
    {
      it->first.clear();
      it->second.clear();
    }
};

void 
TranspositionTable::startObserving(Game* g)
{
  clear();
  HashTable::startObserving(g);
};
