/**********************************************************************
 *
 *   FreeDoko a Doppelkopf-Game
 *    
 *   Copyright (C) 2001-2006  by Diether Knof and Borg Enders
 *
 *   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.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *   You can find this license in the file 'gpl.txt'.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *   MA  02111-1307  USA
 *
 *  Contact:
 *    Diether Knof dknof@gmx.de
 *    Borg Enders  borg@borgsoft.de
 *
 ********************************************************************/

#include "constants.h"
#include <fstream>

#include "w_virtual_games.h"


#include "VirtualGamesInterface.h"
#include "trickweighting.h"
#include "ai.h"
#include "cards_information.h"
#include "team_information.h"
#include "../../game/game.h"
#include "../../game/game_summary.h"
#include "../../game/exception.h"
#include "../../card/trick.h"
#include "../../misc/setting.h"
#include "../../ui/ui.h"

// whether to save the runtime
//#define SAVE_RUNTIME

#ifdef RELEASE
#undef SAVE_RUNTIME
#endif

/**
 **
 ** constructor
 **
 ** @param      vgi              the vgi
 ** @param      future_limit    the future limit
 **
 ** @return     -
 **
 ** @version    0.4.4
 **
 ** @author     Diether Knof
 **
 **/
WVirtualGames::WVirtualGames(VirtualGamesInterface const& vgi, unsigned const& future_limit) :
  vgi_p(&vgi),
  future_limit_p(future_limit),
  end_depth_p(0),
  player_virt_p(),
  weighting_p()
{
  DEBUG_CALLING(INFO_W_VIRTUAL_GAMES && INFO_INIT,
		"WVirtualGames::WVirtualGames()");

  DEBUG_RETURNING(VOID,
		  INFO_W_VIRTUAL_GAMES && INFO_INIT,
		  "WVirtualGames::WVirtualGames()");
} // WVirtualGames::WVirtualGames(unsigned const& future_limit)

/**
 **
 ** destructor
 **
 ** @param      -
 **
 ** @return     -
 **
 ** @version    0.4.4
 **
 ** @author     Diether Knof
 **
 **/
WVirtualGames::~WVirtualGames()
{
  DEBUG_CALLING(INFO_W_VIRTUAL_GAMES && INFO_INIT,
		"WVirtualGames::~WVirtualGames()");

  for (vector<Player*>::iterator player = this->player_virt_p.begin();
       player != this->player_virt_p.end();
       player++)
    delete *player;

  DEBUG_RETURNING(VOID,
		  INFO_W_VIRTUAL_GAMES && INFO_INIT,
		  "WVirtualGames::~WVirtualGames()");
} // WVirtualGames::~WVirtualGames()

/**
 **
 ** -> result
 **
 ** @param      -
 **
 ** @return     the vgi
 **
 ** @version    0.4.4
 **
 ** @author     Diether Knof
 **
 **/
VirtualGamesInterface const&
WVirtualGames::vgi() const
{
  DEBUG_CALLING(INFO_W_VIRTUAL_GAMES && INFO_VALUE,
		"WVirtualGames::vgi()");

  DEBUG_RETURNING(*(this->vgi_p),
		  INFO_W_VIRTUAL_GAMES && INFO_VALUE,
		  "WVirtualGames::vgi()");
} // VirtualGamesInterface const& VirtualGames::vgi() const

/**
 **
 ** -> result
 **
 ** @param      -
 **
 ** @return     the limit of tricks to calc
 **
 ** @version    0.4.4
 **
 ** @author     Diether Knof
 **
 **/
unsigned const&
WVirtualGames::future_limit() const
{
  DEBUG_CALLING(INFO_W_VIRTUAL_GAMES && INFO_VALUE,
		"WVirtualGames::future_limit()");

  DEBUG_RETURNING(this->future_limit_p,
		  INFO_W_VIRTUAL_GAMES && INFO_VALUE,
		  "WVirtualGames::future_limit()");
} // unsigned const& VirtualGames::future_limit() const

/**
 **
 ** -> result
 **
 ** @param      -
 **
 ** @return     the maximal depth to calc into the future (in tricks)
 **
 ** @version    0.4.4
 **
 ** @author     Diether Knof
 **
 **/
