/**********************************************************************
 *
 *   FreeDoko a Doppelkopf-Game
 *
 *   Copyright (C) 2001-2009  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 "heuristics.h"

#include "HeuristicInterface.h"
#include "cards_information.h"
#include "cards_information.of_player.h"
#include "team_information.h"
#include "../../game/game.h"
#include "../../party/party.h"
#include "../../party/rule.h"
#include "../../card/trick.h"

#ifdef BENDERS
#define ANNOUNCE_DEBUG
#endif

/*
 * Steps to create a new heuristic
 *
 *  1) src/player/aiconfig.h
 *     - enum Heuristic: add heuristic
 *  2) src/player/aiconfig.cpp
 *     - function name(): add heuristic
 *     - Aiconfig::init_heuristic_states(): add heuristic to default ai
 *  3) src/player/ai/heuristic.h
 *     - add declaration of heuristic function
 *  4) src/player/ai/ai.cpp
 *     - Ai::nextcard(trick): add heuristic and function call in switch
 *  5) src/ui/gtkmm/players_db.cpp
 *     - PlayersDB::recreate_db(): add heuristic to switch (mind the group)
 *  6) src/player/ai/heuristic.cpp
 *     - add definition of heuristic (here is the work)
 *     - do not forget the documentation (see below)
 *  7) data/translations/de/aiconfig.heuristics.description
 *     - add german translation for heuristic name and description
 *  8) src/player/ai/aiconfigs.preset
 *     - create presets:
 *       a) save standard ai under 'aiconfig.defensive.saved'
 *       b) call 'make'
 *  9) test
 * 10) create references (remember: set the ai to standard types)
 *
 * Mostly the compiler will find an error.
 * To find the places in the files, just search for 'CREATE_FEHL' and 'create_fehl'.
 */

/* Documentation
 *
 * Each heuristic should contain the following documentation for automatic
 * generation of the description.
 * Note that the text shall not be split into multiple lines.
 * The name must be the first entry and the action the last.
 * For a real example look at 'Heuristics::serve_color_trick()'.
 */
// @heuristic::name        the name of the heuristic (as in '::name(Heuristic)')
// @heuristic::idea        the main idea for the heuristic
// @heuristic::comment     a simple comment
// @heuristic::condition   a condition for the heuristic
// @heuristic::condition   a second condition for the heuristic
// @heuristic::action      which card is taken



// missing

// @heuristic::name   choose pfund poverty
// @heuristic::idea   ???

// @heuristic::name   meatless: play highest color
// @heuristic::idea   ???

// @heuristic::name   picture: second best trump
// @heuristic::idea   ???

// @heuristic::name   color: choose ace
// @heuristic::idea   ???

// @heuristic::name   color: best winning
// @heuristic::idea   ???

// @heuristic::name   color: jab for ace
// @heuristic::idea   ???

// @heuristic::name   color: play low high
// @heuristic::idea   ???




// special heuristics

// @heuristic::name      no heuristic
// @heuristic::idea      internal use: no heuristic was used, yet

// @heuristic::name      manual
// @heuristic::idea      The card is played manual (from the human).
//
// @heuristic::name      bug report
// @heuristic::idea      Play the card from the bug report.
// @heuristic::comment   This heuristic is used so that in a bug report replay
// @heuristic::comment   the card suggestion is the card from the bug report.

// @heuristic::name      network
// @heuristic::idea      The card is played by the network player.

// @heuristic::name      only valid card
// @heuristic::idea      If there is only one valid card, play it.


/*
   Ideen

   normales Spiel
 * Partner sitzt hinten:
 Farbe anspielen, die er nicht hat und von der noch mindestens 1 draußen ist
 * Startspieler aber kein Farb-As:
Re: Karo König, Karo Neun, Karo Bube (damit Partner mit Kreuz-Dame rausrückt)
Kontra: Lange Farbe anspielen (>= 4)
 * Partner sitzt hinter einem, beide Gegner vorne (Trumpfstich):
 - Pfunden (wenn Fuchs / Karo Zehn da)
 - rübergehen, damit Partner Sorgen los wird
 * Wenn Partner direkt nach mir sitzt und noch nicht dran war und kein As gespielt hat:
 Spiele Farbe an, damit er mit potentiellen As übernehmen kann

 Armut (z.B. seed 27350 (3) )
 * Erster Kontra Spieler nach Re:
 Wenn Partner noch übertrumpfen kann (trump limit?): Punkte/drunter bleiben.
 (damit er hinten sitzt)
 wenn Partner nicht übertrumpfen kann (-> cards information): selber übertrumpfen oder kleinen rein.
 * Armutler nach Partner:
 Gegner haben Stich: wenig Punkte geben
 */

// ToDo: own trumplimit value for poverty

unsigned number_of_no_trumps_per_color();
Card lowest_card(Hand const& hand, Card::Value const cv,
                 HeuristicInterface const& hi);
Card lowest_jack(Hand const& hand, HeuristicInterface const& hi);
Card lowest_queen(Hand const& hand, HeuristicInterface const& hi);
Card highest_queen(Hand const& hand, HeuristicInterface const& hi);
Card highest_card(Hand const& hand, Card::Value const cv,
                  HeuristicInterface const& hi);
bool better_points_optimize(HandCard const& old_card,
                            HandCard const& test_card,
                            HeuristicInterface const& hi);

// Checks if the card will win the trick
bool cardWillWinTheTrick(Trick const &t, HeuristicInterface const& hi,
                         HandCard const& card);
int calcPointsOfOwnTeam( HeuristicInterface const& hi, Game const& g );
int calcPointsOfOppositeTeam( HeuristicInterface const& hi, Game const& g );

// whether all players behind are of the own team
bool checkAllMyTeam(Trick const& t, HeuristicInterface const& hi);
// whether the opposite team behind still has a trump
bool opposite_trump_behind(Trick const& trick, HeuristicInterface const& hi);
// the highest card of the playes of the opposite team behind
HandCard const& highest_opposite_card_behind(Trick const& trick,
                                             HeuristicInterface const& hi);
// the lowest of the highest trumps
Card lowest_highest_trump(Trick const& trick, HeuristicInterface const& hi);

Card choose_best_fehl(Trick const& trick, HeuristicInterface const& hi,
                      bool const forceFehl = false);

/**
 ** check if own team can still win this trick.
 **
 ** @param      trick   the current trick
 ** @param      hi      heuristic interface
 **
 ** @return     returns true if the own team can win the trick
 **
 ** @author     Borg Enders
 **
 ** @version    ???
 **/
bool 
ownTeamCanWinTrick( Trick const &t, HeuristicInterface const& hi )
{
  bool trickWon = (t.winnerplayer().team() == hi.team());

  // take a look if all players coming in this trick of own team can still win the trick
  for( unsigned i = t.actcardno(); i < hi.game().playerno(); i++ ) {
    if (   (hi.no() != t.player_of_card(i).no())
        && ( maybe_to_team(hi.teamofplayer(t.player_of_card( i ))) == hi.team() ) )
    {
      trickWon = (trickWon
                  || hi.handofplayer(t.player_of_card( i ) 
                                    ).validcards(t).higher_card_exists( t.winnercard() ));
    } // if( maybe_to_team(hi.teamofplayer(t.player_of_card(i))) != hi.team() )
  } // for (i)
  return trickWon;
} // bool ownTeamCanWinTrick ( Trick t, HeuristicInterface hi )

/**
 ** check if opposite team can still win this trick.
 **
 ** @param      trick   the current trick
 ** @param      hi      heuristic interface
 **
 ** @return     returns true if the opposite team can win the trick
 **
 ** @author     Borg Enders
 **
 ** @version    ???
 **/
bool 
oppositeTeamCanWinTrick( Trick const &t, HeuristicInterface const& hi )
{
  bool trickLost = (t.winnerplayer().team() != hi.team());

  // take a look if all players coming in this trick of other team can still win the trick
  for( unsigned i = t.actcardno(); i < hi.game().playerno(); i++ )
    if( maybe_to_team(hi.teamofplayer(t.player_of_card( i ))) != hi.team() )
    {
      trickLost = (trickLost
                   || hi.handofplayer( 
                                      t.player_of_card( i ) 
                                     ).higher_card_exists( t.winnercard() ));
    } // if( maybe_to_team(hi.teamofplayer(t.player_of_card(i))) != hi.team() )
  return trickLost;
} // bool oppositeTeamCanWinTrick ( Trick t, HeuristicInterface hi )

/**
 ** check if the card will win the trick
 **
 ** @param      trick   the current trick
 ** @param      hi      heuristic interface
 ** @param      card    the card to check
 **
 ** @return     returns true if the card will win the trick
 **
 ** @author     Florian Sundermann
 **
 ** @version    0.7.5
 **/
bool 
cardWillWinTheTrick(Trick const &t, HeuristicInterface const& hi,
                    HandCard const& card)
{
  bool cannotwin = !t.winnercard().less(card);

  // take a look if all players coming in this trick of other team can still win the trick
  for( unsigned i = t.actcardno(); i < hi.game().playerno(); i++ )
    if( maybe_to_team(hi.teamofplayer(t.player_of_card( i ))) != hi.teamofplayer(card.player()) )
    {
      if ( t.cardno_of_player( card.player() ) < i ) // Test for dolle etc.
        cannotwin = cannotwin || card.less(hi.handofplayer(i).highest_card());
      else
        cannotwin = cannotwin || !hi.handofplayer(i).highest_card().less(card);
    } // if( maybe_to_team(hi.teamofplayer(t.player_of_card(i))) != hi.team() )
  return ! cannotwin;
} // bool oppositeTeamHasBetterCardForTrick ( Trick t, HeuristicInterface hi )


/**
 ** get the number of "no-trump" cards per color
 **
 ** @param     trick   the current trick
 ** @param     hi      heuristic interface
 **
 ** @return    number of cards per miscolor
 **
 ** @author    Borg Enders
 **
 ** @version   ???
 **/
unsigned
number_of_no_trumps_per_color()
{
  unsigned i;  
  unsigned notrump_per_color=0;

  // calculate number of no trump cards per color
  // only one color can be trump
  // if spade is trump caculate with club otherwise with spade
  if( Card( Card::SPADE, Card::ACE ).istrump( ::party.game() ) )
  {
    for ( i = 0;  i < 2 * ::party.rule()(Rule::NUMBER_OF_CARD_VALUES); i += 2 )
      if( !Card( Card::InttoColor(Card::CLUB), Card::InttoValue(i) ).istrump( 
                                                                             ::party.game() ) 
        )
        notrump_per_color+=2;
  } else { // if( Card( Card::SPADE, Card::ACE ).istrump( ::party.game() ) )
    for ( i = 0;  i < 2 * ::party.rule()(Rule::NUMBER_OF_CARD_VALUES); i += 2 )
      if( !Card( Card::InttoColor( Card::SPADE ),
                Card::InttoValue(i) ).istrump( ::party.game() )
        )
        notrump_per_color+=2;
  } // else

  return notrump_per_color;
} // unsigned number_of_no_trumps_per_color()


/**
 ** returns a card to play for the bride in an open marriage
 **
 ** @param     trick   the current trick
 ** @param     hi      heuristic interface
 **
 ** @return    card to play (or Card())
 **
 ** @author    Borg Enders
 **
 ** @version   0.7.0
 **/
Card
Heuristics::play_to_marry( Trick const& trick,
                          HeuristicInterface const& hi )
{
  // @heuristic::name   play to marry
  // @heuristic::idea   play card to marry
  if( !(   hi.game().type() == GAMETYPE::MARRIAGE 
        && hi.game().soloplayer().no() != hi.no()
       )
    )
    return Card::EMPTY;

  Card::Color color = Card::NOCARDCOLOR;

  if (trick.isempty()) {
    switch (hi.game().marriage_selector()) {
    case MARRIAGE_SELECTOR::SILENT:
    case MARRIAGE_SELECTOR::TEAM_SET:
      return Card::EMPTY;

    case MARRIAGE_SELECTOR::FIRST_FOREIGN:
    case MARRIAGE_SELECTOR::FIRST_TRUMP: {
      // @heuristic::condition   trick empty and first foreign or first trump
      // @heuristic::action      play the highest trump, if only the bride can jab
      Card const trump = lowest_highest_trump(trick, hi);
      if (trump.is_empty())
        return Card::EMPTY;

      if (!trump.less(highest_opposite_card_behind(trick, hi)))
        return trump;

      return Card::EMPTY;
    }
    case MARRIAGE_SELECTOR::FIRST_CLUB:
      color = Card::CLUB;
    case MARRIAGE_SELECTOR::FIRST_SPADE:
      if( color == Card::NOCARDCOLOR )
        color = Card::SPADE;
    case MARRIAGE_SELECTOR::FIRST_HEART:
      if( color == Card::NOCARDCOLOR )
        color = Card::HEART;

      // @heuristic::condition   trick empty and first specific color
      // @heuristic::action      play the ace of this color, if it can get through
      if (   (hi.hand().numberof(Card(color, Card::ACE)) > 0)
          && (hi.cards_information().remaining_others(Card(color, Card::ACE))
              >= hi.game().playerno() - 1) )
        return Card(color, Card::ACE);

      return Card::EMPTY;
    case MARRIAGE_SELECTOR::FIRST_COLOR:
      // this is caught by 'play ace'
      return Card::EMPTY;

    } // switch (hi.game().marriage_selector())
  } else { // if !(trick.isempty())

    // @heuristic::condition   must be a selector trick
    if (!is_selector(trick.startcard().tcolor(),
                     hi.game().marriage_selector()) )
      return Card::EMPTY;

    // @heuristic::condition   the player has the highest trump and can play it
    // @heuristic::action      play the highest trump, if only the bride can jab
    Card const card = choose_for_color_trick(trick, hi);
    if (!card.is_empty())
      return card;

    Card const trump = lowest_highest_trump(trick, hi);
    if (trump.is_empty())
      return Card::EMPTY;
    if (   trick.isvalid(trump, hi.hand())
        && trick.winnercard().less(trump)
        && !trump.less(highest_opposite_card_behind(trick, hi)))
      return trump;
  }  // if !(trick.isempty())

  return Card::EMPTY;
} // static Card Heuristics::play_to_marry(Trick trick, HeuristicInterface hi)

/**
 ** returns a card to play for the bride in an open marriage
 **
 ** @param     trick   the current trick
 ** @param     hi      heuristic interface
 **
 ** @return    card to play (or Card())
 **
 ** @author    Borg Enders
 **
 ** @version   0.7.6
 **/
Card
Heuristics::play_to_get_married( Trick const& trick,
                                HeuristicInterface const& hi )
{
  // @heuristic::name   play to get married
  // @heuristic::idea   play card to get married

  // @heuristic::condition   marriage player
  if( !(   hi.game().type() == GAMETYPE::MARRIAGE 
        && hi.game().soloplayer().no() == hi.no()
       )
    )
    return Card::EMPTY;

  // @heuristic::action   As first player, play card of the marriage color to get married,
  // @heuristic::action   else in a marriage trick, play pfund.
  Card::Color color = Card::NOCARDCOLOR;

  switch( hi.game().marriage_selector() ) {
  case MARRIAGE_SELECTOR::SILENT:
  case MARRIAGE_SELECTOR::TEAM_SET:
    return Card::EMPTY;

  case MARRIAGE_SELECTOR::FIRST_FOREIGN:
    if( trick.isempty() ) {
      vector<Card> cards;
      for (vector<Card::Color>::const_iterator
           c = hi.game().rule().card_colors().begin();
           c != hi.game().rule().card_colors().end();
           ++c) {
        Card::Color const& color = *c;
        if (   Card(color, Card::ACE).istrump(hi.game())
            && !HandCard( hi.hand(), Card(color, Card::ACE)).possible_swine() )
          cards.push_back(Card(color, Card::ACE));
      } // foreach ( color in hi.game().rule().card_colors() )

      for (vector<Card::Color>::const_iterator
           c = hi.game().rule().card_colors().begin();
           c != hi.game().rule().card_colors().end();
           ++c) {
        Card::Color const& color = *c;
        if ( !HandCard( hi.hand(), Card(color, Card::TEN)).isdolle() ) {
          cards.push_back(Card(color, Card::TEN));
        }
      } // foreach ( color in hi.game().rule().card_colors() )

      for (vector<Card::Color>::const_iterator
           c = hi.game().rule().card_colors().begin();
           c != hi.game().rule().card_colors().end();
           ++c) {
        Card::Color const& color = *c;
        cards.push_back(Card(color, Card::KING));
      } // foreach ( color in hi.game().rule().card_colors() )

      for (vector<Card::Color>::const_iterator
           c = hi.game().rule().card_colors().begin();
           c != hi.game().rule().card_colors().end();
           ++c) {
        Card::Color const& color = *c;
        if ( !HandCard( hi.hand(), Card(color, Card::NINE)).possible_hyperswine() )
          cards.push_back(Card(color, Card::NINE));
      } // foreach ( color in hi.game().rule().card_colors() )

      for( vector<Card>::const_iterator card = cards.begin();
          card != cards.end();
          ++card ) {
        if( ( hi.hand().numberof( *card ) > 0 )  )
          return *card;
      } // foreach ( card in cards )

      return Card::EMPTY;
    }
    return Heuristics::choose_pfund_card( trick, hi );

  case MARRIAGE_SELECTOR::FIRST_TRUMP:
    if(   !trick.isempty()
       && trick.startcard().istrump() )
      return Heuristics::choose_pfund_card( trick, hi );

    if( trick.isempty() ) 
    {
      // take a 'good' card
      if(   hi.hand().numberoftrumpaces() > 0 
         && !hi.hand().has_swines()
        )
        return Card(hi.game().trumpcolor(), Card::ACE);

      if(  hi.hand().numberof( Card( hi.game().trumpcolor(), Card::TEN ) ) > 0 )
        return Card(hi.game().trumpcolor(), Card::TEN);

      return Heuristics::lowest_best_trump_card(trick, hi.hand(), hi);
    } // if (trick.startplayer().no() == hi.no())
    break;

  case MARRIAGE_SELECTOR::FIRST_CLUB:
    color = Card::CLUB;
  case MARRIAGE_SELECTOR::FIRST_SPADE:
    if( color == Card::NOCARDCOLOR )
      color = Card::SPADE;
  case MARRIAGE_SELECTOR::FIRST_HEART:
    if( color == Card::NOCARDCOLOR )
      color = Card::HEART;

    if(   !trick.isempty()
       && trick.startcard().tcolor() == color
      )
      return Heuristics::choose_pfund_card( trick, hi );

    if( trick.isempty() ) 
    {
      vector<Card> cards;
      if (!hi.game().rule()(Rule::DOLLEN))
        cards.push_back(Card(color, Card::TEN));
      cards.push_back(Card(color, Card::KING));
      cards.push_back(Card(color, Card::NINE));
      //      cards.push_back(Card(color, Card::ACE)); // With Ace I will probably win the trick bad decision
      for( vector<Card>::const_iterator c = cards.begin();
          c != cards.end();
          ++c )
        if( hi.hand().numberof( *c ) > 0 )
          return *c;
    } // if( trick.isempty() )
    break;

  case MARRIAGE_SELECTOR::FIRST_COLOR:
    if( trick.isempty() )
    {
      vector<Card> cards;
      for (vector<Card::Color>::const_iterator
           c = hi.game().rule().card_colors().begin();
           c != hi.game().rule().card_colors().end();
           ++c) 
      {
        Card::Color const& color = *c;
        if ( !HandCard( hi.hand(), Card(color, Card::TEN)).isdolle() ) 
          cards.push_back(Card(color, Card::TEN));
      } // foreach ( color in hi.game().rule().card_colors() )
      for (vector<Card::Color>::const_iterator
           c = hi.game().rule().card_colors().begin();
           c != hi.game().rule().card_colors().end();
           ++c) 
      {
        Card::Color const& color = *c;
        cards.push_back(Card(color, Card::KING));

      } // foreach ( color in hi.game().rule().card_colors() )
      for (vector<Card::Color>::const_iterator
           c = hi.game().rule().card_colors().begin();
           c != hi.game().rule().card_colors().end();
           ++c) 
      {
        Card::Color const& color = *c;
        cards.push_back(Card(color, Card::NINE));
      } // foreach ( color in hi.game().rule().card_colors() )

      for( vector<Card>::const_iterator card = cards.begin();
          card != cards.end();
          ++card )
      {
        if( ( hi.hand().numberof( *card ) > 0 ) && !card->istrump( hi.game() )  )
          return *card;
      } // foreach ( card in cards )

      return Card::EMPTY;
    } // if( trick.isempty() )

    if(    trick.startplayer().no() != hi.no()
       && !trick.startcard().istrump()
      )
      return Heuristics::choose_pfund_card( trick, hi );

    if( trick.startplayer().no() == hi.no() )
      return Heuristics::lowest_card(trick, hi.hand());

    break;

  } // switch(marriage_selector)

  return Card::EMPTY;
} // static Card Heuristics::play_to_get_married(Trick trick, HeuristicInterface hi)


/**
 ** for a first card in a trick play a color ace
 ** if there are still enough cards of this color in the game
 ** and the color has not been jabbed
 ** choose the ace with the most cards in that color still in the game
 **
 ** @param     trick   current trick
 ** @param     hi      heuristic interface
 **
 ** @return    card to play (color ace or none)
 **
 ** @author    Diether Knof
 ** @author    Borg Enders
 **
 ** @version   0.7.4
 **/
Card
Heuristics::choose_ace(Trick const& trick, HeuristicInterface const& hi)
{
  // @heuristic::name   choose ace
  // @heuristic::idea   for the first card in a trick choose the best color Ace to play

  // I am not the start Player
  if( !trick.isstartcard() )
    return Card::EMPTY;

  // the number of remaining cards for the color
  map<Card::Color, unsigned> number_of_remaining_cards;


  // the card to play
  Card ace_to_play;
  // the maximal number of remaining cards found so far
  unsigned best_modified_remaining_cards = 0;
  for (vector<Card::Color>::const_iterator
       c = hi.game().rule().card_colors().begin();
       c != hi.game().rule().card_colors().end();
       ++c) {
    Card::Color const& color = *c;
    Card const ace(color, Card::ACE);

    // test that the color is no trumpcolor
    if (   (color != hi.game().trumpcolor())
        // test that the player has an ace of the color
        && hi.hand().contains(ace)) {

      // the number of remaining cards for the other players
      unsigned const remaining_cards
        = (hi.game().numberof(color)
           - (hi.cards_information().played(*c) + hi.hand().numberof(*c)));
      // modified remaining cards
      // Modified by the number of aces of the color.
      // This is used to prefer single aces to double aces.
      unsigned const modified_remaining_cards
        = (remaining_cards
           +  (  (hi.hand().numberof(ace) + hi.cards_information().played(ace)
                  < hi.game().rule()(Rule::NUMBER_OF_SAME_CARDS))
               ? (hi.game().numberof(color) - 1) // *Value*
               : 0) );

      // there are enough cards for all players
      if (   (remaining_cards >= hi.game().playerno() - 1)
          // if the color has already been jabbed, it has to be from the own team
          && (   !hi.colorjabbed(color)
              || (   hi.jabbedbyownteam(color))
              && !hi.jabbedbyotherteam(color))
          // no ace found so far
          && (   ace_to_play.is_empty()
              // there must not be less remaining cards then the best
              || (   (modified_remaining_cards >= best_modified_remaining_cards)
                  // if both colors have the same cards out,
                  // take the one the player has fewer aces
                  && (  (modified_remaining_cards
                         == best_modified_remaining_cards)
                      ? (hi.hand().numberof(ace)
                         < hi.hand().numberof(ace_to_play))
                      : true)
                 ) ) ) {
        best_modified_remaining_cards = modified_remaining_cards;
        ace_to_play = ace;
      } // if (take card)

    } // if (the color is no trumpcolor and the player has an ace of the color)
  } // for (i < ha.cardsnumber())

  return ace_to_play;
} // Card Heuristics::choose_ace(Trick trick, HeuristicInterface hi)


/**
 ** for a first card in a trick play a single color ace
 ** if there are still enough cards of this color in the game
 ** and the color has not been jabbed
 ** choose the single ace with the most cards in that color still in the game
 **
 ** @param     trick   current trick
 ** @param     hi      heuristic interface
 **
 ** @return    card to play (color ace or none)
 **
 ** @author    Diether Knof
 ** @author    Borg Enders
 **
 ** @version   0.7.6
 **/
Card
Heuristics::choose_single_ace(Trick const& trick, HeuristicInterface const& hi)
{
  // @heuristic::name   choose single ace
  // @heuristic::idea   for the first card in a trick choose the best single color Ace to play

  // I am not the start Player
  if( !trick.isstartcard() )
    return Card::EMPTY;

  // the number of remaining cards for the color
  map<Card::Color, unsigned> number_of_remaining_cards;


  // the card to play
  Card ace_to_play;
  // the maximal number of remaining cards found so far
  unsigned best_modified_remaining_cards = 0;
  for (vector<Card::Color>::const_iterator
       c = hi.game().rule().card_colors().begin();
       c != hi.game().rule().card_colors().end();
       ++c) {
    Card::Color const& color = *c;
    Card const ace(color, Card::ACE);

    // test that the color is no trumpcolor
    if (   (color != hi.game().trumpcolor())
        // test that the player has an ace of the color
        && hi.hand().contains( ace )
        && hi.hand().numberof( ace.color() ) == 1 ) {

      // the number of remaining cards for the other players
      unsigned const remaining_cards
        = (hi.game().numberof(color)
           - (hi.cards_information().played(*c) + hi.hand().numberof(*c)));
      // modified remaining cards
      // Modified by the number of aces of the color.
      // This is used to prefer single aces to double aces.
      unsigned const modified_remaining_cards
        = (remaining_cards
           +  (  (hi.hand().numberof(ace) + hi.cards_information().played(ace)
                  < hi.game().rule()(Rule::NUMBER_OF_SAME_CARDS))
               ? (hi.game().numberof(color) - 1) // *Value*
               : 0) );

      // there are enough cards for all players
      if (   (remaining_cards >= hi.game().playerno() - 1)
          // if the color has already been jabbed, it has to be from the own team
          && (   !hi.colorjabbed(color)
              || (   hi.jabbedbyownteam(color))
              && !hi.jabbedbyotherteam(color))
          // no ace found so far
          && (   ace_to_play.is_empty()
              // there must not be less remaining cards then the best
              || (   (modified_remaining_cards >= best_modified_remaining_cards)
                  // if both colors have the same cards out,
                  // take the one the player has fewer aces
                  && (  (modified_remaining_cards
                         == best_modified_remaining_cards)
                      ? (hi.hand().numberof(ace)
                         < hi.hand().numberof(ace_to_play))
                      : true)
                 ) ) ) {
        best_modified_remaining_cards = modified_remaining_cards;
        ace_to_play = ace;
      } // if (take card)

    } // if (the color is no trumpcolor and the player has an ace of the color)
  } // for (i < ha.cardsnumber())

  return ace_to_play;
} // Card Heuristics::choose_single_ace(Trick trick, HeuristicInterface hi)

/**
 ** finds lowest card with value cv
 **
 ** @param     h       the hand to search for a card
 ** @param     cv      the value to search for
 ** @param     hi      heuristic interface
 **
 ** @return    lowest card with the value cv (or 'Card()' if no card was found)
 **
 ** @author    Borg Enders
 **
 ** @version   Beta
 **/
Card
lowest_card( Hand const& h, Card::Value const cv, HeuristicInterface const& hi )
{
  Card c;

  unsigned i;

  for( i = 0; i < h.cardsnumber(); i++ )
  {
    // find any card
    if( h.card(i).value() == cv )
    {
      c = h.card(i);
      break;
    } // if ( h.card(i).value() == cv )
  } // for ( i < h.cardsnumber() )

  if (c.is_empty())
    return c;

  for( i = 0; i < h.cardsnumber(); i++ )
  {
    // find lowest card
    if(   h.card(i).value() == cv 
       && h.card(i).less(c) )
      c = h.card(i);
  } // for ( i < h.cardsnumber() )

  return c;
} // Card lowest_card( Hand h, Card::Value cv, HeuristicInterface hi )


/**
 ** finds highest card with value cv
 **
 ** @param     h       the hand to search for a card
 ** @param     cv      the value to search for
 ** @param     hi      heuristic interface
 **
 ** @return    highest card with the value cv (or 'Card()' if no card was found)
 **
 ** @author    Borg Enders
 **
 ** @version   Beta
 **/
Card
highest_card( Hand const& h, Card::Value const cv, HeuristicInterface const& hi )
{
  Card c;

  unsigned i;

  for( i = 0; i < h.cardsnumber(); i++ )
  {
    // find any card
    if( h.card(i).value() == cv )
    {
      c = h.card(i);
      break;
    } // if ( h.card(i).value() == cv )
  } // for ( i < h.cardsnumber() )

  if (c.is_empty())
    return Card::EMPTY;

  for( i = 0; i < h.cardsnumber(); i++ )
  {
    // find highest card
    if(   h.card(i).value() == cv 
       && !h.card(i).less(c) )
      c=h.card(i);
  } // for ( i < h.cardsnumber() )

  return c;
} // Card highest_card( Hand h, Card::Value cv, HeuristicInterface hi )


