/**********************************************************************
 *
 *   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 "ai.h"
#include "cards_information.h"
#include "team_information.h"

#include "heuristics.h"
#include "weighting.h"
#include "aiDb.h"
#include "../../party/party.h"
#include "../../party/rule.h"
#include "../../card/trick.h"
#include "../namegen.h"
#ifndef OUTDATED
// for 'nextcard()' errors
#include "../../misc/bug_report.h"
#endif
#include "../../os/bug_report_replay.h"
#include "../../utils/version.h"

//#define DEBUG_PLAYER ((::party.game().trick_current_no() == 8) ? 2 : 22)
#define DEBUG_PLAYER 22

/**
 **
 ** Construktor
 **
 ** @param	istr	stream with the infos
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 ** @todo	using constructor Aiconfig(istr)
 ** @todo	update to the new format
 **
 **/
Ai::Ai(istream& istr) 
: Player(AI),
  Aiconfig(),
  playedcards_p(),
  cards_information_(NULL),
  team_information_(NULL),
  teaminfo_p(),
  trick_p(::party.rule()(Rule::NUMBER_OF_TRICKS_IN_GAME)),
  trickno_p(0),
  colorjabbed_p(::party.rule()(Rule::NUMBER_OF_CARD_COLORS),
		vector<bool>(::party.rule()(Rule::NUMBER_OF_PLAYERS_IN_GAME),
			     false)),
  color_runs_p(::party.rule()(Rule::NUMBER_OF_CARD_COLORS), 0),
  low_p(true),
  meatlesscolor_p(Card::NOCARDCOLOR),
  trumpless_(),
  last_trick_to_calculate_p(12),
  lastHeuristic_(Aiconfig::NO_HEURISTIC),
  vgi_(new VirtualGamesAi(*this)),
  hi_(new HeuristicAi(*this)),
  silentMarriage_(false)
{
  DEBUG_CALLING(INFO_AI && INFO_INIT,
		"Ai::Ai(istr)");

  delete this->db_;
  this->db_ = new AiDb;

  while (istr.good()) {
    string line;
    getline(istr, line);
    if (istr.fail() || istr.eof())
      break;

    if (*line.rbegin() == '\r')
      line.erase(line.end() - 1);

#ifndef OUTDATED
    // outdated since 0.6.6
    if (line == "# Aiconfig")
      line = "Aiconfig";
#endif

    if ((line == "")
	|| (line[0] == '#'))
      continue;

    if (line == "Aiconfig") {
      // this is the last entry
      this->Aiconfig::load(istr);
      break;
    } else if (line == "Database") {
      this->db_->read(istr);
    } else {
      cerr << "Reading the ai:\n"
	<< "found following unknown line:\n"
	<< line << '\n'
	<< "ignoring it."
	<< endl;
#ifndef RELEASE
      exit(EXIT_FAILURE);
#endif
    }
  }; // while (istr.good())

  DEBUG_RETURNING(VOID,
		  INFO_AI && INFO_INIT,
		  "Ai::Ai(istr)");
} // Ai::Ai(istream& istr)

/**
 ** standard constructor
 **
 ** @param	-
 **
 ** @result	-
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
Ai::Ai() :
  Player(AI),
  Aiconfig(),
  playedcards_p(),
  cards_information_(NULL),
  team_information_(NULL),
  teaminfo_p(),
  trick_p(::party.rule()(Rule::NUMBER_OF_TRICKS_IN_GAME)),
  trickno_p(0),
  colorjabbed_p(::party.rule()(Rule::NUMBER_OF_CARD_COLORS),
		vector<bool>(::party.rule()(Rule::NUMBER_OF_PLAYERS_IN_GAME),
			     false)),
  color_runs_p(::party.rule()(Rule::NUMBER_OF_CARD_COLORS), 0),
  low_p(true),
  meatlesscolor_p(Card::NOCARDCOLOR),
  trumpless_(),
  last_trick_to_calculate_p(12),
  lastHeuristic_(Aiconfig::NO_HEURISTIC),
  vgi_(new VirtualGamesAi(*this)),
  hi_(new HeuristicAi(*this)),
  silentMarriage_(false)
{
  this->set_name( ::generate_name(RAND( 4 ) + 5) );

  delete this->db_;
  this->db_ = new AiDb;
} // Ai::Ai()

/**
 ** constructor
 **
 ** @param	aiconfig	ai configuration
 **
 ** @result	-
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.7.0
 **/
Ai::Ai(Aiconfig const& aiconfig) :
  Player(AI),
  Aiconfig(aiconfig),
  playedcards_p(),
  cards_information_(NULL),
  team_information_(NULL),
  teaminfo_p(),
  trick_p(::party.rule()(Rule::NUMBER_OF_TRICKS_IN_GAME)),
  trickno_p(0),
  colorjabbed_p(::party.rule()(Rule::NUMBER_OF_CARD_COLORS),
		vector<bool>(::party.rule()(Rule::NUMBER_OF_PLAYERS_IN_GAME),
			     false)),
  color_runs_p(::party.rule()(Rule::NUMBER_OF_CARD_COLORS), 0),
  low_p(true),
  meatlesscolor_p(Card::NOCARDCOLOR),
  trumpless_(),
  last_trick_to_calculate_p(12),
  lastHeuristic_(Aiconfig::NO_HEURISTIC),
  vgi_(new VirtualGamesAi(*this)),
  hi_(new HeuristicAi(*this)),
  silentMarriage_(false)
{
  this->set_name( ::generate_name(RAND( 4 ) + 5) );

  delete this->db_;
  this->db_ = new AiDb;
} // Ai::Ai(Aiconfig const& aiconfig)

/**
 **
 ** copy constructor
 **
 ** @param	player	player to copy
 **
 ** @return	-
 **
 ** @version	0.6.0
 **
 ** @author	Diether Knof
 **      
 **/
Ai::Ai(Player const& player) :
  Player(player),
  Aiconfig(),
  playedcards_p(),
  cards_information_(NULL),
  team_information_(NULL),
  teaminfo_p(),
  trick_p(::party.rule()(Rule::NUMBER_OF_TRICKS_IN_GAME)),
  trickno_p(0),
  colorjabbed_p(::party.rule()(Rule::NUMBER_OF_CARD_COLORS),
		vector<bool>(::party.rule()(Rule::NUMBER_OF_PLAYERS_IN_GAME),
			     false)
	       ) ,
  color_runs_p(::party.rule()(Rule::NUMBER_OF_CARD_COLORS), 0),
  low_p(true),
  meatlesscolor_p(Card::NOCARDCOLOR),
  trumpless_(),
  last_trick_to_calculate_p(12),
  lastHeuristic_(Aiconfig::NO_HEURISTIC),
  vgi_(new VirtualGamesAi(*this)),
  hi_(new HeuristicAi(*this)),
  silentMarriage_(false)
{
  DEBUG_CALLING(INFO_AI && INFO_INIT,
		"Ai::Ai(player)");

  this->set_type(AI);

  delete this->db_;
  this->db_ = new AiDb(player.db());

  DEBUG_RETURNING(VOID,
		  INFO_AI && INFO_INIT,
		  "Ai::Ai(player)");
} // Ai::Ai(Player const& player)

/**
 ** copy constructor
 **
 ** @param	player		player to copy
 ** @param	aiconfig	configuration to copy
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **/
Ai::Ai(Player const& player, Aiconfig const& aiconfig) :
  Player(player),
  Aiconfig(aiconfig),
  playedcards_p(),
  cards_information_(NULL),
  team_information_(NULL),
  teaminfo_p(),
  trick_p(::party.rule()(Rule::NUMBER_OF_TRICKS_IN_GAME)),
  trickno_p(0),
  colorjabbed_p(::party.rule()(Rule::NUMBER_OF_CARD_COLORS),
		vector<bool>(::party.rule()(Rule::NUMBER_OF_PLAYERS_IN_GAME),
			     false)
	       ) ,
  color_runs_p(::party.rule()(Rule::NUMBER_OF_CARD_COLORS), 0),
  low_p(true),
  meatlesscolor_p(Card::NOCARDCOLOR),
  trumpless_(),
  last_trick_to_calculate_p(12),
  lastHeuristic_(Aiconfig::NO_HEURISTIC),
  vgi_(new VirtualGamesAi(*this)),
  hi_(new HeuristicAi(*this)),
  silentMarriage_(false)
{
  DEBUG_CALLING(INFO_AI && INFO_INIT,
		"Ai::Ai(player)");

  this->set_type(AI);

  if (::game_status & GAMESTATUS::GAME)
    DEBUG_ASSERTION(false,
		    "Ai::Ai(player):\n"
		    "  in game");

  delete this->db_;
  this->db_ = new AiDb(player.db());

  DEBUG_RETURNING(VOID,
		  INFO_AI && INFO_INIT,
		  "Ai::Ai(player)");
} // Ai::Ai(Player const& player, Aiconfig const& aiconfig)

/**********************************************************************
 *
 ** Ai::Ai(const Ai& ai)
 *
 ** Parameters:  ai - Ai to copy
 *
 ** Result:      -
 *
 ** Version:     0.4.2
 *
 ** Description: constructor
 **      
 *
 **********************************************************************/
Ai::Ai(const Ai& ai) :
  Player(ai),
  Aiconfig(ai),
  playedcards_p(ai.playedcards_p),
cards_information_(ai.cards_information_
		   ? new CardsInformation(ai.cards_information())
		   : NULL),
team_information_(ai.team_information_
		  ? new TeamInformation(ai.team_information())
		  : NULL),
  teaminfo_p(ai.teaminfo_p),
  trick_p(ai.trick_p),
  trickno_p(ai.trickno_p),
  colorjabbed_p(ai.colorjabbed_p),
  color_runs_p(ai.color_runs_p),
  low_p(ai.low_p),
  meatlesscolor_p(ai.meatlesscolor_p),
  trumpless_( ai.trumpless_ ),
  last_trick_to_calculate_p(ai.last_trick_to_calculate_p),
  lastHeuristic_(ai.lastHeuristic_),
  vgi_(new VirtualGamesAi(*this)),
  hi_(new HeuristicAi(*this)),
  silentMarriage_( ai.silentMarriage_ )
{
  DEBUG_CALLING(INFO_AI && INFO_INIT,
		"Ai::Ai(Ai)");

  if (::game_status & GAMESTATUS::GAME)
    DEBUG_ASSERTION((this->trumpless_.size() > 0),
		    "Ai::Ai(ai):\n"
		    "  'trumpless_.size() == 0");

  this->set_type(AI);
  if (this->cards_information_)
    this->cards_information_->set_player(*this);
  if (this->team_information_)
    this->team_information_->set_player(*this);

  delete this->db_;
  this->db_ = new AiDb(*ai.db());

  if (::game_status & GAMESTATUS::GAME) {
    for (unsigned i = 0; i < this->colorjabbed_p.size(); ++i) {
      DEBUG_ASSERTION((ai.colorjabbed_p[i].size() == this->game().playerno()),
		      "Ai::Ai(ai)\n"
		      "ai");
      DEBUG_ASSERTION((this->colorjabbed_p[i].size() == this->game().playerno()),
		      "Ai::Ai(ai)\n"
		      "this");
    }
  } // if (::game_status & GAMESTATUS::GAME)

  DEBUG_RETURNING(VOID,
		  INFO_AI && INFO_INIT,
		  "Ai::Ai(Ai)");
} // Ai::Ai(const Ai& ai)

/**********************************************************************
 *
 **    Ai::~Ai()
 *
 **    Parameters:
 *
 **    Result: destroyed AI
 *
 **    Version: Alpha
 *
 **    Description:
 *
 *
 **********************************************************************/

Ai::~Ai()
{
  DEBUG_CALLING(INFO_AI && INFO_INIT, "Ai::~Ai()");

  delete this->vgi_;
  delete this->hi_;
  delete this->cards_information_;
  delete this->team_information_;

  DEBUG_RETURNING_N(INFO_AI && INFO_INIT, "Ai::~Ai()");
}

/**
 **
 ** clone the player
 **
 ** @param       -
 **
 ** @return      pointer of a clone
 **
 ** @author      Diether Knof
 **
 ** @version     0.5.3
 **
 **/
Ai*
Ai::clone() const
{  
  DEBUG_CALLING(INFO_AI && INFO_INIT,
		"Ai::clone()");

  DEBUG_RETURNING(new Ai(*this),
		  INFO_AI && INFO_INIT,
		  "Ai::clone()");
} // virtual Ai* Ai::clone() const

/**********************************************************************
 *
 **    Ai& Ai::operator=(const Ai& ai)
 *
 **    Parameters:  Ai to copy
 *
 **    Result: copy of ai
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/

Ai& Ai::operator=(const Ai& ai)
{
  DEBUG_CALLING(INFO_AI && INFO_INIT, "Ai::operator=");

  static_cast<Player&>(*this) = static_cast<const Player&>(ai);
  static_cast<Aiconfig&>(*this) = static_cast<const Aiconfig&>(ai);

  this->playedcards_p = ai.playedcards_p;
  delete this->cards_information_;
  this->cards_information_ = (ai.cards_information_
			      ? new CardsInformation(ai.cards_information())
			      : NULL);
  if (this->cards_information_)
    this->cards_information_->set_player(*this);
  delete this->team_information_;
  this->team_information_ = (ai.team_information_
			     ? new TeamInformation(ai.team_information())
			     : NULL);
  if (this->team_information_)
    this->team_information_->set_player(*this);
  this->teaminfo_p = ai.teaminfo_p;
  this->trick_p = ai.trick_p;
  this->trickno_p=ai.trickno_p;
  this->colorjabbed_p = ai.colorjabbed_p;
  this->color_runs_p = ai.color_runs_p;
  this->low_p=ai.low_p;
  this->meatlesscolor_p=ai.meatlesscolor_p;
  this->trumpless_ = ai.trumpless_;
  this->last_trick_to_calculate_p=ai.last_trick_to_calculate_p;
  this->lastHeuristic_ = ai.lastHeuristic_;
  this->silentMarriage_ = ai.silentMarriage_;
  delete this->db_;
  this->db_ = new AiDb(*(ai.db()));

  DEBUG_RETURNING(*this,INFO_AI && INFO_INIT, "Ai::operator=");
}

/**
 **
 ** cast to 'VirtualGamesInterface'
 **
 ** @param	-
 **
 ** @return	the cast
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
Ai::operator VirtualGamesInterface const&() const
{
  DEBUG_CALLING(INFO_AI && INFO_INIT,
		"Ai::operator VirtualGamesInterface()");

  DEBUG_RETURNING(*(this->vgi_),
		  INFO_AI && INFO_INIT,
		  "Ai::operator VirtualGamesInterface()");
} // virtual Ai::operator VirtualGamesInterface const&() const

/**
 **
 ** cast to 'HeuristicInterface'
 **
 ** @param	-
 **
 ** @return	the cast
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
Ai::operator HeuristicInterface const&() const
{
  DEBUG_CALLING(INFO_AI && INFO_INIT,
		"Ai::operator HeuristicInterface()");

  DEBUG_RETURNING(*(this->hi_),
		  INFO_AI && INFO_INIT,
		  "Ai::operator HeuristicInterface()");
} // virtual Ai::operator HeuristicInterface const&() const

/**
 **
 ** writes the ai into the stream
 **
 ** @param	ostr	stream the ai is to be written in
 **
 ** @return	the output stream
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
ostream&
Ai::write(ostream& ostr) const
{
  DEBUG_CALLING(INFO_AI && INFO_IO,
		"Ai::write(ostr)");

  // output of the name, type and database
  this->Player::write(ostr);

  // output of the configuration
  ostr << '\n'
    << "Aiconfig\n"
    << "{\n";
  this->Aiconfig::write(ostr);
  ostr << "}\n";

  DEBUG_RETURNING(ostr,
		  INFO_AI && INFO_IO,
		  "Ai::write(ostr)");
} // virtual ostream& Ai::write(ostream& ostr) const

/**
 **
 ** read the config of the player
 **
 ** @param	config		configuration to read
 ** @param	istr		input stream
 **
 ** @return	whether the configuration was valid
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
bool
Ai::read(Config const& config, istream& istr)
{
  if (config.separator) {
  } else { // if (config.separator)
    if (config.name == "Aiconfig") {
      this->Aiconfig::load(istr);
      return true;
    }
  } // if (config.separator)

  return this->Player::read(config, istr);

} // virtual bool Ai::read(Config config, istream& istr)

/**
 **
 ** compares the '*this' with 'ai'
 **
 ** @param       ai	ai to compare with
 **
 ** @return      whther 'ai' is equal to '*this'
 **
 ** @author      Diether Knof
 **
 ** @version     0.5.4
 **
 ** @todo	test 'cards_information', 'team_information'
 **/
