/**********************************************************************
 *
 *   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 "game.h"

#include "gameplay_actions.h"

#include "../party/party.h"
#include "../party/rule.h"
#include "../player/playersDb.h"
#include "../player/ai/ai.h"
#include "../card/trick.h"
#include "../ui/ui.h"
#include "../misc/setting.h"
#include "../os/bug_report_replay.h"
extern OS_NS::BugReportReplay* bug_report_replay;

/**
 **
 ** plays a game (get reservation, make the tricks, give the result)
 **
 ** @param       -
 **
 ** @return      -
 **
 ** @version     0.6.7
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 */
void
Game::play()
{
  using namespace GAMESTATUS;

  if (::game_status != GAME_NEW)
    return ;

  for (vector<Player*>::const_iterator p = this->players().begin();
       p != this->players().end();
       ++p)
    (*p)->game_open(*this);

  if (!this->isvirtual())
    ::ui->game_open(*this);

redistribute: // if the cards have to be redistributed
  if (::game_status != GAME_NEW) {
    if (!this->isvirtual()) {
      ::ui->game_close();
    }
    return ;
  }

  ::game_status = GAME_INIT;
  this->init();
  if (SEED_OUT)
    return ;

  if (   (::game_status != GAME_RESERVATION)
      && (::game_status != GAME_REDISTRIBUTE))
    return ;

  // set the startplayer
  if (this->rule()(Rule::LUSTSOLO_PLAYER_LEADS)
      && GAMETYPE::is_solo(this->type()))
    this->player_current_ = &(this->soloplayer());
  else
    this->player_current_ = const_cast<Player*>(&(this->startplayer()));

  for (vector<Player*>::iterator player = this->players().begin();
       player != this->players().end();
       player++)
    (*player)->game_start();
  if (!this->isvirtual())
    ::ui->game_start();


  if (::game_status == GAME_REDISTRIBUTE) {
    delete this->poverty_cards_;
    this->poverty_cards_ = NULL;
    this->poverty_shifted_ = false;
    
    this->set_seed(this->party().seed_next());
    ::game_status = GAMESTATUS::GAME_NEW;
    this->set_type(GAMETYPE::NORMAL);

    if (!this->isvirtual())
      ::ui->game_redistribute();

    goto redistribute;
  } // if (::game_status == GAME_REDISTRIBUTE)

  // testing swines
  this->test_swines_from_reservations();

  if (::game_status != GAME_RESERVATION)
    return ;
  ::game_status = GAME_PLAY;

  // the reserve is needed because the players keep pointers to the tricks
  // in their trickpiles
  for (unsigned t = 0; t < this->trickno(); t++) {
    try {
      this->tricks_.push_back(new Trick(this->player_current()));
      for (vector<Player*>::iterator player = this->players().begin();
	   player != this->players().end();
	   player++)
	(*player)->trick_open(this->trick_current());
      if (!this->isvirtual()) {
	::ui->trick_open(this->trick_current());
      }
      // request announcement of the players
      this->announcements_request();

      while(!this->trick_current().isfull()) {
	this->nextplayer();
      } // while(!this->trick_current().isfull())

      ::game_status = GAMESTATUS::GAME_FULL_TRICK;
      this->evaluatetrick();
      ::game_status = GAME_PLAY;
    } catch (...) {
      if (!this->isvirtual()) {
	::ui->gameplay_action(GameplayAction::TrickClosed());
	::ui->trick_close();
      }
      throw;
    } // try

    if (!this->isvirtual()) {
      ::ui->gameplay_action(GameplayAction::TrickClosed());
      ::ui->trick_close();
    }
  } // for (t < this->trickno())

  return ;
} // void Game::play()