/**
 ** finds lowest jack
 **
 ** @param     h       the hand to search for a card
 ** @param     hi      heuristic interface
 **
 ** @return    lowest jack on hand (or 'Card()' if no card was found)
 **
 ** @author    Borg Enders
 **
 ** @version   Beta
 **/
Card
lowest_jack( Hand const& h, HeuristicInterface const& hi )
{
  return lowest_card( h, Card::JACK, hi );
} // Card lowest_jack ( Hand h, HeuristicInterface hi )


/**
 ** finds highest queen
 **
 ** @param     h       the hand to search for a card
 ** @param     hi      heuristic interface
 **
 ** @return    highest queen on hand (or 'Card()' if no card was found)
 **
 ** @author    Borg Enders
 **
 ** @version   Beta
 **/
Card
highest_queen( Hand const& h, HeuristicInterface const& hi )
{
  return highest_card( h, Card::QUEEN, hi );
} // Card highest_queen( Hand h, HeuristicInterface hi )


/**
 ** finds lowest queen
 **
 ** @param     h       the hand to search for a card
 ** @param     hi      heuristic interface
 **
 ** @return    lowest queen on hand (or 'Card()' if no card was found)
 **
 ** @author    Borg Enders
 **
 ** @version   Beta
 **/
Card
lowest_queen( Hand const& h, HeuristicInterface const& hi )
{
  return lowest_card( h, Card::QUEEN, hi );
} // Card lowest_queen ( Hand h, HeuristicInterface hi )


/**
 ** checks if there are any trumps in trick t
 **
 ** @param     trick   trick to check
 **
 ** @return    whether there is a trump card in the trick
 **
 ** @author    Borg Enders
 ** @author    Diether Knof
 **
 ** @version   0.7.5
 **/
bool 
trumpInTrick( Trick const& trick )
{
  for (unsigned i = 0; i < trick.actcardno(); i++)
    if (trick.card(i).istrump())
      return true;

  return false;
} // bool trumpInTrick( Trick trick )


/**
 ** checks if all remaining player in the trick are of my team
 **
 ** @param     trick   trick to check
 ** @param     hi      Heuristic interface
 **
 ** @return    returns true if all remaining players are in the same team
 **
 ** @author    Borg Enders
 **
 ** @version   Beta
 **/
bool
checkAllMyTeam( Trick const& t, HeuristicInterface const& hi )
{
  bool allmyteam = true;

  // take a look if all players coming in this trick are of mine team
  for( unsigned i = t.actcardno(); i < hi.game().playerno(); i++ )
    allmyteam = (   allmyteam
                 && ( hi.team() == hi.teamofplayer( t.player_of_card( i ) ) )); 
  return allmyteam;
} // bool checkAllMyTeam( Trick t, HeuristicInterface hi )


/**
 ** -> result
 **
 ** @param     trick   trick to check
 ** @param     hi      heuristic interface
 **
 ** @return    whether the opposite team has a trump behind
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.6
 **
 ** @todo      check for 'must have' of the color of the trick
 **/
bool
opposite_trump_behind(Trick const& trick, HeuristicInterface const& hi)
{
  for (unsigned i = trick.actcardno() + 1; i < hi.game().playerno(); i++) {
      if (hi.team() == hi.teamofplayer(trick.player_of_card(i)))
        continue;

    // check for 'must have' of the color of the trick
    if (hi.cards_information().of_player(trick.player_of_card(i)).can_have(Card::TRUMP))
      return true;
  } // for (i < hi.game().playerno())

  return false;
} // bool opposite_trump_behind(Trick trick, HeuristicInterface hi)

/**
 ** -> result
 **
 ** @param     trick   trick to check
 ** @param     hi      heuristic interface
 **
 ** @return    the highest card of the playes of the opposite team behind
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.6
 **
 ** @todo      check for 'must have' of the color of the trick
 **/
HandCard const&
highest_opposite_card_behind(Trick const& trick, HeuristicInterface const& hi)
{
  HandCard const* highest_card = &HandCard::EMPTY;

  // take a look if all players coming in this trick are of mine team
  for (unsigned i = trick.actcardno() + 1; i < hi.game().playerno(); i++) {
    if (   (hi.game().type() == GAMETYPE::MARRIAGE)
        && (hi.game().marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET)) {
      if (::is_selector((  trick.isempty()
                         ? Card::TRUMP
                         : trick.startcard().tcolor()),
                        hi.game().marriage_selector())) {
        if (   (hi.team() != TEAM::RE)
            && (hi.game().soloplayer() == trick.player_of_card(i)) ) {
          // in a selector trick, the re player is seen as of the own team
          continue;
        }
      }
    } else { // if (normal game)
      if (hi.team() == hi.teamofplayer(trick.player_of_card(i)))
        continue;
    }

    if (   (hi.game().type() == GAMETYPE::POVERTY)
        && (trick.player_of_card(i).no() == hi.game().soloplayer().no()) ) {
      if (   !trick.isempty()
          && !trick.startcard().istrump()) {
        HandCard const& c
          = hi.handofplayer(trick.player_of_card(i)).highest_card(trick.startcard().tcolor());
        if (highest_card->less(c))
          highest_card = &c;
        continue;
      }
    }
    // check for 'must have' of the color of the trick
    HandCard const& c = hi.handofplayer(trick.player_of_card(i)).highest_card();
    if (highest_card->less(c))
      highest_card = &c;
  } // for (i < hi.game().playerno())

  return *highest_card;
} // HandCard const& highest_opposite_card_behind(Trick trick, HeuristicInterface hi)

/**
 ** -> result
 **
 ** @param     hi      heuristic interface
 **
 ** @return    the lowest trump the player has which gets over the of the opposite team, or the highest trump
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.6
 **
 ** @todo      test
 **/
Card
lowest_highest_trump(Trick const& trick, HeuristicInterface const& hi)
{
  Card lh_trump = hi.hand().highest_trump();
  if (lh_trump == Card::EMPTY)
    return Card::EMPTY;

  HandCard const& highest_card_behind = highest_opposite_card_behind(trick, hi);

  list<Card>::const_reverse_iterator c;
  // first search the highest trump
  for (c = hi.game().trumps().rbegin();
       *c != lh_trump;
       ++c) {
    DEBUG_ASSERTION(c != hi.game().trumps().rend(),
                    "heuristics.cpp::lowest_highest_trump(trick, hi)\n"
                    "  lowest trump " << lh_trump
                    << " not found in the trumps");
  }
  ;
  // now search for a lesser trump
  for ( ; c != hi.game().trumps().rend(); ++c) {
    if (   !trick.isempty()
        && !trick.winnercard().less(*c))
      break;
    if (   !highest_card_behind.is_empty()
        && c->less(highest_card_behind))
      break;
    if (hi.hand().contains(*c))
      lh_trump = *c;
  } // for (c \in hi.game().trumps())

  return lh_trump;
} // Card lowest_highest_trump(Trick trick, HeuristicInterface hi)

/**
 ** finds best card on Hand of hi, which wins this trick, 
 ** non trump ace or lowest trump
 ** greater than jack, only in lastcard lower trumps are allowed
 ** the card will be chosen taking the value of the trick in account
 **
 ** @param     trick     trick to check
 ** @param     v         value of the card
 ** @param     hi        heuristic interface
 ** @param     pointmodi point modifikator to add to points of t
 **
 ** @return    the card to play ( or 'Card()' if no card was found )
 **
 ** @author    Borg Enders
 **
 ** @version   Beta
 **/
Card 
Heuristics::best_winning_card_single_picture(Trick const& t, Card::Value v, 
                                             HeuristicInterface const& hi, unsigned pointmodi)
{
  // @heuristic::name   ?  best winning card single picture  ?
  // @heuristic::idea   Only valid for soli with only one picture as trump: Tries to find the best card to win a trick depending on different values like Aiconfig::LIMITQUEEN    

  if ( t.isstartcard() ) 
    return Card::EMPTY;

  Card c;
  HandCards const ha = hi.hand().validcards( t );
  unsigned i;

  bool allmyteam = checkAllMyTeam( t, hi );

  // find any card that wins this trick greater or equal to lowest_trump_card_limit
  for( i = 0; i < ha.cardsnumber(); i++ )
  {
    if(   t.isvalid( ha.card(i), hi.hand() )  
       && t.is_jabbed(ha.card(i))
       && (   hi.lowest_trump_card_limit().less( ha.card( i ) ) 
           || allmyteam 
          )  
      )
    {
      c = ha.card(i);
      break;
    }
  } // for ( i < ha.cardsnumber() )

  // if can't win this trick and I'am not the last player: that's it
  if (c.is_empty() && !t.islastcard())  
    return Card::EMPTY;

  bool trumpintrick = trumpInTrick( t );

  // or this is a color trick of a first color run with my card the first trump
  allmyteam =  (  allmyteam 
                || (   t.actcardno() > 1
                    && hi.color_runs(t.startcard().color()) == 0
                    && !t.startcard().istrump()
                    && !trumpintrick 
                   ) );

  // find a better card
  for( i = 0; i < ha.cardsnumber(); i++ )
  {

    if(   t.isvalid( ha.card( i ), hi.hand() ) 
       && t.is_jabbed(ha.card(i))
      )
    {
      // non trump ace is always the best choice if color is not already jabbed
      if(   ha.card(i).value() == Card::ACE 
         && !ha.card(i).istrump() 
         && (   !hi.colorjabbed( ha.card(i).color() )
             || hi.jabbedbyownteam( ha.card(i).color() ) 
             || allmyteam 
            )
        )
      {
        c=ha.card(i);
        break;
      }

      if ( ha.card(i).istrump() )
      {

        // find lowest trump
        if( (    hi.lowest_trump_card_limit().less( ha.card(i) ) 
             || t.islastcard() 
             || allmyteam
            )
           && ha.card(i).less( c )
          )
        {

          c = ha.card(i);
          continue;
        }

      }// if card istrump
    } // if winneris
  } // for ( i < ha.cardsnumber() )


  // if last card or first_color_run of trick let's check for a better card
  // Ace, ten, king, nine

  if(   t.islastcard() 
     || allmyteam
     ||(    !t.isstartcard()
        && !t.startcard().istrump()
        && hi.color_runs(t.startcard().color()) < 1
        && (   t.startcard().color()!= Card::HEART
            || !HandCard( hi.hand(), Card::HEART, Card::TEN ).isdolle() 
           )                   
       )
    )
  {

    for( i = 0; i < ha.cardsnumber(); i++ )
    {
      if(   t.isvalid( ha.card( i ), hi.hand() )
         && t.is_jabbed(ha.card(i))
        )
      {

        // ace is always the best card 
        if(  !ha.card(i).isswine() 
           && ha.card(i).value()==Card::ACE 
           && (    allmyteam 
               || !ha.card( i ).istrump() 
               || t.islastcard()
              )
          )
        {          
          c = ha.card(i);
          break;
        } 

        if(   ha.card(i).value() == Card::TEN 
           && !ha.card(i).isdolle() 
           && (     t.islastcard() 
               || allmyteam 
               || (  hi.color_runs( t.startcard().color() ) == 0 
                   && !t.startcard().istrump() 
                  )
              )
          )
        {
          c = ha.card(i);
          if ( t.islastcard() 
              || allmyteam )
            break;
          continue;
        }

        if(   ha.card( i ).value() != v 
           && ha.card( i ).value() < Card::TEN )
        {
          c = ha.card(i);
          continue;
        }

      } // if( t.isvalid( ha.card( i ), hi.hand() ) && t.is_jabbed(ha.card(i))
    } // for (i < ha.cardsnumber())
  } // if ( t.islastcard() || allmyteam || ... )


  return c;
} // Card Heuristics::best_winning_card_single_picture(Trick t, Card::Value v, HeuristicInterface hi, unsigned pointmodi)


/**
 ** finds best card on Hand of hi, which wins this trick, 
 ** non trump ace or lowest trump
 ** greater than jack, only in lastcard lower trumps are allowed
 ** the card will be chosen taking the value of the trick in account
 **
 ** @param     trick     trick to check
 ** @param     v1        value of the first card
 ** @param     v2        value of the second card
 ** @param     hi        heuristic interface
 ** @param     pointmodi point modifikator to add to points of t
 **
 ** @return    the card to play ( or 'Card()' if no card was found )
 **
 ** @author    Borg Enders
 **
 ** @version   Beta
 **/
Card 
Heuristics::best_winning_card_double_picture( 
                                             Trick const& t, Card::Value v1, Card::Value v2, 
                                             HeuristicInterface const& hi, unsigned pointmodi )
{
  // @heuristic::name   ?  best winning card double picture  ?
  // @heuristic::idea   Only valid for soli with only tow picutes as trump: Tries to find the best card to win a trick depending on different values like Aiconfig::LIMITQUEEN    

  if ( t.isstartcard() ) 
    return Card::EMPTY;

  Trick tr;
  Card c;
  HandCards const ha = hi.hand().validcards(t);
  unsigned i;

  bool allmyteam = checkAllMyTeam( t, hi );;


  // find any card that wins this trick greater or equal to lowest_trump_card_limit
  for( i = 0; i < ha.cardsnumber(); i++ )
  {
    tr = t;
    tr += ha.card(i);
    if(   tr.winnerplayer().no() == hi.no() 
       && t.isvalid( ha.card(i),hi.hand() )  
       && (   hi.lowest_trump_card_limit().less( ha.card(i) ) 
           || allmyteam 
          )
      )
    {
      c = ha.card(i);
      break;
    }
  } // for ( i < ha.cardsnumber() )

  // if can't win this trick and I'am not the last player: that's it
  if (c.is_empty() && !t.islastcard() )
    return Card::EMPTY;

  bool trumpintrick = trumpInTrick( t );


  // or this is a color trick of a first color run with my card the first trump
  allmyteam =    allmyteam 
    ||(   t.actcardno() > 1
       && hi.color_runs(t.startcard().color()) == 0
       && !t.startcard().istrump() 
       && !trumpintrick 
      );

  // find a better card
  for ( i = 0; i < ha.cardsnumber(); i++ )
  {
    tr = t;
    tr += ha.card( i );
    if(   tr.winnerplayer().no() == hi.no() 
       && t.isvalid( ha.card(i),hi.hand() ) 
      )
    {
      // non trump ace is always the best choice if color is not already jabbed
      if(   ha.card(i).value() == Card::ACE 
         && !ha.card(i).istrump() 
         && (   !hi.colorjabbed( ha.card(i).color() )
             || hi.jabbedbyownteam(ha.card(i).color()) 
             || allmyteam
            )
        )
      {
        c = ha.card( i );
        break;
      } 

      if( ha.card(i).istrump() )
      {

        // find lowest trump
        if( (   hi.lowest_trump_card_limit().less( ha.card(i) ) 
             || t.islastcard() 
             || allmyteam 
            )
           && ha.card(i).less(c)
          )
        {
          c = ha.card(i);
          continue;
        }

      }// if card istrump

    } // if winneris
  } // for ( i < ha.cardsnumber() )

  // if last card or first_color_run of trick let's check for a better card
  // Ace, ten, king, nine
  if(   t.islastcard() 
     || allmyteam
     ||(   !t.isstartcard()
        && !t.startcard().istrump()
        && hi.color_runs(t.startcard().color())<1
        && (   t.startcard().color()!= Card::HEART
            || !HandCard( hi.hand(), Card::HEART, Card::TEN ).isdolle() 
           )
       )
    )
  {

    for( i = 0; i < ha.cardsnumber(); i++ )
    {
      tr = t;
      tr += ha.card(i);

      if(   tr.winnerplayer().no()==hi.no() 
         && t.isvalid(ha.card(i),hi.hand())
        )
      {
        // ace is always the best card 
        if(   !ha.card(i).isswine() 
           &&  ha.card(i).value()==Card::ACE 
           && (   allmyteam 
               || !ha.card(i).istrump() 
               || t.islastcard()
              )
          )
        {
          c = ha.card(i);
          break;
        } 

        if(   ha.card(i).value() == Card::TEN 
           && !ha.card(i).isdolle() 
           && (   t.islastcard() 
               || allmyteam 
               || (   hi.color_runs(t.startcard().color()) == 0 
                   && !t.startcard().istrump() 
                  )
              )
          )
        {
          c = ha.card(i);
          if ( t.islastcard() 
              || allmyteam )
            break;

          continue;
        }

        if(    ha.card(i).value() != v1 
           && ha.card(i).value() != v2 
           && ha.card(i).value() < Card::TEN )
        {        
          c = ha.card(i);             
          continue;
        }

      } // if (tr.winnerplayer().no()==hi.no() 
    } // for ( i < ha.cardsnumber() )
  } // if ( t.islastcard() || allmyteam || (....) )

  return c;
} // Card Heuristics::best_winning_card_double_picture( ... )


/**
 ** finds best card on Hand of hi, which wins this trick, 
 ** non trump ace or lowest trump
 ** greater than jack, only in lastcard lower trumps are allowed
 ** the card will be chosen taking the value of the trick in account
 **
 ** @param     trick     trick to check
 ** @param     hi        heuristic interface
 ** @param     pointmodi point modifikator to add to points of t
 **
 ** @return    the card to play ( or 'Card()' if no card was found )
 **
 ** @author    Borg Enders
 **
 ** @version   Beta
 **/
Card 
Heuristics::best_winning_card_triple_picture( Trick const& t, 
                                             HeuristicInterface const& hi, unsigned pointmodi )
{
  // @heuristic::name   ?  best winning card triple picture  ?
  // @heuristic::idea Only valid for soli with only three pictures as trump: Tries to find the best card to win a trick depending on different values like Aiconfig::LIMITQUEEN    

  if ( t.isstartcard() ) 
    return Card::EMPTY;

  Trick tr;
  Card c;
  HandCards const ha = hi.hand().validcards( t );
  unsigned i;

  bool allmyteam = checkAllMyTeam( t, hi );;

  // find any card that wins this trick greater or equal to lowest_trump_card_limit
  for( i = 0; i < ha.cardsnumber(); i++ )
  {
    tr = t;
    tr += ha.card( i );

    if(   tr.winnerplayer().no() == hi.no() 
       && t.isvalid( ha.card(i), hi.hand() )  
       && (  hi.lowest_trump_card_limit().less( ha.card(i) ) 
           || allmyteam 
          )
      )
    {
      c = ha.card(i);
      break;
    }
  } // for ( i < ha.cardsnumber() )
  // if can't win this trick and I'am not the last player: that's it
  if( c.is_empty() && !t.islastcard() )  
    return Card::EMPTY;

  bool trumpintrick = trumpInTrick( t );

  // or this is a color trick of a first color run with my card the first trump
  allmyteam =    allmyteam 
    || (   t.actcardno() > 1
        && hi.color_runs(t.startcard().color()) == 0
        && !t.startcard().istrump()
        && !trumpintrick 
       );

  // find a better card

  for( i = 0; i < ha.cardsnumber(); i++ )
  {
    tr = t;
    tr += ha.card(i);
    if(   tr.winnerplayer().no() == hi.no() 
       && t.isvalid( ha.card( i ), hi.hand() ) )
    {
      // non trump ace is always the best choice if color is not already jabbed
      if(   ha.card(i).value() == Card::ACE 
         && !ha.card(i).istrump() 
         && (   !hi.colorjabbed( ha.card( i ).color() )
             || hi.jabbedbyownteam( ha.card( i ).color() ) 
             || allmyteam
            )
        )
      {
        c = ha.card( i );
        break;
      } 

      if( ha.card(i).istrump() )
      {

        // find lowest trump
        if( (   hi.lowest_trump_card_limit().less( ha.card(i) ) 
             || t.islastcard() 
             || allmyteam )
           && ha.card(i).less(c) )
        {

          c = ha.card( i );
          continue;
        }

      }// if card istrump

    } // if winneris
  } // for ( i < ha.cardsnumber() )



  // if last card or first_color_run of trick let's check for a better card
  // Ace, ten, king, nine
  if(   t.islastcard() 
     || allmyteam
     ||(   !t.isstartcard()
        && !t.startcard().istrump()
        && hi.color_runs( t.startcard().color() ) < 1
        && (   t.startcard().color()!= Card::HEART 
            || !HandCard( hi.hand(), Card::HEART, Card::TEN ).isdolle() 
           )
       )
    )
  {

    for( i = 0; i < ha.cardsnumber(); i++ )
    {
      tr = t;
      tr += ha.card( i );

      if(   tr.winnerplayer().no() == hi.no() 
         && t.isvalid( ha.card( i ), hi.hand() ) )
      {

        // ace is always the best card 
        if(   !ha.card(i).isswine() 
           && ha.card(i).value() == Card::ACE 
           && (   allmyteam 
               || !ha.card(i).istrump() 
               || t.islastcard()
              )
          )
        {
          c = ha.card(i);
          break;
        }

        if(    ha.card(i).value() == Card::TEN 
           && !ha.card(i).isdolle() 
           && (   t.islastcard() 
               || allmyteam 
               || (   hi.color_runs( t.startcard().color()) == 0 
                   && !t.startcard().istrump() 
                  )
              )
          )
        {
          c = ha.card( i );
          if ( t.islastcard() 
              || allmyteam )
            break;
          continue;
        }

        if( ha.card(i).value() == Card::NINE )
        {
          c = ha.card(i);
          continue;
        }
      } // if ( tr.winnerplayer().no() == hi.no() && t.isvalid( ... ) )
    } // for ( i < ha.cardsnumber() )
  } // if ( t.islastcard() || allmyteam || ( ...... ) )

  return c;
} // Card Heuristics::best_winning_card_triple_picture( Trick t, HeuristicInterface hi, unsigned pointmodi )


/**
 ** finds best card on Hand of hi, which wins this trick, 
 ** non trump ace or lowest trump
 ** greater than jack, only in lastcard lower trumps are allowed
 ** the card will be chosen taking the value of the trick in account
 **
 ** @param     trick     trick to check
 ** @param     hi        heuristic interface
 ** @param     pointmodi point modifikator to add to points of t
 **
 ** @return    the card to play ( or 'Card()' if no card was found )
 **
 ** @author    Borg Enders
 **
 ** @version   Beta
 **/
Card 
Heuristics::best_winning_card(Trick const& t, HeuristicInterface const& hi,
                              unsigned pointmodi )
{
  // @heuristic::name   best winning card
  // @heuristic::idea   Tries to find the best card to win a trick depending on different values like Aiconfig::LIMITQUEEN    


  switch (hi.game().type()) {
  case GAMETYPE::SOLO_JACK:
    return best_winning_card_single_picture( t, Card::JACK, hi, pointmodi );
  case GAMETYPE::SOLO_QUEEN:
    return best_winning_card_single_picture( t, Card::QUEEN, hi, pointmodi);
  case GAMETYPE::SOLO_KING: 
    return best_winning_card_single_picture( t, Card::KING, hi, pointmodi);
  case GAMETYPE::SOLO_QUEEN_JACK:
    return best_winning_card_double_picture( t, Card::JACK, Card::QUEEN, hi, pointmodi);
  case GAMETYPE::SOLO_KING_JACK:
    return best_winning_card_double_picture( t, Card::JACK, Card::KING, hi, pointmodi);
  case GAMETYPE::SOLO_KING_QUEEN:
    return best_winning_card_double_picture( t, Card::KING, Card::QUEEN, hi, pointmodi);
  case GAMETYPE::SOLO_KOEHLER: 
    return best_winning_card_triple_picture( t, hi, pointmodi);
  default:
    break;
  } // switch (hi.game().type()) 


  if( t.isstartcard() ) 
    return Card::EMPTY;
    

    


  HandCard c( hi.hand() );
  HandCards const ha = hi.hand().validcards( t );
  unsigned i;
  Game const& game = t.game();

  bool allmyteam = checkAllMyTeam(t, hi);

  unsigned tpoints = t.points() + pointmodi + (t.remainingcardno()-1)*1;


  bool trickLost = t.winnercard().less(highest_opposite_card_behind(t, hi));

  if( !trickLost || allmyteam ) {
    // take lowest trump which takes this trick
    for( i = 0; i < ha.cardsnumber(); i++ ) {
      HandCard const& card = ha.card(i);

      if (!t.is_jabbed(card))
        continue; 
      if( (   c.is_empty()
           || card.value() < c.value() 
           || ( card.value() == c.value() 
               && card.less( c ) )
          )
        )
      {
        if (card.is_special()) {
          if ( tpoints >= hi.value( Aiconfig::LIMITDOLLE ) )
            c = card;
        } else {
          c = card;
        }
      }

    } // for (i < ha.cardsnumber())

    if (!c.is_empty()) {
      // improve the card: take the low trumps in the order ace, ten, king, nine
      if (game.trumpcolor() != Card::NOCARDCOLOR) {
        if (c.istrump()) {
          list<Card> cards;
          cards.push_back(Card(game.trumpcolor(), Card::ACE));
          cards.push_back(Card(game.trumpcolor(), Card::TEN));
          cards.push_back(Card(game.trumpcolor(), Card::KING));
          if (hi.game().rule()(Rule::WITH_NINES))
            cards.push_back(Card(game.trumpcolor(), Card::NINE));
          for (list<Card>::const_iterator c = cards.begin();
               c != cards.end();
               ++c) {
            if (!HandCard(hi.hand(), *c).is_special())
              if (hi.hand().contains(*c)
                  && t.is_jabbed(*c)) {
                return *c;
              }
          } // for (c)

        } // if c.istrump())
      } // if (game.trumpcolor() != Card::NOCARDCOLOR)
      return c;

    } // if (!c.is_empty())

  } // if( !trickLost || allmyteam )
  


  // find any card that wins this trick greater or equal to lowest_trump_card_limit
  for( i = 0; i < ha.cardsnumber(); i++ ) {
    HandCard const& card = ha.card(i);

    if (!t.is_jabbed(card))
      continue;

    if (!(   hi.lowest_trump_card_limit().less(card) 
          || allmyteam) )
      continue;

    if(   (card.value() == Card::QUEEN )
       && (tpoints >= hi.value(Aiconfig::LIMITQUEEN))
      )
    {
      c = card;
      if (!t.islastcard())
      {
        break;
      }
    }
    if( card.value() == Card::QUEEN )
      continue;

    if(  (   card.isdolle() 
          || card.possible_swine() 
          || card.possible_hyperswine()
         )
       && tpoints >= hi.value( Aiconfig::LIMITDOLLE )
      )
    {
      c = card;
      if (!t.islastcard())
      {
        break;
      }
    }

    if(   card.isdolle() 
       || card.possible_swine() 
       || card.possible_hyperswine() )
      continue;

    c = card;
    break;
  } // for(i)



  // if can't win this trick and I'am not the last player: that's it
  if(   c.is_empty()
     && !t.islastcard() )  
    return Card::EMPTY;
    


  bool trumpintrick = trumpInTrick( t );

  // or this is a color trick of a first color run with my card the first trump
  allmyteam =   allmyteam 
    ||(   t.actcardno() > 1
       && hi.color_runs(t.startcard().color()) == 0
       && !t.startcard().istrump() 
       && !trumpintrick 
       && (   t.startcard().color()!= Card::HEART 
           || !HandCard(hi.hand(), Card::HEART, Card::TEN ).isdolle() 
          )
      );


  // find a better card
  for( i = 0; i < ha.cardsnumber(); i++ ) {
    HandCard const& card = ha.card(i);

    if (!t.is_jabbed(card))
      continue;

    // non trump ace is always the best choice if color is not already jabbed
    if(   card.value() == Card::ACE 
       && !card.istrump() 
       && (   !hi.colorjabbed( card.color() )
           || hi.jabbedbyownteam( card.color() ) 
           || allmyteam
          )
      )
    {
      c = card;

      break;
    } 

    if( card.istrump() )
    {
      // find lowest trump
      if(     t.islastcard()
         && card.less(Card(Card::DIAMOND, Card::JACK))
         && card.less( c ) 
        )
      { 
        c = card;

        continue;
      }

      if (!card.less(Card(Card::DIAMOND, Card::JACK)))
      {
        if(   !t.isstartcard() 
           && card.less(Card(Card::DIAMOND, Card::QUEEN))
           && !t.startcard().istrump()
           && card.less( c ) 
           && (   !hi.colorjabbed( t.startcard().color() )
               || tpoints <= hi.value( Aiconfig::LIMITQUEEN )
               || ha.numberof( Card::QUEEN ) < 2
               || t.islastcard()
              )
          )
        {
          c = card;


          continue;
        }
        if(    (card.value() == Card::QUEEN)
           && (tpoints >= hi.value( Aiconfig::LIMITQUEEN ) )
           && (  (    c.less(Card(Card::DIAMOND, Card::QUEEN))
                  && !t.islastcard()
                  && (    hi.color_runs( t.startcard().color() ) != 0 
                      || (   hi.color_runs( t.startcard().color() ) == 0 
                          && hi.game().type() == GAMETYPE::POVERTY 
                         )
                      || t.startcard().istrump()
                      || tpoints > hi.value( Aiconfig::LIMITDOLLE ) 
                     )     
                 )
               || (    card.less( c ) 
                   &&  !(    c == Card( Card::CLUB, Card::QUEEN )
                         && (hi.game().teaminfo( hi.no() ) == TEAM::UNKNOWN)
                        )
                  )
               || ( (card == Card( Card::CLUB, Card::QUEEN ))
                   && (hi.game().teaminfo( hi.no() ) == TEAM::UNKNOWN)
                  )
              )
             )
             {

               if ( (hi.hand().numberofclubqueens() > 0) // club queen is as good as dolle
                   && !hi.game().second_dolle_over_first() )
               {
                 c = Card( Card::CLUB, Card::QUEEN );                   
               } else
                 c = card; 


               continue;
             }

        if(  
           (   card.isdolle() 
            || card.possible_swine() 
            || card.possible_hyperswine() 
           )
           && (   card.less(c) 
               || (   tpoints >= hi.value( Aiconfig::LIMITDOLLE ) 
                   && c.less(Card(Card::DIAMOND, Card::QUEEN))
                   && !hi.color_runs( t.startcard().color() ) < 1
                   && !t.islastcard()
                  )
              )
          ) 
        {

          if ( (hi.hand().numberofclubqueens() > 0) // club queen is as good as dolle
              && !hi.game().second_dolle_over_first()
              && card.isdolle() )
          {
            c = Card( Card::CLUB, Card::QUEEN );                   
          } else
            c = card; 



          continue;
        }
      }//if card>jack
    }// if card istrump

  } // if winneris




  if (c.is_empty())
    return Card::EMPTY;
    


  Trick tempTrick = t;
  tempTrick += c;

  //if opposite team can win trick no further optimization

  if (    oppositeTeamCanWinTrick( tempTrick, hi ) 
      && !t.islastcard()
      && !hi.color_runs(t.startcard().color()) == 0 )
  {
    // make it as hard as possible with selected trump type
    if( c.value() ==Card::JACK || c.value() == Card::QUEEN )
      c = highest_card( hi.hand(), c.value(), hi );

    return c;
  }



  bool onlyPovertyPlayer = true;
  for( unsigned i = t.actcardno() + 1; i < hi.game().playerno(); i++ )
    onlyPovertyPlayer = (   onlyPovertyPlayer
                         &&  (   hi.game().type() == GAMETYPE::POVERTY
                              && t.player_of_card( i ) == hi.game().soloplayer() 
                             )); /// @todo poverty partner has no trumps


  // if last card or first_color_run of trick let's check for a better card
  // Ace, ten, king, nine
  if(   t.islastcard()
     || allmyteam
     || onlyPovertyPlayer
     ||(   !t.isstartcard()
        && !t.startcard().istrump()
        && hi.color_runs( t.startcard().color() ) < 1
        && (   t.startcard().color() != Card::HEART
            || !HandCard( hi.hand(), Card::HEART, Card::TEN ).isdolle() 
           ) 
       )
    )
  {

    for( i = 0; i < ha.cardsnumber(); i++ ) {
      HandCard const& card = ha.card(i);


      if (!t.is_jabbed(card))
        continue;

      // Maybe it's time to get the heart ten back home
      if(   card.isdolle() 
         &&(   (  hi.hand().numberoftrumps() < 5
                &&  hi.game().tricks_remaining_no() < 7
                &&  hi.hand().numberof( Card::DOLLE ) == 1
                &&  hi.game().rule()(Rule::EXTRAPOINT_DOLLE_JABS_DOLLE) 
                &&  !hi.cards_information().played(Card::DOLLE)
               )
            || (   hi.hand().numberoftrumps()  < 6
                &&  hi.game().tricks_remaining_no() < 8
                && hi.game().swines_owner() != NULL 
                && hi.teamofplayer( *hi.game().swines_owner() ) != hi.team() 
               )
            || (    hi.hand().numberoftrumps() < 6
                &&  hi.game().tricks_remaining_no()  < 8 
                && hi.game().hyperswines_owner() != NULL 
                && hi.teamofplayer( *hi.game().hyperswines_owner() ) != hi.team() 
               )
           )
        )
      {
        c = card;

        break;
      }

      // ace is always the best card 
      if(   !card.possible_swine()
         && card.value() == Card::ACE
         && (    allmyteam 
             || !card.istrump() 
             || t.islastcard()
            )
        )
      {
        c = card;

        break;
      } 

      if(    card.value() == Card::TEN 
         && !card.isdolle() 
         && c.value() != Card::ACE
         && (   t.islastcard() 
             || allmyteam 
             || (   hi.color_runs( t.startcard().color() ) == 0
                 && hi.game().type() != GAMETYPE::POVERTY 
                 && !t.startcard().istrump() 
                )
            )
        )
      {
        c = card;

        continue;
      }

      if(   card.value() == Card::KING
         && game.type() != GAMETYPE::SOLO_KOEHLER
         && !card.possible_hyperswine()
        )
      {
        if( c.value()!=Card::TEN || c.isdolle() )
        {
          c = card;

        }
        continue;
      }
      if(   card.value() == Card::NINE 
         && !card.possible_hyperswine() )
      {
        if(  (   c.value() != Card::TEN
              && c.value() != Card::KING 
              && c.value() != Card::ACE
              && better_points_optimize( c, card, hi )
             )
           || c.isdolle()
           || c.possible_hyperswine()
          )
        {
          c = card;

        }
        continue;
      }


      if(   c.istrump() 
         && card.istrump() 
         && card.less(c) 

        )
      {
        if(  (   c.value() != Card::TEN
              && c.value() != Card::KING 
              && c.value() != Card::ACE 
              && better_points_optimize( c, card, hi )
              && !(   (c == Card( Card::CLUB, Card::QUEEN ))
                   && (hi.game().teaminfo(hi.no()) == TEAM::UNKNOWN)
                   && !(hi.game().type() == GAMETYPE::MARRIAGE_SILENT))
             )
           || c.isdolle() 
           || c.possible_hyperswine() 
          )
        { 
          c = card;

        }
        continue;
      }
    } // for (i)
  } // if (last card or first color run)


  return c;
} // Card Heuristics::best_winning_card(Trick t, HeuristicInformation hi, unsigned pointmodi)