bool
Ai::isequal(Ai const& ai) const
{
  DEBUG_CALLING(INFO_AI && INFO_OTHER_FUNCTION,
		"Ai::isequal(ai)");

  if (this->playedcards_p != ai.playedcards_p)
    DEBUG_RETURNING(false,
		    INFO_AI && INFO_OTHER_FUNCTION,
		    "Ai::isequal(ai) = false (playedcards)");

  // ToDo: test cards_information
  // ToDo: test team_information

  // vector<vector<bool> > colorjabbed_p;
  if (this->colorjabbed_p.size() != ai.colorjabbed_p.size())
    DEBUG_RETURNING(false,
		    INFO_AI && INFO_OTHER_FUNCTION,
		    "Ai::isequal(ai) = false (colorjabbed)");

  for (unsigned i = 0; i < this->colorjabbed_p.size(); i++) {
    if (this->colorjabbed_p[i].size() != ai.colorjabbed_p[i].size())
      DEBUG_RETURNING(false,
		      INFO_AI && INFO_OTHER_FUNCTION,
		      "Ai::isequal(ai) = false (colorjabbed)");

    for (unsigned j = 0; j < this->colorjabbed_p[i].size(); j++)
      if (this->colorjabbed_p[i][j] != ai.colorjabbed_p[i][j])
	DEBUG_RETURNING(false,
			INFO_AI && INFO_OTHER_FUNCTION,
			"Ai::isequal(ai) = false (colorjabbed)");
  } // for (i < this->colorjabbed_p.size())

  // vector<unsigned> color_runs_p;
  if (this->color_runs_p.size() != ai.color_runs_p.size())
    DEBUG_RETURNING(false,
		    INFO_AI && INFO_OTHER_FUNCTION,
		    "Ai::isequal(ai) = false (color_runs)");

  for (unsigned i = 0; i < this->color_runs_p.size(); i++)
    if (this->color_runs_p[i] != ai.color_runs_p[i])
      DEBUG_RETURNING(false,
		      INFO_AI && INFO_OTHER_FUNCTION,
		      "Ai::isequal(ai) = false (color_runs)");


  // vector<unsigned> trumpless_p;
  if (this->trumpless_.size() != ai.trumpless_.size())
    DEBUG_RETURNING(false,
		    INFO_AI && INFO_OTHER_FUNCTION,
		    "Ai::isequal(ai) = false (trumpless)");

  // vector<bool> trumpless_;
  for (unsigned i = 0; i < this->trumpless_.size(); i++)
    if (this->trumpless_[i] != ai.trumpless_[i])
      DEBUG_RETURNING(false,
		      INFO_AI && INFO_OTHER_FUNCTION,
		      "Ai::isequal(ai) = false (trumpless)");

  // unsigned trickno_p;  
  if (this->trickno_p != ai.trickno_p)
    DEBUG_RETURNING(false,
		    INFO_AI && INFO_OTHER_FUNCTION,
		    "Ai::isequal(ai) = false (trickno)");

  // bool low_p;  
  if (this->low_p != ai.low_p)
    DEBUG_RETURNING(false,
		    INFO_AI && INFO_OTHER_FUNCTION,
		    "Ai::isequal(ai) = false (low)");

  // Card::Color meatlesscolor_p;  
  if (this->meatlesscolor_p != ai.meatlesscolor_p)
    DEBUG_RETURNING(false,
		    INFO_AI && INFO_OTHER_FUNCTION,
		    "Ai::isequal(ai) = false (meatlesscolor)");

  // unsigned last_trick_to_calculate_p;  
  if (this->last_trick_to_calculate_p != ai.last_trick_to_calculate_p)
    DEBUG_RETURNING(false,
		    INFO_AI && INFO_OTHER_FUNCTION,
		    "Ai::isequal(ai) = false (last_trick_to_calculate)");

  // Aiconfig::TypeBool lastHeuristic_;  
  if (this->lastHeuristic_ != ai.lastHeuristic_)
    DEBUG_RETURNING(false,
		    INFO_AI && INFO_OTHER_FUNCTION,
		    "Ai::isequal(ai) = false (lastHeuristic)");

#if 0
  vector<Trick> trick_p; // last played tricks
#endif

  DEBUG_RETURNING(true,
		  INFO_AI && INFO_OTHER_FUNCTION,
		  "Ai::isequal(ai) = true");
} // virtual bool Ai::isequal(Ai const& ai) const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      the aitype for the current trick
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.7
 **
 **/
AiType const&
Ai::aitype() const
{
#ifdef RELEASE
  // Workaround
  if( !( (::game_status >= GAMESTATUS::GAME_PLAY)
	&& (::game_status < GAMESTATUS::GAME_FINISHED) ))
    return this->Aiconfig::aitype(0);
#else
  DEBUG_ASSERTION( (::game_status >= GAMESTATUS::GAME_PLAY)
		  && (::game_status < GAMESTATUS::GAME_FINISHED),
		  "Ai::aitype():\n"
		  "  game status not in game: " << ::game_status);
#endif

  return this->Aiconfig::aitype(this->game().trick_current().no());
} // AiType const& Ai::aitype() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      the future limit for the current trick
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.7
 **
 **/
unsigned const
Ai::future_limit() const
{
  DEBUG_ASSERTION( (::game_status >= GAMESTATUS::GAME_PLAY)
		  && (::game_status < GAMESTATUS::GAME_FINISHED),
		  "Ai::future_limit():\n"
		  "  game status not in game: " << ::game_status);

  return this->Aiconfig::future_limit(this->game().trick_current().no());
} // unsigned const Ai::future_limit() const

/**
 ** sets the game of the ai
 **
 ** @param	game	the new game for the ai
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
void
Ai::set_game(Game& game)
{
  bool const old_isvirtual = this->game().isvirtual();
  this->Player::set_game(game);

  if (false)
    if (!old_isvirtual
	&& game.isvirtual()) {
      // make the ai not count the cards of its own
      Hand const hand = this->hand();
      this->set_hand(hand);
    }

  return ;
} // Hand const& Ai::set_game(Game& game)

/**********************************************************************
 *
 ** Ai::sethand(Hand h, bool const playedcards_update = true)
 *
 ** Parameters:  h                       - new hand for this player
 *
 ** Result:      -
 *
 ** Version:     0.4.2
 *
 ** Description: creation of a new hand for this player with all cards of h
 **              and memorizing of all this cards for not playable by other 
 **              players in the field playedcards_p 
 *
 **********************************************************************/
Hand const&
Ai::set_hand(const Hand& h)
{
  DEBUG_CALLING(INFO_AI && INFO_VALUE,
		"Ai::set_hand(const Hand& h)");

  DEBUG_RETURNING(this->set_hand(h, true),
		  INFO_AI && INFO_VALUE,
		  "Ai::set_hand(const Hand& h)");
} // Hand const& Ai::set_hand(const Hand& h)

/**
 **
 ** Ai::set_hand(Hand h, bool const playedcards_update = true)
 **
 ** Parameters:  h                       - new hand for this player
 **              playedcards_update      - whether to update the played cards
 **
 ** Result:      -
 **
 ** Version:     0.4.2
 **
 ** Description: creation of a new hand for this player with all cards of h
 **              and memorizing of all this cards for not playable by other 
 **              players in the field playedcards_p 
 **
 **/
Hand const&
Ai::set_hand(const Hand& h, bool const playedcards_update)
{
  DEBUG_CALLING(INFO_AI && INFO_VALUE,
		"Ai::set_hand(const Hand& h)");

  // COUT << "Ai::set_hand(" << this->no() << ", " << playedcards_update << ")"
  // << endl;
  Player::set_hand(h);
  this->cards_information().set_hand(*this, h);
  if (playedcards_update)
  {
    // first reset
    for (vector<Card>::const_iterator
	 c = this->game().rule().valid_cards().begin();
	 c != this->game().rule().valid_cards().end();
	 ++c)
      this->playedcards_p[*c] = 0;

    // take new hand into account
    // if the game is virtual, the hand can contain more than 12 cards,
    // so they aren't taken into account
    if (!this->game().isvirtual()) {
      for (unsigned i = 0; i < h.cardsnumber_all(); i++) 
	this->playedcards_p[h.card_all(i)] += 1;	
    }

    if( this->no() == DEBUG_PLAYER ) {
      COUT << "Hand Cards counted" << endl;
      for (vector<Card>::const_iterator
	   c = this->game().rule().valid_cards().begin();
	   c != this->game().rule().valid_cards().end();
	   ++c)
	COUT << *c << " " << this->playedcards_p[*c] << endl;
    }

    this->trickno_p = 0;
    // take already played tricks into account
    for (vector<Trick*>::const_iterator
	 trick = this->game().tricks().begin();
	 trick != this->game().tricks().end();
	 trick++) {
      for (unsigned c = 0; c < (*trick)->actcardno(); ++c)
	if ( ((*trick)->player_of_card(c).no() != this->no())
	    || this->game().isvirtual() )
	  playedcards_p[(*trick)->card(c)] += 1;

      if ((*trick)->isfull())
	this->updateplayedcards(**trick);
    }

    if( this->no() == DEBUG_PLAYER )
    {
      COUT << "Tricks counted" << endl;
      for (vector<Card>::const_iterator
	   c = this->game().rule().valid_cards().begin();
	   c != this->game().rule().valid_cards().end();
	   ++c)
	COUT << *c << " " << this->playedcards_p[*c] << endl;
    }

#ifndef DEBUG_NO_ASSERTS
    if (this->game().isvirtual())
      for (vector<Card>::const_iterator
	   c = this->game().rule().valid_cards().begin();
	   c != this->game().rule().valid_cards().end();
	   ++c) {
	DEBUG_ASSERTION( (this->playedcard(*c) + this->hand().numberof(*c)
			  <= this->game().rule()(Rule::NUMBER_OF_SAME_CARDS)),
			"Ai::set_hand():\n"
			"  Player: " << this->no() << "\n"
			"  card " << *c << " too often in the game\n"
			//<< "Game:\n" << this->game()
			<< "Hand:\n" << h
		       );
	while (this->playedcard(*c) + this->hand().numberof(*c)
	       > this->game().rule()(Rule::NUMBER_OF_SAME_CARDS))
	  this->hand().remove(*c);
      }
#endif
  } // if (playedcards_update)

  low_p = this->hand().numberof( Card::QUEEN ) < this->hand().numberof( Card::JACK ) + 1;

  if( this->no() == DEBUG_PLAYER )
  {
    COUT << "done counting" << endl;
    for (vector<Card>::const_iterator
	 c = this->game().rule().valid_cards().begin();
	 c != this->game().rule().valid_cards().end();
	 ++c)
      COUT << *c << " " << this->playedcards_p[*c] << endl;
  }

  DEBUG_RETURNING(this->hand(),
		  INFO_AI && INFO_VALUE,
		  "Ai::set_hand(const Hand& h)");
} // virtual Hand const& Ai::set_hand(const Hand& h, bool const playedcards_update = true)

/**
 ** the game is started
 **
 ** @param       -
 **
 ** @return      -
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.9
 **/
void
Ai::game_start() 
{ 
  if (::game_status == GAMESTATUS::GAME_REDISTRIBUTE)
    return ;

  this->Player::game_start();

  { // in a poverty the hand can have changed
    this->cards_information().reset();
    this->cards_information().set_hand(*this, this->hand());
  }


  this->cards_information().game_start();
  this->team_information().game_start();

  if (this->type() == Player::AI) {
    // announce swines
    if (this->game().rule()(Rule::SWINES_ANNOUNCEMENT_BEGIN))
      if (this->game().swines_announcement_valid(*this))
	this->game().swines_announce(*this);

    // hyperswines are announced by 'Ai::swines_announced(player)'
  } // if (this->type() == Player::AI)

  return ;
} // void Ai::game_start()

/**
 **
 ** the game is closed
 **
 ** @param       game	game that is closed
 **
 ** @return      -
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.9
 **
 **/
void
Ai::game_close(Game const& game) 
{ 
  this->Player::game_close(game);

  delete this->cards_information_;
  this->cards_information_ = NULL;

  delete this->team_information_;
  this->team_information_ = NULL;

  return ;
} // void Ai::game_close(Game game)


/**
 **
 ** -> result
 ** - if not 'Aiconfig::FAIRPLAYHANDS' the real hand of the player is returned
 **   (independent on 'Rule::SHOW_ALL_HANDS')
 ** - if 'Aiconfig::FAIRPLAYHANDS' the hand is calculated,
 **   see 'CardsInformation'
 **
 ** @param	player		player whose hand is returned
 **
 ** @result	hand of 'player'
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.9
 **
 **/
Hand
Ai::handofplayer(Player const& player) const
{
  if (!this->game().isvirtual()
      && (player.no() == this->no()))
    return this->hand();

  if (!this->Aiconfig::value(Aiconfig::FAIRPLAYHANDS))
    return player.hand();

  // If it is the last trick and the player has already played a card,
  // his hand is empty.
  if ((this->game().tricks_remaining_no() == 1)
      && (this->game().trick_current().cardno_of_player(player)
	  < this->game().trick_current().actcardno()))
    return Hand();
#ifdef DKNOF
  Hand const hand(this->cards_information().possible_hand(player));
  hand.self_check();
  return hand;
#else
  return this->cards_information().possible_hand(player);
#endif
} // Hand Ai::handofplayer(Player const& player) const

/**********************************************************************
 *
 **    Team team(const unsigned i) const; 
 ** 
 *
 **    Parameters:  player
 *
 **    Result: team of player depending on fairplayteams
 *
 **    Version: Alpha
 *
 **    Description: 
 **       
 *
 **********************************************************************/

Team Ai::teamofplayer(Player const& player) const

{
  DEBUG_CALLING(INFO_AI && INFO_VALUE,
		"Ai::team(i)");

  if (this->Aiconfig::value(Aiconfig::FAIRPLAYTEAMS)
      || (this->game().type() == GAMETYPE::MARRIAGE))
  {  
    // in the marriage case, as long as the teams are not determined, the player
    // shall think that every other player is against him
    DEBUG_RETURNING(this->teaminfo( player ),
		    INFO_AI && INFO_VALUE,
		    "Ai::team( player )");
  } else
  {
    DEBUG_RETURNING( player.team(),
		    INFO_AI && INFO_VALUE,
		    "Ai::team( player )");
  }
}

/**
 ** set the teams
 **
 ** @param     teams   teams of the players
 **
 ** @return    -
 **
 ** @author    Diether Knof
 ** @author    Borg Enders
 **
 ** @version   0.7.2
 **/
void
Ai::set_teams(vector<Team> const& teams)
{
  this->team_information().set_teams(teams);
  this->set_team(teams[this->no()]);

  return ;
} // void Ai::set_teams(vector<Team> teams)

/**
 **
 ** the trick is opened
 **
 ** @param      trick	opened trick
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.6.9
 **
 **/
void
Ai::trick_open(Trick const& trick)
{ 
  this->cards_information().trick_open(trick);

  return ;
} // void Ai::trick_open(Trick const& trick)

/**
 **
 ** the trick is full
 **
 ** @param      trick   full trick
 **
 ** @return     -
 **
 ** @version    0.4.5
 **
 ** @author     Diether Knof
 **
 **/
void
Ai::trick_full(Trick const& trick)
{ 
  DEBUG_ASSERT( trick.isfull() );

  this->team_information().trick_full();

  if( trick.startcard().istrump() ) {
    for ( unsigned i = 0; i < trick.actcardno(); i++) {
      if (!trick.card(i).istrump()) {
	DEBUG_ASSERTION((this->trumpless_.size()
			 > trick.player_of_card(i).no()),
			"Ai::trick_full(trick):\n"
			"  'this->trumpless_' is too small: "
			<< this->trumpless_.size() << " <= "
			<< trick.player_of_card(i).no());
	this->trumpless_[ trick.player_of_card(i).no() ] = true;
      }
    }
  }

  this->updateplayedcards(trick);

  return ;
} // void Ai::trick_full(Trick const& trick)


/**********************************************************************
 *
 **    void Ai::updateplayedcards(Trick t)
 *
 **    Parameters: last played trick 
 *
 **    Result: 
 *
 **    Version: Alpha
 *
 **    Description: 
 **      memorizing of all the cards of t for not playable by other 
 **      players in the field playedcards_p 
 *
 *    @todo    remove
 *
 *
 **********************************************************************/