/**
 **
 ** initializes a new game -- get reservations and set the game type
 **
 ** @param       -
 **
 ** @return      -
 **
 ** @version     0.4.4
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 */
void
Game::init()
{
  using namespace GAMESTATUS;

  // reset some variables
  this->soloplayer_ = NULL;

  this->reservation_ = vector<Reservation>(this->playerno());
  this->marriage_selector_ = MARRIAGE_SELECTOR::TEAM_SET;
  this->marriage_determination_trickno_ = 0;
  this->poverty_cards_ = NULL;
  this->poverty_cardno_ = 0;
  this->poverty_shifted_ = false;
  this->announcement_
    = vector<vector<AnnouncementWithTrickno> >(this->playerno(),
					       vector<AnnouncementWithTrickno>(1));
  this->swines_owner_ = NULL;
  this->first_fox_catcher_ = NULL;
  this->swines_announced_ = false;
  this->hyperswines_owner_ = NULL;
  this->hyperswines_announced_ = false;
  this->finished_ = false;

  this->player_current_ = const_cast<Player*>(&(this->startplayer()));

  this->set_type(GAMETYPE::NORMAL);

  // initialise the players
  for (vector<Player*>::iterator player = this->players().begin();
       player != this->players().end();
       player++) {
    (*player)->new_game(*this);
  }

  // distribute the cards
  this->distributecards();

  if (game_status != GAME_INIT)
    return ;

  ::game_status = GAME_RESERVATION;
  ui->game_cards_distributed();
  // get the reservation
  for (unsigned i = 0;
       i < this->playerno();
       i++,
       this->player_current_
       = &(this->player_following(this->player_current()))) {
    ::ui->reservation_ask(this->player_current());
    this->reservation_[this->player_current().no()]
      = this->player_current().reservation_get();
    ::ui->gameplay_action(GameplayAction::Reservation(this->player_current().no(),
						      this->reservation_[this->player_current().no()]));
    ::ui->reservation_got(this->reservation_[this->player_current().no()],
			  this->player_current());
    if (game_status != GAME_RESERVATION)
      return ;
  } // for (this->player_current_)

  if (SEED_OUT)
    cout << "Seed: " << seed() << "\n";

  // testing a solo game
  for (unsigned i = 0;
       i < this->playerno();
       i++,
       this->player_current_
       = &(this->player_following(this->player_current()))) {
    if (GAMETYPE::is_solo(this->reservation(this->player_current()).game_type)
	&& this->rule()(this->reservation(this->player_current()).game_type)) {
      // the player 'p' is playing a solo
      this->set_type(this->reservation(this->player_current()).game_type);
      this->soloplayer_ = &this->player_current();

      if (SEED_OUT)
	cout << "  Player " << this->player_current().no()
	  << ": " << type() << "\n";

      // no other player can play a solo
      break;
    }
  }

  if (this->type() == GAMETYPE::NORMAL) {
    // testing fox highest trump
    if (this->rule()(Rule::THROW_WHEN_FOX_HIGHEST_TRUMP)
	|| SEED_OUT) {
      for (unsigned i = 0;
	   i < this->playerno();
	   i++,
	   this->player_current_
	   = &(this->player_following(this->player_current()))) {
	if ( (this->reservation(this->player_current()).game_type
	      == GAMETYPE::FOX_HIGHEST_TRUMP)
	    || SEED_OUT) {
	  // look, whether there is a card that is higher than the fox
	  unsigned c;
	  for (c = 0; c < this->player_current().hand().cardsnumber(); c++)
	    // check with diamond ten because of swines!
	    if (   Card(Card::DIAMOND, Card::TEN).less(this->player_current().hand().card(c))
		&& !this->player_current().hand().card(c).istrumpace())
	      break;
	  if (c == this->player_current().hand().cardsnumber()) {
	    this->set_type(GAMETYPE::FOX_HIGHEST_TRUMP);
	    ::game_status = GAMESTATUS::GAME_REDISTRIBUTE;
	    this->soloplayer_ = &this->player_current();
	    if (SEED_OUT)
	      cout << "  Player " << this->player_current().no()
		<< ": " << this->type()
		<< "\n";
	    break;
	  } // if (c < this->player(p).hand().cardsnumber())
	} // if (reservation)
      } // for (p < playerno())
    } // if (rule()(Rule::THROW_WHEN_FOX_HIGHEST_TRUMP))

    // testing thrown nines
    if (this->rule()(Rule::THROW_WITH_NINES)
	|| SEED_OUT) {
      for (unsigned i = 0;
	   i < this->playerno();
	   i++,
	   this->player_current_
	   = &(this->player_following(this->player_current()))) {
	if ( ((this->reservation(this->player_current()).game_type
	       == GAMETYPE::THROWN_NINES)
	      || SEED_OUT
	     )
	    && (this->player_current().hand().numberofnines()
		>= this->rule()(Rule::MIN_NUMBER_OF_THROWING_NINES))) {
	  this->set_type(GAMETYPE::THROWN_NINES);
	  ::game_status = GAMESTATUS::GAME_REDISTRIBUTE;
	  this->soloplayer_ = &this->player_current();
	  if (SEED_OUT)
	    cout << "  Player " << this->player_current().no()
	      << ": " << this->type()
	      << " (" << this->player_current().hand().numberofnines()
	      << ")\n";
	  break;
	} // if (reservation)
      } // for (p < playerno())
    } // if (rule()(Rule::THROW_WITH_NINES))

    // testing thrown kings
    if (this->rule()(Rule::THROW_WITH_KINGS)
	|| SEED_OUT) {
      for (unsigned i = 0;
	   i < this->playerno();
	   i++,
	   this->player_current_
	   = &(this->player_following(this->player_current()))) {
	if ( ((this->reservation(this->player_current()).game_type
	       == GAMETYPE::THROWN_KINGS)
	      || SEED_OUT
	     )
	    && (this->player_current().hand().numberofkings()
		>= this->rule()(Rule::MIN_NUMBER_OF_THROWING_KINGS))) {
	  this->set_type(GAMETYPE::THROWN_KINGS);
	  ::game_status = GAMESTATUS::GAME_REDISTRIBUTE;
	  this->soloplayer_ = &this->player_current();
	  if (SEED_OUT)
	    cout << "  Player " << this->player_current().no()
	      << ": " << this->type()
	      << "(" << this->player_current().hand().numberofkings()
	      << ")\n";
	  break;
	} // if (reservation)
      } // for (p < playerno())
    } // if (rule()(Rule::THROW_WITH_KINGS))

    // testing thrown nines and kings
    if (this->rule()(Rule::THROW_WITH_NINES_AND_KINGS)
	|| SEED_OUT) {
      for (unsigned i = 0;
	   i < this->playerno();
	   i++,
	   this->player_current_
	   = &(this->player_following(this->player_current()))) {
	if ( ((this->reservation(this->player_current()).game_type
	       == GAMETYPE::THROWN_NINES_AND_KINGS)
	      || SEED_OUT
	     )
	    && (this->player_current().hand().numberofnines()
		+ this->player_current().hand().numberofkings()
		>= this->rule()(Rule::MIN_NUMBER_OF_THROWING_NINES_AND_KINGS))) {
	  this->set_type(GAMETYPE::THROWN_NINES_AND_KINGS);
	  ::game_status = GAMESTATUS::GAME_REDISTRIBUTE;
	  this->soloplayer_ = &this->player_current();
	  if (SEED_OUT)
	    cout << "  Player " << this->player_current().no()
	      << ": " << this->type()
	      << "(" << (this->player_current().hand().numberofnines()
			 + this->player_current().hand().numberofkings())
	      << ")\n";
	  break;
	} // if (reservation)
      } // for (p < playerno())
    } // if (rule()(Rule::THROW_WITH_NINES_AND_KINGS))

  } // if (this->type() == GAMETYPE::NORMAL)

  if (this->type() == GAMETYPE::NORMAL) {
    // testing a poverty
    if (this->rule()(Rule::POVERTY)
	|| SEED_OUT) {
      for (unsigned i = 0;
	   i < this->playerno();
	   i++,
	   this->player_current_
	   = &(this->player_following(this->player_current()))) {
	if (   (   (this->reservation(this->player_current()).game_type
		    == GAMETYPE::POVERTY)
		|| SEED_OUT
	       )
	    && this->player_current().hand().has_poverty() ) {
	  this->poverty_cardno_ = 0; // just make sure, that the value is valid
	  this->soloplayer_ = &this->player_current();
	  this->set_type(GAMETYPE::POVERTY);
	  if (SEED_OUT) {
	    cout << "  Player " << this->player_current().no()
	      << ": " << this->type()
	      << " (";
	    if (   this->rule()(Rule::POVERTY_FOX_DO_NOT_COUNT)
		&& (this->player_current().hand().numberoftrumpaces() > 0))
	      cout << (this->player_current().hand().numberoftrumps()
		       - this->player_current().hand().numberoftrumpaces())
		<< " + "
		<< this->player_current().hand().numberoftrumpaces();
	    else
	      cout << this->player_current().hand().numberoftrumps();
	    cout << ")\n";
	  }
	  if (!SEED_OUT) {
	    this->test_swines_from_reservations();
	    this->poverty_shift();
	    if (::game_status != GAMESTATUS::GAME_RESERVATION)
	      return ;
	  }
	  break;
	} // if (reservation)
      } // for (p < playerno())
    } // if (rule()(Rule::POVERTY))
  } // if (type() == GAMETYPE::NORMAL)

  if (this->type() == GAMETYPE::NORMAL) {
    // testing a marriage
    for (unsigned i = 0;
	 i < this->playerno();
	 i++,
	 this->player_current_
	 = &(this->player_following(this->player_current()))) {
      if ( ((this->reservation(this->player_current()).game_type
	     == GAMETYPE::MARRIAGE)
	    || SEED_OUT
	   )
	  && (this->player_current().hand().numberofclubqueens() == 2)) {
	this->set_type(GAMETYPE::MARRIAGE);
	this->soloplayer_ = &this->player_current();
	this->marriage_selector_
	  = this->reservation(this->player_current()).marriage_selector;
	DEBUG_ASSERTION(this->rule()(this->marriage_selector()),
			"Game::init():\n"
			"  marriage selector '" << this->marriage_selector_
			<< "' is not valid.\n");
	if (SEED_OUT)
	  cout << "  Player " << this->player_current().no() << ": marriage\n";
      }
    } // for (p < playerno())
  } // if (type() == GAMETYPE::NORMAL)

  // test for a silent marriage
  if (this->type() == GAMETYPE::NORMAL) {
    for (vector<Player*>::const_iterator p = this->players().begin();
	 p != this->players().end();
	 ++p)
      if ((*p)->hand().numberofclubqueens()
	  == this->rule()(Rule::NUMBER_OF_SAME_CARDS)) {
	this->set_type(GAMETYPE::MARRIAGE_SILENT);
	this->soloplayer_ = *p;
	break;
      } // if (silent marriage)
  } // if (this->type() == GAMETYPE::NORMAL)

  if (SEED_OUT) {
    bool swines = false;
    for (unsigned p = 0; p < this->playerno(); p++)
      if (this->player(p).hand().has_swines()) {
	cout << "  Player " << p << ": swines\n";
	swines = true;
      }
    if (swines)
      for (unsigned p = 0; p < this->playerno(); p++)
	if (this->player(p).hand().has_hyperswines())
	  cout << "  Player " << p << ": hyperswines\n";
  } // if (SEED_OUT && (this->type() == GAMETYPE::NORMAL))
  if (SEED_OUT
      && (this->type() == GAMETYPE::NORMAL)) {
    for (unsigned p = 0; p < this->playerno(); p++)
      if (this->player(p).hand().has_possible_genscher())
	cout << "  Player " << p << ": genscher\n";
  } // if (SEED_OUT && (this->type() == GAMETYPE::NORMAL))


  this->players_hands_sort();

  // update the team info in 'game' and in the players
  this->teaminfo_set_at_gamestart();

  return ;
} // void Game::init()