unsigned const&
WVirtualGames::end_depth() const
{
  DEBUG_CALLING(INFO_W_VIRTUAL_GAMES && INFO_VALUE,
		"WVirtualGames::end_depth()");

  DEBUG_RETURNING(this->end_depth_p,
		  INFO_W_VIRTUAL_GAMES && INFO_VALUE,
		  "WVirtualGames::end_depth()");
} // unsigned const& VirtualGames::end_depth() const

/**
 ** -> result
 **
 ** @param      -
 **
 ** @return     the hand to be examined
 **
 ** @author     Diether Knof
 **
 ** @version    0.7.1
 **/
HandCards const&
WVirtualGames::hand() const
{
  return this->hand_p;
} // Hand const& VirtualGames::hand() const

/**
 **
 ** calculates the maximal depth of tricks,
 ** so that no more of 'future limit' tricks are considered
 ** took the code from W_virtual::calctricks()
 ** @see        W_virtual::calctricks()
 **
 ** @param      -
 **
 ** @return     the calculated end depth
 **
 ** @version    0.4.4
 **
 ** @author     Borg Enders
 **
 **/
unsigned const&
WVirtualGames::end_depth_calculate()
{
  DEBUG_CALLING(INFO_W_VIRTUAL_GAMES && INFO_VALUE,
		"WVirtualGames::end_depth_calculate()");

  // #combination for all tricks
  unsigned long int alltricks = 1;
  // #combination for one trick
  unsigned long int onetrick = 1;

  Trick const& trick = this->vgi().game().trick_current();

  // count the number of card-combinations for the current trick
  for (unsigned i = trick.actcardno();
       i < this->vgi().game().playerno();
       i++)
    onetrick *= this->vgi().handofplayer(trick.player_of_card(i)
					).validcards(trick).cardsnumber();

  alltricks *= onetrick;

  // count the number of card-combinations for the other tricks
  // (since I don't know what color is played, I take all cards of the hand)
  for (this->end_depth_p = 1;
       // '<' because also the current trick is counted in tricks_remaining_no
       (this->end_depth_p < this->vgi().game().tricks_remaining_no());
       this->end_depth_p += 1){

    onetrick = 1;
    for (unsigned i = 0; i < this->vgi().game().playerno(); i++) {
#ifndef POSTPHONED
      if (this->vgi().game().trick_current().cardno_of_player(this->vgi().game().player(i))
	  >= this->vgi().game().trick_current().actcardno())
	// the player still has to play a card in the current trick
	onetrick *= (this->vgi().handofplayer(this->vgi().game().player(i)).cardsnumber()
		     - this->end_depth_p);
      else
	// the player has already played a card, so he has one card less 
	// on the hand
	onetrick *= (this->vgi().handofplayer(this->vgi().game().player(i)).cardsnumber()
		     - (this->end_depth_p - 1));

      DEBUG_ASSERTION((onetrick > 0),
		      "WVirtualGames::end_depth_calculate():\n"
		      "  onetrick == 0\n"
		      << "cardsnumber = " << this->vgi().handofplayer(this->vgi().game().player(i)).cardsnumber() << '\n'
		      << "end_depth = " << this->end_depth_p << '\n'
		      << "trickno = " << this->vgi().game().trick_current_no() << '\n'
		      << "remaining trickno = " << this->vgi().game().tricks_remaining_no() << '\n'
		     );
#else
      onetrick *= this->vgi().hand().cardsnumber() - this->end_depth_p;
#endif
    }

    if (alltricks < this->future_limit_p / onetrick) {
      alltricks *= onetrick; 
    } else  {
      break;
    }
  } // for (this->end_depth_p)

  this->end_depth_p = min(this->end_depth(),
			  ((this->vgi().last_trick_to_calculate()
			    >= this->vgi().game().trick_current_no())
			   ? (this->vgi().last_trick_to_calculate()
			      - this->vgi().game().trick_current_no())
			   : 0));

#ifdef POSTPHONED
  this->end_depth_p = max(unsigned(2), this->end_depth());
#endif

#ifdef HEURISTIC_OUTPUT
  if (!this->vgi().game().isvirtual())
    cout << "Player " << this->vgi().no() << ": "
      << "WVirtualGames: "
      << "end trick = " <<  << endl;
#endif



  DEBUG_RETURNING(this->end_depth(),
		  INFO_W_VIRTUAL_GAMES && INFO_VALUE,
		  "WVirtualGames::end_depth_calculate()");
} // unsigned const& VirtualGames::end_depth_calculate()