void Ai::updateplayedcards(const Trick& t) throw(InvalidGameException)
{
  DEBUG_CALLING(INFO_AI && INFO_OTHER_FUNCTION,"Ai::updateplayedcards(const Trick& t)");

  unsigned i;

  trick_p[trickno_p]=t;

  trickno_p++;

  if (!t.startcard().istrump())
  {
    color_runs_p[t.startcard().color()]++;
  }

  // the ai knows too much let's remove the oldest trick(s)
  while(trickno_p > this->Aiconfig::value(Aiconfig::REMEMBERTRICKS))
  {
    Trick const& tr = trick_p[0];

    // lets forget this trick
    for( i = 0 ; i < tr.actcardno(); i++)
    {
      if (!tr.card(i).isdolle()        || 
	  !tr.card(i).isswine()      ||
	  !tr.card(i).ishyperswine() )
      {

	if( !this->game().isvirtual() ) {
#ifndef RELEASE
#ifdef BENDERS
	  if(playedcard(tr.card(i)) == 0)
	    COUT << playedcard(tr.card(i)) << endl;
#endif
#endif
	  DEBUG_ASSERT(playedcard(tr.card(i)) > 0);
	}

	if (playedcards_p[tr.card(i)] <= 0) {
	  DEBUG_THROW( InvalidGameException, InvalidGameException() );
	}
	playedcards_p[tr.card(i)] -= 1;
      }
    }

    // remove this trick from list
    for ( i = 0; i < trickno_p-1; i++)
      trick_p[i]=trick_p[i+1];

    trickno_p--;
  }     
#ifndef DEBUG_NO_ASSERTS
  if (!this->game().isvirtual()) { // test the playedcardsnumber
    unsigned no = 0;
    for (vector<Card>::const_iterator
	 c = this->game().rule().valid_cards().begin();
	 c != this->game().rule().valid_cards().end();
	 ++c)
      no += this->playedcards_p[*c];

    DEBUG_ASSERTION((no <= (this->game().trick_current_no() + 1) * 4
		     + this->game().tricks_remaining_no()),
		    "Ai::updateplayedcards(trick):\n"
		    "  too many played cards: " << no
		    << ", current trick no: " << this->game().trick_current_no());
  } // test the playedcardsnumber
#endif // #ifndef DEBUG_NO_ASSERTS

  // test that the cards are only counted at max as often as they are played
  if (this->game().isvirtual())
    for (vector<Card>::const_iterator
	 c = this->game().rule().valid_cards().begin();
	 c != this->game().rule().valid_cards().end();
	 ++c)
      DEBUG_ASSERTION(this->playedcard(*c) <= this->game().played_no(*c),
		      "Ai::handofplayer():\n"
		      "  card " << *c << " counted wrong:\n"
		      "counted = " << this->playedcard(*c)
		      << " > " << this->game().played_no(*c)
		      << " = played");

  DEBUG_RETURNING(VOID,
		  INFO_AI && INFO_OTHER_FUNCTION,
		  "Ai::updateplayedcards(const Trick& t)");
} // void Ai::updateplayedcards(const Trick& t)


/**********************************************************************
 *
 ** Card Ai::card_get()
 *
 ** Parameters:  -
 *
 ** Result:      card played by the ai
 *
 ** Version:     0.4.4
 *
 ** Description: returns the card, the ai wishes to play
 *
 **********************************************************************/
HandCard
Ai::card_get()
{
  DEBUG_CALLING(INFO_AI && INFO_GAMEPLAY,
		"Ai::card_get()");

  HandCard c(this->hand(), this->nextcard(this->game().trick_current()));

  if (   c.possible_swine()
      && game().swines_announcement_valid( *this ) )
    this->game().swines_announce(*this);
  if (   c.possible_hyperswine()
      && game().hyperswines_announcement_valid( *this ) )
    this->game().hyperswines_announce(*this);

  DEBUG_RETURNING(c,
		  INFO_AI && INFO_GAMEPLAY,
		  "Ai::card_get()");
} // HandCard Ai::card_get() const

/**
 ** -> result
 **
 ** @param	-
 **
 ** @return	suggested card
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
HandCard
Ai::card_suggestion()
{
  extern OS_NS::BugReportReplay* bug_report_replay;

  if (bug_report_replay) {
    static bool bug_report_flip = false;
    if (this->lastHeuristic_ != Aiconfig::BUG_REPORT)
      bug_report_flip = true;
    else
      bug_report_flip ^= true;
    if (bug_report_flip) {
      this->lastHeuristic_ = Aiconfig::BUG_REPORT;
      return HandCard(this->hand(),
		      bug_report_replay->next_card(*this));
    }
  }
  return HandCard(this->hand(),
		  this->nextcard(this->game().trick_current()));
} // HandCard Ai::card_suggestion()

/**
 **
 ** 'player' has played the card 'card'
 **
 ** @param       card    played card
 **
 ** @return      -
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.6.3
 **
 **/
void
Ai::card_played(HandCard const& card)
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Ai::card_played(card)");

  this->cards_information().card_played(card);
  this->team_information().card_played(card);

  if( this->no() == DEBUG_PLAYER ) {
    COUT << "card played " << card << endl;
    COUT << "virtual = " << this->game().isvirtual() << endl;
  }

  Player const& player = card.player();
  Card::Color jabbed=Card::NOCARDCOLOR;


  Trick t = player.game().trick_current();

  if (!t.startcard().istrump())
  {
    jabbed=t.startcard().color();
  }

  // count all played cards of the other players
  if ((player.no() != this->no())
      || this->game().isvirtual())
  {
    playedcards_p[card] += 1;
    if( this->no() == DEBUG_PLAYER )
      COUT << "incremented " << card << " to " << playedcards_p[card]
	<< " played by " << player.no() << endl;
    DEBUG_ASSERTION((this->playedcard(card)
		     - (this->game().isvirtual()
			? 0
			: this->hand().numberof(card))
		     <= this->game().played_no(card)),
		    "Ai::card_played():\n"
		    "  Player: " << this->no() << "\n"
		    << "  playedcard(" << card << ") = "
		    << this->playedcard(card)
		    << " > " << this->game().played_no(card)
		    << " == this->game().played_no(card)\n"
		   );

  }
  DEBUG_ASSERTION((this->playedcard(card)
		   <= this->game().rule()(Rule::NUMBER_OF_SAME_CARDS)),
		  "Ai::card_played():\n"
		  "  this->playedcard(" << card << ") == "
		  << this->playedcard(card) << " > "
		  << this->game().rule()(Rule::NUMBER_OF_SAME_CARDS)
		  << " == NUMBER_OF_SAME_CARDS\n"
		  << "Player = " << this->no() << '\n'
		  << "Trick: " << this->game().trick_current());

#if 0
  if (this->game().isvirtual()) {
    if (this->playedcard(card) + this->hand().numberof(card)
	> this->game().rule()(Rule::NUMBER_OF_SAME_CARDS))
      this->hand().remove(HandCard(*this, card));

    DEBUG_ASSERTION((this->playedcard(card) + this->hand().numberof(card)
		     <= this->game().rule()(Rule::NUMBER_OF_SAME_CARDS)),
		    "Ai::card_played():\n"
		    "  Player " << this->no() << ":\n"
		    << "  this->playedcard(" << card << ") "
		    << "+ this->hand.numberof(card) == "
		    << this->playedcard(card) << " + " 
		    << this->hand().numberof(card)
		    << " > "
		    << this->game().rule()(Rule::NUMBER_OF_SAME_CARDS)
		    << " == NUMBER_OF_SAME_CARDS";
		    this->game().write_tricks(); COUT);
  } // if (this->game().isvirtual())
#endif

  if (jabbed!=Card::NOCARDCOLOR && card.istrump())
  {
    colorjabbed_p[jabbed][player.no()]=true;
  }  
  if(   jabbed != Card::NOCARDCOLOR 
     && card.color() != jabbed
     && remaining_trumps() >=  game().tricks_remaining_no() )
  {
    colorjabbed_p[jabbed][player.no()]=true;
  }  



  if (player == *this) {
    switch (this->lastHeuristic_) {
    case Aiconfig::LOW_HIGH:
    case Aiconfig::COLOR_LOW_HIGH:
      if (! (   this->low_p
	     && (this->game().trick_current().winnerplayer() == *this)) )
      this->check_low_high(card);
      break;

    case Aiconfig::BUG_REPORT:
      // reset
      this->lastHeuristic_ = Aiconfig::NO_HEURISTIC;
      break;

    default:
      break;
    } // switch (this->lastHeuristic_)
  } // if (player == *this)

  this->teaminfo_update();

  DEBUG_RETURNING(VOID,
		  INFO_PLAYER && INFO_VALUE,
		  "Ai::card_played(card)");
} // void Ai::card_played(HandCard const& card)

/**
 ** 'player' has announce swines
 ** if possible announce hyperswines
 **
 ** @param      player	player that has announced the swines
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.6.6
 **/
void
Ai::swines_announced(Player const& player)
{ 
  this->cards_information().swines_announced(player);

  if (   this->game().hyperswines_announcement_valid(*this)
      && this->game().rule()(Rule::HYPERSWINES_ANNOUNCEMENT_BEGIN))
    this->game().hyperswines_announce(*this);

  return ;
} // void Ai::swines_announced(Player const& player)

/**
 **
 ** 'player' has announce hyperswines
 **
 ** @param      player	player that has announced the hyperswines
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.6.6
 **
 **/
void
Ai::hyperswines_announced(Player const& player)
{ 
  this->cards_information().hyperswines_announced(player);

  return ;
} // void Ai::hyperswines_announced(Player const& player)

/**
 ** the marriage partner has found a bride
 ** if the bride is the bridegroom, the bridegroom must play a solo
 **
 ** @param	bridegroom	the player with the marriage
 ** @param	bride		the bride
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.1
 **/
void
Ai::marriage(Player const& bridegroom, Player const& bride)
{
  this->team_information().marriage(bridegroom, bride);
  this->teaminfo_update();

  return ;
} // void Ai::marriage(Player bridegroom, Player bride)

/**
 **
 ** a player has a genscher and selected a new partner
 **
 ** @param	genscher	genscher player
 ** @param	partner		partner of the gensher player
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.9
 **
 **/
void
Ai::genscher(Player const& genscher, Player const& partner)
{ 
  this->cards_information().genscher(genscher, partner);
  this->team_information().genscher(genscher, partner);

  return ;
} // void Ai::genscher(Player genscher, Player partner)