/**
 **
 ** -> result
 **
 ** @param	player	the player
 **
 ** @return	the reservation of 'player'
 **
 ** @version	0.6.1
 **
 ** @author	Diether Knof
 **
 **/
Reservation const&
Game::reservation(Player const& player) const
{
  return this->reservation_[player.no()];
} // Reservation const& Game::reservation(Player const& player) const


/**
 **
 ** make the shifting of the poverty cards
 ** distribute the cards randomly at the players
 **
 ** @param      -
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.4.5
 **
 **/
void
Game::poverty_shift()
{
  if ((this->type() != GAMETYPE::POVERTY)
      || !this->rule()(Rule::POVERTY_SHIFT)
      || ((this->soloplayer().hand().numberoftrumps() <= 1)
	  && this->rule()(Rule::THROW_WITH_ONE_TRUMP)
	 )
     ) {
    this->player_current_ = &(this->soloplayer());
    ::game_status = GAMESTATUS::GAME_REDISTRIBUTE;
    return ;
  } // if (not poverty shift)

  ::game_status = GAMESTATUS::GAME_POVERTY_SHIFT;
  if (!this->isvirtual())
    ::ui->poverty_shifting(this->soloplayer());

  this->poverty_cardno_ = this->soloplayer().hand().numberofpovertycards();

  HandCards cards_to_shift = this->soloplayer().poverty_shift();

  this->poverty_cards_ = &cards_to_shift;

  DEBUG_ASSERTION((this->poverty_cards()->player()
		   == this->soloplayer()),
		  "Game::poverty_shift():\n"
		  "  the soloplayer '" << this->soloplayer().no()
		  << "' shifts cards from player '"
		  << this->poverty_cards_->player().no() << "'");

  DEBUG_ASSERTION((this->soloplayer().hand().numberoftrumps()
		   == 0),
		  "Game::poverty_shift():\n"
		  "  Poverty: the soloplayer still has trump on the hand.\n"
		  "Hand:\n"
		  << this->soloplayer().hand().numberoftrumps()
		  << "shifted cards:\n"
		  << cards_to_shift);

  DEBUG_ASSERTION( (cards_to_shift.size()
		    + this->soloplayer().hand().cardsnumber()
		    == this->rule()(Rule::NUMBER_OF_TRICKS_IN_GAME)),
		  "Game::poverty_shift():\n"
		  "  wrong number of cards shifted: "
		  << cards_to_shift.size());

#ifdef DEBUG
  if (this->rule()(Rule::POVERTY_SHIFT_ONLY_TRUMP))
    DEBUG_ASSERTION( (this->poverty_cards()->numberoftrumps()
		      == this->poverty_cards()->cardsnumber()),
		    "Game::poverty_shift():\n"
		    "  wrong number of cards shifted: "
		    << "trumps = " << this->poverty_cards()->numberoftrumps()
		    << " != " << cards_to_shift.size() << " = cards shifted");
  else if (!this->rule()(Rule::POVERTY_FOX_DO_NOT_COUNT)
	   || this->swines_announced() )
    // normal case: shift at max 3 cards
    DEBUG_ASSERTION( (this->poverty_cards()->cardsnumber()
		      == Rule::MAX_NUMBER_OF_POVERTY_TRUMPS),
		    "Game::poverty_shift():\n"
		    "  wrong number of cards shifted: "
		    << "poverty cards = " << Rule::MAX_NUMBER_OF_POVERTY_TRUMPS
		    << " != " << cards_to_shift.size() << " = cards shifted");
  else if (!this->rule()(Rule::POVERTY_FOX_SHIFT_EXTRA))
    // at max 3 cards or number of trumps
    DEBUG_ASSERTION( (   (this->poverty_cards()->numberoftrumps()
			  == this->poverty_cards()->cardsnumber())
		      || (this->poverty_cards()->cardsnumber()
			  == Rule::MAX_NUMBER_OF_POVERTY_TRUMPS) ),
		    "Game::poverty_shift():\n"
		    "  wrong number of cards shifted: "
		    << "trumps or "
		    << "poverty cards = " << Rule::MAX_NUMBER_OF_POVERTY_TRUMPS
		    << " != " << cards_to_shift.size() << " = cards shifted");
  else
    // fox are shifted extra
    DEBUG_ASSERTION( (this->poverty_cards()->cardsnumber()
		      - this->poverty_cards()->numberoftrumpaces()
		      == Rule::MAX_NUMBER_OF_POVERTY_TRUMPS),
		    "Game::poverty_shift():\n"
		    "  wrong number of cards shifted: "
		    << "poverty cards = " << Rule::MAX_NUMBER_OF_POVERTY_TRUMPS
		    << " != " << cards_to_shift.size() << " - "
		    << this->poverty_cards()->numberoftrumpaces()
		    << " = cards shifted - fox");
#endif // #ifdef DEBUG

#ifndef WORKAROUND
  DEBUG_ASSERTION((this->poverty_cardno() == cards_to_shift.size()),
		  "Game::poverty_shift():\n"
		  "  wrong number of shifted cards:\n"
		  "  calculated = " << this->poverty_cardno() << " != "
		  "shifted = " << cards_to_shift.size());
#else
  this->poverty_cardno_ = cards_to_shift.size();
#endif

  for (vector<Player*>::iterator p = this->players().begin();
       p != this->players().end();
       p++)
    (*p)->poverty_shift(this->soloplayer(), this->poverty_cardno());

  //  this->soloplayer().hand().remove(cards_to_shift);
  if (!this->isvirtual()) {
    ::ui->poverty_shift(this->soloplayer(), this->poverty_cardno());
    ::ui->gameplay_action(GameplayAction::PovertyShift(this->soloplayer().no(),
						       cards_to_shift));
  }

  // ask all players, whether they accept the poverty or not
  bool accept = false;
  for (this->player_current_ = &this->player_following(this->soloplayer());
       this->player_current() != this->soloplayer();
       this->player_current_
       = &(this->player_following(this->player_current()))) {
    if (!this->isvirtual()) {
      ::ui->poverty_ask(this->player_current(), this->poverty_cardno());
      if (   !(FAST_PLAY & FAST_NS::PAUSE)
	  && !(   ::bug_report_replay
	       && ::bug_report_replay->auto_action())) {
	if (this->player_current_->type() != Player::HUMAN)
	  ::ui->sleep(::setting(Setting::CARD_PLAY_DELAY));
      }
      if (::game_status != GAMESTATUS::GAME_POVERTY_SHIFT)
	return ;
    } // if (!this->isvirtual())


    accept = this->player_current().poverty_take_accept(this->poverty_cardno());
    if (::game_status != GAMESTATUS::GAME_POVERTY_SHIFT)
      return ;

    if (accept) {
      ::ui->gameplay_action(GameplayAction::PovertyAccepted(this->player_current().no()));
      break;
    } else { // if !(accept)
      for (vector<Player*>::iterator p = this->players().begin();
	   p != this->players().end();
	   p++)
	(*p)->poverty_take_denied(this->player_current());
      if (!this->isvirtual()) {
	::ui->poverty_take_denied(this->player_current());
	::ui->gameplay_action(GameplayAction::PovertyDenied(this->player_current().no()));
      }
    } // if !(accept)
  } // for (this->player_current_)

  if (!accept) {
    this->player_current_ = &(this->soloplayer());

    for (vector<Player*>::iterator p = this->players().begin();
	 p != this->players().end();
	 p++)
      (*p)->poverty_take_denied_by_all();
    if (!this->isvirtual()) {
      ::ui->poverty_take_denied_by_all();
      ::ui->gameplay_action(GameplayAction::PovertyDeniedByAll());
    }

    this->soloplayer().sorted_hand().add(*this->poverty_cards_);
    this->soloplayer().hand_sort();

    this->poverty_cards_ = new HandCards(*this->poverty_cards_);

    ::game_status = GAMESTATUS::GAME_REDISTRIBUTE;
  } else { // if !(!accept)
    // set the teaminfo
    this->set_teaminfo(this->soloplayer(), TEAM::RE);
    this->set_teaminfo(this->player_current(), TEAM::RE);
    this->soloplayer().set_team(TEAM::RE);
    this->player_current().set_team(TEAM::RE);

    for (vector<Player*>::iterator p = this->players().begin();
	 p != this->players().end();
	 p++) {
      if (this->teaminfo(**p) == TEAM::UNKNOWN) {
	this->set_teaminfo(**p, TEAM::CONTRA);
	(*p)->set_team(TEAM::CONTRA);
      }
    } // for (p)
    this->teaminfo_set_at_gamestart();

    HandCards cards_to_return
      = this->player_current().poverty_cards_change(cards_to_shift);
    if (::game_status != GAMESTATUS::GAME_POVERTY_SHIFT)
      return ;
    this->poverty_cards_ = &cards_to_return;

    DEBUG_ASSERTION((this->poverty_cards_->player()
		     == this->player_current()),
		    "Game::poverty_shift():\n"
		    "  the current player '" << this->player_current().no()
		    << "' shifts back cards from player '"
		    << this->poverty_cards_->player().no() << "'");

    DEBUG_ASSERTION((this->poverty_cardno() == cards_to_return.size()),
		    "Game::poverty_shift():\n"
		    "  number of cards returned ("
		    << cards_to_return.size()
		    << ") is not the same as are shifted ("
		    << this->poverty_cardno() << ").");


    for (vector<Player*>::iterator p = this->players().begin();
	 p != this->players().end();
	 p++)
      (*p)->poverty_take_accepted(this->player_current(),
				  cards_to_return.size(),
				  cards_to_return.numberoftrumps());
    if (!this->isvirtual()) {
      ::ui->poverty_take_accepted(this->player_current(),
				  cards_to_return.size(),
				  cards_to_return.numberoftrumps());
      ::ui->gameplay_action(GameplayAction::PovertyReturned(this->player_current().no(),
							    cards_to_return));
    }


    // add the cards to the player
    this->player_current_ = &this->soloplayer();
    this->soloplayer().poverty_cards_get_back(cards_to_return);
    // save the number of trumps
    this->poverty_cardno_ = Hand(this->soloplayer(),
				 cards_to_return).numberoftrumps();
    if (!this->isvirtual())
      ::ui->gametype_changed();

    // check, that the swines announcement is correct
    if (this->swines_announced()) {
      if (this->swines_owner()->team() == TEAM::RE) {
	for (vector<Player*>::iterator p = this->players().begin();
	     p != this->players().end();
	     ++p) {
	  if ((*p)->hand().numberoftrumpaces()
	      == this->rule()(Rule::NUMBER_OF_SAME_CARDS)) {
	    this->swines_owner_ = *p;

	    if (!this->isvirtual())
	      ::ui->swines_announced(*this->swines_owner());

	    for (vector<Player*>::iterator p2 = this->players().begin();
		 p2 != this->players().end();
		 p2++)
	      (*p2)->swines_announced(**p);

	    break;
	  }
	}
      } // if (this->swines_owner()->team() == TEAM::RE)
    } // if (this->swines_announced())


    if (::game_status != GAMESTATUS::GAME_POVERTY_SHIFT)
      return ;

    this->poverty_cards_ = NULL;
    ::game_status = GAMESTATUS::GAME_RESERVATION;
  } // if !(!accept)

  this->poverty_shifted_ = true;

  return ;
} // void Game::poverty_shift()

