/**********************************************************************
 *
 *   FreeDoko a Doppelkopf-Game
 *    
 *   Copyright (C) 2001-2004  by Diether Knof and Borg Enders
 *
 *   This program is free software; you can redistribute it and/or 
 *   modify it under the terms of the GNU General Public License as 
 *   published by the Free Software Foundation; either version 2 of 
 *   the License, or (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details. 
 *   You can find this license in the file 'gpl.txt'.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
 *   MA  02111-1307  USA
 *
 *  Contact:
 *    Diether Knof dknof@gmx.de
 *    Borg Enders  borg@borgsoft.de
 *
 ********************************************************************/ 

#include "constants.h"

#include "heuristics.h"

#include "HeuristicInterface.h"
#include "../../game/game.h"
#include "../../party/party.h"
#include "../../party/rule.h"

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

/**********************************************************************
 *
 **    int number_of_no_trumps_per_color()
 *
 **    Parameters:  number of cards per miscolor
 *
 **    Result: 
 *
 **    Version: Beta
 *
 **    Description:
 *
 *
 **********************************************************************/
unsigned
number_of_no_trumps_per_color()
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		"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::NINE).istrump())
  {
    for ( i=0;  i < 2 * ::party.rule()(Rule::NUMBER_OF_CARD_VALUES); i+=2)
      if (!Card(Card::InttoColor(Card::CLUB),Card::InttoValue(i)).istrump())
	notrump_per_color+=2;
  } else {
    for ( i=0;  i < 2 * ::party.rule()(Rule::NUMBER_OF_CARD_VALUES); i+=2)
      if (!Card(Card::InttoColor(Card::SPADE),Card::InttoValue(i)).istrump())
	notrump_per_color+=2;
  }

  DEBUG_RETURNING(notrump_per_color,
		  INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		  "number_of_no_trumps_per_color()");

} // unsigned number_of_no_trumps_per_color()

/**********************************************************************
 *
 **    Card Heuristics::choose_ace(Trick const& t,HeursticInterface const& hi)
 *
 **    Parameters:  actual played trick, HeuristicInterface who plays next card
 *
 **    Result: an Color Ace, if there is a good one
 **            otherwise a card with Card::NOCARDVALUE and Card::NOCARDCOLOR
 *
 **    Version: Beta
 *
 **    Description:
 **      for a first card in a trick play a color Ace,
 **      if there are still enough cards of this color in the game
 **      and none of this colors is already been jabbed.
 **      choose then that ace with most cards of that color
 **      still in the game
 *
 *
 **********************************************************************/
Card
Heuristics::choose_ace(Trick const& t, HeuristicInterface const& hi )
{

  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		"Heuristics::choose_ace()");

  // I'am not the start Player
  if (!t.isstartcard() )
    DEBUG_RETURNING(Card(),
		    INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		    "Heuristics::choose_ace()");

  Card c = Card();
  unsigned i, n, h;
  vector<int> numberofcards(party.rule()(Rule::NUMBER_OF_CARD_COLORS), 0);
  unsigned bestcolor=0;


  int notrump_per_color=number_of_no_trumps_per_color();


  // calculate number of played no Trump cards per color
  for (i = 0;  i < hi.game().rule()(Rule::NUMBER_OF_CARD_VALUES); i++)
    for (n = 0; n < hi.game().rule()(Rule::NUMBER_OF_CARD_COLORS); n++)
      if (!Card(n, i).istrump())
	numberofcards[n] += hi.playedcard( Card( n, i ) );

  Hand const& ha = hi.hand().validcards(t);

  for ( i = 0; i < ha.cardsnumber(); i++) {
    // cards still in game of this color
    h = notrump_per_color - numberofcards[ ha.card(i).color() ];

    if (Card(ha.card(i).color(), Card::TEN) == Card::DOLLE && hi.game().rule()(Rule::DOLLEN))
      h-=2;


    // find best ace, which color, which was not already jabbed, or which was
    // last jabbed by an member of own team
    // where are for each player still one card or more in the game
    // and choose than that ace with most cards of its color still in the game
    if (  (ha.card(i).value() == Card::ACE)
	  && (!ha.card(i).istrump())
	  && h+1>=hi.game().playerno()
	  && ( h>bestcolor 
	       || (h ==bestcolor && ha.numberof( ha.card(i) ) < ha.numberof( c )) )
	  && (    c == Card() 
		  || ha.numberof( ha.card(i) ) < ha.numberof( c ) )
	  &&( !hi.colorjabbed(ha.card(i).color())
	      || (    hi.jabbedbyownteam(ha.card(i).color()) 
		      && !hi.jabbedbyotherteam(ha.card(i).color() ) 
		 )
	    )
       )
    {
      bestcolor=h;
      c=ha.card(i);
    }
  }

  DEBUG_RETURNING(c,
		  INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		  "Heuristics::choose_ace()");

}

/**********************************************************************
 *
 **    Card lowest_card(Hand h,Card::Value cv)
 *
 **    Parameters:
 *
 **    Result: finds lowest card with value cv
 *
 **    Version: Beta
 *
 **    Description:
 *
 **********************************************************************/
Card
lowest_card(Hand const& h,Card::Value const cv, HeuristicInterface const& hi)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_card()");

  Card c=Card();

  unsigned i;

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

  if (c==Card()) 
  {
    DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_jack()");
  }

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

  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_card()");
}


/**********************************************************************
 *
 **    Card lowest_card(Hand h,Card::Value cv)
 *
 **    Parameters:
 *
 **    Result: finds lowest card with value cv
 *
 **    Version: Beta
 *
 **    Description:
 *
 **********************************************************************/
Card
highest_card(Hand const& h,Card::Value const cv, HeuristicInterface const& hi)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_card()");

  Card c=Card();

  unsigned i;

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

  if (c==Card()) 
  {
    DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_jack()");
  }

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

  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_card()");
}

/**********************************************************************
 *
 **    Card lowest_jack(Hand h)
 *
 **    Parameters:
 *
 **    Result: finds lowest jack on Hand h
 *
 **    Version: Beta
 *
 **    Description:
 *
 **********************************************************************/
Card
lowest_jack(Hand const& h, HeuristicInterface const& hi)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_jack()");

  DEBUG_RETURNING(lowest_card(h, Card::JACK, hi),
		  INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		  "Heuristics::lowest_jack()");
}

/**********************************************************************
 *
 **    Card lowest_queen(Hand h)
 *
 **    Parameters:
 *
 **    Result: finds lowest queen on Hand h
 *
 **    Version: Beta
 *
 **    Description:
 *
 **********************************************************************/

Card
highest_queen(Hand const& h, HeuristicInterface const& hi)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_queen()");

  DEBUG_RETURNING(highest_card(h, Card::QUEEN, hi),
		  INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		  "Heuristics::lowest_queen()");
}

/**********************************************************************
 *
 **    Card lowest_queen(Hand h)
 *
 **    Parameters:
 *
 **    Result: finds lowest queen on Hand h
 *
 **    Version: Beta
 *
 **    Description:
 *
 **********************************************************************/