/**
 **
 ** selects a card to play
 **
 ** @param	trick	current trick
 ** 
 ** @return	card to play
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
Card
Ai::nextcard(Trick const& trick)
{
  DEBUG_CALLING(INFO_AI && INFO_GAMEPLAY,
		"Ai::nextcard()");

  if (!this->game().isvirtual())
    db()->heuristicInc( Aiconfig::NO_HEURISTIC );

  { // only valid card
    HandCards const valid_cards = this->hand().validcards(trick);
    DEBUG_ASSERTION((valid_cards.cardsnumber() > 0),
		    "Ai::nextcard(Trick, output):\n"
		    "  found no valid card."
		    "Trick: " << trick
		    << "Hand: " << this->hand());
    // if there is only one valid card that's it
    if (valid_cards.cardsnumber() == 1) {
      Card const card = valid_cards.card(0);
      Aiconfig::Heuristic const heuristic = Aiconfig::ONLY_VALID_CARD;

      if (HEURISTIC_OUTPUT
	  && !this->game().isvirtual())
	cout <<  setw(2) << no() << " "
	  << setw(20) << card << " "
	  << ::name(heuristic)
	  << endl;

      this->lastHeuristic_ = heuristic;
      this->db()->heuristicInc(heuristic);

      DEBUG_RETURNING(card,
		      INFO_AI && INFO_GAMEPLAY,
		      "Ai::nextcard()");
    } // if (valid_cards.cardsnumber() == 1)
  } // only valid card

  if ( this->game().trick_current_no() < 
      this->Aiconfig::value(Aiconfig::LASTHEURISTICTRICK ) ) {

    // ToDo: -> Aiconfig

    vector<Aiconfig::Heuristic> heuristics_normal;
    heuristics_normal.push_back(Aiconfig::PLAY_TO_MARRY);
    heuristics_normal.push_back(Aiconfig::CHOOSE_ACE);
    heuristics_normal.push_back(Aiconfig::TRY_FOR_DOPPELKOPF);
    heuristics_normal.push_back(Aiconfig::CHOOSE_FOR_COLOR_TRICK);
    heuristics_normal.push_back(Aiconfig::SERVE_COLOR_TRICK);
    heuristics_normal.push_back(Aiconfig::SERVE_TRUMP_TRICK);
    heuristics_normal.push_back(Aiconfig::JAB_FOX);
    heuristics_normal.push_back(Aiconfig::CHOOSE_PFUND);
    heuristics_normal.push_back(Aiconfig::JAB_FOR_ACE);
    heuristics_normal.push_back(Aiconfig::PLAY_FOR_TEAM);
    heuristics_normal.push_back(Aiconfig::RETRY_COLOR);
    heuristics_normal.push_back(Aiconfig::CREATE_FEHL);
    heuristics_normal.push_back(Aiconfig::BEST_WINNING);
    heuristics_normal.push_back(Aiconfig::LOW_HIGH);
    heuristics_normal.push_back(Aiconfig::DRAW_TRUMP);
    heuristics_normal.push_back(Aiconfig::GET_TRICK_FOR_ANNOUNCEMENT);

    vector<Aiconfig::Heuristic> heuristics_meatless;
    heuristics_meatless.push_back(Aiconfig::MEATLESS_PLAYHIGHESTCOLOR);
    heuristics_meatless.push_back(Aiconfig::CHOOSE_ACE);
    heuristics_meatless.push_back(Aiconfig::SERVE_COLOR_TRICK);
    heuristics_meatless.push_back(Aiconfig::JAB_FOX);
    heuristics_meatless.push_back(Aiconfig::CHOOSE_PFUND);
    heuristics_meatless.push_back(Aiconfig::JAB_FOR_ACE);
    heuristics_meatless.push_back(Aiconfig::PLAY_FOR_TEAM);
    heuristics_meatless.push_back(Aiconfig::CREATE_FEHL);
    heuristics_meatless.push_back(Aiconfig::BEST_WINNING);
    heuristics_meatless.push_back(Aiconfig::LOW_HIGH);
    heuristics_meatless.push_back(Aiconfig::DRAW_TRUMP);

    vector<Aiconfig::Heuristic> heuristics_poverty_soloplayer;
    heuristics_poverty_soloplayer.push_back(Aiconfig::CHOOSE_ACE);
    heuristics_poverty_soloplayer.push_back(Aiconfig::CHOOSE_FOR_COLOR_TRICK);
    heuristics_poverty_soloplayer.push_back(Aiconfig::SERVE_COLOR_TRICK);
    heuristics_poverty_soloplayer.push_back(Aiconfig::SERVE_TRUMP_TRICK);
    heuristics_poverty_soloplayer.push_back(Aiconfig::JAB_FOX);
    heuristics_poverty_soloplayer.push_back(Aiconfig::CHOOSE_PFUND_POVERTY);
    heuristics_poverty_soloplayer.push_back(Aiconfig::POVERTY_PLAYER_PLAY_PFUND);
    heuristics_poverty_soloplayer.push_back(Aiconfig::JAB_FOR_ACE);
    heuristics_poverty_soloplayer.push_back(Aiconfig::CREATE_FEHL);
    heuristics_poverty_soloplayer.push_back(Aiconfig::BEST_WINNING);
    heuristics_poverty_soloplayer.push_back(Aiconfig::LOW_HIGH);
    heuristics_poverty_soloplayer.push_back(Aiconfig::DRAW_TRUMP);
    heuristics_poverty_soloplayer.push_back(Aiconfig::GET_TRICK_FOR_ANNOUNCEMENT);

    vector<Aiconfig::Heuristic> heuristics_silent_marriage;
    heuristics_silent_marriage.push_back(Aiconfig::COLOR_CHOOSE_ACE);
    heuristics_silent_marriage.push_back(Aiconfig::COLOR_JAB_FOR_ACE);
    heuristics_silent_marriage.push_back(Aiconfig::COLOR_BEST_WINNING);
    heuristics_silent_marriage.push_back(Aiconfig::COLOR_LOW_HIGH);
    heuristics_silent_marriage.push_back(Aiconfig::DRAW_TRUMP);
    heuristics_silent_marriage.push_back(Aiconfig::GET_TRICK_FOR_ANNOUNCEMENT);

    vector<Aiconfig::Heuristic> heuristics_colorsolo_soloplayer;
    heuristics_colorsolo_soloplayer.push_back(Aiconfig::COLOR_CHOOSE_ACE);
    heuristics_colorsolo_soloplayer.push_back(Aiconfig::COLOR_JAB_FOR_ACE);
    heuristics_colorsolo_soloplayer.push_back(Aiconfig::SERVE_COLOR_TRICK);
    heuristics_colorsolo_soloplayer.push_back(Aiconfig::SERVE_TRUMP_TRICK);
    heuristics_colorsolo_soloplayer.push_back(Aiconfig::COLOR_BEST_WINNING);
    heuristics_colorsolo_soloplayer.push_back(Aiconfig::COLOR_LOW_HIGH);
    heuristics_colorsolo_soloplayer.push_back(Aiconfig::DRAW_TRUMP);
    heuristics_colorsolo_soloplayer.push_back(Aiconfig::GET_TRICK_FOR_ANNOUNCEMENT);


    vector<Aiconfig::Heuristic> heuristics_single_picturesolo_soloplayer;
    heuristics_single_picturesolo_soloplayer.push_back(Aiconfig::COLOR_CHOOSE_ACE);
    heuristics_single_picturesolo_soloplayer.push_back(Aiconfig::DRAW_TRUMP);
    heuristics_single_picturesolo_soloplayer.push_back(Aiconfig::PICTURE_SECONDBESTTRUMP);
    heuristics_single_picturesolo_soloplayer.push_back(Aiconfig::COLOR_JAB_FOR_ACE);
    heuristics_single_picturesolo_soloplayer.push_back(Aiconfig::SERVE_COLOR_TRICK);
    heuristics_single_picturesolo_soloplayer.push_back(Aiconfig::SERVE_TRUMP_TRICK);
    heuristics_single_picturesolo_soloplayer.push_back(Aiconfig::COLOR_BEST_WINNING);
    heuristics_single_picturesolo_soloplayer.push_back(Aiconfig::COLOR_LOW_HIGH);
    heuristics_single_picturesolo_soloplayer.push_back(Aiconfig::DRAW_TRUMP);
    heuristics_single_picturesolo_soloplayer.push_back(Aiconfig::GET_TRICK_FOR_ANNOUNCEMENT);


    vector<Aiconfig::Heuristic> heuristics_double_picturesolo_soloplayer;
    heuristics_double_picturesolo_soloplayer.push_back(Aiconfig::COLOR_CHOOSE_ACE);
    heuristics_double_picturesolo_soloplayer.push_back(Aiconfig::DRAW_TRUMP);
    heuristics_double_picturesolo_soloplayer.push_back(Aiconfig::PICTURE_SECONDBESTTRUMP);
    heuristics_double_picturesolo_soloplayer.push_back(Aiconfig::COLOR_JAB_FOR_ACE); 
    heuristics_double_picturesolo_soloplayer.push_back(Aiconfig::SERVE_COLOR_TRICK);
    heuristics_double_picturesolo_soloplayer.push_back(Aiconfig::SERVE_TRUMP_TRICK);
    heuristics_double_picturesolo_soloplayer.push_back(Aiconfig::COLOR_BEST_WINNING);
    heuristics_double_picturesolo_soloplayer.push_back(Aiconfig::COLOR_LOW_HIGH);
    heuristics_double_picturesolo_soloplayer.push_back(Aiconfig::DRAW_TRUMP);
    heuristics_double_picturesolo_soloplayer.push_back(Aiconfig::GET_TRICK_FOR_ANNOUNCEMENT);


    vector<Aiconfig::Heuristic> heuristics_koehler_soloplayer;
    heuristics_koehler_soloplayer.push_back(Aiconfig::COLOR_CHOOSE_ACE);
    heuristics_koehler_soloplayer.push_back(Aiconfig::DRAW_TRUMP);
    heuristics_koehler_soloplayer.push_back(Aiconfig::PICTURE_SECONDBESTTRUMP);
    heuristics_koehler_soloplayer.push_back(Aiconfig::COLOR_JAB_FOR_ACE);
    heuristics_koehler_soloplayer.push_back(Aiconfig::SERVE_COLOR_TRICK);
    heuristics_koehler_soloplayer.push_back(Aiconfig::SERVE_TRUMP_TRICK);
    heuristics_koehler_soloplayer.push_back(Aiconfig::COLOR_BEST_WINNING);
    heuristics_koehler_soloplayer.push_back(Aiconfig::COLOR_LOW_HIGH);
    heuristics_koehler_soloplayer.push_back(Aiconfig::DRAW_TRUMP);
    heuristics_koehler_soloplayer.push_back(Aiconfig::GET_TRICK_FOR_ANNOUNCEMENT);


    HeuristicsMap::Map heuristics_map;

    { // maps entries creating
      // default
      {
	HeuristicsMap::Key key;
	key.gametype_group = HeuristicsMap::DEFAULT;
	key.playertype_group = HeuristicsMap::CONTRA;
	heuristics_map[ key ] = heuristics_normal;
      }
      // normal
      {
	HeuristicsMap::Key key;
	key.gametype_group = HeuristicsMap::NORMAL;
	key.playertype_group = HeuristicsMap::CONTRA;
	heuristics_map[ key ] = heuristics_normal;
      }
      {
	HeuristicsMap::Key key;
	key.gametype_group = HeuristicsMap::NORMAL;
	key.playertype_group = HeuristicsMap::RE;
	heuristics_map[ key ] = heuristics_normal;
      }
      // poverty
      {
	HeuristicsMap::Key key;
	key.gametype_group = HeuristicsMap::POVERTY;
	key.playertype_group = HeuristicsMap::SPECIAL;
	heuristics_map[ key ] = heuristics_poverty_soloplayer;
      }
      // silent marriage
      {
	HeuristicsMap::Key key;
	key.gametype_group = HeuristicsMap::MARRIAGE_SILENT;
	key.playertype_group = HeuristicsMap::RE;
	heuristics_map[ key ] = heuristics_silent_marriage;
      }
      // colorsolo
      {
	HeuristicsMap::Key key;
	key.gametype_group = HeuristicsMap::SOLI_COLOR;
	key.playertype_group = HeuristicsMap::RE;
	heuristics_map[ key ] = heuristics_colorsolo_soloplayer;
      }
      // single picture solo
      {
	HeuristicsMap::Key key;
	key.gametype_group = HeuristicsMap::SOLI_SINGLE_PICTURE;
	key.playertype_group = HeuristicsMap::RE;
	heuristics_map[ key ] = heuristics_single_picturesolo_soloplayer;
      }
      // double picture solo
      {
	HeuristicsMap::Key key;
	key.gametype_group = HeuristicsMap::SOLI_DOUBLE_PICTURE;
	key.playertype_group = HeuristicsMap::RE;
	heuristics_map[ key ] = heuristics_double_picturesolo_soloplayer;
      }
      // koehler
      {
	HeuristicsMap::Key key;
	key.gametype_group = HeuristicsMap::SOLO_KOEHLER;
	key.playertype_group = HeuristicsMap::RE;
	heuristics_map[ key ] = heuristics_koehler_soloplayer;
      }
      // meatless
      {
	HeuristicsMap::Key key;
	key.gametype_group = HeuristicsMap::SOLO_MEATLESS;
	key.playertype_group = HeuristicsMap::CONTRA;
	heuristics_map[ key ] = heuristics_meatless;
      }
      {
	HeuristicsMap::Key key;
	key.gametype_group = HeuristicsMap::SOLO_MEATLESS;
	key.playertype_group = HeuristicsMap::RE;
	heuristics_map[ key ] = heuristics_meatless;
      }
    } // maps entries creating

    HeuristicsMap::Key key = HeuristicsMap::key(*this);
    if (this->silentMarriage_)
      key.gametype_group = HeuristicsMap::MARRIAGE_SILENT;

    HeuristicsMap::Map::const_iterator it = heuristics_map.find(key);
    if (it == heuristics_map.end()) {
      HeuristicsMap::Key key
	= {HeuristicsMap::DEFAULT, HeuristicsMap::CONTRA};
      it = heuristics_map.find(key);
      DEBUG_ASSERT(it != heuristics_map.end());
    }

    vector<Aiconfig::Heuristic> const& heuristics_vector = it->second;

    for (vector<Aiconfig::Heuristic>::const_iterator
	 heuristic = heuristics_vector.begin();
	 heuristic != heuristics_vector.end();
	 ++heuristic) {
      if (!this->value(*heuristic))
	continue;
      Card card; // card to play

      switch(*heuristic) {
      case Aiconfig::NO_HEURISTIC:
      case Aiconfig::BUG_REPORT:
      case Aiconfig::ONLY_VALID_CARD:
	DEBUG_ASSERT(false);
	break;
      case Aiconfig::PLAY_TO_MARRY:
	card = Heuristics::play_to_marry(trick, *this);
	break;
      case Aiconfig::CHOOSE_ACE:
	card = Heuristics::choose_ace(trick, *this);
	break;
      case Aiconfig::RETRY_COLOR:
	card = Heuristics::retry_color(trick, *this);
	break;
      case Aiconfig::CHOOSE_FOR_COLOR_TRICK:
	card = Heuristics::choose_for_color_trick(trick, *this);
	break;
      case Aiconfig::SERVE_COLOR_TRICK:
	card = Heuristics::serve_color_trick(trick, *this);
	break;
      case Aiconfig::SERVE_TRUMP_TRICK:
	card = Heuristics::serve_trump_trick(trick, *this);
	break;
      case Aiconfig::CHOOSE_PFUND_POVERTY:
	if ( !trick.islastcard() )
	  break;

      case Aiconfig::CHOOSE_PFUND:
	card = Heuristics::choose_pfund(trick, *this);
	break;
      case Aiconfig::JAB_FOR_ACE:
	card = Heuristics::jab_for_ace(trick, *this);
	break;
      case Aiconfig::CREATE_FEHL:
	card = Heuristics::create_fehl(trick, *this);
	break;
      case Aiconfig::BEST_WINNING:
      case Aiconfig::COLOR_BEST_WINNING:
	if (maybe_to_team(this->teaminfo(trick.winnerplayer())) == this->team())
	  break;

	card = Heuristics::best_winning_card(trick, *this);
	break;
      case Aiconfig::LOW_HIGH:
      case Aiconfig::COLOR_LOW_HIGH:
	card = Heuristics::play_low_high(trick, *this);

	break;
      case Aiconfig::PLAY_FOR_TEAM:
	card = Heuristics::play_for_team(trick, *this);
	break;
      case Aiconfig::JAB_FOX:
	card = Heuristics::jab_fox(trick, *this);
	break;
      case Aiconfig::TRY_FOR_DOPPELKOPF:
	card = Heuristics::try_for_doppelkopf(trick, *this);

	// make an announcement so that the player behind can give points
	if (card
	    && (this->announcement() == ANNOUNCEMENT::NOANNOUNCEMENT)
	    && !trick.islastcard()
	    && (this->teaminfo(trick.player_of_card(this->game().playerno()))
		!= ::opposite(this->team()))
	   )
	  this->game().announcement_make(ANNOUNCEMENT::NO120, *this);

	break;
      case Aiconfig::DRAW_TRUMP:
	card = Heuristics::draw_trump(trick, *this);
	break;
      case Aiconfig::POVERTY_PLAYER_PLAY_PFUND:
	card = Heuristics::poverty_player_play_pfund(trick, *this);
	break;
      case Aiconfig::MEATLESS_PLAYHIGHESTCOLOR:
	if (!trick.isstartcard())
	  break;

	card = this->nextcard_meatless(trick);
	break;
      case Aiconfig::PICTURE_SECONDBESTTRUMP:
	if (trick.isstartcard()
	    && (this->remaining_trumps() > 0)
	    && (this->hand().numberoftrumps() > 1))
	  card = Heuristics::SecondBestTrump(*this);
	break;
      case Aiconfig::COLOR_CHOOSE_ACE:
	{
	  GameType gt=game().type();
	  if ( (gt==GAMETYPE::SOLO_JACK)  ||
	      (gt==GAMETYPE::SOLO_QUEEN) ||
	      (gt==GAMETYPE::SOLO_KING)  ||
	      (gt==GAMETYPE::SOLO_QUEEN_JACK)      ||
	      (gt==GAMETYPE::SOLO_KING_JACK)       ||
	      (gt==GAMETYPE::SOLO_KING_QUEEN)      ||
	      (gt==GAMETYPE::SOLO_KOEHLER)         
	     )

	  {
	    if  (trick.isstartcard() && single_ace())
	      card = Heuristics::choose_ace(trick, *this);
	  } else
	    card = Heuristics::choose_ace(trick, *this);
	}
	break;
      case Aiconfig::COLOR_JAB_FOR_ACE:
	card = Heuristics::jab_for_ace(trick, *this);
	break;
      case Aiconfig::GET_TRICK_FOR_ANNOUNCEMENT:
	card = Heuristics::getTrickForKeepingAnnouncement(trick, *this);
	break;
      case Aiconfig::CHOOSE_BEST_CARD:
	DEBUG_ASSERT(false);
	break;
      } // switch(*heuristic)

      if (card) {
	if (HEURISTIC_OUTPUT
	    && !this->game().isvirtual())
	  cout <<  setw(2) << no() << " "
	    << setw(20) << card << " "
	    << ::name(*heuristic)
	    << endl;

	this->lastHeuristic_ = *heuristic;
	this->db()->heuristicInc(*heuristic);

	DEBUG_RETURNING(card,
			INFO_AI && INFO_GAMEPLAY,
			"Ai::nextcard() -- " << ::name(*heuristic));
      } // if (card)
    } // for (...)
  } // if (actTrick < LASTHEURISTICTRICK)


  { // choosebestcard
    Aiconfig::Heuristic const heuristic = Aiconfig::CHOOSE_BEST_CARD;
#ifdef OUTDATED
    Card const card
      = Weighting(this->aitype()).choosebestcard(*this, trick, this->no(),
						 !this->game().isvirtual());
#else
    Card const card
      = Weighting(this->aitype()).choosebestcard(*this);
#endif

    if (HEURISTIC_OUTPUT
	&& !this->game().isvirtual())
      cout <<  setw(2) << no() << " "
	<< setw(16) << card << " "
	<< setw(39) << ::name(heuristic) << " (" << this->aitype() << ") "
	<< endl;

    this->lastHeuristic_ = heuristic;
    this->db()->heuristicInc(heuristic);

    if (::game_status != GAMESTATUS::GAME_PLAY)
      return Card();

    if (this->aitype() != AITYPE::NO_CHOOSEBESTCARD)
      DEBUG_ASSERT(card);

    DEBUG_RETURNING(card,
		    INFO_AI && INFO_GAMEPLAY,
		    "Ai::nextcard()");
  } // choosebestcard
} // Card Ai::nextcard(Trick const& trick)



/**********************************************************************
 *
 **    int Ai::calculate_meatless_color( Color c)
 *
 **    Parameters:  
 **        c color to calculate
 *
 **    Result: value of card 
 *
 **    Version: 0.6.1
 *
 **    Description:
 **      
 *
 **********************************************************************/
int Ai::calculate_meatless_color( Card::Color co )
{
  int modi = 0;
  if ( playedcard(Card(co,Card::ACE)) < 2 ) 
    modi = -1;
  if ( playedcard(Card(co,Card::ACE)) == 2 ) 
    modi = 1;

  return (static_cast<int>(hand().numberof(co, this->game())
			   * hand().numberof(Card(co,Card::ACE))
			   +  hand().numberof(co, this->game())
			   * hand().numberof(Card(co,Card::TEN)))
	  * modi);
}

/**
 ** -> result
 **
 ** @param	t	current trick
 **
 ** @return	card to play
 **
 ** @author	Borg Enders
 **
 ** @version	0.6.6
 **/
Card
Ai::nextcard_meatless(const Trick& t)
{
  DEBUG_CALLING(INFO_AI && INFO_GAMEPLAY,
		"Ai::nextcard_meatless()");

  Hand ha;
  Card c=Card();
  int maxcards=0;
  if (meatlesscolor_p==Card::NOCARDCOLOR ||
      (hand().numberof( meatlesscolor_p, Card::ACE ) == 0 &&
       playedcard( Card( meatlesscolor_p, Card::ACE )) < 2 ))
  {
    Card::Color co=Card::DIAMOND;

    maxcards=calculate_meatless_color(co);
    meatlesscolor_p=co;

    co=Card::HEART;

    if (calculate_meatless_color(co)>maxcards)
    {
      maxcards=calculate_meatless_color(co);
      meatlesscolor_p=co;
    }

    co=Card::SPADE;

    if (calculate_meatless_color(co)>maxcards)
    {      	
      maxcards=calculate_meatless_color(co);
      meatlesscolor_p=co;
    }

    co=Card::CLUB;

    if (calculate_meatless_color(co)>maxcards)
    {

      maxcards= calculate_meatless_color( co );
      meatlesscolor_p=co;
    }
  } 

  c=Heuristics::play_highest_color(t,*this,meatlesscolor_p);
  if( c==Card() )
    meatlesscolor_p = Card::NOCARDCOLOR;
  if( hand().numberof( c.color() ) == 1 ) //last card of this color
    meatlesscolor_p = Card::NOCARDCOLOR; // trigger new calculation

#if 0
  DEBUG_RETURNING(c,
		  INFO_AI && INFO_GAMEPLAY,
		  "Ai::nextcard_meatless()");
#endif
  if (INFO_AI && INFO_GAMEPLAY)
    return c;
  else
    return c;
} // Card Ai::nextcard_meatless(const Trick& t)


/**********************************************************************
 *
 ** unsigned Ai::playedcard(Card const& c)
 *
 ** Parameters:  c - card for which number of known already playedcards
 *
 ** Result:      number of played cards of c
 *
 ** Version:     0.4.2
 *
 ** Description: -> result
 *
 **********************************************************************/
unsigned
Ai::playedcard(Card const& c) const
{
  DEBUG_CALLING(INFO_AI && INFO_OTHER_FUNCTION,
		"Ai::playedcard(Card)");

#ifdef OUTDATED
#ifdef POSTPHONED
  DEBUG_RETURNING(this->playedcards_p[c],
		  INFO_AI && INFO_OTHER_FUNCTION,
		  "Ai::playedcard(Card)");
#else
  DEBUG_RETURNING(this->playedcards_p.find(c)->second,
		  INFO_AI && INFO_OTHER_FUNCTION,
		  "Ai::playedcard(Card)");
#endif
#else
  return this->cards_information().played(c);
#endif
} // unsigned Ai::playedcard(Card const& c) const


/**********************************************************************
 *
 **    bool Ai::colorjabbed(Card::Color c)
 *
 **    Parameters: color of for which should be known if it was jabbed
 *
 **    Result: true if color was jabbed and c is legal
 **            false otherwise
 *
 **    Version: Alpha
 *
 **    Description:
 *
 *
 **********************************************************************/
bool
Ai::colorjabbed(const Card::Color c) const
{
  DEBUG_CALLING(INFO_AI && INFO_OTHER_FUNCTION,"Ai::colorjabbed(const Card::Color c)");

  bool result=false;
  if (!(c==Card::NOCARDCOLOR)) 
    for(unsigned i=0; i<game().playerno();i++) {
      result=result||colorjabbed_p[c][i];
    }

  DEBUG_RETURNING(result,INFO_AI && INFO_OTHER_FUNCTION,"Ai::colorjabbed(const Card::Color c)");
}