/**
 **
 ** distribute the cards randomly at the players
 **
 ** @param       -
 **
 ** @return      -
 **
 ** @version     0.4.4
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 */
void
Game::distributecards()
{
  ::pseudo_rand_set(this->seed());
  if (!SEED_OUT)
    cout << "Seed: " << this->seed() << "\n";

  vector<Card> all_cards = this->rule().valid_cards();
  for (unsigned i = 1; i < this->rule()(Rule::NUMBER_OF_SAME_CARDS); ++i)
    all_cards.insert(all_cards.end(),
		     this->rule().valid_cards().begin(),
		     this->rule().valid_cards().end());

  vector<vector<Card> > hands(this->playerno());

  while (!all_cards.empty()) {
    for (vector<vector<Card> >::iterator h = hands.begin();
	 h != hands.end();
	 ++h) {
      DEBUG_ASSERTION(!all_cards.empty(),
		      "Game::distributecards():\n"
		      "  valid cards cannot be distributed between the players");
      vector<Card>::iterator
	c = (all_cards.begin() + RAND(all_cards.size()));
      h->push_back(*c);
      all_cards.erase(c);
    } // for (h \in hands)
  } // while (!cards.empty())

  // create the hands for the players
  for (unsigned p = 0;
       p < this->playerno();
       p++)
    this->players_[(p + this->startplayer().no()) % this->playerno()]
      ->set_hand(hands[p]);

  return ;
} // void Game::distributecards()