/**
 ** finds lowest color card on Hand h, wihich is the best in a meatless solo 
 **
 ** @param     trick     trick to check
 ** @param     h         hand to choose the card from
 **
 ** @return    the card to play ( or 'Card()' if no card was found )
 **
 ** @author    Borg Enders
 **
 ** @version   Beta
 **/
Card 
lowest_color_card_meatless( Trick const& t, Hand h )
{
  Card c;
  HandCards const ha = h.validcards( t );
  unsigned i;

  // find any card that's allowed for this trick
  for( i = 0; i < ha.cardsnumber(); i++ )
  {
    if( !ha.card( i ).istrump() )
    {
      c = ha.card( i );
      break;
    }
  } // for ( i < ha.cardsnumber() )

  if (c.is_empty())
    return Card::EMPTY;

  // find a better card
  for( i = 0; i < ha.cardsnumber(); i++ )
  {
    if(   !ha.card( i ).istrump()
       && c.value() <= ha.card(i).value()
       && (   ha.numberof( ha.card(i).color() ) >  ha.numberof( c.color() ) 
           || (   ha.numberof( ha.card(i).color(), Card::TEN ) == 0 
               && ha.numberof( ha.card(i).color(), Card::ACE ) == 0 
              )
          )
      )
      c = ha.card(i);
  } // for ( i < ha.cardsnumber() )

  return c;
} // Card lowest_color_card_meatless( Trick t, Hand h )


/**
 ** finds lowest trump card on Hand h
 **
 ** @param     trick     trick to check
 ** @param     h         hand to choose the card from
 **
 ** @return    the card to play ( or 'Card()' if no card was found )
 **
 ** @author    Borg Enders
 **
 ** @version   Beta
 **/
Card 
lowest_trump_card( Trick const& t, Hand h )
{
  Card c;
  HandCards const ha = h.validcards( t );
  unsigned i;

  // find any card that's allowed for this trick
  for( i = 0; i < ha.cardsnumber(); i++ )
  {
    if( ha.card( i ).istrump() )
    {
      c = ha.card( i );
      break;
    }
  } // for ( i < ha.cardsnumber() )

  if (c.is_empty())
    return Card::EMPTY;

  // find a better card
  for( i = 0; i < ha.cardsnumber(); i++ )
  {
    if(   ha.card(i).less( c ) 
       && ha.card(i).istrump()
      )
      c = ha.card( i );
  } // for ( i < ha.cardsnumber() )

  return c;
} // Card lowest_trump_card( Trick t, Hand h )


/**
 ** finds highest trump card on Hand h
 **
 ** @param     trick     trick to check
 ** @param     h         hand to choose the card from
 **
 ** @return    the card to play ( or 'Card()' if no card was found )
 **
 ** @author    Borg Enders
 **
 ** @version   Beta
 **/
Card 
highest_trump_card( Trick const& t, Hand h )
{
  Card c;
  HandCards const ha = h.validcards( t );
  unsigned i;

  // find any card that's allowed for this trick
  for( i = 0; i < ha.cardsnumber(); i++ )
  {
    if( ha.card( i ).istrump() )
    {
      c = ha.card( i );
      break;
    }
  } // for ( i < ha.cardsnumber() )

  if (c.is_empty())
    return Card::EMPTY;

  // find a better card
  for( i = 0; i < ha.cardsnumber(); i++ )
  {
    if(   c.less( ha.card(i) ) 
       && ha.card(i).istrump()
      )
      c = ha.card( i );
  } // for ( i < ha.cardsnumber() )

  return c;
} // Card highest_trump_card( Trick t, Hand h )


/**
 ** finds lowest trump card on Hand h, but gives only fuchs or ten back
 ** if there are better cards to keep
 **
 ** @param     trick     trick to check
 ** @param     h         hand to choose the card from
 ** @param     hi        heuristic interface
 **
 ** @return    the card to play ( or 'Card()' if no card was found )
 **
 ** @author    Borg Enders
 **
 ** @version   Beta
 **/
Card 
Heuristics::lowest_best_trump_card( Trick const& t, Hand const& h, 
                                   HeuristicInterface const& hi )
{
  // @heuristic::name   ?  lowest best trump  ?
  // @heuristic::idea   find smallest best trump card (avoiding for example a fox in most situations)        

  HandCard c( h );
  HandCards const ha = hi.hand().validcards( t );
  unsigned i;

  // find any card that's allowed for this trick
  for( i = 0; i < ha.cardsnumber(); i++ )
  {
    if ( ha.card( i ).istrump() )
    {
      c = ha.card( i );
      break;
    }
  } // for( i < ha.cardsnumber() )

  if (c.is_empty())
    return Card::EMPTY;

  // find a better card
  for( i = 0; i < ha.cardsnumber(); i++ )
  {
    if(   ha.card( i ).less( c ) 
       && ha.card( i ).istrump() 
       && !ha.card( i ).isfox() 
       && (   ha.card(i).value() != Card::TEN 
           || c.isfox()
          )
      )
      c = ha.card( i );
  } // for( i = 0; i < ha.cardsnumber(); i++ )

  if( !c.less( hi.trump_card_limit() ) )
    // maybe a diamond ten isn't all that bad
  {
    for( i = 0; i < ha.cardsnumber(); i++ )
    {
      if(   ha.card( i ).less( c ) 
         && ha.card( i ).istrump() 
         && !ha.card( i ).isfox()
        )
        c = ha.card( i );
    }
  } // if( !c.less( hi.trump_card_limit() ) )

  if( !c.less( hi.trump_card_limit() ) )
    // maybe a diamond Ace isn't all that bad
  {
    for( i = 0; i < ha.cardsnumber(); i++ )
    {
      if(   ha.card( i ).less( c ) 
         && ha.card(i).istrump()
        )
        c = ha.card( i );
    }
  } // if( !c.less( hi.trump_card_limit() ) )

  return c;
} // Card Heuristics::lowest_best_trump_card( Trick t, Hand h, HeuristicInterface hi )


/**
 ** best pfund on hand: a trump Ass, color ten or Ace, trump ten, a king,
 ** a notrump queen or jack, nine
 **
 ** @param     trick     trick to check
 ** @param     hi        heuristic interface
 **
 ** @return    the card to play ( or 'Card()' if no card was found )
 **
 ** @author    Borg Enders
 **
 ** @version   Beta
 **/
Card 
Heuristics::choose_pfund_card( Trick const& trick, HeuristicInterface const& hi )
{
  // @heuristic::name   ?  choose pfund card  ?
  // @heuristic::idea   find a pfund card

  Trick t = trick;

  DEBUG_ASSERTION( !t.isempty(),
                  "Heuristics::choose_pfund_card():\n"
                  "  Called with empty trick");

  unsigned i;

  bool allmyteam = checkAllMyTeam( t, hi );
  if (t.startcard().istrump()) {
    allmyteam = allmyteam && ownTeamCanWinTrick(t, hi);
  } else { // if !(t.startcard().istrump())
    allmyteam = allmyteam && hi.jabbedbyownteam( t.startcard().color() );
  } // if !(t.startcard().istrump())

  allmyteam =    allmyteam 
    || (   hi.game().type() == GAMETYPE::POVERTY
        && hi.no() == hi.game().soloplayer().no()
        && trick.cardno_of_player(hi.game().poverty_partner()) == 3 );

  // marriage determination for the bride
  if (   (hi.game().type() == GAMETYPE::MARRIAGE)
      && is_selector(t.startcard().tcolor(),
                     hi.game().marriage_selector())
      && (hi.no() == hi.game().soloplayer().no()) )
    allmyteam = true;

  Card c;

  HandCards const ha = hi.hand().validcards( t );

  bool solo_check = 
    (   GAMETYPE::is_solo( hi.game().type() )
     && hi.color_runs(t.startcard().color()) == 0
     && !t.startcard().istrump()
     && t.winnerplayer() == hi.game().soloplayer()
     && t.winnercard().less( hi.trump_card_limit() )
     && !t.islastcard() ) ;

  if( !(   hi.teamofplayer( t.winnerplayer() )== hi.team()
        && t.islastcard()
        && t.cardno_of_player( t.winnerplayer() ) == 0
        && !t.winnercard().istrump() ) ) //only use trump ace when partner is not winning already in first position
  {
    // then find first trump ace
    for( i = 0; i < ha.cardsnumber(); i++ ) {
      if(   ha.card(i).value() == Card::ACE 
         && ha.card(i).istrump() 
         && (   t.islastcard() 
             || allmyteam
             || ha.numberoftrumps() < 3 
             || (   hi.color_runs(t.startcard().color()) == 0
                 && !t.startcard().istrump()
                )
             || (   ! hi.cards_information().higher_card_exists( t.winnercard())
                 //!t.winnercard().less( Card( Card::CLUB, Card::QUEEN ) )
                 && hi.teamofplayer( t.winnerplayer() )== hi.team()  
                )
             || (    hi.game().type() == GAMETYPE::MARRIAGE 
                 && hi.game().soloplayer().no() == hi.no()
                 && hi.game().marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET
                 && hi.game().marriage_selector() == MARRIAGE_SELECTOR::FIRST_FOREIGN 
                )  
            ) 
         && !ha.card(i).possible_swine()
        )
      {
        t += ha.card( i );
        if(   (   (hi.teamofplayer( t.winnerplayer() )== hi.team())
               && !(   hi.game().rule()(Rule::GENSCHER)
                    && (hi.game().type() == GAMETYPE::NORMAL)
                    && !hi.cards_information().played(Card(Card::DIAMOND,
                                                           Card::KING))
                    && (ha.numberoftrumps() >= 6) // *Value*
                   )
              )
           || (    hi.game().type() == GAMETYPE::MARRIAGE 
               && hi.game().soloplayer().no() == hi.no()
               && hi.game().marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET
               // ToDo: other marriage selectors
               && (hi.game().marriage_selector()
                   == MARRIAGE_SELECTOR::FIRST_FOREIGN )
              ) 
          )
        { 
          return ha.card(i);
        }
      }
    } // for (i < ha.cardsnumber)
  } // if partner is start player and with none trump card.


  Card best_ace;
  // choose an ace of a color if the player has two aces
  // or if there are not enough remaining color cards
  for( vector<Card::Color>::const_iterator
      color = hi.game().rule().card_colors().begin();
      color != hi.game().rule().card_colors().end();
      ++color ) 
  {
    Card const local_ace( *color, Card::ACE );
    if(   (   hi.hand().numberof( local_ace )
           == hi.game().rule()(Rule::NUMBER_OF_SAME_CARDS)
           || (    hi.hand().numberof(local_ace) == 1
               && (  (   (hi.cards_information().remaining_others(*color)
                          < hi.game().playerno() - 1)
                      && (hi.game().type() != GAMETYPE::SOLO_MEATLESS))
                   || (hi.hand().numberof(*color) == 1)
                  )
              ) )
       && !local_ace.istrump( hi.game() )
       && t.isvalid(local_ace, hi.hand())
       && (   hi.teamofplayer(t.winnerplayer()) == hi.team() 
           || solo_check 
           || allmyteam 
          ) 
      )
    {
      if(   best_ace.is_empty()
         || (hi.cards_information().remaining_others(*color)
             > hi.cards_information().remaining_others(best_ace.color()))
        )
        best_ace = local_ace;
    }
  } // for (color \in card_colors)

  if(!best_ace.is_empty())
  {
    return best_ace;
  }


  // or a ten of color
  for( i = 0; i < ha.cardsnumber(); i++ )
    if(   ha.card(i).value() == Card::TEN
       && !ha.card(i).istrump()
       && t.isvalid( ha.card( i ),hi.hand() )
       && (   hi.teamofplayer(t.winnerplayer()) == hi.team() 
           || solo_check 
           || allmyteam 
          ) 
      )
    {            
      return ha.card(i);
    }


  bool to_fat_solo =    GAMETYPE::is_solo( hi.game().type() ) 
    && t.points() > hi.value( Aiconfig::LIMITQUEEN )
    && t.player_of_card( 3 ) == hi.game().soloplayer(); 
  // or a Ace of color  
  for( i = 0; i < ha.cardsnumber(); i++ ) {
    int cardsInGame
      = hi.cards_information().remaining_others(ha.card(i).color());

    if(   (ha.card(i) == Card(t.startcard().color(), Card::ACE))
       && (hi.color_runs(ha.card(i).color()) == 0)
       && (hi.hand().numberof(t.startcard().color()) >= 3)
       && !ha.card(i).istrump()
       /// @todo   see 'choose pfund', check that enough cards still remain
       && (   cardsInGame >= 2 
           || ( hi.game().type() == GAMETYPE::POVERTY && hi.no() == hi.game().soloplayer().no() )
          )
       && (   hi.teamofplayer(t.winnerplayer()) == hi.team() 
           || solo_check 
           || allmyteam 
          ) 
      )
      return ha.card(i);

    if(   ha.card(i).value()==Card::ACE
       && (  hi.color_runs(ha.card(i).color()) > 0  
           || (   t.winnercard().istrump() 
               && allmyteam )
          )
       && cardsInGame >= 2 
       && !ha.card(i).istrump() 
       && t.isvalid( ha.card(i),hi.hand() )
       && !to_fat_solo
       && (   (   hi.game().type()!=GAMETYPE::SOLO_JACK // with not much trumps
               && hi.game().type()!=GAMETYPE::SOLO_QUEEN // it is good to
               && hi.game().type()!=GAMETYPE::SOLO_KING  // keep a second ace
              )
           || hi.color_runs(t.startcard().color()) > 0 
          )
      )
    {
      return ha.card(i);
    }
  } // for ( i < ha.cardsnumber() )


  // or a ten of trump
  for( i = 0; i < ha.cardsnumber(); i++ )
    if(   ha.card(i).value() == Card::TEN 
       && ha.card(i).istrump() 
       && !ha.card(i).isdolle()
      )
    {
      return ha.card(i);
    }


  // or a King of color
  for ( i = 0; i < ha.cardsnumber(); i++ )
    if(   ha.card(i).value() == Card::KING 
       && !ha.card(i).istrump()
      )
    {
      return ha.card(i);
    }


  // or a king of trump
  for( i = 0; i < ha.cardsnumber(); i++ )
    if(    ha.card(i).value() == Card::KING
       && !ha.card(i).ishyperswine()
       && ha.card(i).istrump()
       && hi.game().type() != GAMETYPE::SOLO_KING 
       && hi.game().type() != GAMETYPE::SOLO_KING_QUEEN
       && hi.game().type() != GAMETYPE::SOLO_KING_JACK
       && hi.game().type() != GAMETYPE::SOLO_KOEHLER
      )
    {
      return ha.card(i);
    }


  // or Queen if no trump
  for ( i = 0; i < ha.cardsnumber(); i++ )
    if(    ha.card(i).value()==Card::QUEEN 
       && !ha.card(i).istrump()
       && hi.game().type() != GAMETYPE::SOLO_QUEEN 
       && hi.game().type() != GAMETYPE::SOLO_KING_QUEEN
       && hi.game().type() != GAMETYPE::SOLO_QUEEN_JACK
       && hi.game().type() != GAMETYPE::SOLO_KOEHLER
      )
    {
      return ha.card(i);
    }


  // or Jack if no trump
  for( i = 0; i < ha.cardsnumber(); i++ )
    if(   ha.card(i).value() == Card::JACK 
       && !ha.card(i).istrump()
       && hi.game().type() != GAMETYPE::SOLO_JACK 
       && hi.game().type() != GAMETYPE::SOLO_QUEEN_JACK
       && hi.game().type() != GAMETYPE::SOLO_KING_JACK
       && hi.game().type() != GAMETYPE::SOLO_KOEHLER
      )
    {
      return ha.card(i);
    }


  // or a nine of color
  for( i = 0; i < ha.cardsnumber(); i++ )
    if(   ha.card(i).value() == Card::NINE 
       && !ha.card(i).istrump()
      ) 
    {
      return ha.card(i);
    }


  // or a nine of trump
  for ( i = 0; i < ha.cardsnumber(); i++ )
    if(   ha.card(i).value() == Card::NINE 
       && ha.card(i).istrump() 
       && !ha.card(i).ishyperswine() 
      )
    {
      return ha.card(i);
    }


  return c;
} // Card Heuristics::choose_pfund_card( Trick trick, HeuristicInterface hi )


/**
 ** checks if a solo player sits behind the player
 **
 ** @param     t    trick
 ** @param     hi   heuristics interface
 **
 ** @return    whether the solo player sits behind
 **
 ** @author    Borg Enders
 **
 ** @version   0.7.5
 **/ 
bool 
soloPlayerBehind( Trick const& t, HeuristicInterface const& hi )
{
  if( GAMETYPE::is_solo( hi.game().type() ) )
    for( Player const* player = &( t.game().player_following( t.actplayer() ) );
        player != &t.startplayer();
        player = &(t.game().player_following(*player))
       )
      if( *player ==  hi.game().soloplayer () )   
        return true;

  return false;
} // bool soloPlayerBehind( Trick const& t, HeuristicInterface const& hi )


/**
 ** play a good card for the last card in one Trick with color, which
 ** hi doesn't have anymore,
 **
 ** if this trick is won by own team
 **   play a pfund
 ** if there are only color cards in this trick
 **   choose best_winning_card or if there is no lowest_color_card
 ** if there is already a trump try jab this trump with lowest possible
 **   trump, if there are more then a limit of points already in this trick
 **
 ** @param     trick     trick to check
 ** @param     hi        heuristic interface
 **
 ** @return    the card to play ( or 'Card()' if no card was found )
 **
 ** @author    Borg Enders
 **
 ** @version   Beta
 **/
Card 
Heuristics::choose_for_color_trick( Trick const& t,
                                   HeuristicInterface const& hi )
{
  // @heuristic::name   choose for color trick
  // @heuristic::idea   choose a card for a color trick either a pfund for the own team or a small card for the opponents

  if (soloPlayerBehind(t, hi))
    return Card::EMPTY;

  if (t.isempty())
    return Card::EMPTY;

  if (t.startcard().istrump())
    return Card::EMPTY;

  Game const& game = hi.game();

  HandCard c( hi.hand() );

  HandCards ha;

  bool allmyteam = (   checkAllMyTeam( t, hi )
                    && hi.jabbedbyownteam( t.startcard().color() )
                    && !t.islastcard());

  allmyteam = (   allmyteam 
               && (   hi.teamofplayer(t.winnerplayer())==hi.team()
                   || (   t.winnercard().less( hi.trump_card_limit() ) 
                       && t.winnercard().istrump() )
                  ) );

  if (!allmyteam) {
    // ToDo: if the partner has won the trick, check whether the opposite team can still get the trick
    for (unsigned i = t.actcardno() + 2; i < game.playerno(); ++i) {
      Player const& player = t.player_of_card(i);
      if (   (hi.teamofplayer(player) != hi.team())
          && (   (hi.handofplayer(player).existstcolor(t.startcard().tcolor())
                  && t.winnercard().less(hi.handofplayer(player).highest_card(t.startcard().tcolor())) )
              || (!hi.handofplayer(player).existstcolor(t.startcard().tcolor())
                  && hi.handofplayer(player).hastrump() ) ) ) {
        return Card::EMPTY;
      }
    } // for (i)
    // special case: poverty
    if (   (game.type() == GAMETYPE::POVERTY)
        && (hi.team() == TEAM::CONTRA)
        && !t.has_played(game.poverty_partner()) ) {
      return Card::EMPTY;
    }
  } // if (!allmyteam)


  // lets see if this is the last card for this trick
  // or the first run of this  color
  // and first card is no trump
  if ( (   t.islastcard() 
        || allmyteam 
        || (   !t.isstartcard() 
            && hi.color_runs(t.startcard().color()) == 0
           )
       )
      && !t.startcard().istrump()
     )
  {
    ha = hi.hand().validcards( t );

    // first check if this trick goes to my team
    bool pred = ( t.points() >= hi.value(Aiconfig::LIMITDOLLE)
                 ? hi.teamofplayer(t.winnerplayer()) == hi.team()
                 : maybe_to_team(hi.teamofplayer(t.winnerplayer())) == hi.team() );


    if( game.type()==GAMETYPE::MARRIAGE ) {
      if (::is_selector(t.startcard().tcolor(),
                        game.marriage_selector()) ) {
        pred = (hi.no() == game.soloplayer().no());
      } else { // if !(trick determines marriage)
        pred = hi.teamofplayer(t.winnerplayer()) == maybe_to_team( hi.team() );
      } // if !(trick determines marriage)
    }  // if (game.type() == GAMETYPE::MARRIAGE)

    pred = (   pred  
            && (    t.islastcard() 
                || (  (   t.winnercard().value() == Card::ACE
                       &&  hi.color_runs(t.startcard().color()) == 0  )
                    ||(   t.winnercard().istrump()
                       && !t.winnercard().less( hi.trump_card_limit() )
                      )
                   )

               ));

    pred = pred || allmyteam;

    if( game.type() == GAMETYPE::POVERTY ) {
      pred &=    (hi.no() == game.poverty_partner().no()) 
        && (  (   !game.rule()(Rule::DOLLEN) 
               || t.startcard().color() != Card::HEART)                      
            || allmyteam); 
    }

    if (   pred 
        || (   GAMETYPE::is_solo( game.type() )  
            && t.winnerplayer() != game.soloplayer() 
            &&  hi.color_runs(t.startcard().color()) == 0 
            &&  t.winnercard().less( hi.trump_card_limit() ) 
            &&  !t.islastcard() 
           ) 
       ) { 
      Card c = choose_best_fehl( t, hi, false );
      if(   !c.is_empty()
         && hi.hand().numberof( c.color() ) == 1
         && hi.color_runs( c.color() ) == 0 )
        return c;
      return choose_pfund_card( t, hi );
    } // if own Team gets this trick


    // if there are only color cards in this trick
    bool trumpintrick = trumpInTrick( t );

    if( !trumpintrick ) {
      c = best_winning_card( t, hi );

      if( !ha.existstcolor(t.startcard().color() ) ) {
        if(!c.is_empty())
        { 
          if( t.points() > hi.value( Aiconfig::LIMITDOLLE ) )
            return c;
          if(   t.points() > hi.value( Aiconfig::LIMITQUEEN )
             && (  !Card( Card::CLUB, Card::QUEEN ).less( c ) 
                 || t.islastcard() )
            )
            return c;

          if( !Card( Card::CLUB, Card::JACK ).less( c )
             || t.islastcard() )
            return c;

        } // if(!c.is_empty())

        return Card::EMPTY;

      } else if (!c.is_empty()) { // if( !ha.existstcolor(t.startcard().color() ) )

        return c;
      } else { // if (c.is_empty())
        GameType gt = game.type();


        if( gt != GAMETYPE::SOLO_MEATLESS )
        {

          if(   hi.color_runs(t.startcard().color()) == 0 
             && t.winnercard().value() != Card::ACE  
             && ha.numberof( t.startcard().color(), Card::ACE )  > 0 )
            return Card( t.startcard().color(), Card::ACE );


          if( hi.color_runs(t.startcard().color()) > 0) {
            return Heuristics::lowest_color_card(t.startcard().color(),
                                                 hi.hand());
          } else {
            return lowest_best_trump_card(t, hi.hand(), hi );
          }
        } else { // if( gt != GAMETYPE::SOLO_MEATLESS )
          return lowest_color_card_meatless( t, hi.hand() );
        } // if( gt == GAMETYPE::SOLO_MEATLESS )
      } // if (c.is_empty())


      return Card::EMPTY;
    }// there was no other trumps in trick
    else // there is a trump in this trick
    {
      // if there is already a trump try jab this trump with lowest possible trump,
      // and my partner doesn't already win this trick
      // if there are more then 10 points already in this trick


      if( maybe_to_team( hi.teamofplayer( t.winnerplayer() ) ) != hi.team() )
      {
        c = best_winning_card( t, hi );

        if( !c.is_empty() ) { 
          if( t.points() > hi.value( Aiconfig::LIMITDOLLE ) )
            return c;
          if(   t.points() > hi.value( Aiconfig::LIMITQUEEN )
             && !Card( Card::CLUB, Card::QUEEN ).less( c )
            )
            return c;
          if (t.points() < hi.value(Aiconfig::LIMIT_THROW_FEHL)) {
            Card const card = Heuristics::lowest_card(t, hi.hand());
            if (   (card.value() == Card::NINE)
                || (card.value() == Card::KING))
              if (better_points_optimize(c, HandCard(hi.hand(), card), hi))
                return card;
          } // if (t.points() < 5)
          if( !Card( Card::CLUB, Card::JACK ).less( c ) ) {
            return c;
          }

        } // if (!c.is_empty())
      } // if( maybe_to_team( hi.teamofplayer( t.winnerplayer() ) ) != hi.team() )

      return Card::EMPTY;
    } // else

  } // check if trick is valid for this heuristic


  return c;
} // Card Heuristics::choose_for_color_trick( Trick t, HeuristicInterface hi )