/**********************************************************************
 *
 **    bool Ai::jabbedbyownteam(Card::Color c)
 *
 **    Parameters: color of for which should be known if it was jabbed by own team
 *
 **    Result: true if color was jabbed aby own team nd c is legal
 **            false otherwise
 *
 **    Version: Alpha
 *
 **    Description:
 *
 *
 **********************************************************************/

bool
Ai::jabbedbyownteam(const Card::Color c) const
{
  DEBUG_CALLING(INFO_AI && INFO_OTHER_FUNCTION,"Ai::jabbedbyownteam()");

  bool res=false;

  if (!(c==Card::NOCARDCOLOR)) 
    for(unsigned i=0; i<game().playerno();i++) {
      if (i!=no() && maybe_to_team(teaminfo( game().player( i )))==team())
	res=res||colorjabbed_p[c][i];
    }

  DEBUG_RETURNING(res,INFO_AI && INFO_OTHER_FUNCTION,"Ai::jabbedbyownteam()");


}

/**********************************************************************
 *
 **    bool Ai::jabbedbyownteam(Card::Color c)
 *
 **    Parameters: color of for which should be known if it was jabbed by own team
 *
 **    Result: true if color was jabbed aby own team nd c is legal
 **            false otherwise
 *
 **    Version: Alpha
 *
 **    Description:
 *
 *
 **********************************************************************/

bool
Ai::jabbedbyotherteam(const Card::Color c) const
{
  DEBUG_CALLING(INFO_AI && INFO_OTHER_FUNCTION,"Ai::jabbedbyownteam()");

  bool res=false;

  if (!(c==Card::NOCARDCOLOR)) 
    for(unsigned i=0; i<game().playerno();i++) {
      if (i!=no() && maybe_to_team(teaminfo( game().player( i )))!=team())
	res=res||colorjabbed_p[c][i];
    }

  DEBUG_RETURNING(res,INFO_AI && INFO_OTHER_FUNCTION,"Ai::jabbedbyownteam()");


}

/**********************************************************************
 *
 **    int Ai::color_runs(Card::Color c)
 *
 **    Parameters: color of for which should be known how many times played
 *
 **    Result: number of color runs otherwise infinity
 *
 **    Version: Alpha
 *
 **    Description:
 *
 *
 **********************************************************************/
unsigned
Ai::color_runs(const Card::Color c) const
{
  DEBUG_CALLING(INFO_AI && INFO_OTHER_FUNCTION,
		"Ai::color_runs(const Card::Color c)");

  if (c != Card::NOCARDCOLOR)
    DEBUG_RETURNING(color_runs_p[c],
		    INFO_AI && INFO_OTHER_FUNCTION,
		    "Ai::color_runs(const Card::Color c)");

  DEBUG_RETURNING(UINT_MAX,
		  INFO_AI && INFO_OTHER_FUNCTION,
		  "Ai::color_runs(const Card::Color c)");
}


/**********************************************************************
 *
 **     bool Ai::next_low()
 *
 **    Parameters: 
 *
 **    Result: returns true if next card should be low trump otherwise false
 *
 **    Version: Alpha
 *
 **    Description:
 *
 *
 **********************************************************************/

bool Ai::next_low() const
{
  DEBUG_CALLING(INFO_AI && INFO_VALUE, "Ai::next_low()");
  DEBUG_RETURNING(low_p,INFO_AI && INFO_VALUE, "Ai::next_low()");
}


/**********************************************************************
 *
 **     void Ai::check_low_high(Card c)
 *
 **    Parameters: next palyed card
 *
 **    Result: 
 *
 **    Version: Alpha
 *
 **    Description:
 **      sets low_p to true if c>=DIAMOND QUEEN to false if card<DIAMOND QUENN
 *
 **********************************************************************/ 
void
Ai::check_low_high(HandCard const& card)
{
  DEBUG_CALLING(INFO_AI && INFO_OTHER_FUNCTION,
		"Ai::check_low_high(HandCard card)");

  if ( card.istrump()
      && !(card.less(Card(Card::DIAMOND,Card::QUEEN))))
    this->low_p = true;
  else
    this->low_p = false;

  DEBUG_RETURNING(VOID,
		  INFO_AI && INFO_OTHER_FUNCTION,
		  "Ai::check_low_high(HandCard card)");
}

/**********************************************************************   
 **                                                                        
 **    void Ai::new_game()                                             
 **                                                                        
 **    Parameters: none                                                    
 **                                                                        
 **    Result: none                                                        
 **                                                                        
 **    Version: Alpha                                                      
 **                                                                        
 **    Description: inits the player for a new game                        
 **                 (the game-pointer is set in 'Game::Game(Party, int)')  
 **                                                                        
 **********************************************************************/  

void                                                                      
Ai::new_game(Game& game)                                                        
{    
  DEBUG_CALLING(INFO_AI && INFO_INIT,"Ai::new_game()");

  this->Player::new_game(game);

  delete this->cards_information_;
  this->cards_information_ = new CardsInformation(*this);

  delete this->team_information_;
  this->team_information_ = new TeamInformation(*this);

  this->teaminfo_p = vector<Team>(this->game().playerno(), TEAM::UNKNOWN);

  this->meatlesscolor_p=Card::NOCARDCOLOR;

  this->low_p=true;


  this->playedcards_p.clear();

  this->trick_p = vector<Trick>(this->game().rule()(Rule::NUMBER_OF_TRICKS_IN_GAME));

  this->trumpless_ = vector<bool>(this->game().playerno(), false );
  this->trickno_p=0;
  for ( unsigned x = 0;
       x < this->game().rule()(Rule::NUMBER_OF_CARD_COLORS); x++)
  {
    this->colorjabbed_p[x]= vector<bool>(this->game().playerno(), false );
    this->color_runs_p[x]=0;
    for(unsigned y=0;y<this->game().playerno();y++) {
      this->colorjabbed_p[x][y]=false;
    } // for (y < this->game().playerno())
  } // for (x < this->game().playerno())

  this->silentMarriage_ = false;

  DEBUG_RETURNING_N(INFO_AI && INFO_INIT,"Ai::new_game()");                                                                         
}                                                                         


/**********************************************************************
 *
 **    MarriageSelector Ai::get_Marriage() const
 *
 **    Parameters: none
 *
 **    Result: tricktype which determines teams for a marraige
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/

MarriageSelector Ai::get_Marriage() const
{
  DEBUG_CALLING(INFO_AI && INFO_GAMEPLAY,"Marriage Ai::get_Marriage()");   

  // ToDo: Test rules

  if (hand().numberoftrumps()<6
      && hand().numberoftrumpaces()==1
      && ((this->game().startplayer().no() == this->no())
	  || (this->game().rule()(Rule::MARRIAGE_DETERMINATION) >= 4)))
    DEBUG_RETURNING(MARRIAGE_SELECTOR::FIRST_TRUMP,INFO_AI && INFO_INIT,"Marriage Ai::get_Marriage()");   

  if ( Card(Card::HEART,Card::TEN).istrump(this->game()) )
  { 
    if (hand().numberof(Card::HEART)>3 &&
	(hand().numberof(Card::HEART,Card::ACE)>0) )
      DEBUG_RETURNING(MARRIAGE_SELECTOR::FIRST_HEART,INFO_AI && INFO_INIT,"Marriage Ai::get_Marriage()"); 
  } else
  {
    if (hand().numberof(Card::HEART)<2 &&
	((hand().numberof(Card::HEART,Card::ACE)==1) ||
	 (hand().numberof(Card::HEART,Card::TEN)==1)))
      DEBUG_RETURNING(MARRIAGE_SELECTOR::FIRST_HEART,INFO_AI && INFO_INIT,"Marriage Ai::get_Marriage()"); 
  }
  if (hand().numberof(Card::CLUB)<2 &&
      ((hand().numberof(Card::CLUB,Card::ACE)==1) ||
       (hand().numberof(Card::CLUB,Card::TEN)==1)))
    DEBUG_RETURNING(MARRIAGE_SELECTOR::FIRST_CLUB,INFO_AI && INFO_INIT,"Marriage Ai::get_Marriage()"); 

  if (hand().numberof(Card::SPADE)<2 &&
      ((hand().numberof(Card::SPADE,Card::ACE)==1) ||
       (hand().numberof(Card::SPADE,Card::TEN)==1)))
    DEBUG_RETURNING(MARRIAGE_SELECTOR::FIRST_SPADE,INFO_AI && INFO_INIT,"Marriage Ai::get_Marriage()");  

  if (hand().numberoftrumps()>=8)
    DEBUG_RETURNING(MARRIAGE_SELECTOR::FIRST_COLOR,INFO_AI && INFO_INIT,"Marriage Ai::get_Marriage()");  

  DEBUG_RETURNING(MARRIAGE_SELECTOR::FIRST_FOREIGN,INFO_AI && INFO_INIT,"Marriage Ai::get_Marriage()");   
}

/**********************************************************************
 *
 **    Reservation Ai::reservation_get() const
 *
 **    Parameters: none
 *
 **    Result: reservation
 *
 **    Version: Alpha
 *
 **    Description: returns the reservation of the player
 **  
 **      
 *
 **********************************************************************/

Reservation
Ai::reservation_get( bool const isDuty ) 
{
  DEBUG_CALLING(INFO_AI && INFO_GAMEPLAY, "Ai::reservation_get()");

  Reservation res = this->reservation_get_default();
  Reservation best_res = Reservation();
  unsigned solo_best = 0;

  // always announce swines/hyperswines
  // -- the game will reject it if the announcement is not valid
  best_res.swines
    = this->game().rule()(Rule::SWINES_ANNOUNCEMENT_BEGIN);
  best_res.hyperswines
    = this->game().rule()(Rule::HYPERSWINES_ANNOUNCEMENT_BEGIN);


  int solovalue=0;  
  unsigned solomax=0;

  solovalue=checksolo(Card::KING,Card::QUEEN,
		      Card::JACK,GAMETYPE::SOLO_KOEHLER);
  if (solovalue >= 0 && party.rule()(Rule::SOLO_KOEHLER))
  {
    if ( unsigned(solovalue) > this->Aiconfig::value(Aiconfig::TRIPLESOLO) )
    {
      solomax=solovalue-this->Aiconfig::value(Aiconfig::TRIPLESOLO);
      solo_best = solovalue-this->Aiconfig::value(Aiconfig::TRIPLESOLO);
      res.game_type=GAMETYPE::SOLO_KOEHLER;
      best_res.game_type = GAMETYPE::SOLO_KOEHLER;
    }
  }

  solovalue=checksolo(Card::JACK,Card::QUEEN,
		      GAMETYPE::SOLO_QUEEN_JACK);
  if (solovalue >= 0
      && party.rule()(Rule::SOLO_QUEEN_JACK))
  {
    if (unsigned(solovalue) > this->Aiconfig::value(Aiconfig::DOUBLESOLO)
	&& unsigned(solovalue-this->Aiconfig::value(Aiconfig::DOUBLESOLO))>=solomax )
    {
      solomax=solovalue-this->Aiconfig::value(Aiconfig::DOUBLESOLO);
      res.game_type=GAMETYPE::SOLO_QUEEN_JACK;
      solo_best=solovalue-this->Aiconfig::value(Aiconfig::DOUBLESOLO);
      best_res.game_type=GAMETYPE::SOLO_QUEEN_JACK;
    } else
      if ( unsigned(solovalue-this->Aiconfig::value(Aiconfig::DOUBLESOLO))>=solo_best)
      {
	solo_best=solovalue-this->Aiconfig::value(Aiconfig::DOUBLESOLO);
	best_res.game_type=GAMETYPE::SOLO_QUEEN_JACK;
      }
  }

  solovalue=checksolo(Card::JACK,Card::KING,
		      GAMETYPE::SOLO_KING_JACK);
  if (solovalue >= 0
      && party.rule()(Rule::SOLO_KING_JACK))
  {
    if (unsigned(solovalue) > this->Aiconfig::value(Aiconfig::DOUBLESOLO)
	&& unsigned(solovalue-this->Aiconfig::value(Aiconfig::DOUBLESOLO))>=solomax )
    {
      solomax=solovalue-this->Aiconfig::value(Aiconfig::DOUBLESOLO);
      res.game_type=GAMETYPE::SOLO_KING_JACK;
      solo_best=solovalue-this->Aiconfig::value(Aiconfig::DOUBLESOLO);
      best_res.game_type=GAMETYPE::SOLO_KING_JACK;
    } else
      if ( unsigned(solovalue-this->Aiconfig::value(Aiconfig::DOUBLESOLO))>=solo_best)
      {
	solo_best=solovalue-this->Aiconfig::value(Aiconfig::DOUBLESOLO);
	best_res.game_type=GAMETYPE::SOLO_KING_JACK;
      }

  }

  solovalue=checksolo(Card::QUEEN, Card::KING,
		      GAMETYPE::SOLO_KING_QUEEN);
  if (solovalue >= 0
      && party.rule()(Rule::SOLO_KING_QUEEN))
  {
    if (unsigned(solovalue) > this->Aiconfig::value(Aiconfig::DOUBLESOLO)
	&& unsigned(solovalue-this->Aiconfig::value(Aiconfig::DOUBLESOLO))>=solomax )
    {
      solomax=solovalue-this->Aiconfig::value(Aiconfig::DOUBLESOLO);
      res.game_type=GAMETYPE::SOLO_KING_QUEEN;
      solo_best=solovalue-this->Aiconfig::value(Aiconfig::DOUBLESOLO);
      best_res.game_type=GAMETYPE::SOLO_KING_QUEEN;
    } else
      if ( unsigned(solovalue-this->Aiconfig::value(Aiconfig::DOUBLESOLO))>=solo_best)
      {
	solo_best=solovalue-this->Aiconfig::value(Aiconfig::DOUBLESOLO);
	best_res.game_type=GAMETYPE::SOLO_KING_QUEEN;
      }
  }

  solovalue=checksolo(Card::QUEEN,
		      GAMETYPE::SOLO_QUEEN);
  if (solovalue >= 0
      && party.rule()(Rule::SOLO_QUEEN))
  {
    if (unsigned(solovalue) > this->Aiconfig::value(Aiconfig::SINGLESOLO)
	&& unsigned(solovalue-this->Aiconfig::value(Aiconfig::SINGLESOLO))>=solomax )
    {
      solomax=solovalue-this->Aiconfig::value(Aiconfig::SINGLESOLO);
      res.game_type=GAMETYPE::SOLO_QUEEN;
      solo_best=solovalue-this->Aiconfig::value(Aiconfig::SINGLESOLO);
      best_res.game_type=GAMETYPE::SOLO_QUEEN;
    } else
      if ( unsigned(solovalue-this->Aiconfig::value(Aiconfig::SINGLESOLO))>=solo_best)
      {
	solo_best=solovalue-this->Aiconfig::value(Aiconfig::SINGLESOLO);
	best_res.game_type=GAMETYPE::SOLO_QUEEN;
      }
  }

  solovalue=checksolo(Card::KING,
		      GAMETYPE::SOLO_KING);
  if (solovalue >= 0
      && party.rule()(Rule::SOLO_KING))
  {
    if (unsigned(solovalue) > this->Aiconfig::value(Aiconfig::SINGLESOLO)
	&& unsigned(solovalue-this->Aiconfig::value(Aiconfig::SINGLESOLO))>=solomax )
    {
      solomax=solovalue-this->Aiconfig::value(Aiconfig::SINGLESOLO);
      res.game_type=GAMETYPE::SOLO_KING;
      solo_best=solovalue-this->Aiconfig::value(Aiconfig::SINGLESOLO);
      best_res.game_type=GAMETYPE::SOLO_KING;
    } else
      if ( unsigned(solovalue-this->Aiconfig::value(Aiconfig::SINGLESOLO))>=solo_best)
      {
	solo_best=solovalue-this->Aiconfig::value(Aiconfig::SINGLESOLO);
	best_res.game_type=GAMETYPE::SOLO_KING;
      }
  }

  solovalue=checksolo(Card::JACK,
		      GAMETYPE::SOLO_JACK);
  if (solovalue >= 0
      && party.rule()(Rule::SOLO_JACK))
  {
    if (unsigned(solovalue) > this->Aiconfig::value(Aiconfig::SINGLESOLO)
	&& unsigned(solovalue-this->Aiconfig::value(Aiconfig::SINGLESOLO))>=solomax )
    {
      solomax=solovalue-this->Aiconfig::value(Aiconfig::SINGLESOLO);
      res.game_type=GAMETYPE::SOLO_JACK;
      solo_best=solovalue-this->Aiconfig::value(Aiconfig::SINGLESOLO);
      best_res.game_type=GAMETYPE::SOLO_JACK;
    } else
      if ( unsigned(solovalue-this->Aiconfig::value(Aiconfig::SINGLESOLO))>=solo_best)
      {
	solo_best=solovalue-this->Aiconfig::value(Aiconfig::SINGLESOLO);
	best_res.game_type=GAMETYPE::SOLO_JACK;
      }
  }

  solovalue=checksolo();
  if (solovalue >= 0
      && party.rule()(Rule::SOLO_MEATLESS))
  {
    if (unsigned(solovalue) > this->Aiconfig::value(Aiconfig::MEATLESS)
	&& unsigned(solovalue-this->Aiconfig::value(Aiconfig::MEATLESS))>=solomax )
    {
      solomax=solovalue-this->Aiconfig::value(Aiconfig::MEATLESS);
      res.game_type=GAMETYPE::SOLO_MEATLESS;
      solo_best=solovalue-this->Aiconfig::value(Aiconfig::MEATLESS);
      best_res.game_type=GAMETYPE::SOLO_MEATLESS;
    } else
      if ( unsigned(solovalue-this->Aiconfig::value(Aiconfig::MEATLESS))>=solo_best)
      {
	solo_best=solovalue-this->Aiconfig::value(Aiconfig::MEATLESS);
	best_res.game_type=GAMETYPE::SOLO_MEATLESS;
      }
  }

  solovalue=checksolo(Card::DIAMOND,
		      GAMETYPE::SOLO_DIAMOND);
  if (solovalue >= 0
      && party.rule()(Rule::SOLO))
  {
    if (unsigned(solovalue) > this->Aiconfig::value(Aiconfig::COLORSOLO)
	&& unsigned(solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO))>=solomax )
    {
      solomax=solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO);
      res.game_type=GAMETYPE::SOLO_DIAMOND;
      // playing silent solo
      if (hand().numberofclubqueens()==2) 
      {
	res.game_type=GAMETYPE::NORMAL;
	silentMarriage_ = true;
      }
      solo_best=solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO);
      best_res.game_type=GAMETYPE::SOLO_DIAMOND;
    } else
      if ( unsigned(solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO))>=solo_best)
      {
	solo_best=solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO);
	best_res.game_type=GAMETYPE::SOLO_DIAMOND;
      }	


  }

  solovalue=checksolo(Card::HEART,
		      GAMETYPE::SOLO_HEART);

  if (solovalue >= 0
      && party.rule()(Rule::SOLO))
  {
    if (unsigned(solovalue) > this->Aiconfig::value(Aiconfig::COLORSOLO)
	&& unsigned(solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO))>=solomax )
    {
      solomax=solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO);
      res.game_type=GAMETYPE::SOLO_HEART;
      solo_best=solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO);
      best_res.game_type=GAMETYPE::SOLO_HEART;
    } else
      if ( unsigned(solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO))>=solo_best)
      {
	solo_best=solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO);
	best_res.game_type=GAMETYPE::SOLO_HEART;
      }	
  }


  solovalue=checksolo(Card::SPADE,
		      GAMETYPE::SOLO_SPADE);

  if (solovalue >= 0
      && party.rule()(Rule::SOLO))
  {
    if (unsigned(solovalue) > this->Aiconfig::value(Aiconfig::COLORSOLO)
	&& unsigned(solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO))>=solomax )
    {
      solomax=solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO);
      res.game_type=GAMETYPE::SOLO_SPADE;
      solo_best=solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO);
      best_res.game_type=GAMETYPE::SOLO_SPADE;
    } else
      if ( unsigned(solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO))>=solo_best)
      {
	solo_best=solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO);
	best_res.game_type=GAMETYPE::SOLO_SPADE;
      }	
  }

  solovalue=checksolo(Card::CLUB,
		      GAMETYPE::SOLO_CLUB);

  if (  solovalue >= 0
      && party.rule()(Rule::SOLO))
  {
    if (unsigned(solovalue) > this->Aiconfig::value(Aiconfig::COLORSOLO)
	&& unsigned(solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO))>=solomax )
    {
      solomax=solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO);
      res.game_type=GAMETYPE::SOLO_CLUB;
      solo_best=solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO);
      best_res.game_type=GAMETYPE::SOLO_CLUB;
    } else
      if ( unsigned(solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO))>=solo_best)
      {
	solo_best=solovalue-this->Aiconfig::value(Aiconfig::COLORSOLO);
	best_res.game_type=GAMETYPE::SOLO_CLUB;
      }	
  }

  if( isDuty )
  {
    DEBUG_RETURNING(best_res,INFO_AI && INFO_GAMEPLAY, "Ai::reservation_get()");
  }