Card
lowest_queen(Hand const& h, HeuristicInterface const& hi)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_queen()");

  DEBUG_RETURNING(lowest_card(h, Card::QUEEN, hi),
		  INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		  "Heuristics::lowest_queen()");
}

/**********************************************************************
 *
 **    Card Heuristics::best_winning_card(Trick const& t, HeursticInterface const& hi)
 *
 **    Parameters:  actual trick, HeuristicInterface who plays next card
 **                 point modifikator to add to points of t 
 *
 **    Result: 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
 *
 **    Version: Beta
 *
 **    Description:
 *
 **********************************************************************/

Card Heuristics::best_winning_card_single_picture(Trick const& t, Card::Value v, HeuristicInterface const& hi, unsigned pointmodi )
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");


  if ( t.isstartcard() ) DEBUG_RETURNING(Card(),INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");
  ;
  Trick tr;
  Card c=Card();
  Hand ha=hi.hand().validcards(t);
  unsigned i;
  Game const& game = t.game();


  // 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), game)))
    {

      c=ha.card(i);
    }
  }
  // if can't win this trick and I'am not the last player: that's it
  if (c==Card() && !t.islastcard())  {

    DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");

  }
  bool allmyteam=true;

  for (i=t.actcardno(); i<hi.game().playerno(); i++)
    allmyteam=allmyteam && (hi.team()==hi.teaminfo(t.player_of_card(i)));

  bool trumpintrick=false;

  for ( i = 0 ; i < t.actcardno() ; i++)
  {
    trumpintrick=trumpintrick||t.card(i).istrump();
  }

  // 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), game) || t.islastcard() )
	    && (ha.card(i).less(c, game)))
	{

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



      }// if card istrump

    } // if winneris
  }

  // 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)
      /// 2do heart ten non trump, than also for heart tricks
     )
  {

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

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

      }
    }
  }

  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");
}


/**********************************************************************
 *
 **    Card Heuristics::best_winning_card(Trick const& t, HeursticInterface const& hi)
 *
 **    Parameters:  actual trick, HeuristicInterface who plays next card
 **                 point modifikator to add to points of t 
 *
 **    Result: 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
 *
 **    Version: Beta
 *
 **    Description:
 *
 **********************************************************************/

Card Heuristics::best_winning_card_double_picture(Trick const& t, Card::Value v1, Card::Value v2, HeuristicInterface const& hi, unsigned pointmodi )
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");


  if ( t.isstartcard() ) DEBUG_RETURNING(Card(),INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");
  ;
  Trick tr;
  Card c=Card();
  Hand ha=hi.hand().validcards(t);
  unsigned i;
  Game const& game = t.game();


  // 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), game)))
    {

      c=ha.card(i);
    }
  }
  // if can't win this trick and I'am not the last player: that's it
  if (c==Card() && !t.islastcard())  {

    DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");

  }
  bool allmyteam=true;

  for (i=t.actcardno(); i<hi.game().playerno(); i++)
    allmyteam=allmyteam && (hi.team()==hi.teaminfo(t.player_of_card(i)));

  bool trumpintrick=false;

  for ( i = 0 ; i < t.actcardno() ; i++)
  {
    trumpintrick=trumpintrick||t.card(i).istrump();
  }

  // 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), game) || t.islastcard() )
	    && (ha.card(i).less(c, game)))
	{

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



      }// if card istrump

    } // if winneris
  }



  // 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)
      /// 2do heart ten non trump, than also for heart tricks
     )
  {

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

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

      }
    }
  }

  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");
}

/**********************************************************************
 *
 **    Card Heuristics::best_winning_card(Trick const& t, HeursticInterface const& hi)
 *
 **    Parameters:  actual trick, HeuristicInterface who plays next card
 **                 point modifikator to add to points of t 
 *
 **    Result: 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
 *
 **    Version: Beta
 *
 **    Description:
 *
 **********************************************************************/

Card Heuristics::best_winning_card_triple_picture(Trick const& t, HeuristicInterface const& hi, unsigned pointmodi )
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");


  if ( t.isstartcard() ) DEBUG_RETURNING(Card(),INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");
  ;
  Trick tr;
  Card c=Card();
  Hand ha=hi.hand().validcards(t);
  unsigned i;
  Game const& game = t.game();


  // 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), game)))
    {

      c=ha.card(i);
    }
  }
  // if can't win this trick and I'am not the last player: that's it
  if (c==Card() && !t.islastcard())  {

    DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");

  }
  bool allmyteam=true;

  for (i=t.actcardno(); i<hi.game().playerno(); i++)
    allmyteam=allmyteam && (hi.team()==hi.teaminfo(t.player_of_card(i)));

  bool trumpintrick=false;

  for ( i = 0 ; i < t.actcardno() ; i++)
  {
    trumpintrick=trumpintrick||t.card(i).istrump();
  }

  // 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), game) || t.islastcard() )
	    && (ha.card(i).less(c, game)))
	{

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



      }// if card istrump

    } // if winneris
  }



  // 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)
      /// 2do heart ten non trump, than also for heart tricks
     )
  {

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

	  continue;
	}
	if (ha.card(i).value()== Card::NINE )
	{        
	  c=ha.card(i);             
	  continue;
	}

      }
    }
  }

  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");
}


/**********************************************************************
 *
 **    Card Heuristics::best_winning_card(Trick const& t, HeursticInterface const& hi)
 *
 **    Parameters:  actual trick, HeuristicInterface who plays next card
 **                 point modifikator to add to points of t 
 *
 **    Result: 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
 *
 **    Version: Beta
 *
 **    Description:
 *
 **********************************************************************/