/**
 **
 ** creates the game and the players.
 **
 ** @param      -
 **
 ** @return     -
 **
 ** @exception	InvalidGameException	the virtual game is invalid
 **
 ** @version    0.5.4
 **
 ** @author     Borg Enders
 ** @author     Diether Knof
 **
 ** @todo	future limit for the virtual players
 **
 **/
void
WVirtualGames::init()
{
  DEBUG_CALLING(INFO_W_VIRTUAL_GAMES && INFO_INIT,
		"WVirtualGames::init()");

  // calculate the end depth
  this->end_depth_calculate();

  // free the memory
  for (vector<Player*>::iterator player = this->player_virt_p.begin();
       player != this->player_virt_p.end();
       player++)
    delete *player;
  this->player_virt_p.clear();

  // set the cards to the valid cards
  this->hand_p = this->vgi().hand().validcards(this->vgi().game().trick_current()
					      );

  // set the weightings to 0
  this->weighting_p = vector<int>(this->hand().cardsnumber(), 0);

  Ai const& real_ai
    = static_cast<Ai const&>(this->vgi().game().player(this->vgi().no()));
  // create the virtual players
  // (the players have a hand independent of the hand of the vgi, so that
  //  reordering the card is no problem)
  for (vector<Player*>::const_iterator player
       = this->vgi().game().players_begin();
       player != this->vgi().game().players_end();
       player++) {

    this->player_virt_p.push_back(new Ai(real_ai));

    // if the player is not the vgi, some values have to change
    if (*player != &real_ai) {
      unsigned const no = this->player_virt_p.size() - 1;
      Ai& ai_virtual = static_cast<Ai&>(*(this->player_virt_p.back()));

      // set the playernumber
      ai_virtual.set_no(no);

      // set the cards information
      delete ai_virtual.cards_information_;
      ai_virtual.cards_information_
	= new CardsInformation(real_ai.cards_information());

      // set the hand
      ai_virtual.set_hand(this->vgi().handofplayer(**player), false);
      DEBUG_ASSERTION((ai_virtual.hand().cardsnumber() + 1
		       // hack (if the player has already played a card in the trick)
		       >= this->vgi().game().tricks_remaining_no()),
		      "WVirtualGames::init():\n"
		      "  the hand of the virtual player " << ai_virtual.no()
		      << " is too small: "
		      << ai_virtual.hand().cardsnumber()
		      << " < " << this->vgi().game().tricks_remaining_no()
		      << ":\n"
		      << ai_virtual.hand());


      // set the teaminfo
      ai_virtual.set_teams(real_ai.team_information().guessed_teams());

      // change the future limit
#ifndef POSTPHONED
      // *** workaround
      static_cast<Ai&>(ai_virtual).set_future_limit_for_all_tricks(this->future_limit() / 10);
#endif // #ifndef POSTPHONED


    } // if (**player != this->vgi())
  } // for (player)

  DEBUG_RETURNING(VOID,
		  INFO_W_VIRTUAL_GAMES && INFO_INIT,
		  "WVirtualGames::init()");
} // void WVirtualGames::init()

/**
 **
 ** -> result
 **
 ** @param      -
 **
 ** @return     the card, that makes the most points
 **
 ** @version    0.5.4
 **
 ** @author     Borg Enders
 **
 **/