/**
 ** the next player has to play a card
 **
 ** @param       -
 **
 ** @return      -
 **
 ** @version     0.4.4
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @bug         uses processor time, not real time
 */
void
Game::nextplayer()
{
  DEBUG_ASSERT(this->self_check());

#ifdef POSTPHONED
  DEBUG_ASSERTION((this->player_current().hand().cardsnumber()
		   == this->trickno() - this->trick_current_no()),
		  "Game::nextplayer():\n"
		  "  current player has not the right number of cards on the hand\n"
		  "trick " << this->trick_current_no() << "\n"
		  << this->player_current());
#endif


  // ***ToDo DK this uses the processor time
  const clock_t time_before_playing_card = ::clock();

  HandCard const played_card = this->player_current().card_get();

  if (!(::game_status & GAMESTATUS::GAME))
    return ;

  DEBUG_ASSERTION(played_card,
		  "Game::nextplayer():\n"
		  "  result of 'Player::card_get()' is an empty card.\n"
		  "  Player number: " << this->player_current().no() << "\n"
		  "  Player type:   " << this->player_current().type());
  // here always update,
  // so that the user can do something during the calculation of the ai
  ::ui->update();

  // testing, whether the card is valid.
  // if it is not, take the first valid card of the hand.
  if (!this->trick_current().isvalid(played_card)) {
#ifndef RELEASE
    COUT << "ai type = " << played_card.player().type() << endl;
    COUT << "heuristic = " << static_cast<Ai const&>(this->player_current()
						    ).lastHeuristic_
      << endl;
    COUT << *this;
#endif
#ifndef POSTPHONED
    DEBUG_ASSERTION(false,
		    "Game::nextplayer()\n"
		    "  card \"" << played_card << "\" is not valid"
		    << endl);
#else
    // *** the opposite team has won
#endif
  }

  if (   !(FAST_PLAY & FAST_NS::PAUSE)
      && !(   ::bug_report_replay
	   && ::bug_report_replay->auto_action())) {

    // wait a bit, before the card is played
    // if it is the human who has to play
    // Bug: DK
    // When the time wraps around, it is assumed, that the calculation
    // has taken no time

    if (this->player_current().type() & Player::AI) {
      if (!this->isvirtual()) {

#ifdef POSTPHONED
	// ToDo: cannot use this code when using 'clock()'
	while (time_before_playing_card
	       + (::setting(Setting::CARD_PLAY_DELAY)
		  * static_cast<double>(CLOCKS_PER_SEC)
		  / 1000)
	       > ::clock() ) {
#endif

	  ::ui->sleep(max(long(0),
			  long(::setting(Setting::CARD_PLAY_DELAY)
			       - ((::clock()
				   - time_before_playing_card)
				  / (static_cast<double>(CLOCKS_PER_SEC)
				     / 1000) ))));

#ifdef POSTPHONED
	  // ToDo: cannot use this code when using 'clock()'
	} // while (still have to wait)
#endif
      } // if (!this->isvirtual())
    } // if (this->player_current().type() & Player::AI)
  } // if (!(FAST_PLAY & FAST_NS::PAUSE))

  this->check_for_genscher(played_card);

  // remove the card from the hand, add it to the trick
  // and give the message to the ui
  this->player_current().hand().playcard(played_card);
  this->trick_current() += played_card;
  // set the next player as current player
  if (this->trick_current().isfull())
    this->player_current_ = const_cast<Player*>(&(this->trick_current().winnerplayer()));
  else
    this->player_current_ = &this->player_following(this->player_current());

  for (vector<Player*>::iterator player = this->players().begin();
       player != this->players().end();
       player++) {
    (*player)->card_played(played_card);
  }

  this->teaminfo_update();
  if (this->isvirtual())
    ::ui->virtual_card_played(played_card);
  else {
    ::ui->card_played(played_card);
    Aiconfig::Heuristic heuristic = Aiconfig::NO_HEURISTIC;
    switch (played_card.player().type()) {
    case Player::HUMAN:
    case Player::AI:
      heuristic = static_cast<Ai const&>(played_card.player()).lastHeuristic_;
      break;
    case Player::UNSET:
    case Player::AI_DUMMY:
    case Player::AI_RANDOM:
      heuristic = Aiconfig::NO_HEURISTIC;
      break;
    case Player::NETWORK:
      heuristic = Aiconfig::NETWORK;
      break;
    } // switch (played_card.player().type())

    ::ui->gameplay_action(GameplayAction::CardPlayed(played_card.player().no(),
						     played_card,
						     heuristic));
  }

  // request announcement of the players
  this->announcements_request();

  return ;
} // void Game::nextplayer();