/**
 ** Play a color again when not jabbed or the own team has jabbed it
 **
 ** @param        trick        current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author       Borg Enders
 ** @author       Diether Knof
 **
 ** @version      0.7.2
 **/
Card
Heuristics::retry_color(Trick const& trick, HeuristicInterface const& hi)
{
  // @heuristic::name   retry color
  // @heuristic::idea   serve a color again, which was not jabbed or jabbed by the own team        
  if (!trick.isstartcard())
    return Card::EMPTY;

  for (vector<Card::Color>::const_iterator
       c = hi.game().rule().card_colors().begin();
       c != hi.game().rule().card_colors().end();
       ++c) {
    if (   (hi.color_runs(*c) == 0)
        || (hi.hand().numberof(*c) == 0))
      continue;

    if (   hi.colorjabbed(*c)
        && !hi.jabbedbyownteam(*c))
      continue;

    // check that the trick could get through
    if (hi.cards_information().played(*c)
        + (hi.game().playerno() - 1)
        + hi.hand().numberof(*c)
        > hi.game().numberof(*c))
      continue;


    if (   (hi.hand().numberof(Card(*c, Card::TEN)) > 0)
        && hi.jabbedbyownteam(*c)
        && (hi.teamofplayer(trick.lastplayer()) == hi.team()) )
      return Card(*c, Card::TEN);
    if (hi.hand().numberof(Card(*c, Card::NINE)) > 0)
      return Card(*c, Card::NINE);
    if (hi.hand().numberof(Card(*c, Card::KING)) > 0)
      return Card(*c, Card::KING);

  } // for (c \in valid card colors)

  return Card::EMPTY;
} // Card Heuristics::retry_color(Trick trick, HeuristicInterface hi)


/**
 ** Play a color the partner does not have
 ** prerequisites:
 **   1. it must be the first card in the trick
 **   2. the partner does not have the color
 **   3. the players behind the partner can have the color
 ** Then take the card with the greatest value in the shortest color
 **
 **
 ** @param        trick        current trick
 ** @param        hi        heuristic interface
 **
 ** @return        card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author        Diether Knof
 **
 ** @version        0.7.4
 **/
Card
Heuristics::play_color_for_partner(Trick const& trick,
                                   HeuristicInterface const& hi)
{
  // @heuristic::name   play color for partner
  // @heuristic::idea   play a color the partner does not have

  // @heuristic::condition   startplayer in the trick
  if (!trick.isstartcard())
    return Card::EMPTY;

  // best card so far to play
  Card best_card;
  // maximal remaining cards of the selected color
  unsigned max_remaining_cards_no = 0;

  for (vector<Card::Color>::const_iterator
       c = hi.game().rule().card_colors().begin();
       c != hi.game().rule().card_colors().end();
       ++c) {
    Card::Color const& color = *c;
    // test that the color is no trumpcolor
    if (color == hi.game().trumpcolor())
      continue;

    unsigned const remaining_cards_no
      = hi.cards_information().remaining_others(*c);
    // @heuristic::condition   there are at least as many remaining cards as the best so far
    if (remaining_cards_no < max_remaining_cards_no)
      continue;
    // @heuristic::condition   the partner is the last player
    // @heuristic::condition   or there are enough remaining cards for all opponents
    //                         (players - me - partner)
    if (   (::maybe_to_team(hi.teamofplayer(trick.lastplayer())) != hi.team())
        && (remaining_cards_no < hi.game().playerno() - 1 - 1) )
      continue;

    // @heuristic::condition   the partner does not have the color
    // @heuristic::condition   behind the partner all players have the color
    unsigned p;
    for (p = hi.game().playerno() - 1; p > trick.actcardno(); --p) {
      Player const& player = trick.player_of_card(p);
      bool const same_team
        = (::maybe_to_team(hi.teamofplayer(player)) == hi.team());
      if (   same_team
          == (hi.handofplayer(player).existstcolor(color))
         ) {
        p = trick.actcardno();
        break;
      } // if (partner has color or opponent has not the color)
      if (same_team) {
        break;
      }
    } // for (p \in cardno)
    if (p == trick.actcardno())
      continue;

    // search the card with the highest value
    HandCard const& card = hi.hand().highest_card(color);

    if (   best_card.is_empty()
        || (remaining_cards_no > max_remaining_cards_no)
        || (card.value() > best_card.value()) ) {
      best_card = card;
      max_remaining_cards_no = remaining_cards_no;
    } // if (found better card)
  } // for (c \in possible colors)

  // @heuristic::action   play the card with the highest value in the smallest color
  return best_card;
} // Card Heuristics::play_color_for_partner(Trick trick, HeuristicInterface hi)


/**
 ** Play a color the partner hopefully does not have
 ** prerequisites:
 **   1. it must be the first card in the trick
 **   2. the partner is the last player
 **   3. there is only one remaining card of the color
 **   4. another player could have the card
 ** Then take the card with the lowest value in the shortest color
 **
 **
 ** @param        trick        current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author       Diether Knof
 **
 ** @version      0.7.4
 **
 ** @todo         take card value into account
 **/
Card
Heuristics::try_color_for_partner(Trick const& trick,
                                  HeuristicInterface const& hi)
{
  // @heuristic::name   try color for partner
  // @heuristic::idea   try a color the partner hopefully does not have

  // @heuristic::condition   startplayer in the trick
  if (!trick.isstartcard())
    return Card::EMPTY;

  // @heuristic::condition   last player of the trick is partner
  if (!(::maybe_to_team(hi.teamofplayer(trick.lastplayer())) == hi.team()))
    return Card::EMPTY;

  // best card so far to play
  Card best_card;
  // maximal number of other players who can have the card
  // there must be at least one
  unsigned max_other_players = 1;

  for (vector<Card::Color>::const_iterator
       c = hi.game().rule().card_colors().begin();
       c != hi.game().rule().card_colors().end();
       ++c) {
    Card::Color const& color = *c;
    // test that the color is no trumpcolor
    if (color == hi.game().trumpcolor())
      continue;

    // the player has the color
    if (hi.hand().numberof(color) == 0)
      continue;

    // @heuristic::condition   the last player can have the last remaining card of the color
    if (!(  (hi.handofplayer(trick.lastplayer()).existstcolor(color))
          && (hi.cards_information().remaining_others(color) == 1)) )
      continue;

    // number of other players who can have the last card
    unsigned other_players = 0;

    for (unsigned p = hi.game().playerno() - 2; p > trick.actcardno(); --p) {
      Player const& player = trick.player_of_card(p);
      // ToDo: check that the card value for 'p' is greater than
      //       the card value for the partner
      if (hi.handofplayer(player).existstcolor(color))
        other_players += 1;
    } // for (p \in trick.actcardno())

    // search the card with the lowest value
    HandCard const& card = hi.hand().lowest_card(color);

    if (   (other_players > max_other_players)
        || (   (other_players == max_other_players)
            && (   best_card.is_empty()
                || (card.value() < best_card.value())) ) ) {
      best_card = card;
      max_other_players = other_players;
    } // if (found better card)
  } // for (c \in possible colors)

  // @heuristic::action   play the card with the lowest value
  return best_card;
} // Card Heuristics::try_color_for_partner(Trick trick, HeuristicInterface hi)


/**
 ** Play shortest color in game for solo contra in hope solo player and partner 
 ** can jab
 **
 **
 ** @param        trick        current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author       Diether Knof
 **
 ** @version      0.7.4
 **
 ** @todo         take card value into account
 **/
Card
Heuristics::play_color_in_solo(Trick const& trick,
                               HeuristicInterface const& hi)
{
  // @heuristic::name        play color in solo
  // @heuristic::idea        Play shortest color in game for solo contra in hope solo player and partner can jab.

  // @heuristic::condition   start card in the trick
  if (!trick.isstartcard())
    return Card::EMPTY;

  // @heuristic::condition   contra player in a picture or color solo
  if (hi.team() != TEAM::CONTRA)
    return Card::EMPTY;

  if (!(   GAMETYPE::is_picture_solo(hi.game().type())
        || GAMETYPE::is_color_solo(hi.game().type()) )
     )
    return Card::EMPTY;

  unsigned best_remaining = UINT_MAX;
  Card best_card;

  // @heuristic::action      play color card with the least cards remaining
  // 2do color with the minimum remaining points??? (if the re player is last player or all players behind the re players have to serve the color)
  for( vector<Card::Color>::const_iterator
      color = hi.game().rule().card_colors().begin();
      color != hi.game().rule().card_colors().end();
      ++color ) {
    if(   (hi.cards_information().remaining_others(*color) < best_remaining)
       && hi.hand().existstcolor(*color)
       && (*color != hi.game().trumpcolor()) ) {
      best_remaining = hi.cards_information().remaining_others(*color);
      best_card = hi.hand().lowest_card(*color);
    }
  } // for (color \in card_colors)


  return best_card;
} // Card Heuristics::try_color_for_partner(Trick trick, HeuristicInterface hi)

/**
 ** Start a new color hoping the partner has an ace
 ** prerequisites:
 **   1. it must be the first card in the trick
 **   2. first run of the color
 **   3. the partner is behind the player
 **   4. the partner can have the ace
 ** Then take the card with the greatest value in the shortest color
 **
 **
 ** @param        trick        current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author       Diether Knof
 **
 ** @version      0.7.4
 **/
Card
Heuristics::play_color_for_partner_ace(Trick const& trick,
                                       HeuristicInterface const& hi)
{
  // @heuristic::name   play color for partner ace
  // @heuristic::idea   play a color hoping the partner has the ace

  // @heuristic::condition   startplayer in the trick
  if (!trick.isstartcard())
    return Card::EMPTY;

  // the nmber of the next partner in line
  unsigned partnerno = UINT_MAX;
  for (unsigned c = 1; c < hi.game().playerno(); ++c) {
    if (::maybe_to_team(hi.teamofplayer(trick.player_of_card(c)))
        == hi.team()) {
      partnerno = trick.player_of_card(c).no();
      break;
    }
  } // for (c < hi.game().playerno())
  // a partner is found
  if (partnerno == UINT_MAX)
    return Card::EMPTY;


  // best card so far to play
  Card best_card;
  // maximal remaining cards of the selected color
  // @heuristic::condition   or there are enough remaining cards for all players
  //                         (players - me)
  unsigned max_remaining_cards_no = hi.game().playerno() - 1;

  for (vector<Card::Color>::const_iterator
       c = hi.game().rule().card_colors().begin();
       c != hi.game().rule().card_colors().end();
       ++c) {
    Card::Color const& color = *c;
    // test that the color is no trumpcolor
    // @heuristic::condition   first run of the color
    if (   (color == hi.game().trumpcolor())
        || (hi.cards_information().played(color)
            > hi.cards_information().of_player(hi.no()).played(color)) )
      continue;
    Card const ace(color, Card::ACE);

    // the player has the color
    if (hi.hand().numberof(color) == 0)
      continue;

    unsigned const remaining_cards_no
      = hi.cards_information().remaining_others(*c);
    // there are at least as many remaining cards as the best so far
    if (remaining_cards_no < max_remaining_cards_no)
      continue;

    {
      // the position of the partner in the trick
      unsigned const partneractcardno
        = trick.cardno_of_player(trick.game().player(partnerno));
      unsigned c;
      // @heuristic::condition   all players between me and the partner do not have an ace of the color but do have the color
      for (c = 1; c < partneractcardno; ++c) {
        Hand const& hand
          = hi.handofplayer(trick.player_of_card(c));
        if (   !hand.existstcolor(color)
            || hand.contains(ace))
          break;
      } // for (c < partneractcardno)
      if (c < partneractcardno)
        continue;
      // @heuristic::condition   the partner can have an ace of the color
      if (!hi.handofplayer(partnerno).contains(ace))
        continue;
    } // if (remaining_cards_no >= max_remaining_cards_no)


    // search the card with the highest value
    HandCard const& card = hi.hand().highest_card(color);

    if (   (remaining_cards_no > max_remaining_cards_no)
        || (card.value() > best_card.value()) ) {
      best_card = card;
      max_remaining_cards_no = remaining_cards_no;
    } // if (found better card)
  } // for (c \in possible colors)

  // @heuristic::action   play the card with the highest value in the smallest color
  return best_card;
} // Card Heuristics::play_color_for_partner_ace(Trick trick, HeuristicInterface hi)


/**
 ** When a player cannot get a color trick take the card with the smallest value
 ** prerequisites:
 **   1. it must not be the first card in the trick
 **   2. the trick must be a color trick;
 **   3. one must have to serve the color
 **   4. the winnercard must be an ace or a trump or one does not have the ace;
 **   5. the winnerplayer must not be of the own team;
 ** The main case is that one is the last to play and has only got to
 ** take ones lowest card.
 **
 ** @param        trick        current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author       Diether Knof
 **
 ** @version      0.6.6
 **/
Card
Heuristics::serve_color_trick(Trick const& trick, HeuristicInterface const& hi)
{
  // @heuristic::name   serve color trick
  // @heuristic::idea   When a player cannot get a color trick take the card with the smallest value. The main case is that one is the last to play and has only got to take ones lowest card.

  // ToDo: Check, whether the trick can go to the own team


  // @heuristic::condition   it must not be the first card in the trick
  if (trick.isstartcard()) {
    return Card::EMPTY;
  }



  // @heuristic::condition   the trick must be a color trick
  if (trick.startcard().istrump()) {
    return Card::EMPTY;
  }

  Card::Color const color = trick.startcard().color();

  bool canWinTrick = false;
  // @heuristic::condition   one cannot get the trick
  Player const& player = hi.game().player(hi.no());
  bool const swines
    = (  (  (   hi.game().swines_owner()
             && hi.game().swines_owner() == &player
            )
          || hi.game().swines_announcement_valid( player )
         )
       && hi.hand().hastrump()
      );
  bool const hyperswines
    = (  (   (   hi.game().hyperswines_owner()
              && (hi.game().hyperswines_owner() == &player))
          || hi.game().hyperswines_announcement_valid(player)
         )
       && hi.hand().hastrump()
      );
  if (   hi.hand().higher_card_exists(trick.winnercard())
      || swines
      || hyperswines)
    canWinTrick = true;


  // @heuristic::condition   one has to serve the color or one has no trump
  if (   (hi.hand().numberof(color) == 0)
      && hi.hand().hastrump()
      && canWinTrick) {
    return Card::EMPTY;
  }

  HandCards const color_cards = hi.hand().validcards( trick );


  // @heuristic::condition   the winnercard must be an ace or a trump or one does not have the ace in the non-trump case or there are not enough remaining cards to get through
  if (!(   (trick.winnercard().value() == Card::ACE)
        || trick.winnercard().istrump()
        || (   !trick.winnercard().istrump()
            && (color_cards.numberof(Card(color, Card::ACE)) == 0))
        || (hi.cards_information().remaining_others(color)
            < trick.remainingcardno() - 1)
       ) ) {


    return Card::EMPTY;
  } // if (trick.winnercard.value() != Card::ACE) && (...)

  // @heuristic::condition   the winnerplayer must not be of the own team
  if (   (hi.teamofplayer( trick.winnerplayer() ) == hi.team())
      && (   (hi.color_runs(color) != 0)
          || (   trick.winnercard().istrump()
              || (trick.winnercard() == Card(color, Card::ACE))) )
     ) {


    return Card::EMPTY;
  }

  { // @heuristic::condition   no partner can jab

    // first make sure there are not enough cards for everyone
    if (!(   (hi.color_runs(color) == 0)
          && (color_cards.cardsnumber() + (hi.game().playerno() - 1)
              <= hi.game().numberof(color)) )) {
      Player const* p;
      for (p = &hi.game().player_following(trick.actplayer());
           p != &trick.startplayer();
           p = &hi.game().player_following(*p)) {
        if (   (hi.guessedteamofplayer(*p) == hi.team())
            && hi.handofplayer(*p).higher_card_exists(trick.winnercard())) {
          break;
        }
      } // for (p)
      if (p != &trick.startplayer()) {


        return Card::EMPTY;
      }
    } // if (enough cards remain)
  } // no partner can jab

  // @heuristic::condition   it must not be an undetermined marriage
  if (   (hi.game().type() == GAMETYPE::MARRIAGE)
      && (hi.game().marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET)
      && !(   is_selector(color, hi.game().marriage_selector())
           && (hi.no() != hi.game().soloplayer().no()))
     )
  {


    return Card::EMPTY;
  }

  // @heuristic::action   take lowest color card
  return Heuristics::lowest_card(trick, hi.hand());
} // Card Heuristics::serve_color_trick(Trick trick, HeuristicInterface hi)


/**
 ** If a player cannot get a trump trick take the card with the smallest value
 ** prerequisites:
 **   1. it must not be the first card in the trick
 **   2. the trick must be a trump trick;
 **   3. one cannot get the trick
 **   4. if the value of the cards are not the same:
 **      a) the winnerplayer must not be of the own team;
 **      b) the remaining players must not be of the own team
 **   5. There is a smallest card both in value and in jab order
 **      or diamond king against spade jack or higher
 ** The main case is p.e. in a jack solo to play the smallest jack when the
 ** club jack is played
 **
 ** @param        trick     current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author       Diether Knof
 ** @author       Borg Enders
 **
 ** @version        0.7.5
 **/
Card
Heuristics::serve_trump_trick(Trick const& trick,
                              HeuristicInterface const& hi)
{
  // @heuristic::name   serve trump trick
  // @heuristic::idea   When a player cannot get a trump trick take the card with the smallest value. The main case is that one is the last to play and has only got to take ones lowest card.


  // @heuristic::condition   it must not be the first card in the trick
  if (trick.isstartcard())
    return Card::EMPTY;

  // @heuristic::condition   the trick must be a trump trick
  if (!trick.startcard().istrump())
    return Card::EMPTY;

  // @heuristic::condition   one cannot get the trick
  Player const& player = hi.game().player(hi.no());
  bool const swines
    = (  (  (   hi.game().swines_owner()
             && hi.game().swines_owner() == &player
            )
          || hi.game().swines_announcement_valid( player )
         )
       && hi.hand().hastrump()
      );
  bool const hyperswines
    = (  (   (   hi.game().hyperswines_owner()
              && (hi.game().hyperswines_owner() == &player))
          || hi.game().hyperswines_announcement_valid(player)
         )
       && hi.hand().hastrump()
      );
  if (   hi.hand().higher_card_exists(trick.winnercard())
      || swines
      || hyperswines)
    return Card::EMPTY;

  { // @heuristic::condition   if the card values are not the same:
    int value = -1;
    for (HandCards::const_iterator c = hi.hand().cards().begin();
         c != hi.hand().cards().end();
         ++c) {
      if (!c->istrump())
        continue;
      if (value == -1) {
        value = c->value();
        continue;
      }
      if (c->value() != value) {
        value = -2;
        break;
      }
    } // for (c \in hand)

    if (value < 0) {
      // @heuristic::condition   1) the winnerplayer must not be of the own team
      Player const& winnerplayer = trick.winnerplayer();
      if (hi.teamofplayer(winnerplayer) == hi.team()) {
        return Card::EMPTY;
      }

      // @heuristic::condition   2) the remaining players must not be of the own team
      for (Player const*
           player = &(trick.game().player_following(trick.actplayer()));
           player != &trick.startplayer();
           player = &(trick.game().player_following(*player)))
        if (   (hi.teamofplayer(*player) == hi.team())
            && hi.handofplayer(*player).higher_card_exists(trick.winnercard()))
        {


          return Card::EMPTY;

        }
    } // if (value < 0)
  } // if the card values are not the same: the remaining players must not be of the own team

  // @heuristic::action   play the lowest card
  return Heuristics::lowest_card(trick, hi.hand());
} // Card Heuristics::serve_trump_trick(Trick const& trick, HeuristicInterface const& hi)


/**
 ** -> result
 **
 ** @param     trick   current trick
 ** @param     hand    hand of the player
 **
 ** @return    lowest card to play in the trick,
 **            Card::EMPTY, if none is found
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.5
 **/
Card
Heuristics::lowest_card(Trick const& trick,
                        Hand const& hand)
{
  if (trick.isstartcard())
    return Heuristics::lowest_free_card(hand);

  if (!hand.contains(trick.startcard().tcolor()))
    return Heuristics::lowest_free_card(hand);

  if (trick.startcard().istrump())
    return Heuristics::lowest_trump_card(hand);
  else
    return Heuristics::lowest_color_card(trick.startcard().tcolor(), hand);
} // static Card Heuristics::lowest_card(Trick trick, Hand hand)


/**
 ** -> result
 **
 ** @param     hand    hand of the player
 **
 ** @return    lowest trump to play
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.5
 **/
Card
Heuristics::lowest_trump_card(Hand const& hand)
{
  DEBUG_ASSERTION(hand.contains(Card::TRUMP),
                  "Heuristics::lowest_trump_card(hand)\n"
                  "  hand does not contain any trump");

  HandCard const& lowest_trump = hand.lowest_trump();
  Game const& game = hand.game();

  if (   !game.is_special(lowest_trump)
      && (lowest_trump.value() < Card::TEN) )
    return lowest_trump;

  DEBUG_ASSERTION(!GAMETYPE::is_picture_solo(game.type()),
                  "Heuristics::lowest_trump_card(hand)\n"
                  "  picture solo: " << game.type());


  list<Card> const& trumps = game.trumps();
  // search lowest trump
  for (list<Card>::const_iterator t = trumps.begin();
       t != trumps.end();
       ++t)
    if (hand.contains(*t))
      if (   !game.is_special(HandCard(hand, *t))
          && (t->value() < Card::TEN))
        return *t;

  return Card::EMPTY;
} // static Card Heuristics::lowest_trump_card(Hand hand)


/**
 ** -> result
 **
 ** @param     tcolor   tcolor to serve
 ** @param     hand     hand of the player
 **
 ** @return    lowest card to play the tcolor
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.5
 **/
Card
Heuristics::lowest_color_card(Card::TColor const& tcolor,
                              Hand const& hand)
{
  DEBUG_ASSERTION((tcolor != Card::TRUMP),
                  "Heuristics::lowest_color_card(tcolor, hand)\n"
                  "  tcolor ist trump");
  DEBUG_ASSERTION(hand.contains(tcolor),
                  "Heuristics::lowest_color_card(tcolor, hand)\n"
                  "  hand does not contain the color " << tcolor);

  return hand.lowest_card(tcolor);
} // static Card Heuristics::lowest_color_card(Card::TColor tcolor, Hand hand)


/**
 ** -> result
 **
 ** @param     hand     hand of the player
 **
 ** @return    lowest card to play (free color selection),
 **            Card::EMPTY, if none is found
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.5
 **
 ** @todo      replace with Heuristics::choose_best_prefiltered_card()
 **/
Card
Heuristics::lowest_free_card(Hand const& hand)
{
  if (hand.numberoftrumps() == hand.cardsnumber())
    return Heuristics::lowest_trump_card(hand);

  // search the lowest value
  Card::Value lowest_value = Card::ACE;
  for (HandCards::const_iterator c = hand.cards().begin();
       c != hand.cards().end();
       ++c)
    if (c->value() < lowest_value)
      lowest_value = c->value();

  // the card colors with the lowest value and not trump
  list<Card::Color> card_colors;
  for (vector<Card::Color>::const_iterator
       c = hand.game().rule().card_colors().begin();
       c != hand.game().rule().card_colors().end();
       ++c)
    if (!Card(*c, lowest_value).istrump(hand.game()))
      card_colors.push_back(*c);

  if (card_colors.empty())
    return Card::EMPTY;

  if (lowest_value < Card::ACE) {
    // search single card with lowest value
    for (list<Card::Color>::const_iterator
         c = card_colors.begin();
         c != card_colors.end();
         ++c) {
      if (   (hand.numberof(*c) == 1)
          && (hand.contains(Card(*c, lowest_value)))) {
        return Card(*c, lowest_value);
      }
    }
  } // if (lowest_value < Card::ACE)

  if (lowest_value < Card::TEN) {
    // search lowest card of the smallest color without ACE and TEN
    Card::Color best_color = Card::NOCARDCOLOR;
    for (list<Card::Color>::const_iterator
         c = card_colors.begin();
         c != card_colors.end();
         ++c)
      if (   (hand.numberof(Card(*c, Card::ACE)) == 0)
          && (hand.numberof(Card(*c, Card::TEN)) == 0))
        if (   (hand.numberof(*c) > 0)
            && (   (best_color == Card::NOCARDCOLOR)
                || (hand.numberof(*c) < hand.numberof(best_color)) ) )
          best_color = *c;
    if (best_color != Card::NOCARDCOLOR) {
      return hand.lowest_card(best_color);
    }
  } // if (lowest_value < Card::TEN)

  if (lowest_value == Card::ACE) {
    // search double ace
    for (list<Card::Color>::const_iterator
         c = card_colors.begin();
         c != card_colors.end();
         ++c)
      if (hand.numberof(*c) == 2) {
        return Card(*c, lowest_value);
      }
  } // if (lowest_value == Card::ACE)

  if (lowest_value == Card::TEN) {
    // search only tens
    for (list<Card::Color>::const_iterator
         c = card_colors.begin();
         c != card_colors.end();
         ++c)
      if (   hand.contains(Card(*c, lowest_value))
          && (hand.numberof(*c)
              == hand.numberof(Card(*c, lowest_value))) ) {
        return Card(*c, lowest_value);
      }

    // search biggest color
    Card::Color best_color = Card::NOCARDCOLOR;
    for (list<Card::Color>::const_iterator
         c = card_colors.begin();
         c != card_colors.end();
         ++c) {
      if (hand.contains(Card(*c, lowest_value)))
        if (   (best_color == Card::NOCARDCOLOR)
            || (hand.numberof(*c) > hand.numberof(best_color)))
          best_color = *c;
    } // for (c \in card_colors())
    if (best_color != Card::NOCARDCOLOR) {
      return hand.lowest_card(best_color);
    }
  } // if (lowest_value == Card::TEN)

  { // search lowest card of the biggest color
    Card::Color best_color = Card::NOCARDCOLOR;
    unsigned best_cards_no = 2;
    for (list<Card::Color>::const_iterator
         c = card_colors.begin();
         c != card_colors.end();
         ++c)
      if (hand.numberof(*c) > best_cards_no) {
        best_color = *c;
        best_cards_no = hand.numberof(*c);
      }
    if (best_color != Card::NOCARDCOLOR) {
      return hand.lowest_card(best_color);
    }
  } // search lowest card of the biggest color

  { // search lowest card
    Card::Color best_color = Card::NOCARDCOLOR;
    for (list<Card::Color>::const_iterator
         c = card_colors.begin();
         c != card_colors.end();
         ++c)
      if (   hand.contains(Card(*c, lowest_value))
          && (   (best_color == Card::NOCARDCOLOR)
              || (hand.numberof(*c) > hand.numberof(best_color))))
        best_color = *c;
    if (best_color != Card::NOCARDCOLOR) {
      return hand.lowest_card(best_color);
    }
  } // search lowest card

  return Card::EMPTY;
} // Card Heuristics::lowest_free_card(Hand hand)