Card Heuristics::best_winning_card(Trick const& t, HeuristicInterface const& hi, unsigned pointmodi )
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");

  GameType gt = hi.game().type();
  if (gt==GAMETYPE::SOLO_JACK) 
    DEBUG_RETURNING(best_winning_card_single_picture( t, Card::JACK, hi, pointmodi ),INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");
  if (gt==GAMETYPE::SOLO_QUEEN) 
    DEBUG_RETURNING(best_winning_card_single_picture( t, Card::QUEEN, hi, pointmodi ),INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");
  if (gt==GAMETYPE::SOLO_KING)
    DEBUG_RETURNING(best_winning_card_single_picture( t, Card::KING, hi, pointmodi ),INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");

  if (gt==GAMETYPE::SOLO_QUEEN_JACK)
    DEBUG_RETURNING(best_winning_card_double_picture( t, Card::JACK, Card::QUEEN, hi, pointmodi ),INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");

  if (gt==GAMETYPE::SOLO_KING_JACK)
    DEBUG_RETURNING(best_winning_card_double_picture( t, Card::JACK, Card::KING, hi, pointmodi ),INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");

  if (gt==GAMETYPE::SOLO_KING_QUEEN)
    DEBUG_RETURNING(best_winning_card_double_picture( t, Card::KING, Card::QUEEN, hi, pointmodi ),INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");

  if (gt==GAMETYPE::SOLO_KOEHLER) 
    DEBUG_RETURNING(best_winning_card_triple_picture( t, hi, pointmodi ),INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");



  if ( t.isstartcard() ) DEBUG_RETURNING(Card(),INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");
  ;
  Trick tr;
  Card c=Card();
  Hand ha=hi.hand().validcards(t);
  unsigned i;
  Game const& game = t.game();

  unsigned tpoints = t.points() + pointmodi;


  // 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), game)))
    {
    	
      if (ha.card(i).value()==Card::QUEEN && tpoints>hi.value(Aiconfig::LIMITQUEEN))
      {
	c=ha.card(i);
	break;
      } 
      if (ha.card(i).value()==Card::QUEEN)
	continue;


      if ( (ha.card(i).isdolle() ||
	    ha.card(i).isswine() ||
	    ha.card(i).ishyperswine()
	   )
	   && tpoints>hi.value(Aiconfig::LIMITDOLLE))
      {     
	c=ha.card(i);
	break;
      } 

      if ( ha.card(i).isdolle() ||
	   ha.card(i).isswine() ||
	   ha.card(i).ishyperswine()      )
	continue;

      c=ha.card(i);
      break;
    }
  }
  // if can't win this trick and I'am not the last player: that's it
  if (c==Card() && !t.islastcard())  {

    DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");

  }
  bool allmyteam=true;

  for (i=t.actcardno(); i<hi.game().playerno(); i++)
    allmyteam=allmyteam && (hi.team()==hi.teaminfo(t.player_of_card(i)));

  bool trumpintrick=false;

  for ( i = 0 ; i < t.actcardno() ; i++)
  {
    trumpintrick=trumpintrick||t.card(i).istrump();
  }

  // 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 ((t.islastcard()
	     && (ha.card(i).value()<Card::JACK)
	     && (ha.card(i).less(c, game))))
	{

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

	if ( ha.card(i).value()>=Card::JACK )
	{
	  if (!t.isstartcard() && ha.card(i).value()<Card::QUEEN
	      && ( !hi.colorjabbed(t.startcard().color())
		   || tpoints<= hi.value( Aiconfig::LIMITQUEEN )
		   || (ha.numberof( Card::QUEEN ) < 2) ) )

	  {

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

	  if ( ha.card(i).value()==Card::QUEEN
	       && tpoints>hi.value(Aiconfig::LIMITQUEEN)
	       && ( (    c.value() < Card::QUEEN
		          && hi.color_runs(t.startcard().color())< 1 )
		    || ha.card(i).less(c, game) ) )
	  {
	    c=ha.card(i);
	    continue;
	  }


	  if ((ha.card(i).isdolle() ||
	       ha.card(i).isswine() ||
	       ha.card(i).ishyperswine())
	      && tpoints>hi.value(Aiconfig::LIMITDOLLE) &&
	      ( ( c.value() < Card::QUEEN 
		  && !hi.color_runs(t.startcard().color())< 1) 
		|| ha.card(i).less(c, game) ) )
	  {

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


	} //if card>jack
      }// if card istrump

    } // if winneris
  }


  // 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)
      /// 2do heart ten non trump, than also for heart tricks
     )
  {

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

	// Maybe it's time to get the heart ten back home
	if ( ha.card(i).isdolle() && 
	     ha.cardsnumber() < 4 && 
	     hi.game().rule()(Rule::EXTRAPOINT_DOLLE_JABS_DOLLE) )
	{    
	  c=ha.card(i);
	  break;
	} 	 

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

	  continue;
	}
	if (ha.card(i).value()==Card::KING && game.type()!=GAMETYPE::SOLO_KOEHLER)
	{        
	  if (c.value()!=Card::TEN || c.isdolle() )
	  {
	    c=ha.card(i);             
	  }
	  continue;
	}
	if ((ha.card(i).value()==Card::NINE) &&
	    (!ha.card(i).ishyperswine()))
	{
	  if (c.value()!=Card::TEN || c.value()!=Card::KING || c.isdolle() )
	  {

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

	if ( c.istrump() && ha.card(i).istrump() && ha.card(i).less(c, game )  )
	{
	  if (c.value()!=Card::TEN || c.value()!=Card::KING || c.isdolle() || c.ishyperswine() )
	  { 
	    c=ha.card(i);
	  }
	  continue;
	}
      }
    }
  }
  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()");
}

/**********************************************************************
 *
 **    Card lowest_color_card(Trick const& t, Hand h)
 *
 **    Parameters:  actual trick, and hand of player
 *
 **    Result: finds lowest color card on Hand h
 *
 **    Version: Beta
 *
 **    Description:
 *
 **********************************************************************/

Card lowest_color_card(Trick const& t, Hand h)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_color_card()");

  Card c=Card();
  Hand 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;
    }
  }

  if (c==Card()) {
    DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_color_card()");
  }

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

  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_color_card()");
}


/**********************************************************************
 *
 **    Card lowest_color_card_meatless(Trick const& t, Hand h)
 *
 **    Parameters:  actual trick, and hand of player
 *
 **    Result: finds lowest color card on Hand h, wihich is the best 
 ** 	          in a meatless solo
 *
 **    Version: Beta
 *
 **    Description:
 *
 **********************************************************************/

Card lowest_color_card_meatless(Trick const& t, Hand h)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_color_card()");

  Card c=Card();
  Hand 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;
    }
  }

  if (c==Card()) {
    DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_color_card()");
  }

  // find a better card
  for ( i=0; i < ha.cardsnumber(); i++)
  {
    if (ha.card(i).value() < c.value() &&
	!ha.card(i).istrump() &&
	( 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);
  }

  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_color_card()");
}


/**********************************************************************
 *
 **    Card lowest_trump_card(Trick const& t, Hand h)
 *
 **    Parameters:  actual trick, and hand of player
 *
 **    Result: finds lowest trump card on Hand h
 *
 **    Version: Beta
 *
 **    Description:
 *
 **********************************************************************/

Card lowest_trump_card(Trick const& t, Hand h)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_trump_card()");

  Game const& game = t.game();
  Card c=Card();
  Hand 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;
    }
  }

  if (c==Card()) {
    DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_trump_card()");
  }

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

  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_trump_card()");
}


/**********************************************************************
 *
 **    Card lowest_best_trump_card(Trick const& t, Hand h)
 *
 **    Parameters:  actual trick, and hand of player
 *
 **    Result: finds lowest trump card on Hand h, but gives only fuchs or ten back
 **            if there are better cards to keep
 *
 **    Version: Beta
 *
 **    Description:
 *
 **********************************************************************/

Card Heuristics::lowest_best_trump_card(Trick const& t, Hand const& h, HeuristicInterface const& hi)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_best_trump_card()");

  Card c=Card();
  Hand ha=h.validcards(t);
  unsigned i;
  Game const& game = t.game();

  // 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;
    }
  }

  if (c==Card()) {
    DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_best_trump_card()");
  }

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

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

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

  DEBUG_RETURNING(c,
		  INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		  "Heuristics::lowest_best_trump_card()");
}

