/**********************************************************************
 *
 *   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 "../party/party.h"
#include "../party/rule.h"
#include "../player/playersDb.h"
#include "../card/trick.h"
#include "../ui/ui.h"
#include "../misc/setting.h"


/**
 **
 ** 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->player_p.begin();
       p != this->player_p.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 ((::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_p = &(this->soloplayer());
  else
    this->player_current_p = const_cast<Player*>(&(this->startplayer()));

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

  if (::game_status == GAME_REDISTRIBUTE) {
    delete this->poverty_cards_p;
    this->poverty_cards_p = NULL;
    
    this->seed_set(::party.seed_next());
    ::game_status = GAMESTATUS::GAME_NEW;
    this->type_set(GAMETYPE::NORMAL);

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

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

  // testing swines
  if (this->type() != GAMETYPE::POVERTY)
    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++) {
    this->trick_p.push_back(new Trick(this->player_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();
      if (!(::game_status & GAMESTATUS::GAME))
	break;
    } // while(!this->trick_current().isfull())
    if (!(::game_status & GAMESTATUS::GAME)) {
      ::ui->trick_close();
      break;
    }
    this->evaluatetrick();
    if (!this->isvirtual())
      ::ui->trick_close();
    if (!(::game_status & GAMESTATUS::GAME))
      break;
  } // 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_p = NULL;

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

  this->type_set(GAMETYPE::NORMAL);

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

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

  if (game_status != GAME_INIT)
    return ;

  ::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)
      return ;
  } // 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)

  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)
	      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_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");
	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) {
    bool swines = false;
    for (unsigned p = 0; p < this->playerno(); p++)
      if (this->player(p).hand().numberoftrumpaces()
	  == this->rule()(Rule::NUMBER_OF_SAME_CARDS)) {
	cout << "  Player " << p << ": swines\n";
	swines = true;
      }
    if (swines)
      for (unsigned p = 0; p < this->playerno(); p++)
	if (this->player(p).hand().numberoftrumpnines()
	    == this->rule()(Rule::NUMBER_OF_SAME_CARDS))
	  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().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;

  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_p[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_p = &(this->soloplayer());
    ::game_status = GAMESTATUS::GAME_REDISTRIBUTE;
    return ;
  } // if (not poverty shift)

  // testing swines
  this->test_swines_from_reservations();

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

  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)
    return ;

  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)
	return ;
    } // if (!this->isvirtual())


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

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


    Hand cards_to_return
      = this->player_current().poverty_cards_change(cards_to_shift);
    if (::game_status != GAMESTATUS::GAME_POVERTY_SHIFT)
      return ;
    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());



    // 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)
      return ;

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

  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";

#ifndef OUTDATED
  extern bool RAND_OLD;
  if (RAND_OLD) {
    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())
			       );

    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++) {
      Player& player = 
	*this->player_p[(p + this->startplayer().no()) % this->playerno()];
      player.hand_set(Hand(player, cards[p]));
    }

  } else {// if (RAND_OLD)
#endif // #ifndef OUTDATED

    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() - 1));
	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->player_p[(p + this->startplayer().no()) % this->playerno()]
	->hand_set(hands[p]);
#ifndef OUTDATED
  } // if (RAND_OLD)
#endif // #ifndef OUTDATED

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

  Card 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();
  if (!(::game_status & GAMESTATUS::GAME))
    return ;

  // 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))
    return ;

#ifdef OUTEDATED
  // 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;
#endif

  { // 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))
       ) {
      Player const* const genscher_partner
	= this->player_current().genscher_partner();
      if (::game_status != GAMESTATUS::GAME_PLAY)
	return ;

      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))
    return ;

  // update teams on the fly
  this->teaminfo_update();
  if (!(::game_status & GAMESTATUS::GAME))
    return ;


  // 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->player_begin();
	 p != this->player_end();
	 ++p) {
      if (this->trick_current().card_of_player(**p).istrumpace()) {
	this->first_fox_catcher_p = &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->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();
  if (!(::game_status & GAMESTATUS::GAME))
    return ;

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

  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_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;

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