/**
 ** -> result
 **
 ** @param     hi       heuristic interface
 ** @param     hand     hand of the player
 ** @param     cards    cards to choose from
 **
 ** @return    lowest card to play from 'cards'
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.5
 **/
Card
Heuristics::choose_best_prefiltered_card(HeuristicInterface const& hi,
                                         Hand const& hand,
                                         HandCards const& cards)
{
  if (cards.cardsnumber() == 0)
    return Card::EMPTY;
  if (cards.cardsnumber() == 1)
    return cards[0];

  if (cards.numberoftrumps() < cards.cardsnumber())
    return Heuristics::choose_best_prefiltered_color_card(hi, hand, cards);
  else
    return Heuristics::choose_best_prefiltered_trump_card(hi, hand, cards);
} // Card Heuristics::choose_best_prefiltered_card(HeuristicsInterface hi, Hand hand, HandCards cards)

/**
 ** -> result
 **
 ** @param     hi       heuristic interface
 ** @param     hand     hand of the player
 ** @param     cards    cards to choose from
 **
 ** @return    lowest card to play from 'cards',
 **            Card::EMPTY, if none is found
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.5
 **/
Card
Heuristics::choose_best_prefiltered_color_card(HeuristicInterface const& hi,
                                               Hand const& hand,
                                               HandCards const& cards)
{
  DEBUG_ASSERTION(cards.numberoftrumps() < cards.cardsnumber(),
                  "Heuristics::choose_best_prefilterd_color_card(hand, cards)\n"
                  "  'cards' only contains trumps");
  if (cards.cardsnumber() == 0)
    return Card::EMPTY;
  if (cards.cardsnumber() == 1)
    return cards[0];

  // search the lowest value
  Card::Value lowest_value = Card::ACE;
  for (vector<HandCard>::const_iterator c = cards.begin();
       c != cards.end();
       ++c)
    if (   !c->istrump()
        && (c->value() < lowest_value) )
      lowest_value = c->value();

  // the card colors with the lowest value and not trump
  list<Card::Color> card_colors;
  for (vector<Card::Color>::const_iterator
       c = hand.game().rule().card_colors().begin();
       c != hand.game().rule().card_colors().end();
       ++c)
    if (!Card(*c, lowest_value).istrump(hand.game()))
      card_colors.push_back(*c);

  if (card_colors.empty())
    return Card::EMPTY;


  if (lowest_value < Card::ACE) {
    // search single card with lowest value
    for (list<Card::Color>::const_iterator
         c = card_colors.begin();
         c != card_colors.end();
         ++c)
      if (   (hand.numberof(*c) == 1)
          && (cards.contains(*c, lowest_value))) {
        // ToDo: consider two colors with the same number of cards
        return Card(*c, lowest_value);
      }
  } // if (lowest_value < Card::ACE)

  if (lowest_value < Card::TEN) {
    // search lowest card of the smallest color without ACE and TEN
    Card::Color best_color = Card::NOCARDCOLOR;
    for (list<Card::Color>::const_iterator
         c = card_colors.begin();
         c != card_colors.end();
         ++c)
      if (   cards.existstcolor(*c)
          && (hand.numberof(Card(*c, Card::ACE)) == 0)
          && (hand.numberof(Card(*c, Card::TEN)) == 0))
        if (   (best_color == Card::NOCARDCOLOR)
            || (cards.numberof(*c) < hand.numberof(best_color)))
          // ToDo: improve selection -- card value comparison, compare remaining cards of the color, compare jabbing, ...
          best_color = *c;
    if (best_color != Card::NOCARDCOLOR) {
      return cards.lowest_card(best_color);
    }
  } // if (lowest_value < Card::TEN)

  if (lowest_value == Card::ACE) {
    // search double ace
    for (list<Card::Color>::const_iterator
         c = card_colors.begin();
         c != card_colors.end();
         ++c)
      if (   (hand.numberof(*c) == 2)
          && cards.contains(*c, Card::ACE) ) {
        return Card(*c, lowest_value);
      }
  } // if (lowest_value == Card::ACE)
  if (lowest_value == Card::TEN) {
    // search only tens
    for (list<Card::Color>::const_iterator
         c = card_colors.begin();
         c != card_colors.end();
         ++c)
      if (   cards.contains(*c, lowest_value)
          && (hand.numberof(*c)
              == hand.numberof(*c, lowest_value)) ) {
        return Card(*c, lowest_value);
      }

    // search biggest color
    Card::Color best_color = Card::NOCARDCOLOR;
    for (list<Card::Color>::const_iterator
         c = card_colors.begin();
         c != card_colors.end();
         ++c) {
      if (cards.contains(Card(*c, lowest_value)))
        if (   (best_color == Card::NOCARDCOLOR)
            || (hand.numberof(*c) > hand.numberof(best_color)))
          best_color = *c;
    } // for (c \in card_colors())
    // ToDo: compare ace ace ten, ace ten ten
    if (best_color != Card::NOCARDCOLOR) {
      return Card(best_color, lowest_value);
    }
  } // if (lowest_value == Card::TEN)

  { // search lowest card of the biggest color with min 3 cards
    Card::Color best_color = Card::NOCARDCOLOR;
    unsigned best_cards_no = 2;
    for (list<Card::Color>::const_iterator
         c = card_colors.begin();
         c != card_colors.end();
         ++c)
      if (   (hand.numberof(*c) > best_cards_no)
          && (cards.existstcolor(*c)) ) {
        best_color = *c;
        best_cards_no = hand.numberof(*c);
      }
    if (   (best_color != Card::NOCARDCOLOR)
        && cards.contains(hand.lowest_card(best_color)) ) {
      // ToDo: take smallest card from cards
      return hand.lowest_card(best_color);
    }
  } // search lowest card of the biggest color

  { // search lowest card of the largest color
    Card::Color best_color = Card::NOCARDCOLOR;
    for (list<Card::Color>::const_iterator
         c = card_colors.begin();
         c != card_colors.end();
         ++c)
      if (   cards.contains(Card(*c, lowest_value))
          && (   (best_color == Card::NOCARDCOLOR)
              || (hand.numberof(*c) > hand.numberof(best_color))))
        best_color = *c;
    if (best_color != Card::NOCARDCOLOR) {
      return cards.lowest_card(best_color);
    }
  } // search lowest card

  return Card::EMPTY;
} // static Card Heuristics::choose_best_prefiltered_color_card(HeuristicsInterface hi, Hand hand, HandCards cards)


/**
 ** -> result
 **
 ** @param     hi       heuristic interface
 ** @param     hand     hand of the player
 ** @param     cards    cards to choose from
 **
 ** @return    lowest card to play from 'cards'
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.5
 **/
Card
Heuristics::choose_best_prefiltered_trump_card(HeuristicInterface const& hi,
                                               Hand const& hand,
                                               HandCards const& cards)
{
  DEBUG_ASSERTION(cards.numberoftrumps() == cards.cardsnumber(),
                  "Heuristics::choose_best_prefilterd_trump_card(hand, cards)\n"
                  "  'cards' does contain color cards");
  if (cards.cardsnumber() == 0)
    return Card::EMPTY;
  if (cards.cardsnumber() == 1)
    return cards[0];

  HandCard card(hand);

  // find any card that's allowed for this trick
  for(unsigned i = 0; i < cards.cardsnumber(); i++ )
  {
    if ( cards.card( i ).istrump() )
    {
      card = cards.card( i );
      break;
    }
  } // for( i < ha.cardsnumber() )

  if( card.is_empty()) 
    return Card::EMPTY;

  // find a better card
  for(unsigned i = 0; i < cards.cardsnumber(); i++ )
  {
    if(   cards.card( i ).less(card) 
       && cards.card( i ).istrump() 
       && !cards.card( i ).isfox() 
       && (   cards.card(i).value() != Card::TEN 
           || card.isfox()
          )
      )
      card = cards.card( i );
  } // for( i = 0; i < cards.cardsnumber(); i++ )

  if( !card.less( hi.trump_card_limit() ) )
    // maybe a diamond ten isn't all that bad
  {
    for(unsigned i = 0; i < cards.cardsnumber(); i++ )
    {
      if(   cards.card( i ).less( card ) 
         && cards.card( i ).istrump() 
         && !cards.card( i ).isfox()
        )
        card = cards.card( i );
    }
  } // if( !card.less( cards.trump_card_limit() ) )

  if( !card.less( hi.trump_card_limit() ) )
    // maybe a diamond Ace isn't all that bad
  {
    for(unsigned i = 0; i < cards.cardsnumber(); i++ )
    {
      if(   cards.card( i ).less( card ) 
         && cards.card(i).istrump()
        )
        card = cards.card( i );
    }
  } // if( !c.less( hi.trump_card_limit() ) )

  return card;
} // Card Heuristics::choose_best_prefiltered_trump_card(HeuristicsInterface hi, Hand hand, HandCards cards)

/**
 ** for the last card in a trick, which wins your own team 
 ** or where your teammate has already a played a high enough trump
 ** play a pfund
 **
 ** @param        t         current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 **
 ** @author    Borg Enders
 **
 ** @version      Beta
 **/
Card 
Heuristics::choose_pfund( Trick const& t, HeuristicInterface const& hi )
{
  // @heuristic::name   choose pfund
  // @heuristic::idea   choose for trump trick won by the own team a pfund

  // I'm the start Player
  if( t.isstartcard() )
    return Card::EMPTY;

  // undetermined marriage => no pfund
  if (   (hi.game().type() == GAMETYPE::MARRIAGE)
      && (hi.game().marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET)     
      && (  (  !is_selector(t.startcard().color(), hi.game().marriage_selector())
             && (hi.no() == hi.game().soloplayer().no()))
          || (hi.no() != hi.game().soloplayer().no())
         )
     )
    return Card::EMPTY;

  // special case: first color run
  Card::Color color = t.startcard().tcolor();
  if (   (color != Card::TRUMP)
      && (hi.color_runs(color) == 0)
      && (hi.teamofplayer(t.winnerplayer()) == hi.team())
      && (t.winnercard().istrump()
          || (t.winnercard() == Card(color, Card::ACE)))
      && (hi.cards_information().remaining_others_cards_no()
          /// @todo   number of players who have not jabbed, yet
          / 3
          >= 1)
     )
  { 
    return choose_pfund_card( t, hi );
  }


  // some oppenent behind me can jab the trick
  if(   !t.islastcard()
     && !checkAllMyTeam( t, hi )
     && oppositeTeamCanWinTrick( t, hi ))
    return Card::EMPTY;


  if(    t.islastcard()
     && (hi.teamofplayer(t.winnerplayer()) != hi.team()) )
    return Card::EMPTY;


  bool soloPlayer = soloPlayerBehind( t, hi );

  // if winner is own team
  if (   hi.teamofplayer(t.winnerplayer()) == hi.team() 
      &&  !oppositeTeamCanWinTrick( t, hi ) ) {
    return choose_pfund_card( t, hi );
  }

  if (   maybe_to_team(hi.teamofplayer(t.winnerplayer())) == hi.team() 
      && (  !hi.cards_information().higher_card_exists( t.winnercard() )     
          ||(  !soloPlayer
             && (    t.islastcard() 
                 || !t.winnercard().less( hi.trump_card_limit() )
                )
            )
         )
     )
  {
    return choose_pfund_card( t, hi );
  }
  if (   GAMETYPE::is_solo( hi.game().type() )
      && t.winnerplayer() == hi.game().soloplayer()
      && t.winnercard().less( hi.trump_card_limit() )
      && !t.islastcard()
      && choose_pfund_card(t,hi).points() > 0 
      && t.startcard().istrump()  
     )
  {
    return choose_pfund_card( t, hi );
  }

  if (   checkAllMyTeam( t, hi )
      && ownTeamCanWinTrick( t, hi )
      && (    hi.teamofplayer(t.winnerplayer()) == hi.team()
          || (   t.winnercard().less( hi.trump_card_limit() ) 
              && (t.winnercard() != Card(color, Card::ACE))
              && !(!t.startcard().istrump() && t.winnercard().istrump()) 
              && !t.islastcard()
             ) 
         ) 
     )
  {
    return choose_pfund_card( t, hi );
  }

  return Card::EMPTY;
} // Card Heuristics::choose_pfund( Trick t, HeuristicInterface hi )


/**
 ** if the partner has the highest card in the game, play a pfund (>= 10 points)
 ** 
 ** @param     trick   current trick
 ** @param     hi      heuristics interface
 ** 
 ** @return    card to play
 ** 
 ** @author    Diether Knof
 ** 
 ** @version   2006-09-18
 **/ 
Card
Heuristics::choose_pfund_before_partner(Trick const& trick,
                                        HeuristicInterface const& hi)
{
  // @heuristic::name   choose pfund before partner
  // @heuristic::idea   if the partner has the highest card in the game play a pfund

  // @heuristic::condition   the partner has the highest trump still in the game

  // whether the partner has the highest card
  bool partner_has_highest_card = false;

  // the highest trump the other players can have
  Card const highest_trump
    = hi.cards_information().highest_remaining_trump_of_others();

  // the partner
  Player const* partner = hi.team_information().guessed_partner();
  if (partner) {
    // no partner behind
    if (trick.cardno_of_player(trick.game().player(partner->no())) < trick.actcardno() )
      return Card::EMPTY;

    // normal case
    if (   partner
        // the partner has the highest card
        && hi.cards_information().of_player(*partner).must_have(highest_trump)
        // no other player has also the highest card
        && (hi.cards_information().of_player(*partner).must_have(highest_trump)
            + hi.cards_information().played(highest_trump)
            + hi.hand().numberof(highest_trump)
            == hi.game().rule()(Rule::NUMBER_OF_SAME_CARDS) )
       )
      partner_has_highest_card = true;
  } else { // if !(partner)

    // special case: partner re but I do not know who he is
    if (   (hi.game().type() == GAMETYPE::NORMAL)
        // re team
        && (hi.team() == TEAM::RE)
        // startcard or the player before seems to be contra
        && (trick.isstartcard()
            || (   (trick.actcardno() == 1)
                && (hi.guessedteamofplayer(trick.startplayer()) == TEAM::CONTRA))
           )
        // the club queen is the highest card
        && (highest_trump == Card::CLUB_QUEEN)
       )
      partner_has_highest_card = true;

  } // if !(partner)

  if (!partner_has_highest_card)
    return Card::EMPTY;

  // @heuristic::action   play a pfund of at least 10 points
  if (trick.isstartcard()) {
    // play a fox
    if (   (hi.hand().numberoftrumpaces() > 0)
        && !hi.hand().has_swines())
      return Card(hi.game().trumpcolor(), Card::ACE);

    // play a diamond ten
    Card const card(hi.game().trumpcolor(), Card::TEN);
    if (hi.hand().numberof(card) > 0)
      return card;

    // ToDo: play a color card of a color the partner does not have

  } else { // if !(trick.isstartcard())
    // the partner can play the card
    if (   partner
        && (trick.isvalid(highest_trump, hi.handofplayer(*partner)))) {
      // search a pfund card
      Card const card = Heuristics::choose_pfund_card(trick, hi);
      if (card.value() >= Card::TEN)
        return card;
    }
  } // if !(trick.isstartcard())

  return Card::EMPTY;
} // Card Heuristics::choose_pfund_before_partner(Trick trick, HeuristicInterface hi)


/**
 ** return lowest allowed Jack or Queen if they are trump
 ** and there is a ace to play, which is not already jabbed,
 ** else return empty card
 **
 ** @param     t    current trick
 ** @param     hi   heuristic interface
 **
 ** @result    -> description
 **
 ** @author    Borg Enders
 **
 ** @version 0.6.9
 **/
Card 
Heuristics::jab_for_ace( Trick const& t, HeuristicInterface const& hi )
{
  // @heuristic::name   jab for ace
  // @heuristic::idea   jab a trick to serve next trick a ace

  // must not be the first player
  if (t.isstartcard())
    return Card::EMPTY;

  // the ace to jab for
  Card const ace = Heuristics::choose_ace( Trick(), hi );

  if (ace.is_empty())
    return Card::EMPTY;

  unsigned const remaining_cards
    = (hi.game().numberof(ace.color())
       - (hi.cards_information().played(ace.color()) + hi.hand().numberof(ace.color())));
  if(   GAMETYPE::is_solo( hi.game().type() )
     && hi.game().soloplayer().no() != hi.no() 
     && remaining_cards < 5 )
    return Card::EMPTY;

  // for a solo don't jab for ace, if there are players of my team behind me
  // and myself doesn't have that many trumps
  if (   GAMETYPE::is_solo( hi.game().type() )
      && (t.winnerplayer() == hi.game().soloplayer())
      && t.winnercard().less( hi.trump_card_limit() )
      && !t.islastcard()
      && (hi.hand().numberoftrumps() < 4)
     ) 
    return Card::EMPTY;

  if(   (hi.hand().numberof( ace )
         < hi.game().rule()(Rule::NUMBER_OF_SAME_CARDS))
     && (hi.color_runs(ace.color()) == 0)
     && (   (TEAM::maybe_to_team(hi.teamofplayer(t.winnerplayer())) != hi.team())
         || (   (TEAM::maybe_to_team(hi.teamofplayer(t.winnerplayer())) == hi.team())
             && t.winnercard().less( hi.trump_card_limit() )
            )
         || (hi.game().trick_current_no() == 0) 
        ) 
    )
  {
    Card c;
    if(    (hi.game().trick_current_no() == 0)
       && (t.startcard().istrump() 
           && (!t.islastcard())
           && !checkAllMyTeam(t, hi ))
      )
    {
      c = highest_trump_card( t, hi.hand() );
      if (!t.is_jabbed(c))
        return Card::EMPTY;

    } else
    {
	c =  best_winning_card( t, hi, 
                             hi.value( Aiconfig::LIMITDOLLE ) - ( 4 - t.actcardno() ) + 10 );

    }

    if( !c.is_empty() )
    {
      Trick tempTrick = t;
      tempTrick += HandCard( hi.hand(), c );
      if(   ( HandCard( hi.hand(), c ).isdolle() 
             || HandCard( hi.hand(), c ).possible_swine() )
         && oppositeTeamCanWinTrick( tempTrick, hi ) )
        return Card::EMPTY;

      bool trickLost = tempTrick.winnercard().less(highest_opposite_card_behind(tempTrick, hi));
      if(   trickLost 
         && (!c.less(HandCard( hi.hand(), Card(Card::DIAMOND, Card::QUEEN))))
         && (hi.hand().numberof(c.value()) < 3)
        )
        return Card::EMPTY;

    }

    return c;
  } // if ( .... (hi.color_runs(ace.color()) == 0) .... )

  return Card::EMPTY;
} // Card Heuristics::jab_for_ace( Trick t, HeuristicInterface hi )


/**
 ** plays high and low trumps changing
 **
 ** @param        t         current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 **
 ** @author    Borg Enders
 **
 ** @version      Beta
 **/
Card 
Heuristics::play_low_high(Trick const& t, HeuristicInterface const& hi)
{
  // @heuristic::name   play low high
  // @heuristic::idea   play changing low and high trumps to force opponent to jab or either draw his trumps

  if(    GAMETYPE::is_solo( hi.game().type() )
     && hi.game().soloplayer ().no() != hi.no() )
    return Card::EMPTY;

  // @heuristic::condition do not use for undetermined marriage  
  if (   (hi.game().type() == GAMETYPE::MARRIAGE)
      && (hi.game().marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET) 
     )
    return Card::EMPTY;

  // @heuristic::condition trump cards at the opposite players still remain
  if (!opposite_trump_behind(t, hi))
    return Card::EMPTY;


  if(   t.isstartcard() 
     && hi.hand().numberoftrumps() > hi.game().tricks_remaining_no() / 2 
    ) 
  {
    if(  hi.next_low() )
    {
      if( hi.hand().numberof( Card::QUEEN ) < 2 * hi.hand().numberof( Card::JACK ) ) 
      {
        Card c = lowest_jack( hi.hand(), hi );

        if(   !c.is_empty()
           && !t.isvalid(c,hi.hand())) // ToDo: Hier wird doch die erste Karte im Trumpf betrachtet, daher dürfte die Bedingung nie greifen (siehe auch unten)
             c = Card::EMPTY;

        return c;
      }
    } else 
    { // if !(hi.next_low())
      if( hi.hand().numberof( Card::QUEEN ) > 1) 
      {
        Card c = lowest_queen( hi.hand(), hi );

        if(   (hi.hand().numberof( Card::QUEEN ) < 4)
           && (hi.hand().numberofclubqueens() == 1)
           && (hi.game().teaminfo( hi.no() ) == TEAM::UNKNOWN) 
          )
          c = Card::CLUB_QUEEN;


        if(   !c.is_empty()
           && !t.isvalid( c, hi.hand() ) )
          c = Card::EMPTY;


        return c;
      }
    } // if !(hi.next_low())
  } // if (t.isstartcard())

  return Card::EMPTY;
} // Card Heuristics::play_low_high(Trick t,HeuristicInterface hi)


/**
 ** plays the second highest trump (usefull for color soli)
 **
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 **
 ** @author    Borg Enders
 **
 ** @version      Beta
 **/
Card
Heuristics::SecondBestTrump(HeuristicInterface const& hi)
{
  // @heuristic::name   ?  second best trump  ?
  // @heuristic::idea   play the seconmd highest trump (especially useful for solo player in picture soli)
  Hand h = hi.hand();

  Card c;
  Card bestcard;

  // there is a trump to draw
  if( hi.cards_information().remaining_trumps_others() == 0 )
    return c;

  // first find highest trump on hand
  unsigned i;
  unsigned best = 0;
  bestcard = h.card( best );
  for( i = 1; i < h.cardsnumber();i++ )
  {
    if(   h.card(i).istrump()
       && bestcard.less( h.card( i ) )
      ) 
    {
      bestcard = h.card( i );
      best = i;
    }
  } // for ( i < h.cardsnumber() )

  // find second best card
  for (i = 0; i < h.cardsnumber(); i++)
  {
    if(   h.card(i).istrump()
       && (  h.card(i).less(bestcard)
           || h.card(i) == bestcard 
          )
       && c.less( h.card(i) )
       && i != best
      )
    {
      c = h.card( i );
    }
  } // for ( i < h.cardsnumber() )

  DEBUG_ASSERT(!c.is_empty());
  return c;

} // Card Heuristics::SecondBestTrump(HeuristicInterface const& hi)


/**
 ** puts a nice card to a trick of a team mate
 ** returns a king, ten (no dolle), or a ace (no swine) or a nine in this
 ** order
 **
 ** @param        t         current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 **
 ** @author    Borg Enders
 **
 ** @version      Beta
 **/
Card 
Heuristics::play_for_team( Trick const& t, HeuristicInterface const& hi )
{
  // @heuristic::name   play for team
  // @heuristic::idea put a good card in a trick of the team mate

  // I'am the start Player
  if( t.isstartcard() )
    return Card::EMPTY;

  bool soloPlayer =  soloPlayerBehind( t, hi );


  Card c;
  if(    maybe_to_team(hi.teamofplayer(t.winnerplayer())) == hi.team()
     && !soloPlayer
     && !t.winnercard().less(hi.value(Aiconfig::LIMITTHROWING))
    )
  { 
    unsigned i;

    for( i = 0; i < hi.hand().cardsnumber(); i++ )
    {
      Trick tr = t;
      if( tr.isvalid( hi.hand().card(i), hi.hand() ) )
      {
        tr += hi.hand().card( i );
        if(   tr.winnerplayer().no() != hi.no()
           && hi.hand().card(i).value()==Card::KING 
           && !hi.hand().card(i).ishyperswine()
           && hi.game().type() != GAMETYPE::SOLO_KING 
           && hi.game().type() != GAMETYPE::SOLO_KING_QUEEN
           && hi.game().type() != GAMETYPE::SOLO_KING_JACK
          )
          c = hi.hand().card( i );
      } // if ( tr.isvalid( ... ) )
    } // for ( i < hi.hand().cardsnumber() )

    if( !c.is_empty() ) 
      return c;


    for( i = 0; i < hi.hand().cardsnumber(); i++ )
    {
      Trick tr = t;
      if( tr.isvalid( hi.hand().card( i ), hi.hand() ) )
      {
        tr += hi.hand().card( i );
        if(   tr.winnerplayer().no() != hi.no()
           && hi.hand().card(i).value() == Card::TEN
           && !tr.winnercard().less(hi.value(Aiconfig::LIMITHIGH))
           && !hi.hand().card(i).isdolle()
          )
          c=hi.hand().card(i);     
      } // if ( tr.isvalid ( ... ) )
    } // for ( i < hi.hand().cardsnumber() )

    if( !c.is_empty() ) 
      return c;

    for( i = 0; i < hi.hand().cardsnumber(); i++ )
    {
      Trick tr = t;
      if( tr.isvalid( hi.hand().card(i),hi.hand() ) )
      {
        tr += hi.hand().card( i );

        // last player after me is player with poverty
        bool lastPoverty = (soloPlayer 
                            && tr.actcardno() == 3 
                            && hi.game().soloplayer() == tr.player_of_card(3) );

        if(   tr.winnerplayer().no() != hi.no()
           && hi.hand().card(i).value() == Card::ACE
           && (   !tr.winnercard().less( hi.value( Aiconfig::LIMITHIGH ) )
               || t.islastcard() 
               || lastPoverty 
              )
           && !hi.hand().card( i ).isswine() 
           && (   !hi.hand().card( i ).isfox() 
               || t.islastcard() 
               || lastPoverty 
              )
          )
          c = hi.hand().card( i );     
      } // if ( tr.isvalid ( ... ) )
    } // for ( i < hi.hand().cardsnumber() )

    if( !c.is_empty()) 
      return c;


    // ToDo: Wieso ist eine Neun ein Spiel 'für' das eigene Team? Da gibt doch ein Bube mehr Punkte
    for( i = 0; i < hi.hand().cardsnumber(); i++ )
    {
      Trick tr = t;
      if( tr.isvalid( hi.hand().card(i), hi.hand() ) )
      {
        tr += hi.hand().card( i );
        if(   tr.winnerplayer().no() != hi.no()
           && hi.hand().card(i).value() == Card::NINE
           && !hi.hand().card(i).ishyperswine()
          )
          c = hi.hand().card( i );     
      } // if ( tr.isvalid( ... ) )
    } // for ( i < hi.hand().cardsnumber() )

  } // maybe_to_team(hi.teamofplayer(t.winnerplayer())) == hi.team() ...

  return c;
} // Card Heuristics::play_for_team( Trick t, HeuristicInterface hi )


/**
 ** jabs a fox if in this in the trick
 **
 ** @param        t         current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 **
 ** @author    Borg Enders
 **
 ** @version      Beta
 **/
Card 
Heuristics::jab_fox( Trick const& t, HeuristicInterface const& hi )
{
  // @heuristic::name   jab fox
  // @heuristic::idea   jab a fox if played in this trick

  // @heuristic::condition   it must not be an undetermined marriage
  if (   (hi.game().type() == GAMETYPE::MARRIAGE)
      && (hi.game().marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET)
      && (t.isempty()
          || is_selector(t.startcard().color(), hi.game().marriage_selector()))
     )
    return Card::EMPTY;


  Card c;

  bool fox_exists = false;
  // first lets check if there is a fox
  for( unsigned i = 0; i < t.actcardno(); i++ )
  {
    if( t.card( i ).isfox() )
    {
      fox_exists = true;
      break;
    }
  } // for ( i < t.actcardno() )

  if( fox_exists )
  {
    // if lastcard just take the best winning card
    if(   t.islastcard() 
       && hi.teamofplayer(t.winnerplayer()) != hi.team()
      )
    {
      return best_winning_card(t, hi, 10 ); ///@todo 10 replace with AiConfig
    } 

    // lastcard and this is our trick nothing to do.
    if( (    t.islastcard() 
         || !oppositeTeamCanWinTrick( t, hi ) )
       && hi.teamofplayer(t.winnerplayer())==hi.team() )
    {
      return Card::EMPTY;
    }


    { // if I can jab the fox surely, take the card
      // take the best cards of all players behind me that are not in my team
      Trick const& trick = t;
      HandCard highest_card_behind(hi.hand());
      for (Player const* player = &(trick.game().player_following(trick.actplayer()));
           player != &trick.startplayer();
           player = &(trick.game().player_following(*player))) {
        if( hi.teamofplayer(*player) != hi.team() )
        {
          HandCard const highest_card = player->hand().highest_card();
          if(  highest_card_behind.is_empty()
             || highest_card_behind.less( highest_card )
            )
            highest_card_behind = highest_card;
        } // if (hi.teamofplayer(*player) != hi.team())
      } // for (player)

      if (!highest_card_behind.is_empty()) {
        // the partner has the best possible card
        if(   hi.teamofplayer(trick.winnerplayer()) == hi.team()
           && !trick.winnercard().less( highest_card_behind )
           /// @todo next_higher_card_of_other_team             
          )
          return Card::EMPTY;

        // look whether I have the best card
        Card lowest_better_card;
        HandCards const valid_cards = hi.hand().validcards( t );
        for( HandCards::const_iterator c = valid_cards.begin();
            c != valid_cards.end();
            ++c ) 
        {
          Trick tempTrick = trick; 
          tempTrick += *c;
          if (   trick.is_jabbed(*c)
              && !tempTrick.is_jabbed(highest_card_behind) 
              && (   lowest_better_card.is_empty()
                  || lowest_better_card.less(*c)
                 )
             )
            lowest_better_card = *c;
        } // for (c)

        if (!lowest_better_card.is_empty())
          return lowest_better_card;
      } // if (highest_card_behind)
    } // if I can jab the fox surely, take the card

    if(    (hi.game().trick_current_no() == 0)
       && (t.startcard().istrump() 
           && (!t.islastcard()))
      )
    {
      c = highest_trump_card( t, hi.hand() );
      return c;
    }
    // for all other we take our highest queen
    HandCard ca( hi.hand(), highest_queen( hi.hand(), hi) );
    if( ca.is_empty() ) {
      return Card::EMPTY;
    }

    Trick tr = t;
    tr += ca;
    if(   t.isvalid( ca, hi.hand() ) 
       && tr.winnerplayer().no()==hi.no()
      ) 
    {
      return ca;
    }

  } // if ( fox_exists )

  return c;
} // Card Heuristics::jab_fox( Trick t, HeuristicInterface hi )