/**********************************************************************
 *
 **    Card Heuristics::choose_pfund_card(Trick t, HeursticInterface const& hi)
 *
 **    Parameters:  actual played trick, HeuristicInterface who plays next card
 *
 **    Result: result see description, otherwise
 **            result is a card with Card::NOCARDVALUE and Card::NOCARDCOLOR
 *
 **    Version: Beta
 *
 **    Description:
 **     best pfund on hand
 **      a trump Ass, color ten or Ace, trump ten, a king,
 **      a notrump queen or jack, nine
 *
 **********************************************************************/

Card Heuristics::choose_pfund_card(Trick const& trick, HeuristicInterface const& hi)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		"Heuristics::choose_pfund_card()");

  Trick t = trick;

  unsigned i;

  Card c=Card();

  Hand ha=hi.hand().validcards(t);

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


  // 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()) || (ha.numberoftrumps() < 3 )) &&
	(!ha.card(i).isswine()) )
    {
      t+=ha.card(i);
      if (hi.teamofplayer(t.winnerplayer())==hi.team())
	DEBUG_RETURNING(ha.card(i),
			INFO_HEURISTICS && INFO_OTHER_FUNCTION,
			"Heuristics::choose_pfund()");
    }

  // 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 ) )
    {
      DEBUG_RETURNING(ha.card(i),
		      INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		      "Heuristics::choose_pfund()");
    }

  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++)
    if (ha.card(i).value()==Card::ACE &&
	!(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 )

       )
    {
      DEBUG_RETURNING(ha.card(i),INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::choose_pfund()");
    }

  // 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()))
    {
      DEBUG_RETURNING(ha.card(i),INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::choose_pfund()");
    }

  // or a King of color
  for ( i = 0; i < ha.cardsnumber(); i++)
    if (ha.card(i).value()==Card::KING &&
	!(ha.card(i).istrump()))
    {
      DEBUG_RETURNING(ha.card(i),INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::choose_pfund()");
    }

  // or a king of trump
  for ( i = 0; i < ha.cardsnumber(); i++)
    if (ha.card(i).value()==Card::KING &&
	(ha.card(i).istrump())
	&& hi.game().type() != GAMETYPE::SOLO_KING 
	&& hi.game().type() != GAMETYPE::SOLO_KING_QUEEN
	&& hi.game().type() != GAMETYPE::SOLO_KING_JACK
       )
    {
      DEBUG_RETURNING(ha.card(i),INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::choose_pfund()");
    }

  // 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
       )
    {
      DEBUG_RETURNING(ha.card(i),INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::choose_pfund()");
    }

  // 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
       )
    {
      DEBUG_RETURNING(ha.card(i),INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::choose_pfund()");
    }

  // or a nine of color
  for ( i = 0; i < ha.cardsnumber(); i++)
    if (ha.card(i).value()==Card::NINE &&
	!(ha.card(i).istrump())) 
    {
      DEBUG_RETURNING(ha.card(i),INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::choose_pfund()");
    }

  // 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())))
    {
      DEBUG_RETURNING(ha.card(i),INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::choose_pfund()");
    }

  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::choose_pfund()");
}


/**********************************************************************
 *
 **    Card Heuristics::choose_for_color_trick(Trick const& t, HeursticInterface const& hi)
 *
 **    Parameters:  actual palyed trick, HeuristicInterface who plays next card
 *
 **    Result: result see description, if no good card found
 **            result is a card with Card::NOCARDVALUE and Card::NOCARDCOLOR
 *
 **    Version: Beta
 *
 **    Description:
 **      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
 *
 **********************************************************************/

Card Heuristics::choose_for_color_trick(Trick const& t, HeuristicInterface const& hi)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		"Heuristics::choose_for_color_trick() (long)");

  Card c=Card();

  unsigned i;

  Hand ha;


  // 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() 
	 || (!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 = (maybe_to_team(hi.teamofplayer(t.winnerplayer()))==hi.team());


    if (hi.game().type()==GAMETYPE::MARRIAGE) 
    {
      pred=hi.teamofplayer(t.winnerplayer())==hi.team();
    } 
    pred = pred  && ( t.islastcard() 
		      || ( (t.winnercard().value() == Card::ACE || t.winnercard().istrump())
			   && (hi.color_runs(t.startcard().color()) == 0 ) 
			   ||  !t.winnercard().less( hi.trump_card_limit(), hi.game() )
			 ) );
    if( hi.game().type()== GAMETYPE::POVERTY )
	    pred = pred && ( hi.no() == hi.game().povertyPartner().no() ); 

    if ( pred || 
	 (      GAMETYPE::is_solo( hi.game().type() )  
	     && t.winnerplayer() != hi.game().soloplayer() 
	     &&  hi.color_runs(t.startcard().color()) == 0 
	     &&  t.winnercard().less( hi.trump_card_limit(), hi.game() ) 
	     &&  !t.islastcard() ) 
       )
    { 
      DEBUG_RETURNING(choose_pfund_card(t,hi),
		      INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		      "Heuristics::choose_for_color_trick() (long)");   
    } // if own Team gets this trick


    // if there are only color cards in this trick
    bool trumpintrick=false;

    for ( i = 0 ; i < t.actcardno() ; i++)
    {
      trumpintrick=trumpintrick||t.card(i).istrump();
    }

    if (!trumpintrick )
    {

      c=best_winning_card(t,hi);

      if( !ha.existstcolor(t.startcard().color() ) )
      {
	if (!(c==Card()))
	{ 

	  if (t.points()>hi.value(Aiconfig::LIMITDOLLE))
	    DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::choose_for_color_trick() (long)");
	  if (t.points()>hi.value(Aiconfig::LIMITQUEEN)
	      && !Card(Card::CLUB,Card::QUEEN).less(c, hi.game()))
	    DEBUG_RETURNING(c,
			    INFO_HEURISTICS && INFO_OTHER_FUNCTION,
			    "Heuristics::choose_for_color_trick() (long)");
	  if (!c.less(Card(Card::DIAMOND,Card::QUEEN), hi.game()))
	    DEBUG_RETURNING(c,
			    INFO_HEURISTICS && INFO_OTHER_FUNCTION,
			    "Heuristics::choose_for_color_trick() (long)");

	}

      } else
	if (!(c==Card()))
	{

	  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::choose_for_color_trick() (long)");
	} else {
	  GameType gt = hi.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 )
	      DEBUG_RETURNING(Card( t.startcard().color(), Card::ACE ) ,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::choose_for_color_trick() (long)");



	    if( hi.color_runs(t.startcard().color()) > 0)
	      DEBUG_RETURNING(lowest_color_card(t,hi.hand()),INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::choose_for_color_trick() (long)");
	    else
	      DEBUG_RETURNING(lowest_best_trump_card(t, hi.hand(), hi),INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::choose_for_color_trick() (long)");


	  } else {

	    DEBUG_RETURNING(lowest_color_card_meatless(t,hi.hand()),INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::choose_for_color_trick() (long)");
	  }

	}

    }// 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==Card()))
	{ 
	  if (t.points()>hi.value(Aiconfig::LIMITDOLLE))
	    DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::choose_for_color_trick() (long)");
	  if (t.points()>hi.value(Aiconfig::LIMITQUEEN)
	      && !Card(Card::CLUB,Card::QUEEN).less(c, hi.game()))
	    DEBUG_RETURNING(c,
			    INFO_HEURISTICS && INFO_OTHER_FUNCTION,
			    "Heuristics::choose_for_color_trick() (long)");
	  if (!c.less(Card(Card::DIAMOND,Card::QUEEN), hi.game()))
	    DEBUG_RETURNING(c,
			    INFO_HEURISTICS && INFO_OTHER_FUNCTION,
			    "Heuristics::choose_for_color_trick() (long)");

	}
      }
    }

  } // check if trick is valid for this heuristic


  DEBUG_RETURNING(c,
		  INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		  "Heuristics::choose_for_color_trick() (long)");
}


/**********************************************************************
 *
 **    Card Heuristics::choose_pfund(Trick const& t, HeursticInterface const& hi)
 *
 **    Parameters:  actual played trick, HeuristicInterface who plays next card
 *
 **    Result: result see description, otherwise
 **            result is a card with Card::NOCARDVALUE and Card::NOCARDCOLOR
 *
 **    Version: Beta
 *
 **    Description:
 **      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
 *
 **********************************************************************/

Card Heuristics::choose_pfund(Trick const& t, HeuristicInterface const& hi)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		"Heuristics::choose_pfund()");

  // I'am the start Player
  if (t.isstartcard())
    DEBUG_RETURNING(Card(),
		    INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		    "Heuristics::choose_pfund()");

  bool soloPlayer = false;
  if (GAMETYPE::is_solo(hi.game().type()))
    for( unsigned i = t.actcardno(); i < hi.game().playerno(); i++ )
      if ( t.player_of_card( i ) == hi.game().soloplayer () )
	soloPlayer = true;
  // if winner is own team
  if (maybe_to_team(hi.teamofplayer(t.winnerplayer()))
      == hi.team() && ! soloPlayer)
    // if this is the last card or there is already a good trump
    if (t.islastcard() 
	|| (!t.winnercard().less(hi.trump_card_limit(), hi.game())))
    {
      DEBUG_RETURNING(choose_pfund_card(t,hi),
		      INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		      "Heuristics::choose_pfund()");
    }

  DEBUG_RETURNING(Card(),
		  INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		  "Heuristics::choose_pfund()");
}

/**********************************************************************
 *
 **    Card Heuristics::jab_for_ace(Trick const& t,HeursticInterface const& hi)
 *
 **    Parameters:  actual played trick, HeuristicInterface who plays next card
 *
 **    Result: result lowest allowed Jack or Queen if they are trump
 **            and there is a ace to play, which is not already jabbed
 **            result is a card with Card::NOCARDVALUE and Card::NOCARDCOLOR
 *
 **    Version: Beta
 *
 **    Description:
 *
 **********************************************************************/


Card Heuristics::jab_for_ace( Trick const& t, HeuristicInterface const& hi )
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::jab_for_ace()");

  Card c = Card();
  Card ace = choose_ace( Trick(), hi );

  if (!( ace == Card() ) && ( hi.hand().numberof( ace ) < 2 ) && (hi.color_runs(ace.color()) == 0) )
  {    		
    c = best_winning_card( t, hi, hi.value( Aiconfig::LIMITDOLLE ) );
  }

  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::jab_for_ace()");

}

