/**********************************************************************
 *
 *   FreeDoko a Doppelkopf-Game
 *    
 *   Copyright (C) 2001-2004  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 "gamepointstable.h"
#include "../party/party.h"
#include "../party/rule.h"
#include "../ui/ui.h"
#include "../misc/setting.h"

/**
 **
 ** plays a game (get reservation, make the tricks, give the result)
 **
 ** @param       -
 **
 ** @return      -
 **
 ** @version     0.4.4
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 */
void
Game::play()
{
  DEBUG_CALLING(INFO_GAME && INFO_GAMEPLAY,
		"Game::play()");

  using namespace GAMESTATUS;

  if (::game_status != GAME_NEW)
    DEBUG_RETURNING(VOID,
		    INFO_GAME && INFO_GAMEPLAY,
		    "Game::play()");

redistribute: // if the cards have to be redistributed

  if (!this->isvirtual())
    ::ui->game_open();
  if (::game_status != GAME_NEW) {
    if (!this->isvirtual())
      ::ui->game_close();
    DEBUG_RETURNING(VOID,
		    INFO_GAME &&  INFO_GAMEPLAY,
		    "Party::play()");
  }


  ::game_status = GAME_INIT;
  this->init();
  if ((::game_status != GAME_RESERVATION)
      && (::game_status != GAME_REDISTRIBUTE))
    DEBUG_RETURNING(VOID,
		    INFO_GAME && INFO_GAMEPLAY,
		    "Game::play()");

  if (::game_status != GAME_REDISTRIBUTE)
    ::game_status = GAME_SHOW_GAMETYPE;

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

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

  if (::game_status == GAME_REDISTRIBUTE) {
    delete this->poverty_cards_p;
    this->poverty_cards_p = NULL;
    // next seed
    this->seed_set(::party.seed_next());
    ::game_status = GAMESTATUS::GAME_NEW;
    // redistribute the cards
    goto redistribute;
  } // if (::game_status == GAME_REDISTRIBUTE)

  if (this->swines_owner_p
      && this->rule()(Rule::SWINES_ANNOUNCEMENT_BEGIN))
    this->swines_announce();

  if (this->hyperswines_owner_p
      && this->rule()(Rule::HYPERSWINES_ANNOUNCEMENT_BEGIN))
    this->hyperswines_announce();


  if (::game_status == GAME_SHOW_GAMETYPE)
    ::game_status = GAME_PLAY;

  if (::game_status != GAME_PLAY)
    DEBUG_RETURNING(VOID,
		    INFO_GAME && INFO_GAMEPLAY,
		    "Game::play()");

  for (unsigned t = 0; t < this->trickno(); t++) {
    this->trick_p.push_back(Trick(this->player_current()));
    if (!this->isvirtual())
      ::ui->trick_open();
    // request announcement of the players
    this->announcements_request();

    while(!this->trick_current().isfull()) {
      this->nextplayer();
      if (!(::game_status & GAMESTATUS::GAME))
	break;
    } // while(!this->trick_current().isfull())
    if (!(::game_status & GAMESTATUS::GAME))
      break;
    this->evaluatetrick();
    if (!(::game_status & GAMESTATUS::GAME))
      break;
  } // for (t < this->trickno())

  if (!(::game_status & GAMESTATUS::GAME))
    DEBUG_RETURNING(VOID,
		    INFO_GAME && INFO_GAMEPLAY,
		    "Game::play()");

  if (::game_status == GAME_PLAY)
    ::game_status = GAME_FINISHED;
  this->finish();

  DEBUG_RETURNING(VOID,
		  INFO_GAME && INFO_GAMEPLAY,
		  "Game::play()");
} // 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()
{
  DEBUG_CALLING(INFO_GAME && INFO_GAMEPLAY,
		"Game::init()");

  using namespace GAMESTATUS;

  // reset some variables
  this->reservation_p = vector<Reservation>(this->playerno());
  this->marriage_selector_p = MARRIAGE_SELECTOR::TEAM_SET;
  this->marriage_determination_trickno_p = 0;
  this->poverty_cards_p = NULL;
  this->poverty_cardno_p = 0;
  this->announcement_p
    = vector<vector<AnnouncementWithTrickno> >(this->playerno(),
					       vector<AnnouncementWithTrickno>(1));
  this->swines_owner_p = NULL;
  this->first_fox_catcher_p = NULL;
  this->swines_announced_p = false;
  this->hyperswines_owner_p = NULL;
  this->hyperswines_announced_p = false;
  this->finished_p = false;

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

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

  this->type_set(GAMETYPE::NORMAL);

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

  if (game_status != GAME_INIT)
    DEBUG_RETURNING(VOID,
		    INFO_GAME && INFO_GAMEPLAY,
		    "Game::init()");

  ::game_status = GAME_RESERVATION;
  // get the reservation
  for (unsigned i = 0;
       i < this->playerno();
       i++,
       this->player_current_p
       = &(this->player_following(this->player_current()))) {
    this->reservation_p[this->player_current().no()]
      = this->player_current().reservation_get();
    if (game_status != GAME_RESERVATION)
      DEBUG_RETURNING(VOID,
		      INFO_GAME && INFO_GAMEPLAY,
		      "Game::init()");
  } // for (this->player_current_p)

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

  // testing a solo game
  for (unsigned i = 0;
       i < this->playerno();
       i++,
       this->player_current_p
       = &(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->type_set(this->reservation(this->player_current()).game_type);
      this->soloplayer_p = &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_p
	   = &(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++)
	    if (Card(Card::DIAMOND, Card::ACE).less(this->player_current().hand().card(c),
						    *this))
	      break;
	  if (c == this->player_current().hand().cardsnumber()) {
	    this->type_set(GAMETYPE::FOX_HIGHEST_TRUMP);
	    ::game_status = GAMESTATUS::GAME_REDISTRIBUTE;
	    this->soloplayer_p = &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 five nines
    if (this->rule()(Rule::THROW_WITH_FIVE_NINES)
	|| SEED_OUT) {
      for (unsigned i = 0;
	   i < this->playerno();
	   i++,
	   this->player_current_p
	   = &(this->player_following(this->player_current()))) {
	if ( ((this->reservation(this->player_current()).game_type
	       == GAMETYPE::FIVE_NINES)
	      || SEED_OUT
	     )
	     && (this->player_current().hand().numberofnines()
		 >= Rule::MIN_NUMBER_OF_THROWING_NINES)) {
	  this->type_set(GAMETYPE::FIVE_NINES);
	  ::game_status = GAMESTATUS::GAME_REDISTRIBUTE;
	  this->soloplayer_p = &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_FIVE_NINES))

    // testing six kings
    if (this->rule()(Rule::THROW_WITH_SIX_KINGS)
	|| SEED_OUT) {
      for (unsigned i = 0;
	   i < this->playerno();
	   i++,
	   this->player_current_p
	   = &(this->player_following(this->player_current()))) {
	if ( ((this->reservation(this->player_current()).game_type
	       == GAMETYPE::SIX_KINGS)
	      || SEED_OUT
	     )
	     && (this->player_current().hand().numberofkings()
		 >= Rule::MIN_NUMBER_OF_THROWING_KINGS)) {
	  this->type_set(GAMETYPE::SIX_KINGS);
	  ::game_status = GAMESTATUS::GAME_REDISTRIBUTE;
	  this->soloplayer_p = &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_SIX_KINGS))
  } // if (this->type() == GAMETYPE::NORMAL)

  // testing swines
  if (this->rule()(Rule::SWINES)
      || SEED_OUT) {
    for (unsigned i = 0;
	 i < this->playerno();
	 i++,
	 this->player_current_p
	 = &(this->player_following(this->player_current()))) {
      if ( (this->reservation(this->player_current()).swines
	    || ((this->type() == GAMETYPE::POVERTY)
		&& this->swines_owner())
	    || SEED_OUT)
	   && ((!GAMETYPE::is_solo(this->type()))
	       || this->rule()(Rule::SWINES_IN_SOLO))
	   && (this->player_current().hand().numberoftrumpaces()
	       == this->rule()(Rule::NUMBER_OF_SAME_CARDS))) {
	this->swines_owner_p = &(this->player_current());
	this->swines_owner_p->hand_sort();

	if (SEED_OUT)
	  cout << "  Player " << this->player_current().no() << ": swines\n";
      } // if (reservation)
    } // for (p < playerno())
  } // if (rule()(Rule::SWINES))

  // testing hyperswines
  if (this->rule()(Rule::HYPERSWINES)
      || SEED_OUT) {
    if (this->swines_owner()) {
      for (unsigned i = 0;
	   i < this->playerno();
	   i++,
	   this->player_current_p
	   = &(this->player_following(this->player_current()))) {
	if ( (this->reservation(this->player_current()).hyperswines
	      || ((this->type() == GAMETYPE::POVERTY)
		  && this->hyperswines_owner())
	      || ((GAMETYPE::is_solo(this->type()))
		  && this->rule()(Rule::HYPERSWINES_IN_SOLO))
	      || SEED_OUT)
	     && ((!GAMETYPE::is_solo(this->type()))
		 || this->rule()(Rule::HYPERSWINES_IN_SOLO))
	     && (this->player_current().hand().numberoftrumpnines()
		 == this->rule()(Rule::NUMBER_OF_SAME_CARDS))) {
	  this->hyperswines_owner_p = &(this->player_current());
	  this->hyperswines_owner_p->hand_sort();

	  if (SEED_OUT)
	    cout << "  Player " << this->player_current().no()
	      << ": hyperswines\n";
	} // if (reservation)
      } // for (p < playerno())
    } // if (exists_swines)
  } // if (rule()(Rule::HYPERSWINES))

  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_p
	   = &(this->player_following(this->player_current()))) {
	if ( ((this->reservation(this->player_current()).game_type
	       == GAMETYPE::POVERTY)
	      || SEED_OUT
	     )
	     && (this->player_current().hand().numberoftrumps()
		 <= Rule::MAX_NUMBER_OF_POVERTY_TRUMPS)) {
	  this->poverty_cardno_p = 0; // just make sure, that the value is valid
	  this->soloplayer_p = &(this->player_current());
	  this->type_set(GAMETYPE::POVERTY);
	  if (SEED_OUT)
	    cout << "  Player " << this->player_current().no()
	      << ": " << this->type()
	      << " (" << this->player_current().hand().numberoftrumps()
	      << ")\n";
	  if (!SEED_OUT) {
	    this->poverty_shift();
	    if (::game_status != GAMESTATUS::GAME_RESERVATION)
	      DEBUG_RETURNING(VOID,
			      INFO_GAME && INFO_GAMEPLAY,
			      "Game::init()");
	  }
	  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_p
	 = &(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->type_set(GAMETYPE::MARRIAGE);
	this->soloplayer_p = &this->player_current();
	this->marriage_selector_p
	  = this->reservation(this->player_current()).marriage_selector;
	DEBUG_ASSERTION(this->rule()(this->marriage_selector()),
			"Game::init():\n"
			"  marriage selector '" << this->marriage_selector_p
			<< "' is not valid.\n");
	// transfer the marriage selector if the rule is not valid
#ifdef OUTDATED
	// (0.6.1pre, 2004-02-13)
	// Now the rule can be, that only a special color can be selected,
	// so we cannot translate in that case.
	if (!this->rule()(this->marriage_selector())) {
	  if ((this->marriage_selector()
	       == MARRIAGE_SELECTOR::FIRST_CLUB)
	      || (this->marriage_selector()
		  == MARRIAGE_SELECTOR::FIRST_SPADE)
	      || (this->marriage_selector()
		  == MARRIAGE_SELECTOR::FIRST_HEART)) {
	    this->marriage_selector_p
	      = (this->rule()(MARRIAGE_SELECTOR::FIRST_COLOR)
		 ? MARRIAGE_SELECTOR::FIRST_COLOR
		 : MARRIAGE_SELECTOR::FIRST_FOREIGN);
	  } else { // if !(this->marriage_selector() == 'specific color')
	    this->marriage_selector_p = MARRIAGE_SELECTOR::FIRST_FOREIGN;
	  } // if !(this->marriage_selector() == 'specific color')
	} // if (this->rule()(this->marriage_selector()))
#endif // #ifdef OUTDATED
	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->player_p.begin();
	 p != this->player_p.end();
	 ++p)
      if ((*p)->hand().numberofclubqueens()
	  == this->rule()(Rule::NUMBER_OF_SAME_CARDS)) {
	this->type_set(GAMETYPE::MARRIAGE_SILENT);
	this->soloplayer_p = *p;
	break;
      } // if (silent marriage)
  } // if (this->type() == GAMETYPE::NORMAL)

  if (SEED_OUT
      && (this->type() == GAMETYPE::NORMAL)) {
    for (unsigned p = 0; p < this->playerno(); p++)
      if (this->player(p).hand().numberoftrumpkings()
	  == this->rule()(Rule::NUMBER_OF_SAME_CARDS))
	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();

  if (SEED_OUT)
    ::game_status = GAMESTATUS::GAME_FINISHED;

  DEBUG_RETURNING(VOID,
		  INFO_GAME && INFO_GAMEPLAY,
		  "Game::init()");
} // 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
{
  DEBUG_CALLING(INFO_GAME && INFO_VALUE,
		"Game::reservation(player)");

  DEBUG_RETURNING(this->reservation_p[player.no()],
		  INFO_GAME && INFO_VALUE,
		  "Game::reservation(player)");
} // 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()
{
  DEBUG_CALLING(INFO_GAME && INFO_GAMEPLAY,
		"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_p = &(this->soloplayer());
    ::game_status = GAMESTATUS::GAME_REDISTRIBUTE;
    DEBUG_RETURNING(VOID,
		    INFO_GAME && INFO_GAMEPLAY,
		    "Game::poverty_shift()");
  } // if (not poverty shift)

  ::game_status = GAMESTATUS::GAME_POVERTY_SHIFT;

  this->poverty_cardno_p = (this->rule()(Rule::POVERTY_SHIFT_ONLY_TRUMP)
			    ? this->soloplayer().hand().numberoftrumps()
			    : Rule::MAX_NUMBER_OF_POVERTY_TRUMPS);

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

  this->poverty_cards_p = &cards_to_shift;
  if (::game_status != GAMESTATUS::GAME_POVERTY_SHIFT)
    DEBUG_RETURNING(VOID,
		    INFO_GAME && INFO_GAMEPLAY,
		    "Game::poverty_shift()");

  DEBUG_ASSERTION((!this->rule()(Rule::POVERTY_SHIFT_ONLY_TRUMP)
		   && (cards_to_shift.cardsnumber()
		       == Rule::MAX_NUMBER_OF_POVERTY_TRUMPS))
		  || (this->rule()(Rule::POVERTY_SHIFT_ONLY_TRUMP)
		      && (cards_to_shift.cardsnumber()
			  <= Rule::MAX_NUMBER_OF_POVERTY_TRUMPS)
		      && (cards_to_shift.cardsnumber()
			  + this->soloplayer().hand().cardsnumber()
			  == this->rule()(Rule::NUMBER_OF_TRICKS_IN_GAME))
		      && (this->soloplayer().hand().numberoftrumps()
			  == 0)
		      && (Hand(cards_to_shift).numberoftrumps()
			  == cards_to_shift.cardsnumber())
		     ),
		  "Game::poverty_shift():\n"
		  "  wrong number of cards shifted: "
		  << cards_to_shift.cardsnumber());

  for (vector<Player*>::iterator p = this->player_p.begin();
       p != this->player_p.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());

  // ask all players, whether they accept the poverty or not
  bool accept = false;
  for (this->player_current_p = &this->player_following(this->soloplayer());
       this->player_current() != this->soloplayer();
       this->player_current_p
       = &(this->player_following(this->player_current()))) {
    if (!this->isvirtual()) {
      ::ui->poverty_ask(this->player_current(), this->poverty_cardno());
      if (!FAST_PLAY)
	if (this->player_current_p->type() != Player::HUMAN)
	  ::ui->sleep(::setting(Setting::CARD_PLAY_DELAY));
      if (::game_status != GAMESTATUS::GAME_POVERTY_SHIFT)
	DEBUG_RETURNING(VOID,
			INFO_GAME && INFO_GAMEPLAY,
			"Game::poverty_shift()");
    } // if (!this->isvirtual())


    accept = this->player_current().poverty_take_accept(this->poverty_cardno());
    if (::game_status != GAMESTATUS::GAME_POVERTY_SHIFT)
      DEBUG_RETURNING(VOID,
		      INFO_GAME && INFO_GAMEPLAY,
		      "Game::poverty_shift()");

    if (accept) {
      break;
    } else { // if !(accept)
      for (vector<Player*>::iterator p = this->player_p.begin();
	   p != this->player_p.end();
	   p++)
	(*p)->poverty_take_denied(this->player_current());
      if (!this->isvirtual())
	::ui->poverty_take_denied(this->player_current());
    } // if !(accept)
  } // for (this->player_current_p)

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

    for (vector<Player*>::iterator p = this->player_p.begin();
	 p != this->player_p.end();
	 p++)
      (*p)->poverty_take_denied_by_all();
    if (!this->isvirtual())
      ::ui->poverty_take_denied_by_all();

    this->poverty_cards_p = new Hand(*(this->poverty_cards_p));

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

    for (vector<Player*>::iterator p = this->player_p.begin();
	 p != this->player_p.end();
	 p++)
      if (this->teaminfo(**p) == TEAM::UNKNOWN)
	this->teaminfo_set(**p, TEAM::CONTRA);
    this->teaminfo_set_at_gamestart();

    // test swines / hyperswines
    // since all trump had to be shifted, the only re player with swines
    // can be the player, who has accepted the poverty
    if (this->swines_owner()
	&& (this->swines_owner()->team() == TEAM::RE)) {
      this->swines_owner_p = &(this->player_current());
    } // if (swines announced by a re-player)
    if (this->hyperswines_owner()
	&& (this->hyperswines_owner()->team() == TEAM::RE)) {
      // the partner has hyperswines
      this->hyperswines_owner_p = &(this->player_current());
    } // if (hyperswines announced by a re-player)


    Hand cards_to_return
      = this->player_current().poverty_cards_change(cards_to_shift);
    if (::game_status != GAMESTATUS::GAME_POVERTY_SHIFT)
      DEBUG_RETURNING(VOID,
		      INFO_GAME && INFO_GAMEPLAY,
		      "Game::poverty_shift()");
    this->poverty_cards_p = &cards_to_return;

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


    for (vector<Player*>::iterator p = this->player_p.begin();
	 p != this->player_p.end();
	 p++)
      (*p)->poverty_take_accepted(this->player_current(),
				  cards_to_return.cardsnumber(),
				  Hand(cards_to_return).numberoftrumps());
    if (!this->isvirtual())
      ::ui->poverty_take_accepted(this->player_current(), cards_to_return.cardsnumber(),
				  Hand(cards_to_return).numberoftrumps());


    // test swines / hyperswines
    if (this->swines_owner()
	&& (this->swines_owner()->team() == TEAM::RE)) {
      this->swines_owner_p = NULL;
      if (this->player_current().hand().numberoftrumpaces()
	  == this->rule()(Rule::NUMBER_OF_SAME_CARDS)) {
	// the partner has swines
	this->swines_owner_p = &(this->player_current());
      }

      if (this->soloplayer().hand().numberoftrumpaces()
	  == this->rule()(Rule::NUMBER_OF_SAME_CARDS)) {
	// swines has been shifted back
	this->swines_owner_p = &(this->soloplayer());
      }
    } // if (swines announced by a re-player)
    if (!this->swines_owner())
      this->hyperswines_owner_p = NULL;

    if (this->hyperswines_owner()
	&& (this->hyperswines_owner()->team() == TEAM::RE)) {
      this->hyperswines_owner_p = NULL;
      if (this->player_current().hand().numberoftrumpnines()
	  == this->rule()(Rule::NUMBER_OF_SAME_CARDS)) {
	// the partner has hyperswines
	this->hyperswines_owner_p = &(this->player_current());
      }

      if (this->soloplayer().hand().numberoftrumpnines()
	  == this->rule()(Rule::NUMBER_OF_SAME_CARDS)) {
	// hyperswines has been shifted back
	this->hyperswines_owner_p = &(this->soloplayer());
      }
    } // if (hyperswines announced by a re-player)


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


    if (::game_status != GAMESTATUS::GAME_POVERTY_SHIFT)
      DEBUG_RETURNING(VOID,
		      INFO_GAME && INFO_GAMEPLAY,
		      "Game::poverty_shift()");

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

  DEBUG_RETURNING(VOID,
		  INFO_GAME && INFO_GAMEPLAY,
		  "Game::poverty_shift()");
} // 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()
{
  DEBUG_CALLING(INFO_GAME && INFO_GAMEPLAY,
		"Game::distributecards()");

  vector<bool> used(this->rule()(Rule::NUMBER_OF_CARDS), false);
  vector<vector<Card> > cards(this->playerno(),
			      vector<Card>(this->rule()(Rule::NUMBER_OF_CARDS)
					   / this->playerno())
			     );

  ::pseudo_rand_set(this->seed());
  if (!SEED_OUT)
    cout << "Seed: " << this->seed() << "\n";

  for (unsigned i = this->rule()(Rule::NUMBER_OF_CARDS); i > 0; i--)  {
    unsigned r; // random variable (number of cards, still to count)

    r = RAND(i);

    if (r == i)
      r = i - 1;

    r += 1;

    unsigned n; // Number of the selected card (in the end)
    // search th r's unselected card
    for (n = 0; r > 0; n++) {
      if (!used[n]) {
	r--;
	if (r == 0) break;
      }
    }

    // copy the card
    cards[(i - 1) % this->playerno()][(i - 1) / this->playerno()]
      = Card(Card::InttoColor(n % (this->rule()(Rule::NUMBER_OF_CARD_COLORS))),
	     Card::InttoValue(n / (this->rule()(Rule::NUMBER_OF_CARD_COLORS)))
	    );
    // mark card as selected
    used[n] = true;
  } // for (i < NUMBER_OF_CARDS)

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

  DEBUG_RETURNING(VOID,
		  INFO_GAME && INFO_GAMEPLAY,
		  "Game::distributecards()");
} // 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_CALLING(INFO_GAME && INFO_GAMEPLAY,
		"Game::nextplayer()");

#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();

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

  if (!(::game_status & GAMESTATUS::GAME))
    DEBUG_RETURNING(VOID,
		    INFO_GAME && INFO_GAMEPLAY,
		    "Game::nextplayer()");

  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();
  if (!(::game_status & GAMESTATUS::GAME))
    DEBUG_RETURNING(VOID,
		    INFO_GAME && INFO_GAMEPLAY,
		    "Game::nextplayer()");

  // 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,
				     this->player_current().hand())) {
#ifndef POSTPHONED
    DEBUG_ASSERTION(false,
		    "Error: file " << __FILE__ << ", line " << __LINE__ << ", "
		    << "function Game::nextplayer()\n"
		    << "  card \"" << played_card << "\" is not valid"
		    << endl);
#else
    // *** the opposite team has won
#endif
  }

  if (!FAST_PLAY) {

    // wait a bit, before the card is played
    // if it is the human who has to play
    // ***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()'
	  if (!(::game_status & GAMESTATUS::GAME))
	    break;
	} // while (still have to wait)
#endif
      } // if (!this->isvirtual())
    } // if (this->player_current().type() & Player::AI)
  } // if (!FAST_PLAY)
  if (!(::game_status & GAMESTATUS::GAME))
    DEBUG_RETURNING(VOID,
		    INFO_GAME && INFO_GAMEPLAY,
		    "Game::nextplayer()");

  // testing for swines and hyperswines
  if (this->swines_owner()) {
    // announcement during the gameplay
    if (!this->rule()(Rule::SWINES_ANNOUNCEMENT_BEGIN)
	&& (played_card.istrumpace())
	&& (this->player_current().hand().numberoftrumpaces()
	    == this->rule()(Rule::NUMBER_OF_SAME_CARDS))) {
      this->swines_announce();
      if (this->hyperswines_owner())
	this->hyperswines_announce();
    }

    // testing hyperswines
    if (this->hyperswines_owner()
	&& this->swines_announced()) {
      // announcement during the gameplay
      if (!this->rule()(Rule::HYPERSWINES_ANNOUNCEMENT_BEGIN)
	  && (played_card.istrumpnine())
	  && (this->player_current().hand().numberoftrumpnines()
	      == this->rule()(Rule::NUMBER_OF_SAME_CARDS))) {
      } // if (first hyperswine in game)
    } // if (this->hyperswines_owner())
  } // if (this->swines_owner())
  // if there have not been swines announced (til now) and the player has
  // played a trump nine, there can no longer be hyperswines
  if (!this->swines_announced()
      && (played_card.istrumpnine()))
    this->hyperswines_owner_p = NULL;

  { // test for a genscher
    if ((this->type() == GAMETYPE::NORMAL)
	&& this->rule()(Rule::GENSCHER)
	&& played_card.istrumpking()
	&& (this->player_current().hand().numberoftrumpkings()
	    == this->rule()(Rule::NUMBER_OF_SAME_CARDS))
       ) {
      ::game_status = GAMESTATUS::GAME_GENSCHER;
      Player const* const genscher_partner
	= this->player_current().genscher_partner();
      if (::game_status != GAMESTATUS::GAME_GENSCHER)
	DEBUG_RETURNING(VOID,
			INFO_GAME && INFO_GAMEPLAY,
			"Game::nextplayer()");
      ::game_status = GAMESTATUS::GAME_PLAY;

      if (genscher_partner != NULL) {
	this->soloplayer_p = &(this->player_current());
	// set the teams: 'RE' for the genscher players, 'CONTRA' for the others
	for (vector<Player*>::const_iterator player = this->player_begin();
	     player != this->player_end();
	     player++) {
	  if ((**player == this->player_current())
	      || (**player == *genscher_partner))
	    this->teaminfo_set(**player, TEAM::RE);
	  else
	    this->teaminfo_set(**player, TEAM::CONTRA);
	} // for (player \in this->player)
	this->type_set(GAMETYPE::GENSCHER);

	// remove all announcement but 're' and 'contra'
	for (unsigned p = 0; p < this->playerno(); p++) {
	  while (this->announcement_p[p].back().announcement
		 > ANNOUNCEMENT::NO120)
	    this->announcement_p[p].pop_back();
	  if (!this->isvirtual())
	    if (this->announcement_of_player(this->player(p)).announcement
		== ANNOUNCEMENT::NO120)
	      ::ui->announcement_made(ANNOUNCEMENT::NO120, this->player(p));
	} // for (p < this->playerno())

	// tell all players about the genscher
	for (vector<Player*>::const_iterator player = this->player_begin();
	     player != this->player_end();
	     player++)
	  (*player)->genscher(this->player_current(), *genscher_partner);

	if (!this->isvirtual())
	  ::ui->genscher(this->soloplayer(), *genscher_partner);
      } // if (genscher_partner != NULL)
    } // if (genscher)
  } // test for a genscher

  // 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;
  Player const& player_played = this->player_current();
  // set the next player as current player
  if (this->trick_current().isfull())
    this->player_current_p = const_cast<Player*>(&(this->trick_current().winnerplayer()));
  else
    this->player_current_p = &this->player_following(this->player_current());

  for (vector<Player*>::iterator player = this->player_p.begin();
       player != this->player_p.end();
       player++)
    (*player)->card_played(played_card, player_played);
  if (!this->isvirtual())
    ::ui->card_played(played_card, player_played);
  if (!(::game_status & GAMESTATUS::GAME))
    DEBUG_RETURNING(VOID,
		    INFO_GAME && INFO_GAMEPLAY,
		    "Game::nextplayer()");

  // update teames on the fly
  this->teaminfo_update();
  if (!(::game_status & GAMESTATUS::GAME))
    DEBUG_RETURNING(VOID,
		    INFO_GAME && INFO_GAMEPLAY,
		    "Game::nextplayer()");


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

  DEBUG_RETURNING(VOID,
		  INFO_GAME && INFO_GAMEPLAY,
		  "Game::nextplayer()");
} // 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()
{
  DEBUG_CALLING(INFO_GAME && INFO_GAMEPLAY,"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))
    DEBUG_RETURNING(VOID,
		    INFO_GAME && INFO_GAMEPLAY,
		    "Game::nextplayer()");

  // test for catcher of the first fox of swines
  if (this->rule()(Rule::SWINE_ONLY_SECOND)
      && this->swines_owner()
      && !this->first_fox_catcher()
      && this->trick_current().card_of_player(*(this->swines_owner())
					     ).istrumpace()) {
    this->first_fox_catcher_p = &winnerplayer;
    this->swines_owner_p->hand_sort();
    if (!this->isvirtual())
      ::ui->redraw_all();
  } // if (first fox of swines in trick)

  // test whether the player has to make an announcement
  if ((this->trick_current_no() == 1)
      && (this->rule()(Rule::ANNOUNCEMENT_FIRST_TRICK_THIRTY_POINTS))
      && (this->trick_current().points() >= 30)) {
    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->trick_full(this->trick_current());
  if (!(::game_status & GAMESTATUS::GAME))
    DEBUG_RETURNING(VOID,
		    INFO_GAME && INFO_GAMEPLAY,
		    "Game::nextplayer()");

  for (vector<Player*>::const_iterator player = this->player_begin();
       player != this->player_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_p = &this->player(winnerplayer.no());
  if (!this->isvirtual())
    ::ui->trick_close();

  DEBUG_RETURNING(VOID,
		  INFO_GAME && INFO_GAMEPLAY,
		  "Game::evaluatetrick()");
} // void Game::evaluatetrick();



/**
 **
 ** the game is finished
 **
 ** @param       -
 **
 ** @return      -
 **
 ** @version     0.4.4
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 */
void
Game::finish()
{
  DEBUG_CALLING(INFO_GAME && INFO_GAMEPLAY,
		"Game::finish()");

  if ((this->type() == GAMETYPE::MARRIAGE)
      && (this->marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET)) {
    this->marriage_determination_trickno_p = this->trick_current_no();
    this->type_set(GAMETYPE::MARRIAGE_SOLO);
    for (vector<Player*>::const_iterator player = this->player_begin();
	 player != this->player_end();
	 player++)
      this->teaminfo_p[(*player)->no()]
	= ((**player == this->soloplayer())
	   ? TEAM::RE
	   : TEAM::CONTRA);
    this->marriage_selector_p = MARRIAGE_SELECTOR::TEAM_SET;
    // update the teaminfo of the players
    for (vector<Player*>::iterator player = this->player_p.begin();
	 player != this->player_p.end();
	 player++)
      (*player)->teaminfo_update();
  } // if (undetermined marriage)

  this->finished_p = true;

  if (*this == ::party.game())
    this->party().gamepointstable().add(GamePoints(this));

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

  DEBUG_RETURNING(VOID,
		  INFO_GAME && INFO_GAMEPLAY,
		  "Game::finish()");
} // void Game::finish()