/**
 ** -> result
 **
 ** @param        trick        trick
 ** @param        hi        heuristic interface
 **
 ** @return       card with ten points, if the heuristic matches
 **
 ** @author       Borg Enders
 ** @author       Diether Knof
 **
 ** @version      0.6.9
 **/
Card
Heuristics::try_for_doppelkopf( Trick const& trick, 
                               HeuristicInterface const& hi )
{
  // @heuristic::name   try for doppelkopf
  // @heuristic::idea   try to get a doppelkopf for the own team        

  // a doppelkopf gives a specialpoint (t.i. no solo game)
  if (GAMETYPE::is_solo(hi.game().type()))
    return Card::EMPTY;

  // at max one player behind me
  if( trick.actcardno() < hi.game().playerno() - 2 )
    return Card::EMPTY;

  // each player has to give ten points
  if( trick.points() < 10 * trick.actcardno() )
    return Card::EMPTY;


  //last player opposite team ?
  if (   !trick.islastcard()
      && hi.teamofplayer( trick.lastplayer() ) != hi.team() )
    return Card::EMPTY;

  Player const& player = hi.game().player( hi.no() );

  if (   !trick.islastcard()
      && player.announcement() == ANNOUNCEMENT::NOANNOUNCEMENT
      && !hi.game().announcement_valid( ANNOUNCEMENT::NO120, player )
     )
    return Card::EMPTY;

  // search a ten or an ace
  list<Card> try_cards;
  try_cards.push_back( Card( hi.game().trumpcolor(), Card::TEN ) );
  try_cards.push_back( Card( hi.game().trumpcolor(), Card::ACE ) );
  try_cards.push_back( Card::DOLLE );

  for(list<Card>::const_iterator c = try_cards.begin();
      c != try_cards.end();
      ++c )
    if(   hi.hand().numberof(*c) > 0 
       && trick.isvalid( *c, hi.hand() )
       && trick.winnercard().less( *c )
      )
      return *c;

  return Card::EMPTY;
} // Card Heuristics::try_for_doppelkopf(Trick trick,HeuristicInterface hi)


/**
 ** -> result
 **
 ** @param     trick       current trick
 ** @param     hi          heuristic interface
 ** @param     forceFehl   whether to force a fehl card
 **                        default: false
 **
 ** @return    low fehl card with many cards of the color remaining
 **
 ** @author    Borg Enders
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
Card 
choose_best_fehl(Trick const& trick,
                 HeuristicInterface const& hi, bool const forceFehl)
{
  // the best card
  Card best_card;
  // the best number of remaining cards
  // There should be at lest so as many cards remaining
  // as there are other players
  unsigned best_remaining = 0;
  if (!forceFehl)
    best_remaining = (hi.game().playerno() - 1);

  // all valid cards
  HandCards const cards = hi.hand().validcards(trick);

  for (HandCards::const_iterator card = cards.begin();
       card != cards.end();
       ++card) {
    unsigned const remaining
      = hi.cards_information().remaining_others(card->color());
    if(   !card->istrump() 
       && (remaining > best_remaining)
       && (hi.hand().numberof(card->color()) <= 1)
       && (   card->value() == Card::KING 
           || card->value() == Card::NINE )    
      ) {
      best_card = *card;
      best_remaining = remaining;
    } // if (found better card)
  } // for (card \in cards)

  return best_card;
} // Card choose_best_fehl( Trick trick, HeuristicInterface hi, bool forceFehl = false )


/**
 ** play single color nine or king to get fehl in second run of a color
 **
 ** @param     trick   current trick
 ** @param     hi      heuristic interface
 **
 ** @return    card to play, 'Card()' if the heuristic does not match
 **
 ** @author    Borg Enders
 **
 ** @version   0.7.6
 **/
Card 
Heuristics::create_fehl(Trick const& trick, HeuristicInterface const& hi)
{
  // @heuristic::name   create fehl
  // @heuristic::idea   create a missing color (only allowed for first card depending on Aiconfig::FEHLCREATIONONFIRSTCARD)

  if (   (hi.game().type() == GAMETYPE::MARRIAGE)
      && (hi.game().marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET))
    return Card::EMPTY;

  // @heuristic::condition   this trick is still worth fehl creation
  if (!(hi.game().trick_current_no() < hi.value(Aiconfig::LASTFEHLCREATION)))
    return Card::EMPTY;

  // @heuristic::condition   this is the firstcard 
  if (hi.value(Aiconfig::FEHLCREATIONONFIRSTCARD)) 
    if (trick.isstartcard())
      return choose_best_fehl(trick, hi);

  // @heuristic::condition   this is not the first colorrun and there are not more then 10 points 
  if(   !trick.isstartcard()
     && (hi.color_runs(trick.startcard().color()))
     && (trick.points() < hi.value(Aiconfig::LIMIT_THROW_FEHL))
    ) {  
    // @heuristic::condition   - the trick is jabbed high enough 
    if(   trick.winnercard().istrump()
       && !trick.winnercard().less(hi.lowest_trump_card_limit()) 
      ) {
      return choose_best_fehl(trick, hi);
    }

    // @heuristic::condition   - the winnercard is already a no trump ace 
    if(   !trick.winnercard().istrump() 
       && (trick.winnercard().value() == Card::ACE))
      return choose_best_fehl(trick, hi);
  }
  // @heuristic::action   play the best fehl card

  return Card::EMPTY;
} // Card Heuristics::create_fehl(Trick trick, HeuristicInterface hi)


/**
 ** value of cards for announcement
 **
 ** @param        hi        heuristic interface
 ** @param        g         current game
 **
 ** @return       the value of the hand
 **
 ** @author    Borg Enders
 **
 ** @version      Beta
 **/
int 
Heuristics::CalcHandValue( HeuristicInterface const& hi, const Game& g )
{
  // @heuristic::name   ?  calc hand value  ?
  // @heuristic::idea calculates the value of a hand for decision making of announcements, soli decisions,...
  int value = 0;
  unsigned i;

  unsigned v_queen = 0;
  unsigned v_jack = 0;
  unsigned v_highest = 0;
  unsigned v_king = 0;
  unsigned v_ace = 0;
  unsigned v_fehl = 0;

  if( g.type() == GAMETYPE::NORMAL )
  { v_queen = 2; v_jack = 1; v_highest = 3; v_king = 0; v_ace = 1; v_fehl = 2; 
    // Todo: if aggressive
    v_highest += 1;
    if (hi.team() == TEAM::RE)
    {
      value = 1;
    } else
    {
      value = 0;
    }
    // Todo: if aggressive
    //  	value += 1;
  }


  if( g.type() == GAMETYPE::POVERTY )
  { v_queen = 2; v_jack = 1; v_highest = 3; v_king = 0; v_ace = 0; v_fehl = 2;
    value = -3;
  }

  if( g.type() == GAMETYPE::MARRIAGE )
  { v_queen = 2; v_jack = 1; v_highest = 3; v_king = 0; v_ace = 1; v_fehl = 2; }

  if( g.type() == GAMETYPE::SOLO_JACK )
  { v_queen = 0; v_jack = 3; v_highest = 0; v_king = 0; v_ace = 2; v_fehl = 1;
    if (hi.team() == TEAM::RE)
    {
      value = -6;
    } else
    {
      value = -2;
    }
  }

  if (g.type()==GAMETYPE::SOLO_QUEEN)
  { v_queen = 3; v_jack = 0; v_highest = 0; v_king = 0; v_ace = 2; v_fehl = 1;
    if (hi.team() == TEAM::RE)
    {
      value = -6;
    } else
    {
      value = -2;
    }
  }

  if( g.type() == GAMETYPE::SOLO_KING )
  { v_queen = 0; v_jack = 0; v_highest = 0; v_king = 3; v_ace = 2; v_fehl = 1;
    if (hi.team() == TEAM::RE)
    {
      value = -6;
    } else
    {
      value = -2;
    }
  }

  if( g.type() == GAMETYPE::SOLO_QUEEN_JACK )
  { v_queen = 3; v_jack = 2; v_highest = 0; v_king = 0; v_ace = 1; v_fehl = 1;
    if (hi.team() == TEAM::RE)
    {
      value = -6;
    } else
    {
      value = -3;
    }
  }

  if( g.type() == GAMETYPE::SOLO_KING_JACK )
  { v_queen = 0; v_jack = 2; v_highest = 0; v_king = 3; v_ace = 1; v_fehl = 1;
    if (hi.team() == TEAM::RE)
    {
      value = -6;
    } else
    {
      value = -3;
    }
  }

  if( g.type() == GAMETYPE::SOLO_KING_QUEEN )
  { v_queen = 2; v_jack = 0; v_highest = 0; v_king = 3; v_ace = 1; v_fehl = 1;
    if (hi.team() == TEAM::RE)
    {
      value = -6;
    } else
    {
      value = -3;
    }
  }

  if( g.type() == GAMETYPE::SOLO_KOEHLER )
  { v_queen = 2; v_jack = 1; v_highest = 0; v_king = 3; v_ace = 0; v_fehl = 0;
    if (hi.team() == TEAM::RE)
    {
      value = -5;
    } else
    {
      value = -2;
    }
  }

  if(    g.type()==GAMETYPE::SOLO_CLUB 
     || g.type()==GAMETYPE::SOLO_HEART 
     || g.type()==GAMETYPE::SOLO_SPADE 
     || g.type()==GAMETYPE::SOLO_DIAMOND )
  { v_queen = 2; v_jack = 1; v_highest = 3; v_king = 0; v_ace = 1; v_fehl = 2;
    if (hi.team() == TEAM::RE)
    {
      value = -7;
    } else
    {
      value = 0;
    }
  }


  if( g.type() == GAMETYPE::SOLO_MEATLESS )
  { v_queen = 0; v_jack = 0; v_highest = 0; v_king = 0; v_ace = 4; v_fehl = 1; // missing aces
    value = -2; 
  } 

  Player const& player = hi.game().player( hi.no() );

  for( i = 0; i < hi.hand().cardsnumber(); i++ )
  {
    if(   hi.hand().card(i).isdolle()
       || hi.hand().card(i).isswine()
       || hi.hand().card(i).possible_swine()
       || hi.hand().card(i).ishyperswine()
       || hi.hand().card(i).possible_hyperswine()    
      )
      value += v_highest;
    else if( hi.hand().card(i).value()==Card::QUEEN
            || hi.hand().card(i).possible_genscher()  )
      value += v_queen;
    else if( hi.hand().card(i).value()==Card::JACK )
      value += v_jack; 
    else if( hi.hand().card(i).value()==Card::KING )
      value += v_king;
    else if(    hi.hand().card(i).value()==Card::ACE
            && !hi.hand().card(i).istrump() 
            && !hi.jabbedbyotherteam(hi.hand().card(i).color()))
    {
      value += v_ace;
      if (::in_running_game()
          && (hi.game().trick_current().cardno_of_player( player ) == 0 )
          && (hi.hand().numberof( hi.hand().card(i).color() ) == 1) )
      {
        value += 1;
      }
    }
  }

  for (vector<Card::Color>::const_iterator
       c = hi.game().rule().card_colors().begin();
       c != hi.game().rule().card_colors().end();
       ++c)
  {
    Card::Color const color = *c;
    if (   !Card( color, Card::ACE ).istrump( hi.game() ) 
        && !hi.hand().existstcolor( color )
        && !hi.jabbedbyotherteam(color)
       )
      if( ::in_running_game() )
      {
        if(     hi.game().trick_current().actcardno()>0
           && hi.color_runs( color ) == 0
           && (hi.game().trick_current().startcard().tcolor()
               != color) )
          value += v_fehl;
      } else {
        value += v_fehl;
      }
  }

  if( g.type() == GAMETYPE::SOLO_MEATLESS ) {
    for (vector<Card::Color>::const_iterator
         c = hi.game().rule().card_colors().begin();
         c != hi.game().rule().card_colors().end();
         ++c)
    {
      if( hi.hand().existstcolor( *c ) )
        value -=  v_fehl
          * ( 2 - hi.hand().numberof( *c, Card::ACE ) );
    }
    if( hi.no() == hi.game().soloplayer().no() )
    {
      unsigned longColor = 0;
      for (vector<Card::Color>::const_iterator
           c = hi.game().rule().card_colors().begin();
           c != hi.game().rule().card_colors().end();
           ++c)
      {
        if(   hi.hand().numberof(*c,Card::ACE)  == 2 
           && hi.hand().numberof(*c ) > longColor )
          longColor = hi.hand().numberof(*c );
      }
      value += longColor;
    }
  } else  {

    for( vector<Card::Color>::const_iterator 
        c = hi.game().rule().card_colors().begin();
        c != hi.game().rule().card_colors().end();
        ++c ) 
    {
      Card::Color color = *c;

      if( color == hi.game().trumpcolor() )
        continue;
      // including this trick the player does not have the color
      if (    !hi.hand().existstcolor( color )
          && !(    ::in_running_game()
               && ( hi.game().trick_current().actcardno()
                   > hi.game().trick_current().cardno_of_player( player ) )
               && ( hi.game().trick_current().card_of_player( player ).tcolor()
                   == color )
              )
         )
        continue;

      if (  ( hi.hand().numberof( color, Card::ACE ) == 0 )
          && !hi.jabbedbyownteam(color) )
        value -= v_ace;

      if( (   hi.hand().numberof( color )
           + hi.color_runs( color )
           + (   ::in_running_game()
              && hi.game().trick_current().actcardno() > 0
              && ( hi.game().trick_current().startcard().color()
                  == color
                 ) ? 1 : 0 )
           > ( hi.game().different_cards_no( color ) - 1
              - ( hi.game().rule()(Rule::WITH_NINES) ? 0 : 1 ) )
          ) && !hi.jabbedbyownteam(color) )
        value -= v_fehl;

      if ( (   hi.hand().numberof( color )
            + hi.color_runs( color )
            + ( (   ::in_running_game()
                 && hi.game().trick_current().actcardno()>0
                 && ( hi.game().trick_current().startcard().color()
                     == color)
                ) ? 1 : 0)
            >= 3)
          && ( hi.hand().numberof( Card( color, Card::ACE ) ) < 2 )
          && !hi.jabbedbyownteam(color) )
        value -= v_ace;

    } // (for color)
  } // if (...)

  if( g.type() == GAMETYPE::SOLO_KOEHLER ) {
    for( vector<Card::Color>::const_iterator 
        c = hi.game().rule().card_colors().begin();
        c != hi.game().rule().card_colors().end();
        ++c ) 
    {
      if( hi.hand().existstcolor(*c)
         && !hi.jabbedbyownteam(*c) )
        value-=5;
    }
  } // if( g.type() == GAMETYPE::SOLO_KOEHLER )


  if(   (   hi.game().swines_owner() != NULL 
         && hi.game().swines_owner()->no() != hi.no() ) 
     || hi.game().swines_announcement_valid( hi.game().player( hi.no() ) )
    )
  {
    Player const& swines_player = ( hi.game().swines_owner()
                                   ? *hi.game().swines_owner()
                                   : hi.game().player( hi.no() ) );
    if(   hi.teamofplayer(swines_player) == hi.team() 
       || hi.game().swines_announcement_valid( swines_player )
      )
    {
      if(swines_player.no() != hi.no() )
      {
        value += v_highest;
      } else
      {
        value += 1;
      } 
    } else
    {
      value -= 2* v_highest;
    }
  }


  if(  (   hi.game().hyperswines_owner() != NULL 
        && hi.game().hyperswines_owner()->no() != hi.no()
       )
     || hi.game().hyperswines_announcement_valid( hi.game().player( hi.no() ) )
    )
  {
    Player const& hyperswines_player = ( hi.game().hyperswines_owner()
                                        ? *hi.game().hyperswines_owner()
                                        : hi.game().player( hi.no() ) );
    if(   hi.teamofplayer(hyperswines_player) == hi.team() 
       || hi.game().hyperswines_announcement_valid( hyperswines_player ) 
      )
    {
      if(hyperswines_player.no() != hi.no() )
      {
        value += v_highest;
      } else
      {
        value += 1;
      } 
    } else
    {
      value -= 2* v_highest;
    }
  }

  if (hi.hand().numberoftrumps()
      >= ( (hi.cards_information().remaining_trumps_others() / 3)
          + round(  (::in_running_game()
                     ? hi.game().tricks_remaining_no()
                     : hi.game().trickno()
                    )/ 3)
         ) )
    value += 2;

  if (hi.hand().numberoftrumps() >= 10 )
    value += 1;
  if (hi.hand().numberoftrumps() >= hi.game().trickno() - 1 )
    value += 1;
  if (hi.hand().numberoftrumps() >= hi.game().trickno() )
    value += 1;
  if (hi.hand().numberoftrumps() == hi.hand().cardsnumber() )
    value += 1;  

  if (    (::game_status > GAMESTATUS::GAME_START)
      && (hi.game().type() == GAMETYPE::POVERTY)
      && (hi.game().poverty_partner().no() == hi.no()) )
    value -= 2;

  if ( (   g.type() == GAMETYPE::NORMAL
        || g.type() == GAMETYPE::POVERTY )  
      && hi.team() == TEAM::RE )
  {
    if( hi.hand().numberof( Card( Card::SPADE, Card::QUEEN ) ) == 2 )
      value += 2; 
    if( hi.hand().numberof( Card( Card::HEART, Card::QUEEN ) ) == 2 )
      value += 1;
  }


  return value;
} // Heuristics::CalcHandValue( HeuristicInterface hi, Game g )


/**
 ** If the poverty partner is the last player play many points
 **
 ** @param        trick        current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author       Borg Enders
 ** @author       Diether Knof
 **
 ** @version      0.7.2
 **
 ** @todo       if the opposite team has played a high card (p.e. dolle)
 **             do _not_ pfund although the own teammate is last player.
 ** @todo       if an opposite player is behind, check, that the winnercard
 **             of the teammate is high enough
 **                (-> play_pfund?)
 **/
Card
Heuristics::poverty_special_play_pfund(Trick const& trick,
                                       HeuristicInterface const& hi)
{
  // @heuristic::name        poverty: special: play pfund
  // @heuristic::idea        If the trick goes or will go to the own team, play a pfund. This heuristic should only be used by the poverty player.

  if (trick.isstartcard())
    return Card::EMPTY;

  // @heuristic::condition   the last player must be of the own team (oneself or the partner)
  if (hi.teamofplayer(trick.lastplayer()) != hi.team() )
    return Card::EMPTY;

  // the teammate
  vector<Player*>::const_iterator teammate;
  for (teammate = hi.game().players_begin();
       teammate != hi.game().players_end();
       ++teammate)
    if (   ((*teammate)->no() != hi.no())
        && (hi.teamofplayer(**teammate) == TEAM::RE) )
      break;

  // @heuristic::condition   the own team has already the trick or the partner is behind
  if (   (TEAM::maybe_to_team(hi.teamofplayer(trick.winnerplayer())) != hi.team())
      && (trick.cardno_of_player(**teammate) < trick.actcardno()) )
    return Card::EMPTY;

  // @heuristic::condition   if the partner is behind, he can still jab the trick
  if (!trick.winnercard().less(hi.handofplayer(**teammate).highest_trump()))
    return Card::EMPTY;

  // @heuristic::action      play a pfund
  // ToDo: Borg: use 'play_pfund'
  Card c;
  HandCards const ha = hi.hand().validcards( trick );

  // find any card that's allowed for this trick
  for( unsigned i = 0; i < ha.cardsnumber(); i++ )
    if( !ha.card(i).istrump() ) {
      c = ha.card(i);
      break;
    }

  if (c.is_empty()) 
    return Card::EMPTY;

  // find a better card
  for( unsigned i = 0; i < ha.cardsnumber(); i++ ) {
    if(   !ha.card(i).istrump()
       && (ha.card(i).value() != Card::ACE)
       && (ha.card(i).value() > c.value())
       && (   (ha.numberof( ha.card(i).color() ) >  ha.numberof(c.color())) 
           || (ha.numberof( ha.card(i).color(), Card::ACE ) == 0)
          )
      )
      c = ha.card(i);
  } // for ( i < ha.cardsnumber() )

  return c;
} // Card Heuristics::poverty_special_play_pfund(Trick trick, HeuristicInterface hi)


/**
 ** If the poverty partner has played high and still many points on hand play many points.
 **
 ** @param        trick        current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author       Borg Enders
 **
 ** @version      0.7.6
 **/
Card
Heuristics::poverty_special_offer_pfund(Trick const& trick,
                                        HeuristicInterface const& hi)
{
  // @heuristic::name        poverty: special: offer pfund
  // @heuristic::idea        If the poverty partner has played high and still many points on hand play many points.

  if (trick.isstartcard())
    return Card::EMPTY;

  // @heuristic::condition   poverty player
  if (hi.game().type() != GAMETYPE::POVERTY)
    return Card::EMPTY;
  if (hi.no() != hi.game().soloplayer().no())
    return Card::EMPTY;

  // @heuristic::condition   the partner has jabbed with a high card
  if (   (hi.teamofplayer(trick.winnerplayer()) != hi.team())
      || trick.winnercard().less(hi.value(Aiconfig::LIMITHIGH) )  )
    return Card::EMPTY;

  // @heuristic::condition   the player has many high cards
  if (hi.hand().numberof(Card::TEN) + hi.hand().numberof(Card::ACE)
      < hi.hand().cardsnumber() / 2)
    return Card::EMPTY;


  Card c;
  HandCards const ha = hi.hand().validcards( trick );

  // find any card that's allowed for this trick
  for (unsigned i = 0; i < ha.cardsnumber(); i++) {
    if (!ha.card(i).istrump()) {
      c = ha.card(i);
      break;
    } // if (!ha.card(i).istrump())
  } // for ( i < ha.cardsnumber())

  if (c.is_empty())
    return Card::EMPTY;

  // find a better card
  for (unsigned i = 0; i < ha.cardsnumber(); i++) {
    if (   !ha.card(i).istrump()
        && (ha.card(i).value() != Card::ACE)
        && (ha.card(i).value() >= c.value())
        && (   (   ha.numberof( ha.card(i).color() ) >  ha.numberof(c.color()))
            || (ha.numberof( ha.card(i).color(), Card::ACE ) == 0)
           )
       )
      c = ha.card(i);
  }   // for (i < ha.cardsnumber())

  if (c.value() < Card::TEN) {
    for (unsigned i = 0; i < ha.cardsnumber(); i++) {
      if (   !ha.card(i).istrump()
          && (ha.card(i).value() >= c.value())
          && ha.numberof( ha.card(i).color() ) > ha.numberof(c.color())
         )
        c = ha.card(i);
    } // for ( i < ha.cardsnumber() )
  } // if (c.value() < Card::TEN)

  // @heuristic::action      play a ten or ace of the color with the most cards
  return c;
} // Card Heuristics::poverty_special_play_pfund(Trick trick, HeuristicInterface hi)


/**
 ** 1) poverty player
 ** 2) contra players get trick
 ** give as few points as possible
 **
 ** reason: do not give points to the opposite team
 **
 ** @param        trick        current trick
 ** @param        hi        heuristic interface
 **
 ** @return        card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author        Diether Knof
 **
 ** @version        0.7.3
 **
 ** @todo      choose a 'good' color (to keep as much freedom as possible)
 ** @todo      'anfüttern' of a high re-card with a king
 ** @todo      not in the first color run, if the re has or can get the trick
 **/
Card
Heuristics::poverty_special_give_no_points(Trick const& trick,
                                           HeuristicInterface const& hi)
{

  // @heuristic::name        poverty: special: give no points
  // @heuristic::idea        If the contra team gets the trick, give as few points as possible.


  // @heuristic::condition   the player must be the poverty player
  if (hi.game().type() != GAMETYPE::POVERTY)
    return Card::EMPTY;
  if (hi.no() != hi.game().soloplayer().no())
    return Card::EMPTY;

  // the accepter of the poverty
  Player const& re_player = hi.game().poverty_partner();

  // check whether the contra team gets the trick:
  // @heuristic::condition   the partner has played already
  // @heuristic::condition   contra already has the trick or the re player can be overjabbed
  if (trick.cardno_of_player(re_player) > trick.actcardno())
    return Card::EMPTY;

  if (   trick.islastcard()
      && (trick.winnerplayerno() == re_player.no()) )
    return Card::EMPTY;

  if (   trick.startcard().istrump()
      && hi.hand().hastrump())
    return Card::EMPTY;

  /// @todo   Use 'cards information' for checking that the contra team can jab.
  if (   (trick.winnerplayerno() == re_player.no())
      && (!trick.winnercard().less(hi.value(Aiconfig::TRUMPLIMIT_NORMAL))
          || (   !trick.startcard().istrump()
              && (hi.color_runs(trick.startcard().tcolor()) == 0) ) ) ) {
    return Card::EMPTY;
  }

  // @heuristic::action   play the lowest card
  // search the lowest card
  // ToDo: check for a 'good' color
  // ToDo: create and use 'best_loosing_card'
  HandCards const cards = hi.hand().cards_single();
  HandCard card; // the card to play
  for (HandCards::const_iterator c = cards.begin();
       c != cards.end();
       ++c) {
    if (!trick.isvalid(*c))
      continue ;
    if (card.is_empty()) {
      card = *c;
      continue;
    }
    if (c->value() < card.value())
      card = *c;
  } // for (c \in cards)

  return card;
} // Card Heuristics::poverty_special_give_no_points(Trick trick, HeuristicInterface hi)


/**
 ** 1) re player in a poverty
 ** 2) color trick, cannot serve it
 ** play high trump (small queen or so)
 **
 ** reason: jab for the points
 **
 ** note: Should be called after 'serve color trick'
 **       because this is overreacted for the first color run.
 **
 ** @param        trick        current trick
 ** @param        hi        heuristic interface
 **
 ** @return        card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author        Diether Knof
 **
 ** @version        0.7.3
 **
 ** @todo      for more points take a higher card
 **/
Card
Heuristics::poverty_re_trump_color_trick_high(Trick const& trick,
                                              HeuristicInterface const& hi)
{
  // @heuristic::name   poverty: re: trump color trick high
  // @heuristic::idea   Jab the trick with a small queen in order to get the points

  // @heuristic::condition   re player (not poverty player) in a poverty
  if (hi.game().type() != GAMETYPE::POVERTY)
    return Card::EMPTY;
  if (   (hi.team() != TEAM::RE)
      || (hi.no() == hi.game().soloplayer().no()) )
    return Card::EMPTY;

  // @heuristic::condition only my team behind me, I don't need to jab high
  if( checkAllMyTeam( trick, hi ) )
    return Card::EMPTY;

  // @heuristic::condition   neither first nor last card in the trick
  if (trick.isstartcard())
    return Card::EMPTY;
  if (trick.islastcard())
    return Card::EMPTY;
  // @heuristic::condition   color trick which must not be served
  if (   trick.startcard().istrump()
      || hi.hand().existstcolor(trick.startcard().tcolor()))
    return Card::EMPTY;

  // @heuristic::action   play high trump (small queen)
  // ToDo: Borg: use 'choose_best_card'
  // search in the order one of the following cards to play
  list<Card> cards_to_play;

  if(   hi.color_runs( trick.startcard().color() ) > 0
     && !trick.startcard().istrump() 
     && trick.points() >= 10 )
  {
    cards_to_play.push_back(Card(Card::SPADE,   Card::QUEEN));
    cards_to_play.push_back(Card(Card::HEART,   Card::QUEEN));
    cards_to_play.push_back(Card(Card::DIAMOND, Card::QUEEN));
    cards_to_play.push_back(Card(Card::CLUB,    Card::JACK));
    cards_to_play.push_back(Card(Card::SPADE,   Card::JACK));
    cards_to_play.push_back(Card(Card::HEART,   Card::JACK));
    cards_to_play.push_back(Card(Card::DIAMOND, Card::JACK));
  } else
  {
    cards_to_play.push_back(Card(Card::HEART,   Card::QUEEN));
    cards_to_play.push_back(Card(Card::DIAMOND, Card::QUEEN));
    cards_to_play.push_back(Card(Card::CLUB,    Card::JACK));
    cards_to_play.push_back(Card(Card::SPADE,   Card::JACK));
    cards_to_play.push_back(Card(Card::SPADE,   Card::QUEEN));
    cards_to_play.push_back(Card(Card::HEART,   Card::JACK));
    cards_to_play.push_back(Card(Card::DIAMOND, Card::JACK));
  }

  for (list<Card>::const_iterator c = cards_to_play.begin();
       c != cards_to_play.end();
       ++c)
    if (   (hi.hand().numberof(*c) > 0)
        && trick.winnercard().less(*c))
      return *c;

  return Card::EMPTY;
} // Card Heuristics::poverty_re_trump_color_trick_high(Trick trick, HeuristicInterface hi)