#ifndef OLD
  if (res.game_type == GAMETYPE::MARRIAGE) {
    res.marriage_selector=get_Marriage();
#ifndef POSTPHONED
    // ToDo: to be removed
    if (!this->game().rule()(res.marriage_selector))
      res.marriage_selector = this->reservation_get_default().marriage_selector;
#endif
  }
#endif

  DEBUG_RETURNING(res,INFO_AI && INFO_GAMEPLAY, "Ai::reservation_get()");
}

/**
 ** -> result
 **
 ** @param       player whose teaminfo is returned
 **
 ** @return      the team of the given player, as far as this player knows it
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.7.1
 **/
Team const&
Ai::teaminfo(Player const& player) const
{
  return this->team_information().team(player);
} // Team const& Ai::teaminfo(Player const& player) const

/**
 ** updates the information of the teams (uses the current trick)
 **
 ** @param      -
 **
 ** @return     the known teams
 **
 ** @author     Borg Enders
 ** @author     Diether Knof
 **
 ** @version    0.4.4
 **/
void
Ai::teaminfo_update()
{
  DEBUG_CALLING(INFO_AI && INFO_VALUE,
		"Ai::teaminfo_update()");

  using namespace TEAM;
  { // sure information
    // update with the teaminfo of 'game'
    for(vector<Player*>::const_iterator player = this->game().players_begin();
	player != this->game().players_end();
	player++) {
      if ((this->game().teaminfo(**player) == RE)
	  || (this->game().teaminfo(**player) == CONTRA))
	this->teaminfo_p[(*player)->no()] = this->game().teaminfo(**player);
    }

    // set the team of himself
    if ( (this->game().type() == GAMETYPE::NORMAL)
	&& (this->teaminfo(*this) == UNKNOWN) ) {
      // look, whether there is a club queen in the hand
      this->teaminfo_p[this->no()]
	= ((this->hand().numberofclubqueens() > 0) ? RE : CONTRA);
    }

    { // count the re and contra
      unsigned re_no = 0; // number of re
      unsigned contra_no = 0; // number of re

      for(vector<Player*>::const_iterator player = this->game().players_begin();
	  player != this->game().players_end();
	  player++) {
	if (this->teaminfo(**player) == RE)
	  re_no += 1;
	else if (this->teaminfo(**player) == CONTRA)
	  contra_no += 1;
      } // for (player)

      if (re_no + contra_no
	  < this->game().rule()(Rule::NUMBER_OF_PLAYERS_IN_GAME)) {
	// there are no more the two players in the re team
	if (re_no == this->game().rule()(Rule::NUMBER_OF_PLAYERS_PER_TEAM))
	  for(vector<Player*>::const_iterator player = this->game().players_begin();
	      player != this->game().players_end();
	      player++)
	    if (this->teaminfo(**player) != RE) {
	      this->teaminfo_p[(*player)->no()] = CONTRA;
	    }

	// one player must be re
	if ((contra_no == this->game().rule()(Rule::NUMBER_OF_PLAYERS_IN_GAME) - 1)
	    || ((contra_no
		 == this->game().rule()(Rule::NUMBER_OF_PLAYERS_IN_GAME) - 2)
		&& (this->team() == RE))) {
	  // if there are 3 contra, the remaining player must be re
	  // if I am re and there are two contra, the remaining player must be re
	  for(vector<Player*>::const_iterator player = this->game().players_begin();
	      player != this->game().players_end();
	      player++)
	    if (this->teaminfo(**player) != CONTRA) {
	      this->teaminfo_p[(*player)->no()] = RE;
	    }
	} // if (contra max)
      } // if (not all teams known)
    } // count the re and contra
  } // sure information

  if( silentMarriage_ )
    for (unsigned i = 0; i < 4; i++)   
      if( i != this->no() )
	this->teaminfo_p[ i ] = CONTRA;

  if (::game_status == GAMESTATUS::GAME_RESERVATION) {
    if (this->game().type() == GAMETYPE::MARRIAGE) {
      for (unsigned p = 0; p < this->game().playerno(); p++)
	if (this->teaminfo_p[p] == TEAM::UNKNOWN)
	  this->teaminfo_p[p] = TEAM::MAYBE_CONTRA;
    } // if (this->game().type() == GAMETYPE::MARRIAGE)
  } // if (::game_status == GAMESTATUS::RESERVATION)

  if (::game_status >= GAMESTATUS::GAME_PLAY) {

    // without this return in virtual games a player can be set to 'maybe re'
    // when he 'pfunds' the marriage player.
    if ((this->game().type() == GAMETYPE::MARRIAGE)
	&& (this->game().marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET))
      return ;

    // set some maybe-teaminfo
    Trick const& trick = this->game().trick_current();
    if (trick.isfull()) {
      bool anyKnown = false;
      for (unsigned i = 0; i < trick.actcardno(); i++) {
	// the team is already set
	if ( (this->game().teaminfo(trick.player_of_card(i)) == RE) ||
	    (this->game().teaminfo(trick.player_of_card(i)) == CONTRA) )
	  anyKnown = true;
      }

      if (!anyKnown) return;
      for (unsigned i = 0; i < trick.actcardno(); i++) {

	// jab a club queen
	if ( (trick.card(i) == Card::CLUB_QUEEN)
	    && (trick.winnerplayer() != trick.player_of_card(i))
	    && (this->teaminfo(trick.winnerplayer()) != RE)
	    && (this->teaminfo(trick.winnerplayer()) != CONTRA)
	   )
	{
	  this->teaminfo_p[trick.winnerplayer().no()] = team_to_maybe(CONTRA);
	}

	// the team is already set
	if ( (this->teaminfo(trick.player_of_card(i)) == RE) ||
	    (this->teaminfo(trick.player_of_card(i)) == CONTRA) )
	  continue;

	// no jab in (color) trick (and there are trumps remaining)
	if ( (trick.card(i).tcolor() != trick.startcard().tcolor())
	    && (!trick.card(i).istrump())
	    && (trick.winnerplayer() != trick.player_of_card(i))
	    && (this->game().trumps_no()
		> (this->game().trumps_played_no()
		   + this->hand().numberoftrumps())
	       )
	   )
	{

	  this->teaminfo_p[trick.player_of_card(i).no()]
	    = team_to_maybe(this->teaminfo(trick.winnerplayer()));
	}
	// pfund in a trick
	if ( (trick.card(i).tcolor() == trick.startcard().tcolor())
	    &&(trick.winnerplayer() != trick.player_of_card(i))
	    && (trick.card(i).value() >= 10)
	    && this->value(Aiconfig::TRUSTING)
	   ) {
	  this->teaminfo_p[trick.player_of_card(i).no()]
	    = team_to_maybe(this->teaminfo(trick.winnerplayer()));
	}
      } // for (i < trick.actcard())
    } // if (trick.isfull())
    else
    {
      for (unsigned i = 0; i < trick.actcardno(); i++) {
	// the team is already set


	// jab a club queen
	if ( (trick.card(i) == Card::CLUB_QUEEN)
	    && (trick.winnerplayer() != trick.player_of_card(i))
	    && 	(this->teaminfo(trick.winnerplayer()) != RE)
	    && 	(this->teaminfo(trick.winnerplayer()) != CONTRA)
	   )
	{
	  this->teaminfo_p[trick.winnerplayer().no()] = team_to_maybe(CONTRA);
	}
      }

      if ( !trick.isstartcard()
	  && (this->game().type() == GAMETYPE::MARRIAGE) ) {
	switch (this->game().marriage_selector()) {
	case MARRIAGE_SELECTOR::TEAM_SET:
	  // the marriage is determined
	  break;
	case MARRIAGE_SELECTOR::FIRST_COLOR:
	case MARRIAGE_SELECTOR::FIRST_FOREIGN:
	  if (!trick.card(0).istrump()
	      && (trick.card(0).value() == Card::ACE)
	      && (this->color_runs( trick.card( 0 ).color() ) == 0) )
	  {//2do jabbing for colors
	    this->teaminfo_p[trick.player_of_card(0).no()] = TEAM::MAYBE_RE;
	  }
	  if (this->game().marriage_selector()
	      == MARRIAGE_SELECTOR::FIRST_COLOR)
	    break;
	case MARRIAGE_SELECTOR::FIRST_TRUMP:
	  // ToDo
	  break;
	case MARRIAGE_SELECTOR::FIRST_CLUB:
	  if ( (trick.card(0) == Card(Card::CLUB, Card::ACE))
	      && (this->color_runs( trick.card( 0 ).color() ) == 0) )
	  {//2do jabbing for colors
	    this->teaminfo_p[trick.player_of_card(0).no()] = TEAM::MAYBE_RE;
	  }
	  break;
	case MARRIAGE_SELECTOR::FIRST_SPADE:
	  if ( (trick.card(0) == Card(Card::SPADE, Card::ACE))
	      && (this->color_runs( trick.card( 0 ).color() ) == 0) )
	  {//2do jabbing for colors
	    this->teaminfo_p[trick.player_of_card(0).no()] = TEAM::MAYBE_RE;
	  }
	  break;
	case MARRIAGE_SELECTOR::FIRST_HEART:
	  if ( (trick.card(0) == Card(Card::HEART, Card::ACE))
	      && (this->color_runs( trick.card( 0 ).color() ) == 0) )
	  {//2do jabbing for colors
	    this->teaminfo_p[trick.player_of_card(0).no()] = TEAM::MAYBE_RE;
	  }
	  break;
	} // switch (this->game().marriage_selector())
      } // if !(marriage && !trick.isstartcard())
    } // if !(trick.isfull())

  } // if (::game_status >= GAMESTATUS::GAME_PLAY)

  DEBUG_RETURNING(VOID,
		  INFO_AI && INFO_VALUE,
		  "Ai::teaminfo_update()");
} // void Ai::teaminfo_update()


/**
 **
 ** -> result
 ** (uses Heuristics)
 **
 ** @see        Heuristics::make_announcement()
 ** @see        Heuristics::say_no90
 ** @see        Heuristics::say_no60
 ** @see        Heuristics::say_no30
 ** @see        Heuristics::say_no0
 **
 ** @param      -
 **
 ** @return     announcement of the player
 **
 ** @version    0.4.4
 **
 ** @author     Borg Enders
 ** @author     Diether Knof
 **
 **/
Announcement
Ai::announcement_request() const
{
  DEBUG_CALLING(INFO_AI && INFO_GAMEPLAY,
		"Ai::announcement_request()");

  Announcement res = ANNOUNCEMENT::NOANNOUNCEMENT;

  if (Heuristics::make_announcement(*this, this->game()))
    res = ANNOUNCEMENT::NO120;

  for (unsigned a = std::max(int(ANNOUNCEMENT::NO90),
			     this->announcement() + 1);
       a < ANNOUNCEMENT::NUMBER;
       a++) {
    // make the announcement as late as possible
    if ((this->game().rule().remaining_tricks(Announcement(a))
	 == this->game().tricks_remaining_no())
	&& (this->game().trick_current().isfull())
       ) {
      switch(Announcement(a)) {
      case ANNOUNCEMENT::NOANNOUNCEMENT:
      case ANNOUNCEMENT::REPLY:
      case ANNOUNCEMENT::NO120_REPLY:
      case ANNOUNCEMENT::NO90_REPLY:
      case ANNOUNCEMENT::NO60_REPLY:
      case ANNOUNCEMENT::NO30_REPLY:
      case ANNOUNCEMENT::NO0_REPLY:
      case ANNOUNCEMENT::NO120:
	DEBUG_ASSERTION(false,
			"Ai::announcement_request():\n"
			"  wrong announcement in 'switch': "
			<< Announcement(a));
	break;
      case ANNOUNCEMENT::NO90:
	if (Heuristics::say_no90(*this, this->game()))
	  res = Announcement(a);
	break;
      case ANNOUNCEMENT::NO60:
	if (Heuristics::say_no60(*this, this->game()))
	  res = Announcement(a);
	break;
      case ANNOUNCEMENT::NO30:
	if (Heuristics::say_no30(*this, this->game()))
	  res = Announcement(a);
	break;
      case ANNOUNCEMENT::NO0:
	if (Heuristics::say_no0(*this, this->game()))
	  res = Announcement(a);
	break;
      } // switch(Announcement(a))
    } // if (last chance for announcement)
  } 
  // for (a \in announcements)

  if ( ( res == ANNOUNCEMENT::NOANNOUNCEMENT )
      && this->game().trick_current().isfull()
      && this->game().announcement_valid(ANNOUNCEMENT::REPLY, *this) )
    res = Heuristics::make_reply(*this, this->game());

  DEBUG_RETURNING(res,
		  INFO_AI && INFO_GAMEPLAY,
		  "Ai::announcement_request()");
}

/**
 **
 ** the announcement 'announcement' has been made by player 'player'
 **
 ** @param	announcement	the announcement
 ** @param	player		the player, who has made the announcement
 **
 ** @return	-
 **
 ** @version	0.6.9
 **
 ** @author	Diether Knof
 **
 **/
void
Ai::announcement_made(Announcement const& announcement,
		      Player const& player)
{
  this->cards_information().announcement_made(announcement, player);
  this->team_information().announcement_made(announcement, player);

  this->teaminfo_update();

  return ;
} // void Ai::announcement_made(Announcement announcement, Player player)