/**
 **
 ** evaluates who is startplayer for nextcard and updates player
 **
 ** @param       -
 **
 ** @return      -
 **
 ** @version     0.4.4
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 */
void
Game::evaluatetrick()
{
  // Winnerplayer has as result the number of the winner
  Player const& winnerplayer = this->trick_current().winnerplayer();

  // test for marriage
  this->determine_marriage();
  if (!(::game_status & GAMESTATUS::GAME))
    return ;

  // test for catcher of the first fox of swines
  if (this->rule()(Rule::SWINE_ONLY_SECOND)
      && !this->first_fox_catcher()) {
    for (vector<Player*>::const_iterator p = this->players_begin();
	 p != this->players_end();
	 ++p) {
      if (this->trick_current().card_of_player(**p).istrumpace()) {
	this->first_fox_catcher_ = &winnerplayer;
	(*p)->hand_sort();
	break;
      } // if (is trump ace)
    } // for (p \in this->player)
  } // if (fox in trick)

  // test whether the player has to make an announcement
  if (   (this->type() == GAMETYPE::NORMAL)
      && (this->trick_current_no() == 1)
      && (this->rule()(Rule::ANNOUNCEMENT_FIRST_TRICK_THIRTY_POINTS))
      && (this->trick_current().points() >= 30)
      && (    !this->rule()(Rule::ANNOUNCEMENT_FIRST_TRICK_THIRTY_POINTS_ONLY_FIRST)
	  || (   (this->announcement_of_team(TEAM::RE)
		  == ANNOUNCEMENT::NOANNOUNCEMENT)
	      && (this->announcement_of_team(TEAM::CONTRA)
		  == ANNOUNCEMENT::NOANNOUNCEMENT) )
	 )
     ) {
    this->announcement_make(ANNOUNCEMENT::NO120,
			    this->trick_current().winnerplayer());
  } // if (player must make an announcement)

  // request announcement of the players
  this->announcements_request();

  // tell the ui und the players, that the trick is full
  if (this->isvirtual())
    ::ui->virtual_trick_full();
  else {
    ::ui->gameplay_action(GameplayAction::TrickFull(this->trick_current()));
    ::ui->trick_full();
  }
  if (!(::game_status & GAMESTATUS::GAME))
    return ;

  for (vector<Player*>::const_iterator player = this->players_begin();
       player != this->players_end();
       player++)
    (*player)->trick_full(this->trick_current());

  // move the trick in the trickpile
  this->trick_current().move_in_trickpile();

  // request announcement of the players
  this->announcements_request();

  // Startplayer for next round 
  this->player_current_ = &this->player(winnerplayer.no());

  return ;
} // void Game::evaluatetrick();

/**
 **
 ** the game is finished
 **
 ** @param       -
 **
 ** @return      -
 **
 ** @version     0.4.4
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 */
void
Game::finish()
{
  if ((this->type() == GAMETYPE::MARRIAGE)
      && (this->marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET)) {
    this->marriage_determination_trickno_ = this->trick_current_no();
    this->set_type(GAMETYPE::MARRIAGE_SOLO);
    for (vector<Player*>::const_iterator player = this->players_begin();
	 player != this->players_end();
	 player++)
      this->teaminfo_[(*player)->no()]
	= ((**player == this->soloplayer())
	   ? TEAM::RE
	   : TEAM::CONTRA);
    this->marriage_selector_ = MARRIAGE_SELECTOR::TEAM_SET;
    // update the teaminfo of the players
    for (vector<Player*>::iterator player = this->players().begin();
	 player != this->players().end();
	 player++)
      (*player)->marriage(this->soloplayer(), this->soloplayer());
  } // if (undetermined marriage)

  this->finished_ = true;

  return ;
} // void Game::finish()