Card
WVirtualGames::best_card()
{
  DEBUG_CALLING(INFO_W_VIRTUAL_GAMES && INFO_OTHER_FUNCTION,
		"WVirtualGames::best_card()");

  // create the virtual game and the virtual players
  this->init();


  // calculate the weightings
  this->weightings_calc();

  // search the best valid card

  // the number of the best card
  HandCard best_card = this->hand().card(0);
  int best_weighting = this->weighting_p[0];
  // search a better valid card
#ifndef RELEASE
  if (HEURISTIC_OUTPUT) {
    if (!this->vgi().game().isvirtual()) {
      clog << this->vgi().no() << std::endl;
      clog << this->hand().card(0) << " " << this->weighting_p[0] << std::endl;
    }
  }
#endif
  for (unsigned c = 1; c < this->hand().cardsnumber(); c++) {
#ifndef RELEASE
    if (HEURISTIC_OUTPUT) {
      if (!this->vgi().game().isvirtual()) {
	clog << this->hand().card(c) << " " << this->weighting_p[c] << std::endl;
      }
    }
#endif
    if(   this->weighting_p[c] > best_weighting // find best weighting
       || (   this->weighting_p[c] == best_weighting // there is not one best
	   && (   (   this->hand().card(c).less(best_card) // smallest card
		   && (   !this->hand().card(c).isfox()
		       || this->weighting_p[c]>0 ) // no Fox
		  )
	       || (best_card.isfox() && best_weighting < 0) // replace fox
	      )
	  )
      )	    
    {
      best_card = this->hand().card(c);
      best_weighting = this->weighting_p[c];
    } // if (better card found)
  } // for (c < this->hand().cardsnumber())

  if( best_weighting < 0 ) {
    int validcards = 0;
    for (unsigned c = 1; c < this->hand().cardsnumber(); c++) 
      if( this->weighting_p[c] != INT_MIN )
      {
	validcards++;
      }
#ifdef WORKAROUND
    if (  (validcards == 1)
	&& (this->hand().cardsnumber() > 1) ) {
#ifndef RELEASE
      cerr << "WARNING: Virtual_games only one valid card found, "
	"taking smallest card!" << std::endl;
#endif               
      for (unsigned c = 1; c < this->hand().cardsnumber(); c++) 

	if(  this->hand().card(c).less(best_card)// smallest card
	   && (!this->hand().card(c).isfox())
	  )
	{
	  best_card = this->hand().card(c);
	}

    } // if ( (validcards == 1) && (this->hand().cardsnumber() > 1) )
#endif
  }  // if( best_weighting < 0 )

  DEBUG_RETURNING(best_card,
		  INFO_W_VIRTUAL_GAMES && INFO_OTHER_FUNCTION,
		  "WVirtualGames::best_card()");
} // Card WVirtualGames::best_card()

/**
 **
 ** calculates the weightings
 ** and writes the values into the vector 'weighting_p;
 **
 ** @param      -
 **
 ** @return     -
 **
 ** @version    0.4.4
 **
 ** @author     Borg Enders
 **
 **/