/**********************************************************************
 *
 **    Card Heuristics::play_low_high(Trick const& t,HeursticInterface const& hi)
 *
 **    Parameters:  actual played trick, HeuristicInterface who plays next card
 *
 **    Result: plays high and low trumps changing
 *
 **    Version: Beta
 *
 **    Description: 
 *
 **********************************************************************/  
Card Heuristics::play_low_high(Trick const& t,HeuristicInterface const& hi)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		"Heuristics::play_low_high");


  if (t.isstartcard() 
      && (hi.hand().numberoftrumps() > (hi.game().tricks_remaining_no() / 2 ))) 
  {
    if (hi.next_low()) {
      Card c=lowest_jack(hi.hand(), hi);

      if (c != Card()
	  && !t.isvalid(c,hi.hand()))
	c=Card();
      DEBUG_RETURNING(c,
		      INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		      "Heuristics::play_low_high()"
		      " = jack");
    } else { // if !(hi.next_low())
      Card c=lowest_queen(hi.hand(), hi);

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

      DEBUG_RETURNING(c,
		      INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		      "Heuristics::play_low_high()"
		      " = queen");
    } // if !(hi.next_low())
  } // if (t.isstartcard())

  DEBUG_RETURNING(Card(),
		  INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		  "Heuristics::play_low_high()"
		  " = card()");
}


/**********************************************************************
 *
 **    Card Heuristics::SecondBestTrump(HeuristicInterface const& hi)
 *
 **    Parameters:  actual played trick, HeuristicInterface who plays next card
 *
 **    Result: plays the scond highest trump
 *
 **    Version: Beta
 *
 **    Description: 
 **      usefull for color soli
 *
 **********************************************************************/  
Card
Heuristics::SecondBestTrump(HeuristicInterface const& hi)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::SecondBestTrump");
  Hand h=hi.hand();

  Card c=Card();
  Card bestcard;
	
  if( hi.remaining_trumps() == 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), hi.game())) {
      bestcard=h.card(i);
      best=i;
    }
  }

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

  DEBUG_ASSERT( c );
  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::SecondBestTrump");

  // ***
  // problem with the compiler :-(

  DEBUG_ASSERTION(false,
		  "Heuristics::SecondBestTrump(HeuristicInterface):\n"
		  "  control is after 'DEBUG_RETURNING'");

  return c; // ***
} // Card Heuristics::SecondBestTrump(HeuristicInterface const& hi)


/**********************************************************************
 *
 **    Card Heuristics::play_for_team(Trick const& t,HeursticInterface const& hi)
 *
 **    Parameters:  actual played trick, HeuristicInterface who plays next card
 *
 **    Result: puts a nice card to a trick of a team mate
 *
 **    Version: Beta
 *
 **    Description: 
 **      result a ten (no dolle), or a Ace (no swine)
 **      or a king, or a nine in this order
 *
 **********************************************************************/  
Card Heuristics::play_for_team(Trick const& t,HeuristicInterface const& hi)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::play_for_team");

  // I'am the start Player
  if (t.isstartcard())
    DEBUG_RETURNING(Card(),
		    INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		    "Heuristics::choose_pfund()");

  bool soloPlayer = false;
  if (GAMETYPE::is_solo(hi.game().type()))
    for( unsigned i = t.actcardno(); i < hi.game().playerno(); i++ )
      if ( t.player_of_card( i ) == hi.game().soloplayer () )
	soloPlayer = true;

  Card c=Card();
  if ((maybe_to_team(hi.teamofplayer(t.winnerplayer()))==hi.team()) 
      && !soloPlayer
      && !(t.winnercard().less(hi.value(Aiconfig::LIMITTHROWING),
			       hi.game())))
  { 
    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::TEN
	    && !(tr.winnercard().less(hi.value(Aiconfig::LIMITHIGH),
				      hi.game()))
	    && !hi.hand().card(i).isdolle())
	  c=hi.hand().card(i);     
      }           
    }

    if (c!=Card()) 
      DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::play_for_team");

    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
	// DK: 'soloPlayer &&' hinzugefuegt: ansonsten gibt es einen assert bei 'hi.game().soloplayer()'
    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),
				      hi.game())) || t.islastcard() || lastPoverty )
	    && !hi.hand().card(i).isswine() 
	    && ( !hi.hand().card(i).isfox() || t.islastcard() || lastPoverty ))
	  c=hi.hand().card(i);     
      }           
    }

    if (c!=Card()) 
      DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::play_for_team");

    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.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 (c!=Card()) 
      DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::play_for_team");

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


  }

  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::play_for_team");
}