/**********************************************************************   
 **                                                                        
 **    int Ai::checksolo(Card::Value c)                                          
 **                                                                        
 **    Parameters: Value of Car dor which to check if cardvalue for solo                                                 
 **                                                                        
 **    Result: cardvalue for solo                                                        
 **                                                                        
 **    Version: Alpha                                                      
 **                                                                        
 **    Description: 
 **                                                                        
 **********************************************************************/  

int Ai::checksolo(Card::Value c,GameType t) const
{
  DEBUG_CALLING(INFO_AI && INFO_OTHER_FUNCTION,"Ai::checksolo(Card::Value c)");

  int res=0;
  for (unsigned i=0; i<hand().cardsnumber();i++)
  {
    if (hand().card(i).value()==c)
    {
      if (hand().card(i).color()==Card::CLUB)
	res+=4;

      if (hand().card(i).color()==Card::SPADE)
	res+=3;

      if (hand().card(i).color()==Card::HEART)
	res+=2;  

      if (hand().card(i).color()==Card::DIAMOND)
	res+=1;
      continue;
    }

    if (hand().card(i).value()==Card::ACE)
    {
      res+=1;
      continue;
    }
    res -= 1;
  }

  res+=number_of_fehl(t)*2;

  res-=number_of_single_tens(t)*4;


  DEBUG_RETURNING(res,INFO_AI && INFO_OTHER_FUNCTION,"Ai::checksolo(Card::Value c)");
}

/**********************************************************************   
 **                                                                        
 **    int Ai::checksolo(Card::Value c1, Card::Value c2) const                                      
 **                                                                        
 **    Parameters: c1 highest trumpcardvalue, c2 second trump cardvalue                                                    
 **                                                                        
 **    Result: cardvalue for solo                                                        
 **                                                                        
 **    Version: Alpha                                                      
 **                                                                        
 **    Description: 
 **                                                                        
 **********************************************************************/  

int Ai::checksolo(Card::Value c1, Card::Value c2,GameType t) const
{
  DEBUG_CALLING(INFO_AI && INFO_OTHER_FUNCTION,"Ai::checksolo(Card::Value c1, Card::Value c2)");
  int res=0;
  for (unsigned i=0; i<hand().cardsnumber();i++)
  {
    if (hand().card(i).value()==c1)
    {
      if (hand().card(i).color()==Card::CLUB)
	res+=8;

      if (hand().card(i).color()==Card::SPADE)
	res+=7;

      if (hand().card(i).color()==Card::HEART)
	res+=6;  

      if (hand().card(i).color()==Card::DIAMOND)
	res+=5;
      continue;
    }

    if (hand().card(i).value()==c2)
    {
      if (hand().card(i).color()==Card::CLUB)
	res+=4;

      if (hand().card(i).color()==Card::SPADE)
	res+=3;

      if (hand().card(i).color()==Card::HEART)
	res+=2;  

      if (hand().card(i).color()==Card::DIAMOND)
	res+=1;
      continue;
    }

    if (hand().card(i).value()==Card::ACE)
    {
      res+=1;
      continue;
    }

    res-=2;
  }

  res+=number_of_fehl(t)*6;
  res-=number_of_single_tens(t)*8;

  DEBUG_RETURNING(res,INFO_AI && INFO_OTHER_FUNCTION,"Ai::checksolo(Card::Value c1, Card::Value c2)");
}

/**********************************************************************   
 **                                                                        
 **    int Ai::checksolo(Card::Value c1, Card::Value c2, Card::Value c3) const;                                         
 **                                                                        
 **    Parameters : c1 highest trumpcardvalue, c2 second trump cardvalue                                                    
 **                  c3 third trump cardvalue
 **                                                                        
 **    Result: cardvalue for solo                                                       
 **                                                                        
 **    Version: Prototype                                                      
 **                                                                        
 **    Description: 
 **                                                                        
 **********************************************************************/  

int Ai::checksolo(Card::Value c1, Card::Value c2, Card::Value c3,GameType t) const
{
  DEBUG_CALLING(INFO_AI && INFO_OTHER_FUNCTION,"Ai::checksolo(Card::Value c1, Card::Value c2, Card::Value c3)");
  int res=0;
  for (unsigned i=0; i<hand().cardsnumber();i++)
  {

    if (hand().card(i).value()==c1)
    {
      if (hand().card(i).color()==Card::CLUB)
	res+=12;

      if (hand().card(i).color()==Card::SPADE)
	res+=11;

      if (hand().card(i).color()==Card::HEART)
	res+=10;  

      if (hand().card(i).color()==Card::DIAMOND)
	res+=9;
      continue;
    }

    if (hand().card(i).value()==c2)
    {
      if (hand().card(i).color()==Card::CLUB)
	res+=8;

      if (hand().card(i).color()==Card::SPADE)
	res+=7;

      if (hand().card(i).color()==Card::HEART)
	res+=6;  

      if (hand().card(i).color()==Card::DIAMOND)
	res+=5;
      continue;
    }

    if (hand().card(i).value()==c3)
    {
      if (hand().card(i).color()==Card::CLUB)
	res+=4;

      if (hand().card(i).color()==Card::SPADE)
	res+=3;

      if (hand().card(i).color()==Card::HEART)
	res+=2;  

      if (hand().card(i).color()==Card::DIAMOND)
	res+=1;
      continue;
    }

    if (hand().card(i).value()==Card::ACE)
    {
      res+=1;
      continue;
    }

    res -= 3;
  }

  res+=number_of_fehl(t)*10;

  res-=number_of_single_tens(t)*12;

  if (t==GAMETYPE::SOLO_KOEHLER)
    for (vector<Card::Color>::const_iterator
	 c = this->game().rule().valid_card_colors().begin();
	 c != this->game().rule().valid_card_colors().end();
	 ++c)
      if (this->hand().existstcolor(*c))
	res-=5;

  DEBUG_RETURNING(res,
		  INFO_AI && INFO_OTHER_FUNCTION,
		  "Ai::checksolo(Card::Value c1, Card::Value c2, Card::Value c3)");
}

/**********************************************************************   
 **                                                                        
 **    int Ai::checksolo(Card::Color c) const;                                           
 **                                                                        
 **    Parameters: trumpcolor                                                    
 **                                                                        
 **    Result: cardvalue for solo                                              
 **                                                                        
 **    Version: Alpha                                              
 **                                                                        
 **    Description: 
 **                                                                        
 **********************************************************************/  

int Ai::checksolo(Card::Color c,GameType t) const
{
  DEBUG_CALLING(INFO_AI && INFO_OTHER_FUNCTION,"Ai::checksolo(Card::Color c)");
  int res=0;

  if ((hand().numberof(Card(c,Card::ACE))==2) && party.rule()(Rule::SWINES_IN_SOLO))
  {
    res+=9;
  } 

  for (unsigned i=0; i<hand().cardsnumber();i++)
  {  
    if (hand().card(i).isdolle())
    {

      res+=4;
      continue;
    }

    if (hand().card(i).value()==Card::QUEEN)
    {
      res+=3;
      continue;

    }

    if (hand().card(i).value()==Card::JACK)
    {
      res+=2;
      continue;

    }

    if (hand().card(i).value()==Card::ACE && hand().card(i).color()!=c && hand().numberof(hand().card(i).color())<3)
    {
      res+=1;
      continue;
    }

    if( hand().card(i).color() != c )
    {
      res -= 1;
    }

  }

  res+=number_of_fehl(t)*2;

  if (hand().numberof(c)==0) res-=3;

  res-=number_of_single_tens(t)*4;



  DEBUG_RETURNING(res,INFO_AI && INFO_OTHER_FUNCTION,"Ai::checksolo(Card::Color c)");
}

/**********************************************************************   
 **                                                                        
 **   int Ai::checksolo() const;                                         
 **                                                                        
 **    Parameters: none                                                    
 **                                                                        
 **    Result: cardvalue for solo                                                      
 **                                                                        
 **    Version: Prototype                                                      
 **                                                                        
 **    Description: 
 **                                                                        
 **********************************************************************/  

int Ai::checksolo() const
{
  DEBUG_CALLING(INFO_AI && INFO_OTHER_FUNCTION,"Ai::checksolo()");
  int res=0;

  Card::Color co=Card::DIAMOND;
  res+=hand().numberof(co)*hand().numberof(Card(co,Card::ACE))+
    hand().numberof(co)*hand().numberof(Card(co,Card::TEN));

  co=Card::HEART;
  res+=hand().numberof(co)*hand().numberof(Card(co,Card::ACE))+
    hand().numberof(co)*hand().numberof(Card(co,Card::TEN));

  co=Card::SPADE; 
  res+=hand().numberof(co)*hand().numberof(Card(co,Card::ACE))+
    hand().numberof(co)*hand().numberof(Card(co,Card::TEN));

  co=Card::CLUB;
  res+=hand().numberof(co)*hand().numberof(Card(co,Card::ACE))+
    hand().numberof(co)*hand().numberof(Card(co,Card::TEN));

  res-=number_of_single_tens(GAMETYPE::SOLO_MEATLESS)*5;

  for (vector<Card::Color>::const_iterator
       c = this->game().rule().valid_card_colors().begin();
       c != this->game().rule().valid_card_colors().end();
       ++c)
    if ( this->hand().existstcolor(*c))
      res-=2*(2 - this->hand().numberof(*c, Card::ACE) );


  DEBUG_RETURNING(res,INFO_AI && INFO_OTHER_FUNCTION,"Ai::checksolo()");
}





/**********************************************************************   
 **                                                                        
 **   unsigned Ai::remaining_trumps()                              
 **                                                                        
 **    Parameters: none 
 *
 **    Result: number of trumps still in game                                            
 **                                                                        
 **    Version: Alpha                                                    
 **                                                                        
 **    Description: 
 **                                                                        
 **********************************************************************/ 
unsigned Ai::remaining_trumps() const
{
  DEBUG_CALLING(INFO_AI && INFO_VALUE,"int Ai::remaining_trumps()");

  int result=game().trumps_no();


  for (vector<Card>::const_iterator
       c = this->game().rule().valid_cards().begin();
       c != this->game().rule().valid_cards().end();
       ++c)
    if(c->istrump(this->game()))
      if ( playedcard(*c) < 3 )
	result -= playedcard(*c);
      else
	result -= 2;


  DEBUG_RETURNING(result > 0 ? result : 0,
		  INFO_AI && INFO_VALUE,
		  "int Ai::remaining_trumps()");

}

/**********************************************************************   
 **                                                                        
 **   unsigned Ai::number_of_single_tens()                         
 **                                                                        
 **    Parameters: none 
 *
 **    Result: number of single tens on hand                                            
 **                                                                        
 **    Version: Alpha                                                    
 **                                                                        
 **    Description: 
 **                                                                        
 **********************************************************************/

unsigned Ai::number_of_single_tens(GameType t) const
{

  DEBUG_CALLING(INFO_AI && INFO_VALUE, "int Ai::number_of_single_tens()");

  bool const dollen = this->game().rule()(Rule::DOLLEN);

  unsigned result=0;
  if (hand().numberof(Card::DIAMOND)<=2 && hand().numberof(Card::DIAMOND,Card::ACE)==0 
      && !Card(Card::DIAMOND,Card::ACE).istrump(t, dollen))
    result+=hand().numberof(Card::DIAMOND,Card::TEN);
  if (hand().numberof(Card::HEART)<=2 && hand().numberof(Card::HEART,Card::ACE)==0
      && !Card(Card::HEART,Card::ACE).istrump(t, dollen))
    result+=hand().numberof(Card::HEART,Card::TEN);
  if (hand().numberof(Card::SPADE)<=2 && hand().numberof(Card::SPADE,Card::ACE)==0 
      && !Card(Card::SPADE,Card::ACE).istrump(t, dollen))
    result+=hand().numberof(Card::SPADE,Card::TEN);
  if (hand().numberof(Card::CLUB)<=2 && hand().numberof(Card::CLUB,Card::ACE)==0 
      && !Card(Card::CLUB,Card::ACE).istrump(t, dollen))
    result+=hand().numberof(Card::CLUB,Card::TEN);


  DEBUG_RETURNING(result,INFO_AI && INFO_VALUE, "int Ai::number_of_single_tens()");  
}

/**********************************************************************   
 **                                                                        
 **   unsigned Ai::number_of_fehl()                      
 **                                                                        
 **    Parameters: none 
 *
 **    Result: number of colors not on hand                                           
 **                                                                        
 **    Version: Alpha                                                  
 **                                                                        
 **    Description: 
 **                                                                        
 **********************************************************************/

unsigned Ai::number_of_fehl(GameType t) const
{
  DEBUG_CALLING(INFO_AI && INFO_VALUE, "int Ai::number_of_fehl()");

  bool const dollen = this->game().rule()(Rule::DOLLEN);

  unsigned result=0;
  if (hand().numberof(Card::DIAMOND, t, dollen)==0)
  {
    result++;
  }
  if (hand().numberof(Card::HEART, t, dollen)==0)
  {
    result++;
  }
  if (hand().numberof(Card::SPADE, t, dollen)==0)
  {
    result++;
  }
  if (hand().numberof(Card::CLUB, t, dollen)==0)
  {
    result++;
  }

  DEBUG_RETURNING(result,INFO_AI && INFO_VALUE, "int Ai::number_of_fehl()");  
} 


/**********************************************************************   
 **                                                                        
 **   bool Ai::single_ace()                         
 **                                                                        
 **    Parameters: none 
 *
 **    Result: number of single tens on hand                                            
 **                                                                        
 **    Version: Alpha                                                    
 **                                                                        
 **    Description: 
 **                                                                        
 ** @todo	'Card::inttovalue()' in the Card-constructors
 **                                                                        
 **********************************************************************/
bool
Ai::single_ace() const
{
  DEBUG_CALLING(INFO_AI && INFO_VALUE,
		"int Ai::single_ace()");

  bool result = false;

  for (unsigned x = 0;
       x < this->game().rule()(Rule::NUMBER_OF_CARD_COLORS) ;
       x++ )
  {
    Card::TColor const c(static_cast<Card::TColor>(x));
    if ( (hand().numberof( Card( c, Card::ACE )) == 1)
	&& !Card(c, Card::ACE).istrump(this->game())
	&& (hand().numberof(c, Card::ACE ) 
	    + hand().numberof(c, Card::TEN )
	    == hand().numberof(static_cast<Card::TColor>(x)) ) )
    {
      result=true;
      break;
    }
  }


  DEBUG_RETURNING(result,
		  INFO_AI && INFO_VALUE,
		  "int Ai::single_ace()");  
} // bool Ai::single_ace() const


/**
 ** -> result
 **
 ** @param      -
 **
 ** @return     modificator for the end depth for calculating tricks
 **             in WVirtualGames
 **
 ** @version    0.4.4
 **
 ** @author     Borg Enders
 **
 **/
unsigned const&
Ai::last_trick_to_calculate() const
{

  DEBUG_CALLING(INFO_AI && INFO_VALUE,
		"Ai::last_trick_to_calculate()");

  DEBUG_RETURNING(this->last_trick_to_calculate_p,
		  INFO_AI && INFO_VALUE,
		  "Ai::last_trick_to_calculate()");
} // unsigned const& Ai::last_trick_to_calculate() const

/**
 ** sets the parameter to the last trick to calculate
 **
 ** @param      last trick to calculate to be seted
 **
 ** @return     modificator for the end depth for calculating tricks
 **             in WVirtualGames
 **
 ** @version    0.4.4
 **
 ** @author     Borg Enders
 **
 **/
unsigned const&
Ai::set_last_trick_to_calculate(unsigned const last_trick_to_calculate)
{

  DEBUG_CALLING(INFO_AI && INFO_VALUE,
		"Ai::set_last_trick_to_calculate()");

  this->last_trick_to_calculate_p = last_trick_to_calculate;

  DEBUG_RETURNING(this->last_trick_to_calculate(),
		  INFO_AI && INFO_VALUE,
		  "Ai::set_last_trick_to_calculate()");
} // unsigned const& Ai::set_last_trick_to_calculate(short const last_trick_to_calculate)

/**
 **
 ** returns which cards the player shifts
 **
 ** @param      -
 **
 ** @return     the cards that are to be shifted
 **
 ** @version    0.4.5
 **
 ** @author     Borg Enders
 **
 **/