/**
 ** 1) re player in a poverty
 ** 2) first player
 ** play a trump (diamond jack, ..., club queen)
 **
 ** reason: draw trump from the contra players
 **
 ** note: this heuristic shall be called after 'draw trump'
 **
 ** @param        trick        current trick
 ** @param        hi        heuristic interface
 **
 ** @return        card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author        Diether Knof
 **
 ** @version        0.7.3
 **/
Card
Heuristics::poverty_re_play_trump(Trick const& trick,
                                  HeuristicInterface const& hi)
{
  // @heuristic::name   poverty: re: play trump
  // @heuristic::idea   As first player draw trump fro the contra players.

  // @heuristic::condition   re player (not poverty player) in a poverty
  if (hi.game().type() != GAMETYPE::POVERTY)
    return Card::EMPTY;

  if (   (hi.team() != TEAM::RE)
      || (hi.no() == hi.game().soloplayer().no()) )
    return Card::EMPTY;


  // @heuristic::condition   first player
  if (!trick.isstartcard())
    return Card::EMPTY;


  list<Card> cards_to_play;

  // @heuristic::condition   partner has no trump
  if (hi.cards_information().of_player(hi.game().soloplayer()).does_not_have(Card::TRUMP))
  {
    // @heuristic::action   play a small jack
    bool jacksAdded = false;
    if(   (hi.game().tricks_remaining_no() > hi.game().trickno() / 2)
       || (hi.hand().numberof( Card::JACK ) > hi.hand().numberof( Card::QUEEN) )
      )
    {
      jacksAdded = true;
      cards_to_play.push_back(Card(Card::CLUB,    Card::JACK));  
      cards_to_play.push_back(Card(Card::SPADE,   Card::JACK));
      cards_to_play.push_back(Card(Card::HEART,   Card::JACK));
      cards_to_play.push_back(Card(Card::DIAMOND, Card::JACK));
    }
    cards_to_play.push_back(Card(Card::DIAMOND, Card::QUEEN));
    cards_to_play.push_back(Card(Card::HEART,   Card::QUEEN));
    cards_to_play.push_back(Card(Card::SPADE,   Card::QUEEN));
    cards_to_play.push_back(Card(Card::CLUB,    Card::QUEEN));
    if( ! jacksAdded ) 
    {
      cards_to_play.push_back(Card(Card::CLUB,    Card::JACK));  
      cards_to_play.push_back(Card(Card::SPADE,   Card::JACK));
      cards_to_play.push_back(Card(Card::HEART,   Card::JACK));
      cards_to_play.push_back(Card(Card::DIAMOND, Card::JACK));
    } // if ( ! jacksAdded )
  } else // partner has trump
  {
    // @heuristic::comment   \n\n
    // @heuristic::condition   partner has trump
    // @heuristic::action   play a high trump
    if( hi.hand().numberof( Card::DOLLE ) == 2 ) 
      cards_to_play.push_back(Card::DOLLE);

    cards_to_play.push_back(Card(Card::CLUB,    Card::QUEEN));
    cards_to_play.push_back(Card(Card::SPADE,   Card::QUEEN));
    cards_to_play.push_back(Card(Card::HEART,   Card::QUEEN));
    cards_to_play.push_back(Card(Card::DIAMOND, Card::QUEEN));
    cards_to_play.push_back(Card(Card::CLUB,    Card::JACK));  
    cards_to_play.push_back(Card(Card::SPADE,   Card::JACK));
    cards_to_play.push_back(Card(Card::HEART,   Card::JACK));
    cards_to_play.push_back(Card(Card::DIAMOND, Card::JACK));
  } // end of: partner has trump

  for (list<Card>::const_iterator c = cards_to_play.begin();
       c != cards_to_play.end();
       ++c)
    if (hi.hand().numberof(*c) > 0)
      return *c;


  return Card::EMPTY;
} // Card Heuristics::poverty_re_play_trump(Trick trick, HeuristicInterface hi)


/**
 ** 1) contra player in a poverty
 ** 2) first player
 ** play a color
 **
 ** reason: do not draw trump
 **
 ** @param        trick        current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author       Diether Knof
 **
 ** @version       0.7.3
 **/
Card
Heuristics::poverty_contra_play_color(Trick const& trick,
                                      HeuristicInterface const& hi)
{
  // @heuristic::name   poverty: contra: play color
  // @heuristic::idea   Start with a color.

  // @heuristic::condition   contra player in a poverty
  if (hi.game().type() != GAMETYPE::POVERTY)
    return Card::EMPTY;
  if (hi.team() != TEAM::CONTRA)
    return Card::EMPTY;

  // @heuristic::condition   first player
  if (!trick.isstartcard())
    return Card::EMPTY;


  // the player with the poverty
  Player const& poverty_player = hi.game().soloplayer();
  // the accepter of the poverty
  Player const& re_player = hi.game().poverty_partner();
  // the partner
  // Bug: this formula does only work with four players
  Player const& partner = hi.game().player( (0 + 1 + 2 + 3)
                                           - poverty_player.no()
                                           - re_player.no()
                                           - hi.no());

  // @heuristic::action   Play a color the partner does not have; if the partner is behind the re player, take a high card, else take a low one. Else take the longest color.
  { // search a color to play
    vector<Card::Color> const& colors = hi.game().rule().card_colors();
    vector<Card::Color>::const_iterator c;
    // first search for a color the partner does not have

    for (c = colors.begin();
         c != colors.end();
         ++c)
      if (   hi.cards_information().of_player(partner).does_not_have(*c)
          && hi.hand().existstcolor(*c))
        break;

    if (c != colors.end()) {
      // There is a color the partner does not have.
      HandCards const cards = hi.hand().cards_single();
      HandCard card; // the card to play
      for (HandCards::const_iterator c = cards.begin();
           c != cards.end();
           ++c) {
        if (c->istrump())
          continue;
        if (!hi.cards_information().of_player(partner).does_not_have(c->tcolor()))
          continue;
        if (card.is_empty()) {
          card = *c;
          continue;
        }
        // If the partner is behind the re player, take the highest card
        // else take the lowest
        if (   (c->value() > card.value())
            == (trick.cardno_of_player(partner)
                > trick.cardno_of_player(re_player)) )
          card = *c;
      } // for (c \in cards)

      return card;

    } else { // if !(c != colors.end())
      // There is no color the partner does not have.
      // Play the color I have the most number of.
      Card::TColor color = Card::NOCARDCOLOR;
      unsigned max_num = 0;
      for (vector<Card::Color>::const_iterator c = colors.begin();
           c != colors.end();
           ++c)
        if (hi.hand().numberof(*c) > max_num)
          color = *c, max_num = hi.hand().numberof(*c);

      // play the smallest card of the color
      HandCards const cards = hi.hand().cards_single();
      HandCard card; // the card to play
      for (HandCards::const_iterator c = cards.begin();
           c != cards.end();
           ++c) {
        if (c->tcolor() != color)
          continue;
        if (c->value() < card.value())
          card = *c;
      } // for (c \in cards)

      return card;
    } // if !(c != colors.end())

  } // search a color to play

  return Card::EMPTY;
} // Card Heuristics::poverty_contra_play_color(Trick trick, HeuristicInterface hi)


/**
 ** 1) contra player in a poverty
 ** 2) color trick, cannot serve it
 ** 3) re player is behind
 ** 4) a) partner before:
 **       - partner has played low
 **       - there are some points in the trick
 **    b) partner behind:
 **       - partner can have the color
 ** play high trump (small queen or so)
 **
 ** reason: The re player does in most cases not have the color
 **         so make the trick expensive for him.
 **
 ** @param        trick        current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author       Diether Knof
 **
 ** @version      0.7.3
 **
 ** @todo       use 'best_winning_card()'
 **/
Card
Heuristics::poverty_contra_trump_color_trick_high(Trick const& trick,
                                                  HeuristicInterface const& hi)
{
  // @heuristic::name   poverty: contra: trump color trick high
  // @heuristic::idea   Play a high trump (small queen) in color tricks, so that the trick is expensive for the re player.

  // @heuristic::condition   contra player in a poverty
  if (hi.game().type() != GAMETYPE::POVERTY)
    return Card::EMPTY;
  if (hi.team() != TEAM::CONTRA)
    return Card::EMPTY;

  // @heuristic::condition   a color trck the player must not serve
  if (trick.isstartcard())
    return Card::EMPTY;
  if (   trick.startcard().istrump()
      || hi.hand().existstcolor(trick.startcard().tcolor()))
    return Card::EMPTY;


  // the player with the poverty
  Player const& poverty_player = hi.game().soloplayer();
  // the accepter of the poverty
  Player const& re_player = hi.game().poverty_partner();
  // the partner
  // Bug: this formula does only work with four players
  Player const& partner = hi.game().player( (0 + 1 + 2 + 3)
                                           - poverty_player.no()
                                           - re_player.no()
                                           - hi.no());


  // @heuristic::condition   the re player is behind
  if (trick.cardno_of_player(re_player) < trick.actcardno())
    return Card::EMPTY;

  if (trick.cardno_of_player(partner) < trick.actcardno()) {
    // @heuristic::condition   a) the partner has played low (trump limit)
    if (!(   !trick.card_of_player(partner).istrump()
          || trick.card_of_player(partner).less(hi.value(Aiconfig::TRUMPLIMIT_NORMAL)))
       )
      return Card::EMPTY;

    // @heuristic::condition   a) there are some points (>= 8) in the trick
    if (trick.points() < 8) // *Value*
      return Card::EMPTY;
  } else { // if !(partner before)
    // @heuristic::condition   b) the partner is behind
    // @heuristic::condition   b) the partner can have the color
    if (hi.cards_information().of_player(partner).does_not_have(trick.startcard().tcolor()))
      return Card::EMPTY;
  } // if !(partner before)
  // the partner was before and has played low

  // @heuristic::action   play high trump (small queen)
  // ToDo: Borg: use 'best_winning_card'
  // search in the order one of the following cards to play
  list<Card> cards_to_play;
  cards_to_play.push_back(Card(Card::HEART,   Card::QUEEN));
  cards_to_play.push_back(Card(Card::DIAMOND, Card::QUEEN));
  cards_to_play.push_back(Card(Card::CLUB,    Card::JACK));
  cards_to_play.push_back(Card(Card::SPADE,   Card::JACK));
  cards_to_play.push_back(Card(Card::SPADE,   Card::QUEEN));
  cards_to_play.push_back(Card(Card::HEART,   Card::JACK));
  cards_to_play.push_back(Card(Card::DIAMOND, Card::JACK));

  for (list<Card>::const_iterator c = cards_to_play.begin();
       c != cards_to_play.end();
       ++c)
    if (hi.hand().numberof(*c) > 0)
      return *c;

  return Card::EMPTY;
} // Card Heuristics::poverty_contra_trump_color_trick_high(Trick trick, HeuristicInterface hi)


/**
 ** 1) contra player in a poverty
 ** 2) re has played trump
 ** 3) partner is behind and can jab the trick
 ** play a small trump so that the partner can get the trick
 **
 ** reason: make myself be behind the re player
 **
 ** @param        trick        current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author       Diether Knof
 **
 ** @version      0.7.3
 **/
Card
Heuristics::poverty_leave_to_partner(Trick const& trick,
                                     HeuristicInterface const& hi)
{
  // @heuristic::name   poverty: contra: leave to partner
  // @heuristic::idea   Make myself be behind the re player.

  // @heuristic::condition   contra player in a poverty
  if (hi.game().type() != GAMETYPE::POVERTY)
    return Card::EMPTY;
  if (   (hi.team() != TEAM::CONTRA)
      && (hi.no() != hi.game().soloplayer().no()) )
    return Card::EMPTY;

  // the player with the poverty
  Player const& poverty_player = hi.game().soloplayer();
  // the accepter of the poverty
  Player const& re_player = hi.game().poverty_partner();
  // the partner
  // Bug: this formula does only work with four players
  Player const& partner = hi.game().player( (0 + 1 + 2 + 3)
                                           - poverty_player.no()
                                           - re_player.no()
                                           - hi.no());


  // @heuristic::condition   the re player has played a trump
  // more precise: it has been started with trump and re has already played
  // (contains the case that the poverty player has started with trump)
  if (trick.isstartcard())
    return Card::EMPTY;
  if (!trick.startcard().istrump())
    return Card::EMPTY;
  if (trick.cardno_of_player(re_player) > trick.actcardno())
    return Card::EMPTY;

  // @heuristic::condition   the partner is behind and can jab the trick
  if (trick.cardno_of_player(partner) < trick.actcardno())
    return Card::EMPTY;
  // ToDo: use cards information
  if (!trick.winnercard().less(hi.value(Aiconfig::TRUMPLIMIT_NORMAL)))
    return Card::EMPTY;

  // @heuristic::action   play a low trump
  // ToDo: Borg: use 'play_pfund'?
  list<Card> cards_to_play;

  // special case:
  //   poverty player behind has still trump and
  //   re player has played a small trump
  if (!(   (hi.game().type() == GAMETYPE::POVERTY)
        && (trick.startplayer().team() == TEAM::RE)
        // ToDo: better card value
        && trick.startcard().less(hi.value(Aiconfig::LIMITHIGH))
        && (trick.cardno_of_player(hi.game().soloplayer()) > trick.actcardno())
        && !hi.cards_information().of_player(hi.game().soloplayer()).does_not_have(Card::TRUMP)) ) {
    if (!hi.hand().has_swines())
      cards_to_play.push_back(Card(Card::DIAMOND, Card::ACE));
    cards_to_play.push_back(Card(Card::DIAMOND, Card::TEN));
  } // if (special case poverty)
  cards_to_play.push_back(Card(Card::DIAMOND, Card::KING));
  cards_to_play.push_back(Card(Card::DIAMOND, Card::NINE));
  // ToDo: Hand function 'next greater card'
  cards_to_play.push_back(Card(Card::DIAMOND, Card::JACK));
  cards_to_play.push_back(Card(Card::HEART,   Card::JACK));
  cards_to_play.push_back(Card(Card::SPADE,   Card::JACK));
  cards_to_play.push_back(Card(Card::CLUB,    Card::JACK));
  cards_to_play.push_back(Card(Card::DIAMOND, Card::QUEEN));
  cards_to_play.push_back(Card(Card::HEART,   Card::QUEEN));
  cards_to_play.push_back(Card(Card::SPADE,   Card::QUEEN));
  cards_to_play.push_back(Card(Card::CLUB,    Card::QUEEN));

  for (list<Card>::const_iterator c = cards_to_play.begin();
       c != cards_to_play.end();
       ++c)
    if (hi.hand().numberof(*c) > 0)
      return *c;

  return Card::EMPTY;
} // Card Heuristics::poverty_leave_to_partner(Trick trick, HeuristicInterface hi)


/**
 ** 1) contra player in a poverty
 ** 2) re player has won with a trump
 ** 3) can play a better card than the re player
 ** play next higher card
 **
 ** reason: If you can, overjab the re player in order to get points.
 **
 ** note: Should be called after 'leave to partner'
 **
 ** @param        trick        current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author       Diether Knof
 **
 ** @version      0.7.3
 **/
Card
Heuristics::poverty_overjab_re(Trick const& trick,
                               HeuristicInterface const& hi)
{
  // @heuristic::name   poverty: contra: overjab re
  // @heuristic::idea   Overjab the re player in order to get the points.

  // @heuristic::condition   contra player in a poverty
  if (hi.game().type() != GAMETYPE::POVERTY)
    return Card::EMPTY;
  if (hi.team() != TEAM::CONTRA)
    return Card::EMPTY;

  // @heuristic::condition   the re player has won so far with a trump
  if (trick.winnerplayer().no() != hi.game().poverty_partner().no())
    return Card::EMPTY;
  if (!trick.winnercard().istrump())
    return Card::EMPTY;

  // @heuristic::condition   the player can play a better card than the re player
  if (!(   trick.startcard().istrump()
        || !hi.hand().existstcolor(trick.startcard().tcolor()) ) )
    return Card::EMPTY;

  // @heuristic::action   Take the best winning card.
  return Heuristics::best_winning_card(trick, hi);
} // Card Heuristics::poverty_overjab_re(Trick trick, HeuristicInterface hi)


/**
 ** best winning card for the last card
 * 
 ** @param        trick        current trick
 ** @param        hi        heuristic interface
 **
 ** @return       card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author       Diether Knof
 **
 ** @version      0.7.3
 **/
Card
Heuristics::poverty_best_winning_card(Trick const& trick,
                                      HeuristicInterface const& hi)
{
  // @heuristic::name   poverty: best winning card
  // @heuristic::idea   As last player in a trick take the lowest card to win the trick.

  // @heuristic::condition   only for the not poverty player in a poverty
  if (hi.game().type() != GAMETYPE::POVERTY)
    return Card::EMPTY;
  if (   (hi.team() != TEAM::RE)
      || (hi.no() == hi.game().soloplayer().no()) )
    return Card::EMPTY;

  // @heuristic::condition   last player in the trick
  if (!trick.islastcard() )
    return Card::EMPTY;

  // @heuristic::action   Play the best winning card.
  return Heuristics::best_winning_card(trick, hi);
} // Card Heuristics::poverty_best_winning_card(Trick trick, HeuristicInterface hi)


/**
 ** checks if an announcement should be made
 **
 ** @param        hi        heuristic interface
 ** @param        g         current game
 **
 ** @return       returns true if an announcement should be made
 **
 ** @author    Borg Enders
 **
 ** @version      Beta
 **/
bool 
Heuristics::make_announcement( HeuristicInterface const& hi, const Game& g )
{
  // @heuristic::name   ?  make announcement  ?
  // @heuristic::idea announcement decision bases on Heuristics::CalcHandValue
  int value=0;

  value= CalcHandValue( hi, g );

  value += calcPointsOfOwnTeam( hi, g ) / 25;


  // (trumps - no trumps) = trumps - (cards on hand - trumps ) = 2* trumps - cards on hand
  if (   ( 2*hi.hand().numberoftrumps() > hi.hand().cardsnumber() )  ) // ToDo: only for aggressive AI?
    value += (2*hi.hand().numberoftrumps() - hi.hand().cardsnumber() ) /5;

  if (   (hi.game().type() == GAMETYPE::MARRIAGE)
      && (hi.game().marriage_selector() == MARRIAGE_SELECTOR::TEAM_SET)
      && ( hi.team() == TEAM::RE )
      && (hi.game().soloplayer().no() != hi.no() )
     )
    value += 6; // 2do should be 3*numberofqueens still in game

#ifdef ANNOUNCE_DEBUG
  if( !g.isvirtual() )
    cout << "RE/CO: " << hi.no() << "\t" << value << "\t" 
      << (int)hi.value(Aiconfig::ANNOUNCELIMIT) << " + " 
      << (int)hi.value(Aiconfig::ANNOUNCECONFIG) << std::endl; 
#endif

  if( (    GAMETYPE::is_solo( hi.game().type() ) 
       ||  (hi.game().marriage_selector() == MARRIAGE_SELECTOR::SILENT) )
     && !g.last_chance_to_announce(ANNOUNCEMENT::NO120, g.player(hi.no()) ) )
    return false;


  return ( value >=  (static_cast<int>(hi.value(Aiconfig::ANNOUNCELIMIT)) 
                      + static_cast<int>(hi.value(Aiconfig::ANNOUNCECONFIG))));
} // bool Heuristics::make_announcement( HeuristicInterface hi, Game g )


/**
 ** calculates all points of own team in Game g
 **
 ** @param        hi        heuristic interface
 ** @param        g         current game
 **
 ** @return       points of own team in the game
 **
 ** @author    Borg Enders
 **
 ** @version      Beta
 **/
int 
calcPointsOfOwnTeam( HeuristicInterface const& hi, Game const& g )
{
  if (!::in_running_game())
    return 0;

  int points_p = 0;

  for( unsigned int i = 0; i < g.playerno(); i++ )
  {
    if( hi.teamofplayer( g.player(i) ) == hi.team() )
    {
      points_p += g.points_of_player( g.player(i) );
    }
  } // for ( i < g.playerno() )

  Trick tr = g.trick_current();
  if( tr.isfull() )
    if( TEAM::maybe_to_team(hi.teamofplayer(tr.winnerplayer())) == hi.team() )
    {
      points_p += tr.points();
    } 

  return points_p;
} // int calcPointsOfOwnTeam( HeuristicInterface hi, Game g )


/**
 ** calculates all points of opposite team in Game g
 **
 ** @param        hi        heuristic interface
 ** @param        g         current game
 **
 ** @return       points of other team in game
 **
 ** @author    Borg Enders
 **
 ** @version      Beta
 **/
int 
calcPointsOfOppositeTeam( HeuristicInterface const& hi, Game const& g)
{
  if (!::in_running_game())
    return 0;

  int points_p = 0;

  for( unsigned int i = 0; i < g.playerno(); i++ )
  {
    if( hi.teamofplayer( g.player(i) ) != hi.team() )
    {
      points_p += g.points_of_player( g.player(i) );
    }
  } // for ( i < g.playerno() )

  Trick tr = g.trick_current();
  if( tr.isfull() )
    if( TEAM::maybe_to_team(hi.teamofplayer(tr.winnerplayer())) != hi.team() )
    {
      points_p += tr.points();
    } 

  return points_p;
} // int calcPointsOfOppositeTeam( HeuristicInterface hi, Game g)


/**
 ** checks if No90 should be said
 **
 ** @param        hi        heuristic interface
 ** @param        g         current game
 **
 ** @return       true if hi should say No90
 **
 ** @author    Borg Enders
 **
 ** @version      Beta
 **/
bool 
Heuristics::say_no90( HeuristicInterface const& hi ,const Game& g )
{
  // @heuristic::name   ?  say no 90  ?
  // @heuristic::idea decision to make the annoncement no 90 depending on Heuristics::CalcHandValue
  int value = 0;

  if( g.announcement_of_team( opposite( hi.team() ) ).announcement 
     > ANNOUNCEMENT::NO120 )
    return false;

  value = CalcHandValue( hi, g ) 
    - std::max( 0, (int)g.tricks_remaining_no() - 8) 
    * static_cast<int>(hi.value(Aiconfig::ANNOUNCELIMITDEC));

  for( vector<Card::Color>::const_iterator 
      c = hi.game().rule().card_colors().begin();
      c != hi.game().rule().card_colors().end();
      ++c ) 
  {
    Card::Color color = *c;

    if( color == hi.game().trumpcolor() )
      continue;

    if (  ( hi.hand().numberof( color, Card::ACE ) == 0 )
        && !hi.jabbedbyownteam(color) 
        && hi.hand().numberof( color ) > 0 )
      value -= (hi.color_runs( color )+hi.hand().numberof( color ));

  } // (for color)

  if(    !g.hastrick(::opposite(hi.team())) )
    value += 2 * static_cast<int>(hi.value(Aiconfig::ANNOUNCELIMITDEC));


  int own_p = calcPointsOfOwnTeam( hi, g );
  int opp_p = calcPointsOfOppositeTeam( hi, g );

  if( own_p > 150 )
    return true;


  opp_p+= 4 * g.tricks_remaining_no(); //previous: 5
  own_p+= 7 * g.tricks_remaining_no(); // previous: 6

  own_p += (int)(1.9 * hi.hand().numberoftrumps()
                 * hi.hand().numberofswines());
  own_p += (int)(1.4 * hi.hand().numberoftrumps()
                 * hi.hand().numberofhyperswines());


  if( GAMETYPE::is_solo( hi.game().type() ) )
  {
    own_p += 20 * hi.hand().numberoftrumps();
    opp_p += 20 * hi.cards_information().remaining_trumps_others();
  }

#ifdef ANNOUNCE_DEBUG
  if( !g.isvirtual() )
    cout << "NO90: " << hi.no() << "\t" << value << " + " 
      << 2 * (int)hi.value(Aiconfig::ANNOUNCELIMITDEC ) << "\t"
      << (int)hi.value(Aiconfig::ANNOUNCELIMIT) << " + " 
      << 2 * (int)hi.value(Aiconfig::ANNOUNCECONFIG) << std::endl;
  cout << "\t" << own_p << "\t" << 1.5 * opp_p << std::endl;
#endif
  return (   (    value + 2 * (int)hi.value(Aiconfig::ANNOUNCELIMITDEC )
              >     (int)hi.value(Aiconfig::ANNOUNCELIMIT)
              + 2*(int)hi.value(Aiconfig::ANNOUNCECONFIG)
             )

          && own_p > 1.5 * opp_p  // previous: 2
          && opp_p < 90 
          && (   opp_p > 0  
              || g.last_chance_to_announce(ANNOUNCEMENT::NO90,
                                           g.player(hi.no()))
             )
         );
} // bool Heuristics::say_no90( HeuristicInterface hi ,Game g )


/**
 ** checks if No60 should be said
 **
 ** @param        hi        heuristic interface
 ** @param        g         current game
 **
 ** @return       true if hi should say No60
 **
 ** @author    Borg Enders
 **
 ** @version      Beta
 **/
bool 
Heuristics::say_no60( HeuristicInterface const& hi, const Game& g )
{
  // @heuristic::name   ?  say no 60  ?
  // @heuristic::idea decision to make the annoncement no 60 depending on Heuristics::CalcHandValue
  int value = 0;

  if( g.announcement_of_team( opposite( hi.team() ) ).announcement 
     > ANNOUNCEMENT::NO120 )
    return false;

  value = CalcHandValue( hi, g ) 
    - std::max( 0, (int)g.tricks_remaining_no() - 5) 
    * static_cast<int>(hi.value(Aiconfig::ANNOUNCELIMITDEC));

  int own_p = calcPointsOfOwnTeam( hi, g );
  int opp_p = calcPointsOfOppositeTeam( hi, g );

  if( own_p > 180 )
    return true;


  opp_p+= 4 * g.tricks_remaining_no(); //previous: 5
  own_p+= 6 * g.tricks_remaining_no(); // previous: 5

  own_p += 3 * hi.hand().numberoftrumps() * hi.hand().numberofswines(); 
  own_p += 3 * hi.hand().numberoftrumps() * hi.hand().numberofhyperswines();

#ifdef ANNOUNCE_DEBUG
  if( !g.isvirtual() )
    cout << "NO60: " << hi.no() << "\t" << value << " + " 
      << 4 * (int)hi.value(Aiconfig::ANNOUNCELIMITDEC ) << "\t" 
      << (int)hi.value(Aiconfig::ANNOUNCELIMIT) << " + " 
      << 2 * (int)hi.value(Aiconfig::ANNOUNCECONFIG) << std::endl; 
#endif
  return (   (  value + 4 * (int)hi.value(Aiconfig::ANNOUNCELIMITDEC)
              >   (int)hi.value(Aiconfig::ANNOUNCELIMIT)
              + 2 * (int)hi.value(Aiconfig::ANNOUNCECONFIG)
             )
          && own_p > 2 * opp_p  // previous: 3 
          && opp_p < 60 
          && (   opp_p > 0  
              || g.last_chance_to_announce(ANNOUNCEMENT::NO60,
                                           g.player(hi.no()))
             )
         );
} // bool Heuristics::say_no60( HeuristicInterface hi, Game g )


/**
 ** checks if No30 should be said
 **
 ** @param        hi        heuristic interface
 ** @param        g         current game
 **
 ** @return       true if hi should say No30
 **
 ** @author    Borg Enders
 **
 ** @version      Beta
 **/