/**********************************************************************
 *
 **    Card Heuristics::jab_fox(Trick const& t,HeursticInterface const& hi)
 *
 **    Parameters:  actual played trick, HeuristicInterface who plays next card
 *
 **    Result: jabs a fox if in this in the trick
 *
 **    Version: Beta
 *
 **    Description: 
 *
 **********************************************************************/  
Card Heuristics::jab_fox(Trick const& t,HeuristicInterface const& hi)
{
  DEBUG_CALLING(INFO_HEURISTICS&&INFO_OTHER_FUNCTION,"Heuristics::jab_fox");
  Card c=Card();

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

  if (fox_exists)
  {
    // if lastcard just take the best winning card
    if (t.islastcard() && hi.teamofplayer(t.winnerplayer())!=hi.team())
    {
      DEBUG_RETURNING(best_winning_card(t,hi),INFO_HEURISTICS&&INFO_OTHER_FUNCTION,"Heuristics::jab_fox");
    } 

    // for all other we take our lowest queen
    Card ca=highest_queen(hi.hand(), hi);
    if (!ca) {
      DEBUG_RETURNING(ca,
		      INFO_HEURISTICS&&INFO_VALUE,
		      "Heuristics::jab_fox");
    }

    Trick tr=t;
    tr+=ca;
    if (t.isvalid(ca,hi.hand()) && tr.winnerplayer().no()==hi.no()) {
      DEBUG_RETURNING(ca,
		      INFO_HEURISTICS&&INFO_OTHER_FUNCTION,
		      "Heuristics::jab_fox");
    } 
  } 

  DEBUG_RETURNING(c,INFO_HEURISTICS&&INFO_OTHER_FUNCTION,"Heuristics::jab_fox");
}

/**********************************************************************
 *
 **    Card choose_best_fehl(Trick const& t,HeursticInterface const& hi)
 *
 **    Parameters:  actual played trick, HeuristicInterface who plays next card
 *
 **    Result: single color nine or king to get fehl
 **            otherwise Card()
 *
 **    Version: Beta
 *
 **    Description: 
 *
 **********************************************************************/

Card choose_best_fehl(Trick const& t,HeuristicInterface const& hi)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics choose_best_fehl()");
  unsigned i,n;
  vector<int> numberofcards(party.rule()(Rule::NUMBER_OF_CARD_COLORS));
  unsigned bestcolor=0;
  vector<int> co(::party.rule()(Rule::NUMBER_OF_CARD_COLORS));
  Card c=Card();

  Hand h=hi.hand().validcards(t);

  for ( i = 0; i < ::party.rule()(Rule::NUMBER_OF_CARD_COLORS); i++)
    co[i]=0;

  for ( i = 0; i<h.cardsnumber(); i++) 
  {
    if (!h.card(i).istrump()) 
    {
      (co[h.card(i).color()])++;
    }
  }




  int notrump_per_color=number_of_no_trumps_per_color();

  for ( i = 0; i < ::party.rule()(Rule::NUMBER_OF_CARD_COLORS); i++)
    numberofcards[i]=0;

  // calculate number of played no Trump cards per color
  for ( i=0;  i < 2 * ::party.rule()(Rule::NUMBER_OF_CARD_VALUES); i+=2)
    for (n=0; n < ::party.rule()(Rule::NUMBER_OF_CARD_COLORS); n++)
      if (!Card(Card::InttoColor(n),Card::InttoValue(i)).istrump())
	(numberofcards[n])+=hi.playedcard(Card(Card::InttoColor(n),
					       Card::InttoValue(i)));


  for ( i = 0; i<h.cardsnumber(); i++)
  {
    // cards still in game of this color
    unsigned const cn = notrump_per_color-numberofcards[h.card(i).color()];
    if ( (!h.card(i).istrump()) &&
	 (cn>bestcolor) &&
	 (cn >= hi.game().playerno() ) &&
	 t.isvalid(h.card(i),hi.hand()) &&
	 (co[h.card(i).color()]<2) &&
	 (h.card(i).value()==Card::KING ||
	  h.card(i).value()==Card::NINE)) 
    {
      c=h.card(i);
      bestcolor=cn;
    }
  }// for
  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics choose_best_fehl()");
}

/**********************************************************************
 *
 **    Card Heuristics::create_fehl(Trick const& t,HeursticInterface const& hi)
 *
 **    Parameters:  actual played trick, HeuristicInterface who plays next card
 *
 **    Result: result play single color nine or king to get fehl
 **            in second run of a color
 **            result is a card with Card::NOCARDVALUE and Card::NOCARDCOLOR
 *
 **    Version: Alpha
 *
 **    Description: 
 *
 **********************************************************************/