HandCards
Ai::poverty_shift()
{ 
  DEBUG_CALLING(INFO_AI && INFO_GAMEPLAY,
		"Ai::poverty_shift()");

  DEBUG_ASSERT( this->hand().numberoftrumps() < 4 );

  SortedHand& sh = this->sorted_hand();
  Hand const& h = this->hand();

  HandCards res;

  for( unsigned int i = 0; i < h.cardsnumber(); i++ )
    if ( h.card( i ).istrump())
    {
      res.push_back( h.card( i ) );
    }

  sh.remove( res );

  int rem = 3 - res.size();

  if ( !this->game().rule()( Rule::POVERTY_SHIFT_ONLY_TRUMP ) && rem > 0  )
  {
    HandCards addon;

    Card::Color c = Card::HEART ;
    unsigned int size = h.numberof( c );

    if ( h.numberof( Card::SPADE ) < size )
    {
      c = Card::SPADE;
      size = h.numberof( Card::SPADE );      
    }

    if ( h.numberof( Card::CLUB ) < size )
    {
      c = Card::CLUB;
      size = h.numberof( Card::CLUB );      
    }

    unsigned int i = 0;
    while ( rem > 0 )
    {
      if ( i >= h.cardsnumber() )
	i = 0;
      if ( size > 0 )
      {
	if ( h.card( i ).color() == c )
	{
	  addon.push_back( h.card( i ) );
	  sh.remove( h.card( i ) );
	  size--;
	  rem--;
	}
      } else
      {
	addon.push_back( h.card( i ) );
	sh.remove( h.card( i ) );
	rem--;
      }
      i += 1;
    }

    res.insert(res.end(), addon.begin(), addon.end());
  }// !this->game().rule()( Rule::POVERTY_SHIFT_ONLY_TRUMP ) && rem > 0

  DEBUG_RETURNING(res,
		  INFO_AI && INFO_GAMEPLAY,
		  "Ai::poverty_shift()");
} // HandCards Ai::poverty_shift(Player const& player)

/**
 **
 ** returns whether 'player' accepts the shifted cards
 **
 ** @param      cardno  the number of shifted cards
 **
 ** @return     whether to accept the cards
 **
 ** @version    0.4.5
 **
 ** @author     Borg Enders
 **
 **/
bool
Ai::poverty_take_accept(unsigned const cardno)
{ 
  DEBUG_CALLING(INFO_AI && INFO_GAMEPLAY,
		"Ai::poverty_take_accept(cardno)");

  unsigned trumpno_possible = cardno;
  if (!this->game().rule()(Rule::POVERTY_SHIFT_ONLY_TRUMP)) {
    if (!this->game().rule()(Rule::THROW_WITH_ONE_TRUMP))
      trumpno_possible = 2;
    else 
      trumpno_possible = 1;
  }

  int value = Heuristics::CalcHandValue( *this, this->game() );

  if( this->hand().numberoftrumps() >= 12 - cardno )
    value += this->hand().numberof( Card::QUEEN );

  multimap<unsigned, Card::Color> color_nums;
  for (vector<Card::Color>::const_iterator
       c = this->game().rule().valid_card_colors().begin();
       c != this->game().rule().valid_card_colors().end();
       ++c) {
    color_nums.insert(make_pair(this->hand().numberof(*c), *c));
  }

  for (multimap<unsigned, Card::Color>::const_iterator
       c = color_nums.begin(); 
       c != color_nums.end(); 
       ++c) {
    if (c->first > trumpno_possible)
      break;

    value += 2;
    trumpno_possible -= c->first;
  }

  if( this->hand().numberoftrumps() >= 12 - cardno - 1 )
    value += (this->hand().numberof( Card::QUEEN ) 
	      + this->hand().numberof( Card::JACK )
	      + this->hand().numberoftrumpaces());

  DEBUG_RETURNING( value
		  >= static_cast<signed>(this->value(Aiconfig::TAKEPOVERTY)),
		  INFO_AI && INFO_GAMEPLAY,
		  "Ai::poverty_take_accept(cardno)");
} // void Ai::poverty_take_accept(unsigned const cardno)

/**
 **
 ** changes the cards from the poverty-player
 **
 ** @param      cards   the cards that are given to the player
 **
 ** @return     the cards that are returned to the poverty-player
 **
 ** @version    Prototype
 **
 ** @author     Borg Enders
 **
 **/
HandCards
Ai::poverty_cards_change(HandCards const& cards)
{ 
  DEBUG_CALLING(INFO_AI && INFO_GAMEPLAY,
		"Ai::poverty_cards_change(cards)");

  SortedHand& sh = this->sorted_hand();
  Hand const& h = this->hand();

  sh.add(cards);


  HandCards res;
  unsigned rem = cards.size();

  // create Fehl for Club
  if( h.numberof( Card::CLUB ) > 0 && h.numberof( Card::CLUB ) <= rem )
  {
    HandCards addon;
    for( unsigned int i = 0; i < h.cardsnumber(); i++ )
      if ( ( h.card( i ).color() == Card::CLUB ) && !h.card(i).istrump() )
	addon.push_back( h.card( i ) );
    sh.remove( addon );
    res.insert(res.end(), addon.begin(), addon.end());
    rem-= addon.size();
  }

  // create Fehl for Spade
  if( h.numberof( Card::SPADE ) > 0 && h.numberof( Card::SPADE ) <= rem )
  {
    HandCards addon;
    for( unsigned int i = 0; i < h.cardsnumber(); i++ )
      if( ( h.card( i ).color() == Card::SPADE ) && !h.card(i).istrump() )
	addon.push_back( h.card( i ) );
    sh.remove( addon );
    res.insert(res.end(), addon.begin(), addon.end());
    rem-= addon.size();
  }

  // create Fehl for Heart
  if( h.numberof( Card::HEART ) > 0 && h.numberof( Card::HEART ) <= rem )
  {
    HandCards addon;
    for( unsigned int i = 0; i < h.cardsnumber(); i++ )
      if( ( h.card( i ).color() == Card::HEART ) && !h.card(i).istrump() )
	addon.push_back( h.card( i ) );
    sh.remove( addon );
    res.insert(res.end(), addon.begin(), addon.end());
    rem-= addon.size();
  }



  while ( rem > 0 )
  {
    //adding highest color card
    if ( h.numberoftrumps() < h.cardsnumber() && rem > 0 )
    {
      HandCard c;
      for( unsigned int i = 0; i < h.cardsnumber(); i++ )
	if ( !h.card( i ).istrump() )
	  c = h.card( i );

      if( c )
      {
	for( unsigned int i = 0; i < h.cardsnumber(); i++ )
	  if ( !h.card( i ).istrump() && !h.card( i ).less(c) )
	    c = h.card( i );

	sh.remove( c );
	res.push_back( c );
	rem--;      
	continue;
      }
    }

    //adding lowest trump card
    if (  rem > 0 )
    {
      HandCard c;
      for( unsigned int i = 0; i < h.cardsnumber(); i++ )
	if ( h.card( i ).istrump() )
	  c = h.card( i );

      if( c )
      {
	for( unsigned int i = 0; i < h.cardsnumber(); i++ )
	  if ( h.card( i ).istrump() && h.card( i ).less(c) )
	    c = h.card( i );

	sh.remove( c );
	res.push_back( c );
	rem--;      
	continue;
      }
    }
  }

  this->cards_information().reset();
  this->set_hand( this->hand() ); // to update playedcards

  DEBUG_RETURNING( res,
		  INFO_AI && INFO_GAMEPLAY,
		  "Ai::poverty_cards_change(cards)");
} // HandCards Ai::poverty_cards_change(HandCards const& cards)


/**
 **
 ** gets the cards from the partner and add them to the hand
 **
 ** @param	cards	the cards that are given to the player
 **
 ** @return	-
 **
 ** @author	Borg Enders
 **
 ** @version	0.6.1
 **
 **/
void
Ai::poverty_cards_get_back(HandCards const& cards)
{ 
  DEBUG_CALLING(INFO_AI && INFO_GAMEPLAY,
		"AI::poverty_cards_get_back(cards)");

  this->sorted_hand().add(cards);
  this->cards_information().reset();
  this->set_hand( this->hand() ); // to update playedcards

  DEBUG_RETURNING(VOID,
		  INFO_AI && INFO_GAMEPLAY,
		  "Ai::poverty_cards_get_back(cards)");
} // void Ai::poverty_cards_get_back(HandCards const& cards)


/**********************************************************************
 *
 **    Card trump_card_limit()
 *
 **    Parameters:  
 *
 **    Result: limit card for some heuristic decisions
 *
 **    Version: Beta
 *
 **    Description:
 **       Results: 
 **          Normal    : Heart Queen
 **          Color Solo: Heart Queen
 **          Jack Solo : Spade Jack
 **          Queen Solo: Spade Queen
 **          King Solo : Spade King
 **          Queen-Jack: Club Jack
 **          King-Jack : Club Jack
 **          King-Queen: Club Queen
 **          Köhler    : Club Queen
 **          Meatless  : Diamond Ten
 *
 **********************************************************************/

Card Ai::trump_card_limit() const
{
  DEBUG_CALLING(INFO_AI && INFO_OTHER_FUNCTION, "Card trump_card_limit()");

  GameType gt=party.game().type();


  if  ( (gt==GAMETYPE::SOLO_CLUB) ||
       (gt==GAMETYPE::SOLO_HEART) ||
       (gt==GAMETYPE::SOLO_SPADE) ||
       (gt==GAMETYPE::SOLO_DIAMOND) ||
       silentMarriage_ )
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::TRUMPLIMIT_SOLOCOLOR),INFO_AI && INFO_OTHER_FUNCTION, "Card trump_card_limit()");
  }

  if  (gt==GAMETYPE::SOLO_JACK) 
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::TRUMPLIMIT_SOLOJACK),INFO_AI && INFO_OTHER_FUNCTION, "Card trump_card_limit()");
  }

  if  (gt==GAMETYPE::SOLO_QUEEN) 
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::TRUMPLIMIT_SOLOQUEEN),INFO_AI && INFO_OTHER_FUNCTION, "Card trump_card_limit()");
  }

  if  (gt==GAMETYPE::SOLO_KING) 
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::TRUMPLIMIT_SOLOKING),INFO_AI && INFO_OTHER_FUNCTION, "Card trump_card_limit()");
  }

  if   (gt==GAMETYPE::SOLO_QUEEN_JACK)      
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::TRUMPLIMIT_SOLOJACKQUEEN),INFO_AI && INFO_OTHER_FUNCTION, "Card trump_card_limit()");
  }
  if      (gt==GAMETYPE::SOLO_KING_JACK)       
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::TRUMPLIMIT_SOLOJACKKING),INFO_AI && INFO_OTHER_FUNCTION, "Card trump_card_limit()");
  }

  if (gt==GAMETYPE::SOLO_KING_QUEEN)
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::TRUMPLIMIT_SOLOQUEENKING),INFO_AI && INFO_OTHER_FUNCTION, "Card trump_card_limit()");
  }
  if    (gt==GAMETYPE::SOLO_KOEHLER) 
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::TRUMPLIMIT_SOLOKOEHLER),INFO_AI && INFO_OTHER_FUNCTION, "Card trump_card_limit()");
  }

  if (gt==GAMETYPE::SOLO_MEATLESS)
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::TRUMPLIMIT_MEATLESS),INFO_AI && INFO_OTHER_FUNCTION, "Card trump_card_limit()");
  }

  DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::TRUMPLIMIT_NORMAL),INFO_AI && INFO_OTHER_FUNCTION, "Card trump_card_limit()");
}


/**********************************************************************
 *
 **    Card lowest_trump_card_limit()
 *
 **    Parameters:  
 *
 **    Result: limit card for some heuristic decisions
 *
 **    Version: Beta
 *
 **    Description:
 **      Results:
 **        Normal    : Diamond jack
 **        Color Solo: Diamond jack
 **        Jack Solo : Heart jack
 **        Queen Solo: heart Queen
 **        King Solo : heart king
 **        Queen-jack: Spade jack
 **        King-jack : Spade jack
 **        King-Queen: Spade Queen
 **        Koehler   : Spade Queen
 **        Meatless  : Diamond Queen
 *
 *
 **********************************************************************/

Card Ai::lowest_trump_card_limit() const
{
  DEBUG_CALLING(INFO_AI && INFO_OTHER_FUNCTION, "Card LOWEST_trump_card_limit()");

  GameType gt=party.game().type();


  if  ( (gt==GAMETYPE::SOLO_CLUB) ||
       (gt==GAMETYPE::SOLO_HEART) ||
       (gt==GAMETYPE::SOLO_SPADE) ||
       (gt==GAMETYPE::SOLO_DIAMOND) ||
       silentMarriage_ )
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::LOWEST_TRUMPLIMIT_SOLOCOLOR),INFO_AI && INFO_OTHER_FUNCTION, "Card LOWEST_trump_card_limit()");
  }

  if  (gt==GAMETYPE::SOLO_JACK) 
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACK),INFO_AI && INFO_OTHER_FUNCTION, "Card LOWEST_trump_card_limit()");
  }

  if  (gt==GAMETYPE::SOLO_QUEEN) 
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::LOWEST_TRUMPLIMIT_SOLOQUEEN),INFO_AI && INFO_OTHER_FUNCTION, "Card LOWEST_trump_card_limit()");
  }

  if  (gt==GAMETYPE::SOLO_KING) 
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::LOWEST_TRUMPLIMIT_SOLOKING),INFO_AI && INFO_OTHER_FUNCTION, "Card LOWEST_trump_card_limit()");
  }

  if   (gt==GAMETYPE::SOLO_QUEEN_JACK)      
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACKQUEEN),INFO_AI && INFO_OTHER_FUNCTION, "Card LOWEST_trump_card_limit()");
  }
  if      (gt==GAMETYPE::SOLO_KING_JACK)       
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACKKING),INFO_AI && INFO_OTHER_FUNCTION, "Card LOWEST_trump_card_limit()");
  }

  if (gt==GAMETYPE::SOLO_KING_QUEEN)
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::LOWEST_TRUMPLIMIT_SOLOQUEENKING),INFO_AI && INFO_OTHER_FUNCTION, "Card LOWEST_trump_card_limit()");
  }
  if    (gt==GAMETYPE::SOLO_KOEHLER) 
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::LOWEST_TRUMPLIMIT_SOLOKOEHLER),INFO_AI && INFO_OTHER_FUNCTION, "Card LOWEST_trump_card_limit()");
  }

  if (gt==GAMETYPE::SOLO_MEATLESS)
  {
    DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::LOWEST_TRUMPLIMIT_MEATLESS),INFO_AI && INFO_OTHER_FUNCTION, "Card LOWEST_trump_card_limit()");
  }

  DEBUG_RETURNING(this->Aiconfig::value(Aiconfig::LOWEST_TRUMPLIMIT_NORMAL),INFO_AI && INFO_OTHER_FUNCTION, "Card LOWEST_trump_card_limit()");
}

/**********************************************************************
 *
 **    Player const* genscher_partner()
 *
 **    Parameters:  
 *
 **    Result: Genscher Partner
 *
 **    Version: 0.5.4
 *
 **    Description:
 **      
 *
 *
 **********************************************************************/

Player const* Ai::genscher_partner()
{
  Player const* res = NULL;

  // first find original teammate
  for ( unsigned i = 0; i < this->game().playerno(); i++ ) {
    if( this->teamofplayer( this->game().player(i) ) == this->team() &&
       this->game().player(i).no() != this->no())
    {	
      res = &(this->game().player(i));
      break;
    }
  }
  // check Specialpoints
  std::vector<int> bonusPoints( this->game().playerno(), 0 );
  for( unsigned i = 0; i < trick_p.size(); i++ )
  {
    // DK: if hinzugefuegt
    if (!trick_p[i].isempty())
      bonusPoints[ trick_p[i].winnerplayer().no() ] += trick_p[i].specialpoints().size() * 30;
  }

  // secure victory
  unsigned int points = 0;
  bool found = false;
  if ( this->game().points_of_team( this->team() ) < 120 )
    for ( unsigned i = 0; i < this->game().playerno(); i++ ) 
    {
      if(   this->game().points_of_player( this->game().player(i) ) 
	 + this->game().points_of_player( this->game().player(this->no()) ) 
	 > 120 && this->game().player(i).no() != this->no() &&
	 this->game().points_of_player( this->game().player(i) )
	 + bonusPoints[ this->game().player(i).no() ] > points )
      {	
	res = &(this->game().player(i));
	points = this->game().points_of_player( this->game().player(i) )
	  + bonusPoints[ this->game().player(i).no() ] ;
	found = true;

      }
    }
  if( found )
    return res;

  for ( unsigned i = 0; i < this->game().playerno(); i++ ) 
  {
    if( this->game().points_of_player( this->game().player(i) )
       + bonusPoints[ this->game().player(i).no() ]  > points &&
       this->game().player(i).no() != this->no() )
    {  
      points = this->game().points_of_player( this->game().player(i) )
	+ bonusPoints[ this->game().player(i).no() ] ;
      res = &(this->game().player(i));
    }
  }

  Announcement highest_announcement = ANNOUNCEMENT::NOANNOUNCEMENT;
  // calculate highest announcements of this team
  for( unsigned i = 0; i < this->game().playerno(); i++ )
  {
    Player const& pl = this->game().player( i );
    if( this->game().team( this->game().player( i ) ) == this->team() )
    {
      if( pl.announcement() > highest_announcement )
	highest_announcement = pl.announcement();
    }
  }

  if ( highest_announcement >= ANNOUNCEMENT::NO0 &&
      this->game().hastrick( opposite( this->team() ) ) ) 
    return res;

  if ( highest_announcement >= ANNOUNCEMENT::NO30 &&
      this->game().points_of_team( opposite( this->team() ) ) >= 30 )
    return res;

  if ( highest_announcement >= ANNOUNCEMENT::NO60 &&
      this->game().points_of_team( opposite( this->team() ) ) >= 60 )
    return res;

  if ( highest_announcement >= ANNOUNCEMENT::NO90 &&
      this->game().points_of_team( opposite( this->team() ) ) >= 90 )
    return res;

  // don't use genscher
  return NULL;
}