bool 
Heuristics::say_no30( HeuristicInterface const& hi, const Game& g )
{
  // @heuristic::name   ?  say no 30  ?
  // @heuristic::idea decision to make the annoncement no 30 depending on Heuristics::CalcHandValue
  int value = 0;

  if( g.announcement_of_team( opposite( hi.team() ) ).announcement
     > ANNOUNCEMENT::NO120 )
    return false;

  value = CalcHandValue( hi, g ) 
    - std::max( 0, (int)g.tricks_remaining_no() - 3) 
    * static_cast<int>(hi.value(Aiconfig::ANNOUNCELIMITDEC));

  int own_p = calcPointsOfOwnTeam( hi, g );
  int opp_p = calcPointsOfOppositeTeam( hi, g );

  if( own_p > 210 )
    return true;


  opp_p+= 4 * g.tricks_remaining_no();
  own_p+= 5 * g.tricks_remaining_no();


  return (  (   value + 6 * (int)hi.value(Aiconfig::ANNOUNCELIMITDEC)
             >   (int)hi.value(Aiconfig::ANNOUNCELIMIT)
             + (int)hi.value(Aiconfig::ANNOUNCECONFIG)
            )
          && own_p > 7 * opp_p  
          && opp_p < 30   
          && (    opp_p > 0   
              || g.last_chance_to_announce(ANNOUNCEMENT::NO30,
                                           g.player(hi.no()))
             )
         );
} // bool Heuristics::say_no30( HeuristicInterface hi, Game g )


/**
 ** test whether a 'no 0' could be announced
 ** checks, that the other team does not have a trick
 ** and that the hand value is big enoug.
 **
 ** @param     hi     heuristic interface
 ** @param     game   current gaem
 **
 ** @return    whether to announce 'no 0'
 **
 ** @author    Borg Enders
 ** @author    Diether Knof
 **
 ** @version   0.7.3
 **/
bool 
Heuristics::say_no0( HeuristicInterface const& hi, Game const& game )
{
  // @heuristic::name   ?  say no 0  ?
  // @heuristic::idea decision to make the annoncement no 0 depending on Heuristics::CalcHandValue
  if( game.announcement_of_team( opposite( hi.team() ) ).announcement 
     != ANNOUNCEMENT::NOANNOUNCEMENT )
    return false;

  // make sure, that the other team does not have a trick
  for (unsigned p = 0; p < game.playerno(); ++p)
    if (   (hi.teamofplayer(game.player(p)) != hi.team())
        && game.hastrick(game.player(p)))
      return false;

  // as long as the current trick is not closed, it has to be taken into account
  if (   game.trick_current().isfull()
      && (hi.teamofplayer(game.trick_current().winnerplayer())
          != hi.team()) )
    return false;

  // wait for the last possible moment
  if (!game.last_chance_to_announce(ANNOUNCEMENT::NO0,
                                    game.player(hi.no())))
    return false;

  // ToDo: check that no opposite player has the highest trump card
  // Test: force a player by 'ANNOUNCELIMITDEC' high

  int const value = CalcHandValue( hi, game ) 
    - std::max( 0, (int)game.tricks_remaining_no() ) 
    * static_cast<int>(hi.value(Aiconfig::ANNOUNCELIMITDEC));

  return (value + 4 * static_cast<int>(hi.value(Aiconfig::ANNOUNCELIMITDEC))
          > static_cast<int>(hi.value(Aiconfig::ANNOUNCELIMIT)
                             + 3 * hi.value(Aiconfig::ANNOUNCECONFIG))
         );
} // bool Heuristics::say_no0( HeuristicInterface hi, Game game )


/**
 ** finds highest card of color c
 **
 ** @param     trick    trick to check
 ** @param     hi       heuristic interface
 ** @param     tcolor   color to choose
 **
 ** @return    the card to play ( or 'Card()' if no card was found )
 **
 ** @author    Borg Enders
 ** @author    Diether Knof
 **
 ** @version   0.7.6
 **
 ** @todo      play the lowest highest card
 **/
Card 
Heuristics::play_highest_color(Trick const& trick, 
                               HeuristicInterface const& hi,
                               Card::TColor const& tcolor)
{
  // @heuristic::name   meatless: play highest color
  // @heuristic::idea   Heuristic for solo::MEATLESS to play the longest color or follow previous color

  HandCard const& card = hi.hand().highest_card(tcolor);

  if (card.value() == Card::ACE)
    return card;

  // @heuristic::condition   the player can jab the trick
  if (!(   trick.isempty()
        || trick.winnercard().less(card)))
    return Card::EMPTY;

  // @heuristic::condition   the player has the highest card
  if (card.less(hi.cards_information().highest_remaining_card_of_others(tcolor)))
    return Card::EMPTY;

  // @heuristic::action   play the highest card of the color
  return card;
} // Card Heuristics::play_highest_color( Trick t, HeuristicInterface hi, Card::Color co )

/**
 ** As first player and the partner in backhand, take a small trump.
 ** prerequisites:
 **   1. first player in the trick
 **   2. last player is partner
 ** take a small trump
 ** If the partner has the highest card still in the game, take a trump
 ** with a high value (fox or ten)
 **
 ** @param     trick   current trick
 ** @param     hi      heuristic interface
 **
 ** @return    card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **
 ** @todo      check that the partner has no problems with his trumps
 **/
Card
Heuristics::partner_backhand_draw_trump(Trick const& trick,
                                        HeuristicInterface const& hi)
{
  // @heuristic::name   partner backhand draw trump
  // @heuristic::idea   as first player and the partner in backhand, draw trump

  // @heuristic::condition   first player in the trick
  if (!trick.isstartcard() )
    return Card::EMPTY;

  // @heuristic::condition   last player is partner
  if (!(hi.teamofplayer(trick.lastplayer()) == hi.team()))
    return Card::EMPTY;

  // the partner
  Player const& partner = trick.lastplayer();

  bool partner_has_highest_trump = false;
  { // check whether the partner has the highest trump in the game
    HandCard const highest_trump
      = HandCard(hi.hand(),
                 hi.cards_information().highest_remaining_trump_of_others());
    if (hi.handofplayer(partner).contains(highest_trump))
    {
      // check that no other player does have the card, also
      if (   highest_trump.isdolle()
          && hi.game().second_dolle_over_first()
          && hi.cards_information().of_player(partner).must_have(Card::DOLLE)) {
        partner_has_highest_trump = true;
      } else {

        partner_has_highest_trump = true;
        for (unsigned p = 0; p < hi.game().playerno(); ++p) {
          Player const& player = hi.game().player(p);
          if (   (hi.teamofplayer(player) != hi.team())
              && (hi.handofplayer(player).contains(highest_trump))) {
            partner_has_highest_trump = false;
            break;
          }
        } // for (p < hi.game().playerno())
      } // if !(second dolle over first)
    } // if (partner has highest trump)
  } // check whether the partner has the highest trump in the game

  list<Card> cards_to_play;
  if (partner_has_highest_trump) {
    cards_to_play.push_back(Card(Card::DIAMOND, Card::ACE));
    cards_to_play.push_back(Card(Card::DIAMOND, Card::TEN));
  } else if (hi.hand().numberoftrumps() >= 3) { // *Value*
    cards_to_play.push_back(Card(Card::DIAMOND, Card::KING));
    cards_to_play.push_back(Card(Card::DIAMOND, Card::JACK));
    cards_to_play.push_back(Card(Card::HEART,   Card::JACK));
    cards_to_play.push_back(Card(Card::SPADE,   Card::JACK));
    cards_to_play.push_back(Card(Card::DIAMOND, Card::NINE));
  }

  // @heuristic::condition   at least three trump on the hand if the partner does not have the highest card
  // ToDo: improve

  for (list<Card>::const_iterator c = cards_to_play.begin();
       c != cards_to_play.end();
       ++c)
    if (  hi.hand().contains(*c)
        && !hi.game().is_special(HandCard(hi.hand(), *c)))
      return *c;

  return Card::EMPTY;
} // static Card Heuristics::partner_backhand_draw_trump(Trick trick, HeuristicInterface hi)

/**
 ** play trumps to draw the last trumps
 **
 ** @param     trick   current trick
 ** @param     hi      heuristic interface
 **
 ** @return    card to play
 **
 ** @author    Borg Enders
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
Card 
Heuristics::draw_trump( Trick const& trick, HeuristicInterface const& hi )
{
  // @heuristic::name   draw trump
  // @heuristic::idea play trumps to force other players to play also trumps        

  // @heuristic::condition   first player
  if( !trick.isstartcard() )
    return Card::EMPTY;

  // @heuristic::condition   more trumps then remaining trumps
  if (! (   (hi.hand().numberoftrumps()
             > hi.cards_information().remaining_trumps_others()) 
         && hi.cards_information().remaining_trumps_others() ) )
    return Card::EMPTY;

  return lowest_highest_trump(trick, hi);
} // Card Heuristics::draw_trump(Trick trick, HeuristicInterface hi)


/**
 ** 
 ** prerequisites:
 **   1. startplayer
 **   2. no trumps remain in the game in the opposite team
 **   3. the player has the highest color card of a color
 ** take the highest color card
 **
 ** @param     trick   current trick
 ** @param     hi      heuristic interface
 **
 ** @return    card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author    Borg Enders
 ** @author    Diether Knof
 **
 ** @version   0.7.6
 **/
Card
Heuristics::play_highest_color_card_in_game(Trick const& trick,
                                            HeuristicInterface const& hi)
{
  // @heuristic::name   play highest color card in game
  // @heuristic::idea   Make a sure trick with a color card
  // @heuristic::condition   startplayer
  if (!trick.isempty())
    return Card::EMPTY;

  HandCards const cards = hi.hand().cards_single();
  Card best_card; // the card to play
  for (HandCards::const_iterator c = cards.begin();
       c != cards.end();
       ++c) {
    if (c->istrump())
      continue;

    Trick t(trick);
    t += *c;
    if (oppositeTeamCanWinTrick(t, hi))
      continue;

    if (best_card.is_empty()
        || (c->points() > best_card.points()))
      best_card = *c;

    // ToDo: points equal, take the color with more points remaining
  } // for (c \in cards)

  // @heuristic::action   take color card the opposite team can not get with the most points 
  return best_card;
} // Card Heuristics::play_highest_color_card_in_game(Trick trick, HeuristicInterface hi)

/**
 ** as last player grab the trick
 ** prerequisites:
 **   1. the player must be the last player or the players behind cannot get the trick
 **   2. the player can get the trick
 ** take the best card to win the trick
 **
 ** @param     trick   current trick
 ** @param     hi      heuristic interface
 **
 ** @return    card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author    Diether Knof
 **
 ** @version   0.7.4
 **/
Card
Heuristics::grab_trick(Trick const& trick,
                       HeuristicInterface const& hi)
{
  // @heuristic::name   grab trick
  // @heuristic::idea   as last player jab the trick if possible

  // @heuristic::condition   last player in the trick
  if (!trick.islastcard()
      && oppositeTeamCanWinTrick(trick, hi))
    return Card::EMPTY;

  // @heuristic::condition   the trick does not go to the own team
  if (hi.guessedteamofplayer(trick.winnerplayer()) == hi.team())
    return Card::EMPTY;

  // @heuristic::action   Play the best winning card.
  return Heuristics::best_winning_card(trick, hi,
                                       Card::ACE * hi.game().playerno());
} // Card Heuristics::grab_trick(Trick trick, HeuristicInterface hi)


/**
 ** With only trump on hand play best trump card
 **
 ** @param     trick   current trick
 ** @param     hi      heuristic interface
 **
 ** @return    card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author    Borg Enders
 **
 ** @version   0.7.6
 **/
Card
Heuristics::play_trump(Trick const& trick,
                       HeuristicInterface const& hi)
{
  // @heuristic::name        play trump
  // @heuristic::idea        with only trump on the hand play the best trump card

  // @heuristic::condition   no startcard
  if (trick.isstartcard())
    return Card::EMPTY;

  if(   hi.game().type() == GAMETYPE::POVERTY 
     && hi.hand().numberof( trick.startcard().color() ) == 0 
    ) 
  {
    Player const& re_player = hi.game().poverty_partner();
    if ( !(trick.cardno_of_player(re_player) < trick.actcardno()) )
    {
      if( hi.hand().numberof(Card(hi.game().trumpcolor(), Card::TEN)) > 0 )
        return Card(hi.game().trumpcolor(), Card::TEN );

      return lowest_best_trump_card( trick, hi.hand(), hi );
    }
  }  

  // @heuristic::condition   only trumps
  if (hi.hand().hascolor())
    return Card::EMPTY;

  // @heuristic::action      play best winning card
  return Heuristics::best_winning_card(trick, hi,
                                       Card::ACE * hi.game().playerno());
} // Card Heuristics::grab_trick(Trick trick, HeuristicInterface hi)

/**
 ** I can throw fehl and the trick is not worth taking I'am third or forth
 **
 ** @param     trick   current trick
 ** @param     hi      heuristic interface
 **
 ** @return    card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author    Borg Enders
 ** @author    Diether Knof
 **
 ** @version   0.7.6
 **/
Card
Heuristics::let_trick_pass(Trick const& trick,
                           HeuristicInterface const& hi)
{
  // @heuristic::name   let trick pass
  // @heuristic::idea   not enough points to grab trick, throw fehl

  // @heuristic::condition   third or forth player in trick
  if (trick.remainingcardno() > 2 )
    return Card::EMPTY;

  Card::TColor const tcolor = trick.startcard().tcolor();
  // @heuristic::condition  color trick
  if (tcolor == Card::TRUMP)
    return Card::EMPTY;

  // @heuristic::condition  can't serve color
  if ( hi.hand().existstcolor(tcolor))
    return Card::EMPTY;

  // @heuristic::condition  There are not many points in this trick
  if (trick.points() > hi.value(Aiconfig::LIMIT_THROW_FEHL) )
    return Card::EMPTY;

  int modi = 0;
  if (!trick.islastcard()) {
    // ToDo: analyse the cards (and team) the last player has (t.i. estimate, what he will play)
    Player const& player = trick.lastplayer();
    Hand const& hand = hi.handofplayer(player);
    if (hi.guessedteamofplayer(player) == hi.team()) {
      if (hand.existstcolor(tcolor))
        modi += hand.lowest_value(tcolor);
      else
        modi += hand.lowest_value();
    } else { // if !(same team)
      // @heuristic::condition   Do not leave the trick to the opposite team
      if (!hand.existstcolor(tcolor)
          || (hi.guessedteamofplayer(trick.winnerplayer()) != hi.team()) )
        return Card::EMPTY;
      if (hand.existstcolor(tcolor))
        modi += hand.highest_value(tcolor);
      else
        modi += hand.highest_value();
    } // if !(same team)
  } // if (!trick.islastcard())


  // There are not many points in this trick
  if (trick.points() + modi > hi.value(Aiconfig::LIMIT_THROW_FEHL) )
    return Card::EMPTY;

  // the card to play (or none)
  Card const card = choose_best_fehl(trick, hi, true);
  modi += card.value();

  // There are not many points in this trick
  if (trick.points() + modi > hi.value(Aiconfig::LIMIT_THROW_FEHL) )
    return Card::EMPTY;

  // @heuristic::action   Play the best fehl
  return card;
} // Card Heuristics::let_trick_pass(Trick trick, HeuristicInterface hi)


/**
 ** get a trick for announcement
 **
 ** @param     t         trick to check
 ** @param     hi        heuristic interface
 **
 ** @return    the card to play ( or 'Card()' if no card was found )
 **
 ** @author    Borg Enders
 **
 ** @version   0.7.0
 **/
Card 
Heuristics::getTrickForKeepingAnnouncement( Trick const& t, 
                                           HeuristicInterface const& hi )
{
  // @heuristic::name   get trick for announcement
  // @heuristic::idea   If this trick would open the possibility for the other team to win there announcement try to win this trick for the own team        
  // ToDo: Gegenansagen
  Card c;
  if( hi.game().announcement_of_team(  hi.team() ).announcement 
     != ANNOUNCEMENT::NOANNOUNCEMENT )
  {
    unsigned oppositeToGet = 120;
    for( int a = (int)ANNOUNCEMENT::NO90;
        a <= hi.game().announcement_of_team(  hi.team() ).announcement;
        a++ )
      oppositeToGet -= 30; 

    // ToDo: use calcPointsOfOppositeTeam
    if(    hi.game().points_of_team( opposite( hi.team() ) ) + t.points() + 10 
       >= oppositeToGet
       && TEAM::maybe_to_team(hi.teamofplayer(t.winnerplayer())) == opposite( hi.team() )
      )
      c = best_winning_card( t, hi, 30 );
  } // if (announcement_of_team( hi.team() ) != ANNOUNCEMENT::NOANNOUNCEMENT)

#ifdef POSTPHONED
  if( hi.game().announcement_of_team(  opposite( hi.team() ) ).announcement 
     != ANNOUNCEMENT::NOANNOUNCEMENT )
  {
    unsigned ownToGet = 120;
    for( int a = (int)ANNOUNCEMENT::NO90;
        a <= hi.game().announcement_of_team( opposite( hi.team() ) ).announcement;
        a++ )
      ownToGet -= 30; 

    // ToDo: use calcPointsOfOppositeTeam
    if(    hi.game().points_of_team( hi.team() ) + t.points() + 10 >= ownToGet
       && TEAM::maybe_to_team(hi.teamofplayer(t.winnerplayer())) 
       == opposite( hi.team() )
      )
      c = best_winning_card( t, hi, 30 );
  } // if(announcement_of_team( opposite( hi.team() ) ) != ANNOUNCEMENT::NOANNOUNCEMENT )
#endif
  return c;
} // Card Heuristics::getTrickForKeepingAnnouncement( Trick t, HeuristicInterface hi )

/**
 ** Play a worrie card in a trump trick if the partner will win the trick
 **
 ** @param     trick current trick
 ** @param     hi    heuristic interface
 **
 ** @return    card to play, 'Card()' if the heuristic does not match
 **
 ** @author    Diether Knof
 **
 ** @version   0.7.6
 **/
Card 
Heuristics::play_worrie_for_partner(Trick const& trick, HeuristicInterface const& hi)
{
  // @heuristic::name   play worrie for partner
  // @heuristic::idea   Plays "worrie-cards" (like fox) in a trump trick if the partner will get the trick


  // @heuristic::condition   empty or trump trick
  if (!(   trick.isempty()
        || trick.startcard().istrump()) )
    return Card::EMPTY;

  Player const* partner = hi.team_information().guessed_partner();
  if (!partner)
    return Card::EMPTY;

  // @heuristic::condition   partner is behind
  if (trick.cardno_of_player(*partner) > trick.actcardno() )
    return Card::EMPTY;

  // @heuristic::condition   the partner has the highest card behind
  Card const highest_card = hi.handofplayer(*partner).highest_card();
  if (   trick.winnercard().less(highest_card)
      && highest_opposite_card_behind(trick, hi).less(highest_card)) {
    // @heuristic::action   play a pfund card with at least 10 points
    Card const card = Heuristics::choose_pfund_card(trick, hi);
    if (card.value() >= Card::TEN)
      return card;
  }

  return Card::EMPTY;
} // Card Heuristics::play_worrie_for_partner(Trick trick, HeuristicInterface hi)

/**
 ** Gives the partner a chance to drop his worries
 **
 ** @param     trick current trick
 ** @param     hi    heuristic interface
 **
 ** @return    card to play, 'Card()' if the heuristic does not match
 **
 ** @author    Florian Sundermann
 **
 ** @version   0.7.5
 **/
Card 
Heuristics::play_for_partner_worries(Trick const& trick,
                                     HeuristicInterface const& hi)
{
  // @heuristic::name   play for partner worries
  // @heuristic::idea   Plays a card that will win the trick so that the partner can drop his "worry-cards"
  Player const* partner = hi.team_information().guessed_partner();
  if( !partner )
    return Card::EMPTY;

  if ( trick.isstartcard() )
    return Card::EMPTY;

  if( !trick.startcard().istrump() )
    return Card::EMPTY;

  if( trick.cardno_of_player(*partner) < trick.actcardno() )
    return Card::EMPTY;


#if 0 //BE: old statement for four ifs above.
  if ( !((trick.isempty() || trick.startcard().istrump()) && partner 
         && trick.cardno_of_player(*partner) > trick.actcardno() ))
    return Card::EMPTY;
#endif
  if ( cardWillWinTheTrick( trick, hi, hi.hand().highest_card()) )
  { // We can win the trick, check for worries
    HandCards const validcards = partner->hand().validcards(trick);
    for (HandCards::const_iterator card = validcards.begin();
         card != validcards.end();
         card++)
    {
      HandCard const& actCard = *card;
      if (actCard.value() >= 10 && (!actCard.isdolle()) 
          && (!actCard.isswine()) && (!actCard.ishyperswine()))
      { // partner has worries so search for the lowest card that will win the trick
        Card winningCard;

        HandCards const validcards = hi.hand().validcards(trick);
        for ( HandCards::const_iterator owncard =validcards.begin();
             owncard != validcards.end();
             owncard++)
        {
          HandCard const& wincard = *owncard;
          if ( cardWillWinTheTrick(trick, hi, wincard)
              && ( winningCard.is_empty() || wincard.less(winningCard)) )
          {
            winningCard = wincard;
          }
        } // search for lowest winning card

        return winningCard; // return the lowest winningcard
      } // partner has worries
    } // search for worries
  } // chance to win the trick

  return Card::EMPTY;
} // Card Heuristics::ask_partner_for_worries(Trick trick, HeuristicInterface hi)

/**
 ** Start with a low color to find the partner
 **
 ** @param     trick   current trick
 ** @param     hi      heuristic interface
 **
 ** @return    card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author    Florian Sundermann
 ** @author    Diether Knof
 **
 ** @version   0.7.6
 **/
Card
Heuristics::start_with_low_color(Trick const& trick,
                                 HeuristicInterface const& hi)
{
  // @heuristic::name   start with low color
  // @heuristic::idea   Start the trick with a low color to find the partner

  if (GAMETYPE::is_solo(hi.game().type())
      || !trick.isstartcard() 
      || hi.team_information().guessed_partner() )
    return Card::EMPTY;

  Card c;
  if (!hi.hand().hascolor())
    return Card::EMPTY; // Everything below need color cards!

  // @heuristic::action   when a singleton color card is found, take it
  { // take singleton color card
    for (HandCards::const_iterator card = hi.hand().cards().begin();
         card != hi.hand().cards().end();
         card++)
    {
      HandCard const& actCard = *card;
      if ((! actCard.istrump())
          && (hi.hand().numberof(actCard.color()) == 1))
      {
        if (c.is_empty())
        {
          c = actCard;
        }
        else if (hi.color_runs(c.color()) > 0)
        {
          if (hi.color_runs(actCard.tcolor()) == 0)
            c = actCard;
          else if (c.value() > actCard.value())
            c = actCard;
        } // if ( color_runs > 0)
      } // if( ! actCard.istrump && numberof(actCard.color) == 1)
    } // for (actCard in hi.hand().cards())

    if (!c.is_empty())
      return c;
  } // take singleton color card

  // @heuristic::action   take smallest card from the longest color
  {
    Card::Color longestcolor = Card::NOCARDCOLOR;
    // Determine the longest color
    for (vector<Card::Color>::const_iterator
         col = hi.game().rule().card_colors().begin();
         col != hi.game().rule().card_colors().end();
         ++col) 
    {
      Card::Color const& color = *col; 
      if (longestcolor == Card::NOCARDCOLOR 
          || hi.hand().numberof(color) > hi.hand().numberof(longestcolor))
        longestcolor = color;
    } // for each color

    c = hi.hand().lowest_card(longestcolor); // choose the lowest card
  } // take smallest card from the longest color

  return c;
} // Card Heuristics::start_with_low_color(Trick trick, HeuristicInterface hi)

/**
 ** Start with a low trump to find the partner
 **
 ** @param     trick   current trick
 ** @param     hi      heuristic interface
 **
 ** @return    card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author    Florian Sundermann
 ** @author    Diether Knof
 **
 ** @version   0.7.6
 **/
Card
Heuristics::start_with_low_trump(Trick const& trick,
                                 HeuristicInterface const& hi)
{
  // @heuristic::name   start with low trump
  // @heuristic::idea   Start the trick with a low trump to find the partner
  if (GAMETYPE::is_solo(hi.game().type())
      || !trick.isstartcard() 
      || hi.team_information().guessed_partner() )
    return Card::EMPTY;

  // @heuristic::action   with enough trumps take a small trump
  if (hi.hand().numberoftrumps() >= 6 // 6 trump cards or 60% trump on hand
      || ((double)hi.hand().numberoftrumps()
          / (double)hi.hand().cardsnumber()
          >= 0.6 ) ) /// @todo add a constant or configuration for this
  {
    return Heuristics::lowest_best_trump_card(trick, hi.hand(), hi);
  }

  return Card::EMPTY;
} // Card Heuristics::start_with_low_trump(Trick trick, HeuristicInterface hi)

/**
 ** play low trump to jab later with high trump
 **
 ** @param     trick   current trick
 ** @param     hi      heuristic interface
 **
 ** @return    card to play, 'Card()' if the heuristic does not match
 ** 
 ** @author    Borg Enders
 **
 ** @version   0.7.6
 **/
Card
Heuristics::play_to_jab_later(Trick const& trick,
                              HeuristicInterface const& hi)
{
  // @heuristic::name      play to jab later
  // @heuristic::idea      play low trump to jab later with high trump


  // @heuristic::condition   startcard
  if (!trick.isstartcard() )
    return Card::EMPTY;

  // @heuristic::condition   only trumps on the hand
  if (hi.hand().hascolor())
    return Card::EMPTY;

  list<Card> cards_to_play;
  if (hi.game().rule()(Rule::WITH_NINES))
    cards_to_play.push_back(Card(Card::DIAMOND, Card::NINE));
  cards_to_play.push_back(Card(Card::DIAMOND, Card::JACK));
  cards_to_play.push_back(Card(Card::HEART,   Card::JACK));
  cards_to_play.push_back(Card(Card::DIAMOND, Card::KING));


  // @heuristic::action      play a low trump
  for (list<Card>::const_iterator c = cards_to_play.begin();
       c != cards_to_play.end();
       ++c)
    if (   hi.hand().contains(*c)
        && !hi.game().is_special(HandCard(hi.hand(), *c)))
      return *c;

  return Card::EMPTY;
} //Card Heuristics::start_with_color(Trick trick, HeuristicInterface const& hi)


/**
 ** checks if an announcement should be replied with an other announcement
 **
 ** @param     hi        heuristic interface
 ** @param     g         current game
 **
 ** @return    Announcement::Reply if wanted
 **
 ** @author    Borg Enders
 **
 ** @version   0.6.3
 **/
Announcement 
Heuristics::make_reply( HeuristicInterface const& hi, const Game& g )
{
  // @heuristic::name   ?  make reply  ?
  // @heuristic::idea announcement reply decision bases on Heuristics::CalcHandValue

  if( g.announcement_of_team( opposite( hi.team() ) ).announcement 
     != ANNOUNCEMENT::NOANNOUNCEMENT 
     && hi.hand().numberoftrumps() > hi.game().tricks_remaining_no() / 2 )
  {
    int value = 0;

    value = CalcHandValue( hi, g ); 

    for( int a = (int)ANNOUNCEMENT::NO90;
        a <= g.announcement_of_team( opposite( hi.team() ) ).announcement;
        a++ ) 
      value += (int)hi.value(Aiconfig::ANNOUNCECONFIGREPLY);


    for( unsigned i = 0; i < hi.hand().cardsnumber(); i++ )
    {
      if(   hi.hand().card(i).isdolle()
         || hi.hand().card(i).isswine()
         || hi.hand().card(i).possible_swine()
         || hi.hand().card(i).ishyperswine()
         || hi.hand().card(i).possible_hyperswine() )
        value += (int)hi.value(Aiconfig::ANNOUNCECONFIGREPLY);
    } // for (i < hi.hand().cardsnumber())

#ifdef ANNOUNCE_DEBUG
    if( !g.isvirtual() )
      cout << "REPLY: " << hi.no() << "\t" << value << "\t" 
        << (int)hi.value(Aiconfig::ANNOUNCELIMITREPLY) << std::endl; 
#endif
    if( value >=  (int)hi.value(Aiconfig::ANNOUNCELIMITREPLY) )
      return ANNOUNCEMENT::REPLY;
  } // if (g.announcement_of_team (opposite) != ANNOUNCEMENT::NOANNOUNCEMENT

  return ANNOUNCEMENT::NOANNOUNCEMENT;
} // Announcement Heuristics::make_reply( HeuristicInterface const& hi, const Game& g )


/**
 ** -> result
 **
 ** @param        old_card        best card till now
 ** @param        test_card        card to test
 ** @param        hi                hi (with the configuration)
 **
 ** @return        whether the card 'test_card' is to preferred to 'old_card'
 **                that is has more points
 **
 ** @author        Borg Enders
 **
 ** @version        0.6.9
 **/
bool
better_points_optimize(HandCard const& old_card,
                       HandCard const& test_card,
                       HeuristicInterface const& hi )
{
  return (  (  hi.game().trick_current_no()
             >= hi.value(Aiconfig::FIRST_TRICK_FOR_TRUMP_POINTS_OPTIMIZATION)
            )
          &&   ( old_card.value() < test_card.value() )
          || ( test_card.less( old_card ) && old_card.value() == test_card.value() )
         );
} // bool better_points_optimize(HandCard old_card, HandCard test_card, Ai hi)