Card Heuristics::create_fehl(Trick const& t,HeuristicInterface const& hi)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::create_fehl()");


  Card c=Card();

  // if this trick is still worth fehl creation
  if (hi.game().trick_current_no() < hi.value(Aiconfig::LASTFEHLCREATION))
  {

    // if this is the firstcard 
    if( hi.value(Aiconfig::FEHLCREATIONONFIRSTCARD) ) 
      if (t.actcardno() == 0)
	DEBUG_RETURNING(choose_best_fehl(t,hi),INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::create_fehl()");  

    // this is not the first colorrun and there are not more then 10 points 
    if (t.actcardno() > 0 && (hi.color_runs(t.startcard().color()) > 0) && (t.points()<10))
    {  
      // the trick is jabbed high enough 
      if (t.winnercard().istrump()
	  &&  !(t.winnercard().less(hi.lowest_trump_card_limit(), hi.game())))
	DEBUG_RETURNING(choose_best_fehl(t,hi),
			INFO_HEURISTICS && INFO_OTHER_FUNCTION,
			"Heuristics::create_fehl()");  

      // the winnercard is already a no trump ace 
      if (!t.winnercard().istrump() && t.winnercard().value() >= Card::ACE)
	DEBUG_RETURNING(choose_best_fehl(t,hi),INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::create_fehl()");          
    }
  }
  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::create_fehl()");
}

/**********************************************************************
 *
 **    int calchandvalue(HeursticInterface const& hi)
 *
 **    Parameters:  HeuristicInterface who checks for an announcement
 *
 **    Result: value of cards for announcement
 *
 **    Version: Beta
 *
 **    Description: 
 *
 **********************************************************************/

int Heuristics::CalcHandValue(HeuristicInterface const& hi, const Game& g)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::CalcHandValue");
  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;
  }

  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;
    value = -5;
  }

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

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

  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;
    value = -6;
  }  

  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;
    value = -6; 
  }    

  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;
    value = -6;
  }  

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

  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;
    value = -7;

  }  

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

  for ( i = 0; i< hi.hand().cardsnumber(); i++)
  {
    if (hi.hand().card(i).isdolle() || hi.hand().card(i).isswine() ||
	hi.hand().card(i).ishyperswine()) value+=v_highest;

    if (hi.hand().card(i).value()==Card::QUEEN) value+=v_queen;

    if (hi.hand().card(i).value()==Card::JACK) value+=v_jack; 

    if (hi.hand().card(i).value()==Card::KING) value+=v_king;

    if (hi.hand().card(i).value()==Card::ACE && !hi.hand().card(i).istrump()) value+=v_ace;
  }

  for ( i=0; i < ::party.rule()(Rule::NUMBER_OF_CARD_COLORS);i++)
  {
    if (    !Card(Card::InttoColor(i),Card::NINE).istrump() 
         && !hi.hand().existstcolor(Card::InttoColor(i))
         && hi.color_runs( Card::InttoColor(i) ) == 0
         )
      value+=v_fehl;
  }

  if (g.type()==GAMETYPE::SOLO_MEATLESS)
  {
    for ( i=0; i < ::party.rule()(Rule::NUMBER_OF_CARD_COLORS);i++)
    {
      if ( hi.hand().existstcolor(Card::InttoColor(i)) )
	value-=v_fehl*(2 - hi.hand().numberof(Card::InttoColor(i),Card::ACE) );
    }
    if( hi.no() == hi.game().soloplayer().no() )
    {
      unsigned longColor = 0;
      for ( i=0; i < ::party.rule()(Rule::NUMBER_OF_CARD_COLORS);i++)
      {
	if( hi.hand().numberof(Card::InttoColor(i),Card::ACE)  == 2 &&
	    hi.hand().numberof(Card::InttoColor(i) ) > longColor )
	  longColor = hi.hand().numberof(Card::InttoColor(i) );
      }
      value += longColor;
    }

  } else
  {
    for ( i=0; i < ::party.rule()(Rule::NUMBER_OF_CARD_COLORS);i++)
    {
      if ( hi.hand().existstcolor(Card::InttoColor(i)) && !Card(Card::InttoColor(i),Card::NINE).istrump() )
      {
		if ( hi.hand().numberof(Card::InttoColor(i),Card::ACE) == 0 )
	  	  value-=v_fehl;
		if( hi.hand().numberof(Card::InttoColor(i) ) > 3 )
		  value-=v_fehl;
		if( hi.hand().numberof(Card::InttoColor(i) ) == 3 && 
		    hi.hand().numberof(Card::InttoColor(i),Card::ACE) < 2 )
		    value -= v_ace;
      }
    }
  }

  if (g.type()==GAMETYPE::SOLO_KOEHLER)
    for ( i=0; i < ::party.rule()(Rule::NUMBER_OF_CARD_COLORS);i++)
    {
      if ( hi.hand().existstcolor(Card::InttoColor(i)) )
		value-=5;
    }

  if( hi.game().swines_owner() != NULL &&
      hi.game().swines_owner()->no() != hi.no() )
  {
    if(  hi.teamofplayer(*(hi.game().swines_owner())) == hi.team() )
    {
      value += v_highest;
    } else
    {
      value -= 2* v_highest;
    }
  }

  if( hi.game().hyperswines_owner() != NULL && 
      hi.game().hyperswines_owner()->no() != hi.no() )
  {
    if( hi.teamofplayer(*(hi.game().hyperswines_owner())) == hi.team() )
    {
      value += v_highest;
    } else
    {
      value -= 2* v_highest;
    }
  }


  DEBUG_RETURNING(value,INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::CalcHandValue");
}

/**********************************************************************
 *
 **    bool Heuristics::make_announcement(HeursticInterface const& hi)
 *
 **    Parameters:  HeuristicInterface who checks for an announcement
 *
 **    Result: true if hi should say re or contra
 **            false otherwise
 *
 **    Version: Beta
 *
 **    Description: 
 *
 **********************************************************************/

bool Heuristics::make_announcement(HeuristicInterface const& hi,const Game& g)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::make_announcement");
  int value=0;

  value=CalcHandValue(hi,g);



  DEBUG_RETURNING( value >=   (int)hi.value(Aiconfig::ANNOUNCELIMIT) 
		   + (int)hi.value(Aiconfig::ANNOUNCECONFIG),
		   INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		   "Heuristics::make_announcement" );
} 


/**********************************************************************
 *
 **     bool Heuristics::say_no90(HeuristicInterface const& hi ,Game g)
 *
 **    Parameters:  HeuristicInterface who checks for an announcement
 *
 **    Result: true if hi should say No90
 **            false otherwise
 *
 **    Version: Beta
 *
 **    Description: 
 *
 **********************************************************************/