void
WVirtualGames::weightings_calc()
{
  DEBUG_CALLING(INFO_W_VIRTUAL_GAMES && INFO_OTHER_FUNCTION,
		"WVirtualGames::weightings_calc()");

  ::ui->update();
#ifdef SAVE_RUNTIME
  // for measuring the runtime
  ofstream ostr("VirtualGames.time", ios::app);
  clock_t time_begin = 0;
  if (!this->vgi().game().isvirtual())
    time_begin = clock();
#endif

  // some statistics
  static unsigned counter = 0;
  static unsigned virtual_depth = 0;
  static unsigned virtual_depth_min = 0;
  static unsigned counter_last = 0;
  if (!this->vgi().game().isvirtual()) {
    counter = 0;
    virtual_depth = 0;
    virtual_depth_min = 0;
    counter_last = 0;
  }


  virtual_depth += 1;

  if (INFO_W_VIRTUAL_GAMES) {
    if (counter >= counter_last + 500) {
      counter_last = counter;
      virtual_depth_min = virtual_depth;
      cout << "VirtualGames: depth: " << virtual_depth
	<< "\t\t(counter: " << counter << ")" << endl;
    }
    if (virtual_depth < virtual_depth_min) {
      virtual_depth_min = virtual_depth;
      cout << "VirtualGames: depth: " << virtual_depth << endl;
    }
  } // if (INFO_W_VIRTUAL_GAMES)

  for (unsigned c = 0; c < this->hand().cardsnumber(); c++) {
    ::ui->ai_test_card(this->hand().card(c), this->vgi().no());
    // this->hand() has only valid cards
    if (INFO_W_VIRTUAL_GAMES)
      if (!this->vgi().game().isvirtual())
	cout << "VirtualGames: calculating card "
	  << this->hand().card(c)
	  << "\t(" << c + 1 << " / " << this->hand().cardsnumber() << ")" << endl;

    if (INFO_W_VIRTUAL_GAMES)
      if (!this->vgi().game().isvirtual())
	cout << "  " << this->hand().card(c) << endl;

    // create the players
    vector<Player*> ai_virt;
    for (vector<Player*>::const_iterator ai
	 = this->player_virt_p.begin();
	 ai != this->player_virt_p.end();
	 ai++) {
      ai_virt.push_back(new Ai(*static_cast<Ai*>(*ai)));
    }
    // create the virtual game
    Game game_virt(this->vgi().game(), ai_virt);

    { // play the card 'c'
      HandCard const card(game_virt.player_current().hand(),
			  this->hand().card(c));
      // make swines announcements
      if (   card.possible_swine()
	  && game_virt.swines_announcement_valid(game_virt.player_current()))
	game_virt.swines_announce(game_virt.player_current());
      if (   card.possible_hyperswine()
	  && game_virt.hyperswines_announcement_valid(game_virt.player_current()))
	game_virt.hyperswines_announce(game_virt.player_current());

      // play the card
      // code copied from 'Game::nextcard()'
      game_virt.trick_current() += card;
      game_virt.player_current().hand().playcard(card);
      game_virt.teaminfo_update();
      game_virt.player_current_
	= &game_virt.player_following(game_virt.player_current());
      for (vector<Player*>::iterator p = game_virt.players_begin();
	   p != game_virt.players_end();
	   p++) {
	(*p)->card_played(card);
      }
    } // play the card 'c'
    try {
      // the other virtual players play a card
      while(!game_virt.trick_current().isfull()) {
	counter += 1;

	// This is needed, so that a card is not played more times
	// than it is in the game.
	if (this->vgi().game().isvirtual()
	    || (game_virt.player_current().no() != this->vgi().no())) {
	  game_virt.player_current().set_hand(static_cast<Ai&>(game_virt.player(this->vgi().no())).handofplayer(game_virt.player_current()));

	}
	DEBUG_ASSERTION((game_virt.player_current().hand().cardsnumber() > 0),
			"WVirtualGames::weightings_calc():\n"
			"  current player " << game_virt.player_current().no()
			<< " has an empty hand");
#ifdef DKNOF
	game_virt.player_current().self_check();
#endif
	game_virt.nextplayer();
      }

      // first trick is full
      game_virt.evaluatetrick();


      // play tricks till the end depth
      for (unsigned t = 1;
	   ((t < this->end_depth())
	    && (game_virt.trick_current_no() < game_virt.trickno()));
	   t++) {
	if (INFO_W_VIRTUAL_GAMES)
	  if (!this->vgi().game().isvirtual())
	    cout << "  trick depth " << t
	      << " (" << this->end_depth() - 1 << ")" << endl;


	// set the future limit of the ai, so that they don't calculate too much
	for (vector<Player*>::iterator ai = ai_virt.begin();
	     ai != ai_virt.end();
	     ai++)
	  static_cast<Ai*>(*ai)->set_last_trick_to_calculate(game_virt.trick_current_no()
							     + (this->end_depth()
								- t));

	// start a new trick
	game_virt.tricks().push_back(new Trick(game_virt.player_current()));
	for (vector<Player*>::iterator p = game_virt.players().begin();
	     p != game_virt.players().end();
	     p++) {
	  (*p)->trick_open(game_virt.trick_current());
	}

	while(!game_virt.trick_current().isfull()) {
	  counter += 1;
	  // This is needed, so that a card is not played more times
	  // than it is in the game.
	  game_virt.player_current().set_hand(static_cast<Ai&>(game_virt.player(this->vgi().no())).handofplayer(game_virt.player_current()));
	  game_virt.nextplayer();
	}
	game_virt.evaluatetrick();
      } // for (t < this->end_depth())

      // finished with creating tricks,
      // now calc the modi for each trick
      for (unsigned t = this->vgi().game().trick_current_no();
	   t < game_virt.trick_current_no();
	   t++)
	// add the modi to the weighting
	this->weighting_p[c]
	  += TrickWeighting::modi(this->vgi(), game_virt.trick(t),
				  game_virt.player(this->vgi().no()).team(),
				  game_virt.trick(t).card_of_player(game_virt.player(this->vgi().no()) ) );

      if (game_virt.trick_current_no() < game_virt.trickno() - 1) {
	// add some points, if the own team is in the back,
	this->weighting_p[c]
	  += TrickWeighting::backhand(this->vgi(), this->hand().card(c), game_virt );      	
      } // if (game_virt.trick_current_no() < game_virt.trickno() - 1)


      // game finished, the main reason is the final result...

      if( game_virt.tricks_remaining_no() == 0 ) {
	game_virt.finish();
	GameSummary const game_summary(game_virt);
	// the correspoding virtual player to the ai
	Ai const& virt_ai
	  = dynamic_cast<Ai const&>(game_virt.player(this->vgi().no()));
	if (game_summary.winnerteam() == TEAM::NOTEAM) {
	  this->weighting_p[c]
	    += 10000 * (game_summary.points(virt_ai.team())
			- game_summary.points(opposite(virt_ai.team())));
	} else { // if !(game_summary.winnerteam() == TEAM::NOTEAM)
	  if ( game_summary.winnerteam() == virt_ai.team())
	    this->weighting_p[c] += 10000 * game_summary.points();
	  else
	    this->weighting_p[c] -= 10000 * game_summary.points();
	} // if !(game_summary.winnerteam() == TEAM::NOTEAM)
      }

#if 0
      // output of the modi
      if (this->vgi().game() == ::party.game()) {
	clog << this->hand().card(c)
	  << ": "
	  << this->weighting_p[c]
	  << endl;

      } // if (this->vgi().game() == ::party.gam())

#endif // output of the modi

    } catch (InvalidGameException const& e) {
      // if the game is invalid, don't take the card
      this->weighting_p[c] = INT_MIN;
#ifndef RELEASE
      if (!this->vgi().game().isvirtual()) {

#ifdef DEBUG_ASSERT
	cerr << "cards information\n";
	cerr << static_cast<Ai const&>(game_virt.player_current()).cards_information() << endl;
	cerr << '\n';
	cerr << "previous trick = " << game_virt.trick_current_no() - 1 << endl;
	cerr << game_virt.trick(game_virt.trick_current_no() - 1);
	cerr << '\n';
	cerr << "current trick = " << game_virt.trick_current_no() << endl;
	cerr << game_virt.trick_current();
	cerr << '\n';
	cerr << "Hand:\n";
	cerr << game_virt.player_current().hand();
	cerr << '\n';
	cerr << "last heuristic: " << static_cast<Ai const&>(game_virt.player_current()).lastHeuristic_ << endl;
	cerr << '\n';
	cerr << __FILE__ << " line " << __LINE__ << '\n';
	cerr << "no valid game found for card '" << this->hand().card(c) << "'"
	  << endl;
#endif
	ExceptionTerminateHandler::terminate();
      }
      DEBUG_ASSERTION(this->vgi().game().isvirtual(),
		      "WVirtualGames::weightings_calc():\n"
		      "  no valid game found for card '" << this->hand().card(c)
		      << "'");
#endif
      DEBUG_CAUGHT();
    } catch (...) {
      // free the memory
      for (vector<Player*>::iterator ai = ai_virt.begin();
	   ai != ai_virt.end();
	   ai++)
	delete *ai;

      throw;
    } // try

    ::ui->ai_card_weighting(this->weighting_p[c]);

    // free the memory
    for (vector<Player*>::iterator ai = ai_virt.begin();
	 ai != ai_virt.end();
	 ai++)
      delete *ai;

    if (INFO_W_VIRTUAL_GAMES)
      if (!this->vgi().game().isvirtual())
	cout << "weighting " << this->hand().card(c) << ": "
	  << this->weighting_p[c] << "\n";

  } // for (c < this->hand().cardsnumber())

  if (INFO_W_VIRTUAL_GAMES)
    if (!this->vgi().game().isvirtual())
      cout << "VirtualGames: counter " << counter 
	<< "  (" << this->vgi().value(Aiconfig::FUTURE_LIMIT) << ")"
	<< endl;

#ifdef POSTPHONED
  DEBUG_ASSERTION(((this->end_depth() == 1)
		   || (counter <= this->future_limit())),
		  "WVirtualGames::weightings_calc():\n"
		  "  counter is greater than the future limit:\n"
		  "  " << counter << " > " << this->future_limit()
		  << "\t\t(end_depth: " << this->end_depth() << ")");
#endif

#ifdef SAVE_RUNTIME
  if (!this->vgi().game().isvirtual())
    if (counter >= 2000) {
      unsigned const used_time = ((clock() - time_begin)
				  / (CLOCKS_PER_SEC / 1000));
      ostr << setw(8) << counter
	<< "\t" << setw(8) << used_time
	<< "\t" << setw(8) << (used_time * 1000 / counter) 
	<< endl;
    } // if (counter >= 2000)
#endif // #ifdef SAVE_RUNTIME


  virtual_depth -= 1;

  DEBUG_RETURNING(VOID,
		  INFO_W_VIRTUAL_GAMES && INFO_OTHER_FUNCTION,
		  "WVirtualGames::weightings_calc()");
} // void WVirtualGames::weightings_calc()