bool Heuristics::say_no90(HeuristicInterface const& hi ,const Game& g)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no90");
  int value=0;

  value=CalcHandValue(hi,g);

  int own_p = 0;
  int opp_p = 0;

  for( unsigned int i = 0; i < g.playerno(); i++ )
  {
    if( hi.teamofplayer( g.player(i) ) != hi.team() )
    {
      opp_p += g.points_of_player( g.player(i) );
    } else
    {
      own_p += g.points_of_player( g.player(i) );
    }
  }
  
  if( own_p > 150 )
    DEBUG_RETURNING( true, 
		  INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no90");
  
  
  opp_p+= 5 * g.tricks_remaining_no();
  own_p+= 6 * g.tricks_remaining_no();

  if( hi.game().swines_owner() != NULL && 
      hi.game().swines_owner()->no() == hi.no())
  {
    own_p += 4 * hi.hand().numberoftrumps() * hi.hand().numberoftrumpaces();
  }
  if( hi.game().hyperswines_owner() != NULL && 
      hi.game().hyperswines_owner()->no() == hi.no())
  {
    own_p += 4 * hi.hand().numberoftrumps() * hi.hand().numberoftrumpnines();
  }


  DEBUG_RETURNING((( value + 3 * (int)hi.value(Aiconfig::ANNOUNCELIMITDEC)
		     > (int)hi.value(Aiconfig::ANNOUNCELIMIT)
		     + (int)hi.value(Aiconfig::ANNOUNCECONFIG))
		   && own_p > 2*opp_p  && opp_p<90 
		   && 
		   ( (opp_p>0 ) 
		     || (g.rule().remaining_tricks(ANNOUNCEMENT::NO90)
			 == g.tricks_remaining_no()))), 
		  INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no90");
}

/**********************************************************************
 *
 **    bool Heuristics::say_no60(HeuristicInterface const& hi ,Game g)
 *
 **    Parameters:  HeuristicInterface who checks for an announcement
 *
 **    Result: true if hi should No60
 **            false otherwise
 *
 **    Version: Beta
 *
 **    Description: 
 *
 **********************************************************************/
bool Heuristics::say_no60(HeuristicInterface const& hi ,const Game& g)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no60");
  int value=0;

  value=CalcHandValue(hi,g);

  int own_p = 0;
  int opp_p = 0;

  for( unsigned int i = 0; i < g.playerno(); i++ )
  {
    if( hi.teamofplayer( g.player(i) ) != hi.team() )
    {
      opp_p += g.points_of_player( g.player(i) );
    } else
    {
      own_p += g.points_of_player( g.player(i) );
    }
  }  
  
  if( own_p > 180 )
    DEBUG_RETURNING( true, 
		  INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no60");
  
  
  opp_p+= 5 * g.tricks_remaining_no();
  own_p+= 5 * g.tricks_remaining_no();

  if( hi.game().swines_owner() != NULL && 
      hi.game().swines_owner()->no() == hi.no())
  {
    own_p += 5 * hi.hand().numberoftrumps() * hi.hand().numberoftrumpaces();
  }
  if( hi.game().hyperswines_owner() != NULL && 
      hi.game().hyperswines_owner()->no() == hi.no())
  {
    own_p += 5 * hi.hand().numberoftrumps() * hi.hand().numberoftrumpnines();
  }
  
	
  DEBUG_RETURNING((( value + 5 * (int)hi.value(Aiconfig::ANNOUNCELIMITDEC)
		     > (int)hi.value(Aiconfig::ANNOUNCELIMIT)
		     + (int)hi.value(Aiconfig::ANNOUNCECONFIG))
		   && own_p > 3*opp_p  && opp_p<60 
		   &&
		   ( (opp_p>0 ) 
		     || (g.rule().remaining_tricks(ANNOUNCEMENT::NO60)
			 == g.tricks_remaining_no()))), 
		  INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no60"); 
}


/**********************************************************************
 *
 **    bool Heuristics::say_no30(HeuristicInterface const& hi ,Game g)
 *
 **    Parameters:  HeuristicInterface who checks for an announcement
 *
 **    Result: true if hi should say no30
 **            false otherwise
 *
 **    Version: Beta
 *
 **    Description: 
 *
 **********************************************************************/
bool Heuristics::say_no30(HeuristicInterface const& hi ,const Game& g)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no30");
  int value=0;

  value=CalcHandValue(hi,g);

  int own_p = 0;
  int opp_p = 0;

  for( unsigned int i = 0; i < g.playerno(); i++ )
  {
    if( hi.teamofplayer( g.player(i) ) != hi.team() )
    {
      opp_p += g.points_of_player( g.player(i) );
    } else
    {
      own_p += g.points_of_player( g.player(i) );
    }
  }  
  
  if( own_p > 210 )
    DEBUG_RETURNING( true, 
		  INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no30");
  
  
  opp_p+= 4 * g.tricks_remaining_no();
  own_p+= 5 * g.tricks_remaining_no();


  DEBUG_RETURNING((( 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.rule().remaining_tricks(ANNOUNCEMENT::NO30)
			 == g.tricks_remaining_no()))), 
		  INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no60");                  
}


/**********************************************************************
 *
 **     static bool Heuristics::say_no0(HeuristicInterface const& hi ,Game g)
 *
 **    Parameters:  HeuristicInterface who checks for an announcement
 *
 **    Result: true if hi should say No0
 **            false otherwise
 *
 **    Version: Beta
 *
 **    Description: 
 *
 **********************************************************************/
bool Heuristics::say_no0(HeuristicInterface const& hi ,const Game& g)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no0");
  int value=0;

  value=CalcHandValue(hi,g);

  bool has_trick = false;

  for( unsigned int i = 0; i < g.playerno(); i++ )
  {
    if( hi.teamofplayer( g.player(i) ) != hi.team() )
    {
      has_trick = has_trick || ( g.numberoftricks_of_player( g.player(i) ) != 0 );
    } 
  }  

  DEBUG_RETURNING(((value + 6*(int)hi.value(Aiconfig::ANNOUNCELIMITDEC)
		    > (int)hi.value(Aiconfig::ANNOUNCELIMIT)
		    + (int)hi.value(Aiconfig::ANNOUNCECONFIG)) &&
		   !has_trick && (g.rule().remaining_tricks(ANNOUNCEMENT::NO0)
				  == g.tricks_remaining_no()) && false),
		  INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no0"); 


}

/**********************************************************************
 *
 **    Card play_highest_color(Trick const& t,AI& hi,Card::COLOR c)
 *
 **    Parameters:
 *
 **    Result: finds highest card of color c
 *
 **    Version: Beta
 *
 **    Description:
 *
 **********************************************************************/

Card Heuristics::play_highest_color(Trick const& t, HeuristicInterface const& hi,Card::Color co)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::play_highest_color");

  Card c=Card();
  Hand h=hi.hand();
  unsigned i;

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

  if (c==Card()) 
  {
    DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::play_highest_color");
  }

  for ( i=0; i < h.cardsnumber(); i++)
  {
    // find highest card
    if (h.card(i).color()==co &&
	c.less(h.card(i), hi.game()))
      c=h.card(i);
  }

  DEBUG_RETURNING(c,INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::play_highest_color");
}


/**********************************************************************
 *
 **    Card drawTrumps(Trick const& t,AI& hi )
 *
 **    Parameters:
 *
 **    Result: play trumps to draw the last trumps
 *
 **    Version: 0.6.1
 *
 **    Description:
 *
 **********************************************************************/

Card Heuristics::draw_trump(Trick const& t, HeuristicInterface const& hi )
{
  Card c = Card();
  if( !t.isstartcard() )
    return c;
    
  if(    hi.hand().numberoftrumps() > hi.remaining_trumps() 
      && hi.remaining_trumps() > 0 )
  {	
  Hand h = hi.hand().validcards(t);
  unsigned i;
  
  for ( i=0; i < h.cardsnumber(); i++)
  {
    // find any trump
    if (h.card(i).istrump() )
    {
      c=h.card(i);
      break;
    }
  }

  if (c==Card()) 
  {
  	return c;
  }

  for ( i=0; i < h.cardsnumber(); i++)
  {
    // find highest card
    if (h.card(i).istrump() &&
	!h.card(i).less(c, hi.game()))
      c=h.card(i);
  }
  }
  return c;
}

/**********************************************************************
 *
 **    Announcement make_reply(HeuristicInterface const& hi ,const Game& g)
 *
 **    Parameters:
 *
 **    Result: Announcment::Reply if wanted
 *
 **    Version: 0.6.3
 *
 **    Description:
 *
 **********************************************************************/
Announcement Heuristics::make_reply(HeuristicInterface const& hi,const Game& g)
{
  DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::make_reply");
  if( g.announcement_of_team( opposite( hi.team() ) ).announcement != ANNOUNCEMENT::NOANNOUNCEMENT )
  {
  	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);

    if( value >=   (int)hi.value(Aiconfig::ANNOUNCELIMITREPLY) )
  	 DEBUG_RETURNING( ANNOUNCEMENT::REPLY,
		   INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		   "Heuristics::make_reply" );
  }
  DEBUG_RETURNING( ANNOUNCEMENT::NOANNOUNCEMENT,
		   INFO_HEURISTICS && INFO_OTHER_FUNCTION,
		   "Heuristics::make_reply" );
  
} 
