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

#include "../party/party.h"
#include "../party/rule.h"
#include "../misc/setting.h"


unsigned const AITYPE::NUMBER = (AITYPE::AITYPE_FIRST
				 - AITYPE::AITYPE_LAST + 1);

unsigned const Aiconfig::HEURISTIC_NUMBER = (Aiconfig::HEURISTIC_LAST
					- Aiconfig::HEURISTIC_FIRST + 1);
unsigned const Aiconfig::BOOL_NUMBER = (Aiconfig::BOOL_LAST
					- Aiconfig::BOOL_FIRST + 1);
unsigned const Aiconfig::UNSIGNED_NUMBER = (Aiconfig::UNSIGNED_LAST
					    - Aiconfig::UNSIGNED_FIRST + 1);
unsigned const Aiconfig::CARD_NUMBER = (Aiconfig::CARD_LAST
					- Aiconfig::CARD_FIRST + 1);

/**
 **
 ** -> return
 **
 ** @param	h	the heuristic type
 **
 ** @return	whether 'h' is a general heuristic
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
Aiconfig::is_general(Aiconfig::Heuristic const h)
{
  return (!Aiconfig::is_solo(h)
	  && (h != Aiconfig::NO_HEURISTIC)
	  && (h != Aiconfig::BUG_REPORT)
	  && (h != Aiconfig::ONLY_VALID_CARD)
	  && (h != Aiconfig::CHOOSE_BEST_CARD));
} // static bool Aiconfig::is_general(Aiconfig::Heuristic const h)

/**
 **
 ** -> return
 **
 ** @param	h	the heuristic type
 **
 ** @return	whether 'h' was made for a solo
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
Aiconfig::is_solo(Aiconfig::Heuristic const h)
{
  return (Aiconfig::is_solo_color(h)
	  || Aiconfig::is_solo_picture(h)
	  || Aiconfig::is_solo_meatless(h));
} // static bool Aiconfig::is_solo(Aiconfig::Heuristic const h)

/**
 **
 ** -> return
 **
 ** @param	h	the heuristic type
 **
 ** @return	whether 'h' was made for a color solo
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
Aiconfig::is_solo_color(Aiconfig::Heuristic const h)
{
  switch (h) {
  case COLOR_CHOOSE_ACE:
  case COLOR_BEST_WINNING:
  case COLOR_JAB_FOR_ACE:
  case COLOR_LOW_HIGH:
    return true;
    break;
  default:
    return false;
    break;
  }; // switch(h)
} // static bool Aiconfig::is_solo_color(Aiconfig::Heuristic const h)

/**
 **
 ** -> return
 **
 ** @param	h	the heuristic type
 **
 ** @return	whether 'h' was made for a picture solo
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
Aiconfig::is_solo_picture(Aiconfig::Heuristic const h)
{
  switch (h) {
  case PICTURE_SECONDBESTTRUMP:
    return true;
    break;
  default:
    return false;
    break;
  }; // switch(h)
} // static bool Aiconfig::is_solo_picture(Aiconfig::Heuristic const h)

/**
 **
 ** -> return
 **
 ** @param	h	the heuristic type
 **
 ** @return	whether 'h' was made for a meatless solo
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
Aiconfig::is_solo_meatless(Aiconfig::Heuristic const h)
{
  switch (h) {
  case MEATLESS_PLAYHIGHESTCOLOR:
    return true;
    break;
  default:
    return false;
    break;
  }; // switch(h)
} // static bool Aiconfig::is_solo_meatless(Aiconfig::Heuristic const h)


/**
 **
 ** constructor
 **
 ** @param	-
 **
 ** @result	-
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
Aiconfig::Aiconfig() :
aitype_p(::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME)),
future_limit_p(::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME)),
  heuristic_p(HEURISTIC_NUMBER),
  bool_p(BOOL_NUMBER),
  unsigned_p(UNSIGNED_NUMBER),
card_p(CARD_NUMBER)
{
  this->reset_to_hardcoded();

  return ;
} // Aiconfig::Aiconfig()

/**
 **
 ** Konstruktor
 **
 ** @param	istr	stream with the infos
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
Aiconfig::Aiconfig(istream& istr)
{
  this->load(istr);

  return ;
} // Aiconfig::Aiconfig(istream& istr)

/**********************************************************************
 *
 ** Aiconfig::Aiconfig(Aiconfig const& aiconfig)
 *
 ** Parameters:  aiconfig        - aiconfig to set equal
 *
 ** Result:      -
 *
 ** Version:     0.4.2
 *
 ** Description: constructor
 *
 **********************************************************************/
Aiconfig::Aiconfig(Aiconfig const& aiconfig) :
aitype_p(aiconfig.aitype_p),
future_limit_p(aiconfig.future_limit_p),
  heuristic_p(aiconfig.heuristic_p),
  bool_p(aiconfig.bool_p),
  unsigned_p(aiconfig.unsigned_p),
card_p(aiconfig.card_p)
{
  return ;
} // Aiconfig::Aiconfig(Aiconfig const& aiconfig) const

/**********************************************************************
 *
 ** Aiconfig& Aiconfig::operator=(Aiconfig const& aiconfig)
 *
 ** Parameters:  aiconfig        - aiconfig to set equal
 *
 ** Result:      new aiconfig
 *
 ** Version:     0.4.2
 *
 ** Description: sets the aiconfig '*this' equal 'aiconfig'
 *
 **********************************************************************/
Aiconfig&
Aiconfig::operator=(Aiconfig const& aiconfig)
{
  if (this == &aiconfig)
    return *this;

  for (unsigned t = 0; t < ::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME);
       ++t) {
    this->set_aitype(t, aiconfig.aitype(t));
    this->set_future_limit(t, aiconfig.future_limit(t));
  }
  for (unsigned i = HEURISTIC_FIRST; i <= HEURISTIC_LAST; i++)
    this->set(Heuristic(i), aiconfig.value(Heuristic(i)));
  for (unsigned i = BOOL_FIRST; i <= BOOL_LAST; i++)
    this->set(TypeBool(i), aiconfig.value(TypeBool(i)));
  for (unsigned i = UNSIGNED_FIRST; i <= UNSIGNED_LAST; i++)
    this->set(TypeUnsigned(i), aiconfig.value(TypeUnsigned(i)));
  for (unsigned i = CARD_FIRST; i <= CARD_LAST; i++)
    this->set(TypeCard(i), aiconfig.value(TypeCard(i)));

  return *this;
} // Aiconfig& Aiconfig::operator=(Aiconfig const& aiconfig) const

/**********************************************************************
 *
 ** Aiconfig::~Aiconfig()
 *
 ** Parameters:  -
 *
 ** Result:      -
 *
 ** Version:     0.4.2
 *
 ** Description: destructor - nothing to do
 *
 **********************************************************************/
Aiconfig::~Aiconfig()
{
  return ;
} // Aiconfig::~Aiconfig() const

/**
 **
 ** resets the aiconfig to the hardcoded
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
void
Aiconfig::reset_to_hardcoded()
{
  this->set(TRUSTING,           	true);
  this->set(FAIRPLAYHANDS,      	true);
  this->set(FAIRPLAYTEAMS,		true);

  this->set(CHOOSE_ACE,			true);     
  this->set(CHOOSE_FOR_COLOR_TRICK,	true);
  this->set(SERVE_COLOR_TRICK,		true);
  this->set(SERVE_TRUMP_TRICK,		true);
  this->set(CHOOSE_PFUND,		true);
  this->set(CHOOSE_PFUND_POVERTY,	true);
  this->set(JAB_FOR_ACE,		true);
  this->set(CREATE_FEHL,		true);
  this->set(BEST_WINNING,		true);
  this->set(LOW_HIGH,			true);
  this->set(PLAY_FOR_TEAM,		true);
  this->set(JAB_FOX,			true);
  this->set(DRAW_TRUMP,			true);


  this->set(MEATLESS_PLAYHIGHESTCOLOR,	true);
  this->set(PICTURE_SECONDBESTTRUMP,	true);

  this->set(COLOR_CHOOSE_ACE,		true);
  this->set(COLOR_BEST_WINNING,		true);
  this->set(COLOR_JAB_FOR_ACE,		true);
  this->set(COLOR_LOW_HIGH,		true);
  this->set(FEHLCREATIONONFIRSTCARD,	true);

  this->set(REMEMBERTRICKS,     ::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME));
  this->set(LIMITQUEEN,         10);
  this->set(LIMITDOLLE,         19);

  this->set(LASTFEHLCREATION,    4);
  this->set(LASTHEURISTICTRICK,  9);

  this->set(ANNOUNCELIMIT,      10);
  this->set(ANNOUNCELIMITDEC,    1);
  this->set(ANNOUNCECONFIG,      1);

  this->set(ANNOUNCELIMITREPLY,       8);
  this->set(ANNOUNCECONFIGREPLY,      1);


  this->set(TAKEPOVERTY,        13);

  this->set(SINGLESOLO,         18);
  this->set(DOUBLESOLO,         50);
  this->set(TRIPLESOLO,         100);
  this->set(COLORSOLO,          28);
  this->set(MEATLESS,           26);

  this->set(FUTURE_LIMIT,       10000);

  this->set(LIMITTHROWING,      Card(Card::DIAMOND,Card::QUEEN));
  this->set(LIMITHIGH,          Card(Card::HEART,Card::QUEEN));

  this->set(TRUMPLIMIT_SOLOCOLOR,     Card(Card::HEART,Card::QUEEN));
  this->set(TRUMPLIMIT_SOLOJACK,      Card(Card::DIAMOND,Card::JACK));
  this->set(TRUMPLIMIT_SOLOQUEEN,     Card(Card::DIAMOND,Card::QUEEN));
  this->set(TRUMPLIMIT_SOLOKING,      Card(Card::DIAMOND,Card::KING));
  this->set(TRUMPLIMIT_SOLOJACKKING,  Card(Card::CLUB,Card::JACK));
  this->set(TRUMPLIMIT_SOLOJACKQUEEN, Card(Card::CLUB,Card::JACK));
  this->set(TRUMPLIMIT_SOLOQUEENKING, Card(Card::CLUB,Card::QUEEN));
  this->set(TRUMPLIMIT_SOLOKOEHLER,   Card(Card::CLUB,Card::QUEEN));
  this->set(TRUMPLIMIT_MEATLESS,      Card(Card::DIAMOND,Card::TEN));
  this->set(TRUMPLIMIT_NORMAL,        Card(Card::HEART,Card::QUEEN));

  this->set(LOWEST_TRUMPLIMIT_SOLOCOLOR,     Card(Card::HEART,Card::JACK));
  this->set(LOWEST_TRUMPLIMIT_SOLOJACK,      Card(Card::HEART,Card::JACK));
  this->set(LOWEST_TRUMPLIMIT_SOLOQUEEN,     Card(Card::HEART,Card::QUEEN));
  this->set(LOWEST_TRUMPLIMIT_SOLOKING,      Card(Card::HEART,Card::KING));
  this->set(LOWEST_TRUMPLIMIT_SOLOJACKKING,  Card(Card::SPADE,Card::JACK));
  this->set(LOWEST_TRUMPLIMIT_SOLOJACKQUEEN, Card(Card::SPADE,Card::JACK));
  this->set(LOWEST_TRUMPLIMIT_SOLOQUEENKING, Card(Card::SPADE,Card::QUEEN));
  this->set(LOWEST_TRUMPLIMIT_SOLOKOEHLER,   Card(Card::SPADE,Card::QUEEN));
  this->set(LOWEST_TRUMPLIMIT_MEATLESS,      Card(Card::DIAMOND,Card::QUEEN));
  this->set(LOWEST_TRUMPLIMIT_NORMAL,        Card(Card::DIAMOND,Card::JACK));

  DEBUG_ASSERTION((::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME)
		   == 12),
		  "Aiconfig::reset_to_hardcoded():\n"
		  "  maximal number of tricks is not 12 but "
		  << ::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME));

  this->set_aitype      ( 0, AITYPE::VIRTUAL_GAMES);
  this->set_future_limit( 0, 10000);
  this->set_aitype      ( 1, this->aitype( 0));
  this->set_future_limit( 1, this->future_limit( 0));
  this->set_aitype      ( 2, this->aitype( 1));
  this->set_future_limit( 2, this->future_limit( 1));
  this->set_aitype      ( 3, this->aitype( 2));
  this->set_future_limit( 3, this->future_limit( 2));
  //this->set_aitype      ( 4, AITYPE::MONTE_CARLO);
  //this->set_future_limit( 4, 2500);
  this->set_aitype      ( 4, this->aitype( 3));
  this->set_future_limit( 4, this->future_limit( 3));
  this->set_aitype      ( 5, this->aitype( 4));
  this->set_future_limit( 5, this->future_limit( 4));
  this->set_aitype      ( 6, this->aitype( 4));
  this->set_future_limit( 6, this->future_limit( 5));
  this->set_aitype      ( 7, this->aitype( 6));
  this->set_future_limit( 7, this->future_limit( 6));
  this->set_aitype      ( 8, AITYPE::GAMETREE);
  this->set_future_limit( 8, 10000);
  this->set_aitype      ( 9, this->aitype( 8));
  this->set_future_limit( 9, this->future_limit( 8));
  this->set_aitype      (10, this->aitype( 9));
  this->set_future_limit(10, this->future_limit(10));
  this->set_aitype      (11, this->aitype(10));
  this->set_future_limit(11, this->future_limit(11));

  return ;
} // void Aiconfig::reset_to_hardcoded()

/**
 **
 ** -> result
 **
 ** @param	trickno		trick number
 **
 ** @return	the aitype for trick 'trickno'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
AiType const&
Aiconfig::aitype(unsigned const trickno) const
{
  return this->aitype_p[trickno];
} // AiType const& Aiconfig::aitye(unsigned const trickno) const;

/**
 **
 ** sets the aitype for trick 'trickno'
 **
 ** @param	trickno		trick number
 ** @param	aitype		new aitype
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
void
Aiconfig::set_aitype(unsigned const trickno, AiType const& aitype)
{
  this->aitype_p[trickno] = aitype;

  return ;
} // void Aiconfig::set_aitype(unsigned const trickno, AiType const& aitype) const

/**
 **
 ** sets the aitype for all tricks
 **
 ** @param	aitype		new aitype
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
void
Aiconfig::set_aitype_for_all_tricks(AiType const& aitype)
{
  for (unsigned i = 0; i < this->aitype_p.size(); ++i)
    this->set_aitype(i, aitype);

  return ;
} // void Aiconfig::set_aitype_for_all_tricks(AiType const& aitype) const

/**
 **
 ** -> result
 **
 ** @param	trickno		trick number
 **
 ** @return	the future limit for trick 'trickno'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
unsigned const 
Aiconfig::future_limit(unsigned const trickno) const
{
  return this->future_limit_p[trickno];
} // unsigned const Aiconfig::aitye(unsigned const trickno) const;

/**
 **
 ** sets the future limit for trick 'trickno'
 **
 ** @param	trickno		trick number
 ** @param	future_limit	new future limit
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
void
Aiconfig::set_future_limit(unsigned const trickno, unsigned const future_limit)
{
  this->future_limit_p[trickno] = future_limit;

  return ;
} // void Aiconfig::set_future_limit(unsigned const trickno, unsigned const future_limit) const

/**
 **
 ** sets the future limit for all tricks
 **
 ** @param	future_limit		new future limit
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
void
Aiconfig::set_future_limit_for_all_tricks(unsigned const future_limit)
{
  for (unsigned i = 0; i < this->future_limit_p.size(); ++i)
    this->set_future_limit(i, future_limit);

  return ;
} // void Aiconfig::set_future_limit_for_all_tricks(unsigned const future_limit) const

/**
 **
 ** -> result
 **
 ** @param	type	the heuristic type
 **
 ** @return	the value of the aiconfig 'type'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
Aiconfig::value(Heuristic const type) const
{
  return this->heuristic_p[type - HEURISTIC_FIRST];
} // bool Aiconfig::value(Heuristic const type) const

/**
 **
 ** -> result
 **
 ** @param	type	the bool type
 **
 ** @return	the value of the aiconfig 'type'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
Aiconfig::value(TypeBool const type) const
{
  return this->bool_p[type - BOOL_FIRST];
} // bool Aiconfig::value(TypeBool) const;

/**
 **
 ** -> result
 **
 ** @param	type	the unsigned type
 **
 ** @return	the value of the aiconfig 'type'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
unsigned
Aiconfig::value(TypeUnsigned const type) const
{
  return this->unsigned_p[type - UNSIGNED_FIRST];
} // unsigned Aiconfig::value(TypeUnsigned) const;

/**
 **
 ** -> result
 **
 ** @param	type	the card type
 **
 ** @return	the value of the aiconfig 'type'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
Card
Aiconfig::value(TypeCard const type) const
{
  return this->card_p[type - CARD_FIRST];
} // Card Aiconfig::value(TypeCard const type) const

/**********************************************************************
 *
 ** unsigned min(TypeUnsigned const& type)
 *
 ** Parameters:  type    - Aiconfigtype
 *
 ** Result:      the minimal value of the aiconfig 'type'
 *
 ** Version:     0.4.2
 *
 ** Description: -> result
 *
 **********************************************************************/
unsigned
Aiconfig::min(TypeUnsigned const& type) const
{
  unsigned value = UINT_MAX;

  switch(type) {
  case REMEMBERTRICKS:
  case LASTFEHLCREATION:
  case LASTHEURISTICTRICK:
    value = 0;
    break;

  case LIMITQUEEN:
  case LIMITDOLLE:
    value = 0;
    break;

  case ANNOUNCELIMIT:
  case ANNOUNCELIMITDEC:
  case ANNOUNCECONFIG:
  case ANNOUNCELIMITREPLY:
  case ANNOUNCECONFIGREPLY:

    value = 0;
    break;

  case TAKEPOVERTY:
    value = 0;
    break;

  case SINGLESOLO:
  case DOUBLESOLO:
  case TRIPLESOLO:
  case COLORSOLO:
  case MEATLESS:
    value = 0;
    break;

  case FUTURE_LIMIT:
    value = 1;
    break;
  } // switch(type)

  return value;
} // unsigned Aiconfig::min(TypeUnsigned const& type) const

/**********************************************************************
 *
 ** unsigned max(TypeUnsigned const& type)
 *
 ** Parameters:  type    - Aiconfigtype
 *
 ** Result:      the maximal value of the aiconfig 'type'
 *
 ** Version:     0.4.2
 *
 ** Description: -> result
 *
 **********************************************************************/
unsigned
Aiconfig::max(TypeUnsigned const& type) const
{
  unsigned value = UINT_MAX;

  switch(type) {
  case REMEMBERTRICKS:
  case LASTFEHLCREATION:
  case LASTHEURISTICTRICK:
    // when changing 'with nines' -> 'without nines' -> 'with nines'
    // it should keep '12'
    //value = ::party.rule()(Rule::NUMBER_OF_TRICKS_IN_GAME);
    value = ::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME);
    break;

  case LIMITQUEEN:
  case LIMITDOLLE:
    value = 1000;
    break;

  case ANNOUNCELIMIT:
  case ANNOUNCELIMITDEC:
  case ANNOUNCECONFIG:
  case ANNOUNCELIMITREPLY:
  case ANNOUNCECONFIGREPLY:

    value = 1000;
    break;

  case TAKEPOVERTY:
    value = 1000;
    break;

  case SINGLESOLO:
  case DOUBLESOLO:
  case TRIPLESOLO:
  case COLORSOLO:
  case MEATLESS:
    value = 1000;
    break;

  case FUTURE_LIMIT:
    value = static_cast<unsigned const>(1e9);
    break;
  } // switch(type)

  return value;
} // unsigned Aiconfig::max(TypeUnsigned const& type) const

/**
 **
 ** sets 'type' to 'value'
 **
 ** @param	type	Aiconfigtype
 ** @param	value	new value
 **
 ** @return	'true', if the type is valid, otherwise 'false'
 **
 ** @version	0.6.6
 **
 ** @author	Diether Knof
 **   
 **/
bool
Aiconfig::set(string const& type, string const& value)
{
  unsigned i;

  for (i = Aiconfig::HEURISTIC_FIRST; i <= Aiconfig::HEURISTIC_LAST; i++) {
    if (type == name(Aiconfig::Heuristic(i))) {
      this->set(Aiconfig::Heuristic(i), value);
      return true;
    } // if (type == name(Aiconfig::Heuristic(i)))
  } // (i \in BOOL)
  for (i = Aiconfig::BOOL_FIRST; i <= Aiconfig::BOOL_LAST; i++) {
    if (type == name(Aiconfig::TypeBool(i))) {
      this->set(Aiconfig::TypeBool(i), value);
      return true;
    } // if (type == name(Aiconfig::TypeBool(i)))
  } // (i \in BOOL)
  for (i = Aiconfig::UNSIGNED_FIRST; i <= Aiconfig::UNSIGNED_LAST; i++) {
    if (type == name(Aiconfig::TypeUnsigned(i))) {
      this->set(Aiconfig::TypeUnsigned(i), value);
      return true;
    } // if (type == name(Aiconfig::TypeUnsigned(i)))
  } // (i \in UNSIGNED)
  for (i = Aiconfig::CARD_FIRST; i <= Aiconfig::CARD_LAST; i++) {
    if (type == name(Aiconfig::TypeCard(i))) {
      this->set(Aiconfig::TypeCard(i), value);
      return true;
    } // if (type == name(Aiconfig::TypeCard(i)))
  } // (i \in CARD)

  return false;
} // bool Aiconfig::set(string const& type, string const& value)

/**
 **
 ** sets 'type' to 'value'
 **
 ** @param	type	Aiconfigtype
 ** @param	value	new value
 **
 ** @return	-
 **
 ** @version	0.6.6
 **
 ** @author	Diether Knof
 **   
 **/
void
Aiconfig::set(Heuristic const type, string const& value)
{
  if ((value != "true")
      && (value != "false")
      && (value != "yes")
      && (value != "no")
      && (value != "0")
      && (value != "1")) {
    cerr << "Aiconfig::set(TypeBool, value):\n"
					     << "illegal value '" << value << "' for '" << type << "', "
					       << "must be a boolean ('true' or 'false' or 'yes' or 'no' or '1' or '0'. "
					       << "Taking 'false'."
					       << endl;
  }
  this->set(type, (((value == "false")
		    || (value == "no")
		    || (value == "0"))
		   ? false :	true));

  return ;
} // void Aiconfig::set(Heuristic type, string const& value)

/**
 **
 ** sets 'type' to 'value'
 **
 ** @param	type	Aiconfigtype
 ** @param	value	new value
 **
 ** @return	-
 **
 ** @version	0.6.6
 **
 ** @author	Diether Knof
 **   
 **/
void
Aiconfig::set(TypeBool const type, string const& value)
{
  if ((value != "true")
      && (value != "false")
      && (value != "yes")
      && (value != "no")
      && (value != "0")
      && (value != "1")) {
    cerr << "Aiconfig::set(TypeBool, value):\n"
					     << "illegal value '" << value << "' for '" << type << "', "
					       << "must be a boolean ('true' or 'false' or 'yes' or 'no' or '1' or '0'. "
					       << "Taking 'false'."
					       << endl;
  }
  this->set(type, (((value == "false")
		    || (value == "no")
		    || (value == "0"))
		   ? false :	true));

  return ;
} // void Aiconfig::set(const TypeBool type, string const& value)

/**
 **
 ** sets 'type' to 'value'
 **
 ** @param	type	Aiconfigtype
 ** @param	value	new value
 **
 ** @return	-
 **
 ** @version	0.6.6
 **
 ** @author	Diether Knof
 **   
 **/
void
Aiconfig::set(TypeUnsigned const type, string const& value)
{
  char* end_ptr;
  unsigned number = strtoul(value.c_str(), &end_ptr, 0);
  if (*end_ptr != '\0') {
    cerr << "Aiconfig::set(TypeUnsigned, value):\n"
						 << "illegal value '" << value << "' for '" << type << "', "
						   << "must be a digit. "
						   << "Taking " << number << "."
						   << endl;
  }

  this->set(type, number);

  return ;
} // void Aiconfig::set(const TypeUnsigned type, string const& value)

/**
 **
 ** sets 'type' to 'value'
 **
 ** @param	type	Aiconfigtype
 ** @param	value	new value
 **
 ** @return	-
 **
 ** @version	0.6.6
 **
 ** @author	Diether Knof
 **   
 **/
void
Aiconfig::set(TypeCard const type, string const& value)
{
  this->set(type, Card(value));

  return ;
} // void Aiconfig::set(const TypeCard type, string const& value)

/**
 **
 ** sets the aiconfig 'type' to the value 'value'
 **
 ** @param	type	heuristic type
 ** @param	value	new value
 **
 ** @result	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
void
Aiconfig::set(Heuristic const type, bool const value)
{
  this->heuristic_p[type - HEURISTIC_FIRST] = value;

  return ;
} // void Aiconfig::set(Heuristic, bool);

/**
 **
 ** sets the aiconfig 'type' to the value 'value'
 **
 ** @param	type	heuristic type
 ** @param	value	new value
 **
 ** @result	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
void
Aiconfig::set(TypeBool const type, bool const value)
{
  this->bool_p[type - BOOL_FIRST] = value;

  return ;
} // void Aiconfig::set(TypeBool, bool);

/**
 **
 ** sets the aiconfig 'type' to the value 'value'
 **
 ** @param	type	heuristic type
 ** @param	value	new value
 **
 ** @result	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
void
Aiconfig::set(TypeUnsigned const type, unsigned const value)
{
  this->unsigned_p[type - UNSIGNED_FIRST] = value;

  return ;
} // void Aiconfig::set(TypeUnsigned, unsigned);

/**
 **
 ** sets the aiconfig 'type' to the value 'value'
 **
 ** @param	type	heuristic type
 ** @param	value	new value
 **
 ** @result	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
void
Aiconfig::set(TypeCard const type, Card const value)
{
  this->card_p[type - CARD_FIRST] = value;

  return ;
} // void Aiconfig::set(TypeCard, card);

/**
 ** writes the aiconfig in the output stream
 **
 ** @param	ostr	output stream
 **
 ** @result	output stream
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 ** 
 ** @version	0.4.2
 **
 **/
ostream&
Aiconfig::write(ostream& ostr) const
{
  for (unsigned i = 0; i < this->aitype_p.size(); ++i) {
    ostr << "type = " << i << ": " << this->aitype(i) << '\n';
    ostr << "future limit = " << i << ": " << this->future_limit(i) << '\n';
  }
  ostr << TRUSTING << " = "
    << this->value(TRUSTING) << '\n'
    << FAIRPLAYHANDS << " = "
    << this->value(FAIRPLAYHANDS) << '\n'
    << FAIRPLAYTEAMS << " = "
    << this->value(FAIRPLAYTEAMS) << '\n'
    << '\n'
    << CHOOSE_ACE << " = "
    << this->value(CHOOSE_ACE) << '\n' 
    << CHOOSE_FOR_COLOR_TRICK  << " = "
    << this->value(CHOOSE_FOR_COLOR_TRICK) << '\n'
    << SERVE_COLOR_TRICK  << " = "
    << this->value(SERVE_COLOR_TRICK) << '\n'
    << SERVE_TRUMP_TRICK  << " = "
    << this->value(SERVE_COLOR_TRICK) << '\n'
    << CHOOSE_PFUND            << " = "
    << this->value(CHOOSE_PFUND) << '\n'
    << CHOOSE_PFUND_POVERTY            << " = "
    << this->value(CHOOSE_PFUND_POVERTY) << '\n'
    << JAB_FOR_ACE             << " = "
    << this->value(JAB_FOR_ACE ) << '\n'
    << CREATE_FEHL             << " = "
    << this->value(CREATE_FEHL ) << '\n'
    << BEST_WINNING           << " = "
    << this->value(BEST_WINNING) << '\n'
    << LOW_HIGH                << " = "
    << this->value(LOW_HIGH ) << '\n'
    << PLAY_FOR_TEAM           << " = "
    << this->value(PLAY_FOR_TEAM) << '\n'
    << JAB_FOX                << " = "
    << this->value(JAB_FOX) << '\n'
    << DRAW_TRUMP                << " = "
    << this->value(DRAW_TRUMP) << '\n'
    << MEATLESS_PLAYHIGHESTCOLOR      << " = "
    << this->value(MEATLESS_PLAYHIGHESTCOLOR) << '\n'
    << PICTURE_SECONDBESTTRUMP<< " = "
    << this->value(PICTURE_SECONDBESTTRUMP) << '\n'
    << COLOR_CHOOSE_ACE<< " = "
    << this->value(COLOR_CHOOSE_ACE)<< '\n'
    << COLOR_BEST_WINNING<< " = "
    << this->value(COLOR_BEST_WINNING) << '\n'
    << COLOR_JAB_FOR_ACE<< " = "
    << this->value(COLOR_JAB_FOR_ACE) << '\n'
    << COLOR_LOW_HIGH  << " = "
    << this->value(COLOR_LOW_HIGH) << '\n'
    << '\n'
    << FEHLCREATIONONFIRSTCARD  << " = "
    << this->value(FEHLCREATIONONFIRSTCARD) << '\n'
    << '\n'
    << REMEMBERTRICKS << " = "
    << this->value(REMEMBERTRICKS) << '\n'
    << '\n'
    << LIMITQUEEN << " = "
    << this->value(LIMITQUEEN) << '\n'
    << LIMITDOLLE << " = "
    << this->value(LIMITDOLLE) << '\n'
    << '\n'
    << LASTFEHLCREATION << " = "
    << this->value(LASTFEHLCREATION) << '\n'
    << '\n'
    << LASTHEURISTICTRICK << " = "
    << this->value(LASTHEURISTICTRICK) << '\n'
    << '\n'
    << ANNOUNCELIMIT << " = "
    << this->value(ANNOUNCELIMIT) << '\n'
    << ANNOUNCELIMITDEC << " = "
    << this->value(ANNOUNCELIMITDEC) << '\n'
    << '\n'
    << ANNOUNCECONFIG << " = "
    << this->value(ANNOUNCECONFIG) << '\n'
    << '\n'
    << ANNOUNCELIMITREPLY << " = "
    << this->value(ANNOUNCELIMITREPLY) << '\n'
    << ANNOUNCECONFIGREPLY << " = "
    << this->value(ANNOUNCECONFIGREPLY) << '\n'
    << '\n'
    << TAKEPOVERTY << " = "
    << this->value(TAKEPOVERTY) << '\n'
    << '\n'
    << SINGLESOLO << " = "
    << this->value(SINGLESOLO) << '\n'
    << DOUBLESOLO << " = "
    << this->value(DOUBLESOLO) << '\n'
    << TRIPLESOLO << " = "
    << this->value(TRIPLESOLO) << '\n'
    << COLORSOLO << " = "
    << this->value(COLORSOLO) << '\n'
    << MEATLESS << " = "
    << this->value(MEATLESS) << '\n'
    << '\n'
    << FUTURE_LIMIT << " = "
    << this->value(FUTURE_LIMIT) << '\n'
    << '\n'
    << LIMITTHROWING << " = "
    << this->value(LIMITTHROWING) << '\n'
    << '\n'
    << LIMITHIGH << " = "
    << this->value(LIMITHIGH) << '\n'
    << '\n'
    << TRUMPLIMIT_SOLOCOLOR << " = "
    << this->value(TRUMPLIMIT_SOLOCOLOR) << '\n'
    << '\n'
    << TRUMPLIMIT_SOLOJACK << " = "
    << this->value(TRUMPLIMIT_SOLOJACK) << '\n'
    << '\n'
    << TRUMPLIMIT_SOLOQUEEN << " = "
    << this->value(TRUMPLIMIT_SOLOQUEEN) << '\n'
    << '\n'
    << TRUMPLIMIT_SOLOKING << " = "
    << this->value(TRUMPLIMIT_SOLOKING) << '\n'
    << '\n'
    << TRUMPLIMIT_SOLOJACKKING << " = "
    << this->value(TRUMPLIMIT_SOLOJACKKING) << '\n'
    << '\n'
    << TRUMPLIMIT_SOLOJACKQUEEN << " = "
    << this->value(TRUMPLIMIT_SOLOJACKQUEEN) << '\n'
    << '\n'
    << TRUMPLIMIT_SOLOQUEENKING << " = "
    << this->value(TRUMPLIMIT_SOLOQUEENKING) << '\n'
    << '\n'
    << TRUMPLIMIT_SOLOKOEHLER << " = "
    << this->value(TRUMPLIMIT_SOLOKOEHLER) << '\n'
    << '\n'
    << TRUMPLIMIT_MEATLESS << " = "
    << this->value(TRUMPLIMIT_MEATLESS) << '\n'
    << '\n'
    << TRUMPLIMIT_NORMAL << " = "
    << this->value(TRUMPLIMIT_NORMAL) << '\n'
    << '\n'
    << LOWEST_TRUMPLIMIT_SOLOCOLOR << " = "
    << this->value(LOWEST_TRUMPLIMIT_SOLOCOLOR) << '\n'
    << '\n'
    << LOWEST_TRUMPLIMIT_SOLOJACK << " = "
    << this->value(LOWEST_TRUMPLIMIT_SOLOJACK) << '\n'
    << '\n'
    << LOWEST_TRUMPLIMIT_SOLOQUEEN << " = "
    << this->value(LOWEST_TRUMPLIMIT_SOLOQUEEN) << '\n'
    << '\n'
    << LOWEST_TRUMPLIMIT_SOLOKING << " = "
    << this->value(LOWEST_TRUMPLIMIT_SOLOKING) << '\n'
    << '\n'
    << LOWEST_TRUMPLIMIT_SOLOJACKKING << " = "
    << this->value(LOWEST_TRUMPLIMIT_SOLOJACKKING) << '\n'
    << '\n'
    << LOWEST_TRUMPLIMIT_SOLOJACKQUEEN << " = "
    << this->value(LOWEST_TRUMPLIMIT_SOLOJACKQUEEN) << '\n'
    << '\n'
    << LOWEST_TRUMPLIMIT_SOLOQUEENKING << " = "
    << this->value(LOWEST_TRUMPLIMIT_SOLOQUEENKING) << '\n'
    << '\n'
    << LOWEST_TRUMPLIMIT_SOLOKOEHLER << " = "
    << this->value(LOWEST_TRUMPLIMIT_SOLOKOEHLER) << '\n'
    << '\n'
    << LOWEST_TRUMPLIMIT_MEATLESS << " = "
    << this->value(LOWEST_TRUMPLIMIT_MEATLESS) << '\n'
    << '\n'
    << LOWEST_TRUMPLIMIT_NORMAL << " = "
    << this->value(LOWEST_TRUMPLIMIT_NORMAL) << '\n'
    ;

  return ostr;
} // ostream& Aiconfig::write(ostream& ostr) const

/**
 **
 ** loads the infos from the file
 **
 ** @param	filename	file to load the aiconfig from
 **
 ** @return	whether the loading was successful
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
Aiconfig::load(string const& filename)
{
  {
    ifstream istr(filename.c_str());
    if (istr.good())
      return this->load(istr);
  }
  {
    ifstream istr((::setting(Setting::PRIVATE_DATA_DIRECTORY)
		   + "/" + ::setting(Setting::AI_DIRECTORY)
		   + "/" + filename).c_str());
    if (istr.good())
      return this->load(istr);
  }
  {
    ifstream istr((::setting(Setting::PUBLIC_DATA_DIRECTORY)
		   + "/" + ::setting(Setting::AI_DIRECTORY)
		   + "/" + filename).c_str());
    if (istr.good())
      return this->load(istr);
  }

  return false;
} // bool Aiconfig::load(string const& filename)

/**
 **
 ** loads the infos from the stream
 **
 ** @param	istr	stream with the infos
 **
 ** @return	whether the loading was successful
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
bool
Aiconfig::load(istream& istr)
{
#ifndef POSTPHONED
  // if the following is an empty line, ignore it
  if ((istr.peek() == '\n')
      || (istr.peek() == '\r'))
    return true;
#endif

  unsigned depth = 0;

  // load the configuration
  while (istr.good()) {
    Config config;
    istr >> config;
    if (istr.fail())
      break;

    // finished with the config file
    if ((config.name == "") && (config.value == ""))
      break;

    if (config.separator) {
      // a setting
      if (config.name == "type") {
#ifndef OUTDATED
	// 0.6.7   2004-11-21
	{
	  int t;
	  for (t = AITYPE::AITYPE_FIRST; t <= AITYPE::AITYPE_LAST; t++) {
	    if (config.value == ::name(AiType(t))) {
	      this->set_aitype_for_all_tricks(AiType(t));
	      break;
	    }
	  }
	  if (t <= AITYPE::AITYPE_LAST)
	    continue;
	}
#endif
	try {
	  stringstream istr(config.value);

	  // tricknumber
	  unsigned trickno;
	  istr >> trickno;
	  if (!istr.good()) {
	    throw config.value;
	  }

	  // separator
	  if (istr.peek() != ':')
	    throw config.value;
	  istr.get();

	  while (std::isspace(istr.peek())
		 && istr.good())
	    istr.get();

	  if (!istr.good())
	    throw config.value;

	  // aitype
	  string aitype;
	  std::getline(istr, aitype);

	  {
	    int t;
	    for (t = AITYPE::AITYPE_FIRST; t <= AITYPE::AITYPE_LAST; t++)
	      if (aitype == ::name(AiType(t))) {
		this->set_aitype(trickno, AiType(t));
		break;
	      }
	    if (t > AITYPE::AITYPE_LAST) {
	      throw config.value;
	    }
	  }

	} // try
	catch (string value) {
	  cerr << "aiconfig: "
	    << "illegal aitype '" << value << "'."
	    << endl;
	}
      } else if (config.name == "future limit") {
	try {
	  stringstream istr(config.value);

	  // tricknumber
	  unsigned trickno;
	  istr >> trickno;
	  if (!istr.good()) {
	    throw config.value;
	  }

	  // separator
	  if (istr.peek() != ':') {
	    throw config.value;
	  }
	  istr.get();

	  while (std::isspace(istr.peek())
		 && istr.good())
	    istr.get();

	  if (!istr.good()) {
	    throw config.value;
	  }

	  // future limit
	  unsigned future_limit;
	  istr >> future_limit;
	  if (istr.fail()) {
	    throw config.value;
	  }

	  this->set_future_limit(trickno, future_limit);
	} // try
	catch (string value) {
	  cerr << "aiconfig: "
	    << "illegal future limit '" << value << "'."
	    << endl;
	}
      } else {
	if (!this->set(config.name, config.value)) {
	  cerr << "aiconfig: "
	    << "illegal config '" << config.name << "'."
	    << endl;
	}
      } // if (config.name == "type")
    } else { // if (config.separator)
      // a setting
      // if the value is in parentencies, remove both
      if(config.name == "!end") {
	// ignore the rest of the file
	break;
      } else if(config.name == "!stdout") {
	// output of the data to 'stdout'
	cout << config.value << endl;
      } else if(config.name == "!stderr") {
	// output of the data to 'stderr'
	cerr << config.value << endl;
      } else if(config.name == "{") {
	depth += 1;
      } else if(config.name == "}") {
	if (depth == 0) {
	  cerr << "Aiconfig: found a '}' without a '{' before.\n"
	    << "Finish reading the the file."
	    << endl;
	  break;
	} // if (depth == 0)
	depth -= 1;
	if (depth == 0)
	  break;
      } else if(config.name == "") {
	cerr << "Aiconfig: "
	  << "Ignoring line \'" << config.value << "\'.\n";
      } else {
	cerr << "Aiconfig: "
	  << "type '" << config.name << "' unknown.\n"
	  << "Ignoring it.\n";
      } // if (config.name == .)
    } // config.separator
  } // while (istr.good())

  return istr.good();
} // bool Aiconfig::load(istream& istr)

/**
 **
 ** save the infos in the file
 **
 ** @param	filename	file to save the aiconfig
 **
 ** @return	whether the saving was successful
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
bool
Aiconfig::save(string const& filename) const
{
  ofstream ostr(filename.c_str());
  if (ostr.fail())
    return false;

  ostr << *this;

  return ostr.good();
} // bool Aiconfig::save(string const& filename) const

/**
 **
 ** -> result
 **
 ** @param	type	heuristic type
 **
 ** @return	the name of 'type'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
string
name(Aiconfig::Heuristic const type)
{
  string name;

  switch(type) {
  case Aiconfig::NO_HEURISTIC:
    name = "no heuristic";
    break;
  case Aiconfig::BUG_REPORT:
    name = "Heuristics::bug report";
    break;
  case Aiconfig::ONLY_VALID_CARD:
    name = "Heuristics::only valid card";
    break;
  case Aiconfig::CHOOSE_ACE:
    name = "Heuristics::choose_ace";
    break;              
  case Aiconfig::CHOOSE_FOR_COLOR_TRICK:
    name = "Heuristics::choose_for_color_trick";
    break;  
  case Aiconfig::SERVE_COLOR_TRICK:
    name = "Heuristics::serve_color_trick";
    break;  
  case Aiconfig::SERVE_TRUMP_TRICK:
    name = "Heuristics::serve_trump_trick";
    break;  
  case Aiconfig::CHOOSE_PFUND:
    name = "Heuristics::choose_pfund";
    break;           
  case Aiconfig::CHOOSE_PFUND_POVERTY:
    name = "Heuristics::choose_pfund_poverty";
    break;           
  case Aiconfig::JAB_FOR_ACE:
    name = "Heuristics::jab_for_ace";
    break;             
  case Aiconfig::CREATE_FEHL:
    name = "Heuristics::create_fehl";
    break;             
  case Aiconfig::BEST_WINNING:
    name = "Heuristics::best_winning_card";
    break;            
  case Aiconfig::LOW_HIGH:
    name = "Heuristics::play_low_high";
    break;                     
  case Aiconfig::PLAY_FOR_TEAM:
    name = "Heuristics::play_for_team";
    break;           
  case Aiconfig::JAB_FOX:
    name = "Heuristics::jab_fox";
    break;                 
  case Aiconfig::DRAW_TRUMP:
    name = "Heuristics::draw_trump";
    break;                 

  case Aiconfig::MEATLESS_PLAYHIGHESTCOLOR:
    name = "Meatless: Heuristics::play_highest_color";
    break;        
  case Aiconfig::PICTURE_SECONDBESTTRUMP:
    name = "picture: Heuristics::second_best_trump";
    break;
  case Aiconfig::COLOR_CHOOSE_ACE:
    name = "color: Heuristics::choose_ace";
    break;
  case Aiconfig::COLOR_BEST_WINNING:
    name = "color: Heuristics::Best_Winning";
    break;
  case Aiconfig::COLOR_JAB_FOR_ACE:
    name = "color: Heuristics::jab_for_ace";
    break;
  case Aiconfig::COLOR_LOW_HIGH:
    name = "color: Heuristics::play_low_high";
    break;
  case Aiconfig::CHOOSE_BEST_CARD:
    name = "choose best card";
    break;
  } // switch(type)

  return name;
} // string name(Aiconfig::Heuristic name type)


/**
 **
 ** -> result
 **
 ** @param	type	bool type
 **
 ** @return	the name of 'type'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
string
name(Aiconfig::TypeBool const type)
{
  string name;

  switch(type) {
  case Aiconfig::TRUSTING:
    name = "trusting";
    break;
  case Aiconfig::FAIRPLAYHANDS:
    name = "fairplay hands";
    break;
  case Aiconfig::FAIRPLAYTEAMS:
    name = "fairplay teams";
    break;
  case Aiconfig::FEHLCREATIONONFIRSTCARD:
    name = "first card fehl creation";
    break;
  } // switch(type)

  return name;
} // string name(Aiconfig::TypeBool name type)

/**
 **
 ** -> result
 **
 ** @param	type	unsigned type
 **
 ** @return	the name of 'type'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
string
name(Aiconfig::TypeUnsigned const type)
{
  string name;

  switch(type) {
  case Aiconfig::REMEMBERTRICKS:
    name = "remember tricks";
    break;
  case Aiconfig::LIMITQUEEN:
    name = "limit queen";
    break;
  case Aiconfig::LIMITDOLLE:
    name = "limit dolle";
    break;
  case Aiconfig::LASTFEHLCREATION:
    name = "last fehlcreation";
    break;
  case Aiconfig::LASTHEURISTICTRICK:
    name = "last trick with heuristics";
    break;
  case Aiconfig::ANNOUNCELIMIT:
    name = "announce limit";
    break;
  case Aiconfig::ANNOUNCELIMITDEC:
    name = "announce limit decrement";
    break;
  case Aiconfig::ANNOUNCECONFIG:
    name = "announce config";
    break;  
  case Aiconfig::ANNOUNCELIMITREPLY:
    name = "announce limit reply";
    break;
  case Aiconfig::ANNOUNCECONFIGREPLY:
    name = "announce config reply";
    break;  

  case Aiconfig::TAKEPOVERTY:
    name = "take poverty";
    break;
  case Aiconfig::SINGLESOLO:
    name = "handvalue single solo";
    break;
  case Aiconfig::DOUBLESOLO:
    name = "handvalue double solo";
    break;
  case Aiconfig::TRIPLESOLO:
    name = "handvalue trible solo";
    break;
  case Aiconfig::COLORSOLO:
    name = "handvalue color solo";
    break;
  case Aiconfig::MEATLESS:
    name = "handvalue meatless";
    break;
  case Aiconfig::FUTURE_LIMIT:
    name = "future calculating limit";
    break;
  } // switch(type)

  return name;
} // string name(Aiconfig::TypeUnsigned const type)

/**
 **
 ** -> result
 **
 ** @param	type	card type
 **
 ** @return	the name of 'type'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
string
name(Aiconfig::TypeCard const type)
{
  string name;

  switch(type) {
  case Aiconfig::LIMITTHROWING:
    name = "limit throwing";
    break;
  case Aiconfig::LIMITHIGH:
    name = "limit high";
    break;
  case Aiconfig::TRUMPLIMIT_SOLOCOLOR:
    name = "trump limit color";
    break;
  case Aiconfig::TRUMPLIMIT_SOLOJACK:
    name = "trump limit jack";
    break;
  case Aiconfig::TRUMPLIMIT_SOLOQUEEN:
    name = "trump limit queen";
    break;
  case Aiconfig::TRUMPLIMIT_SOLOKING:
    name = "trump limit king";
    break;
  case Aiconfig::TRUMPLIMIT_SOLOJACKKING:
    name = "trump limit jack king";
    break;
  case Aiconfig::TRUMPLIMIT_SOLOJACKQUEEN:
    name = "trump limit jack queen";
    break;
  case Aiconfig::TRUMPLIMIT_SOLOQUEENKING:
    name = "trump limit queen king";
    break;
  case Aiconfig::TRUMPLIMIT_SOLOKOEHLER:
    name = "trump limit koehler";
    break;
  case Aiconfig::TRUMPLIMIT_MEATLESS:
    name = "trump limit meatless";
    break;
  case Aiconfig::TRUMPLIMIT_NORMAL:
    name = "trump limit normal";
    break;
  case Aiconfig::LOWEST_TRUMPLIMIT_SOLOCOLOR:
    name = "lowest trump limit color";
    break;
  case Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACK:
    name = "lowest trump limit jack";
    break;
  case Aiconfig::LOWEST_TRUMPLIMIT_SOLOQUEEN:
    name = "lowest trump limit queen";
    break;
  case Aiconfig::LOWEST_TRUMPLIMIT_SOLOKING:
    name = "lowest trump limit king";
    break;
  case Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACKKING:
    name = "lowest trump limit jack king";
    break;
  case Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACKQUEEN:
    name = "lowest trump limit jack queen";
    break;
  case Aiconfig::LOWEST_TRUMPLIMIT_SOLOQUEENKING:
    name = "lowest trump limit queen king";
    break;
  case Aiconfig::LOWEST_TRUMPLIMIT_SOLOKOEHLER:
    name = "lowest trump limit koehler";
    break;
  case Aiconfig::LOWEST_TRUMPLIMIT_MEATLESS:
    name = "lowest trump limit meatless";
    break;
  case Aiconfig::LOWEST_TRUMPLIMIT_NORMAL:
    name = "lowest trump limit normal";
    break;
  } // switch(type)

  return name;
} // string name(Aiconfig::TypeCard const& type)

/**
 **
 ** writes the name of 'type' in 'ostr'
 **
 ** @param	ostr	stream to write in
 ** @param	type	type to write the name of
 **
 ** @return	output stream
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
ostream&
operator<<(ostream& ostr, Aiconfig::Heuristic const type)
{
  ostr << name(type);

  return ostr;
} // ostream& operator<<(ostream& ostr, Aiconfig::Heuristic const type)

/**
 **
 ** writes the name of 'type' in 'ostr'
 **
 ** @param	ostr	stream to write in
 ** @param	type	type to write the name of
 **
 ** @return	output stream
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
ostream&
operator<<(ostream& ostr, Aiconfig::TypeBool const type)
{
  ostr << name(type);

  return ostr;
} // ostream& operator<<(ostream& ostr, Aiconfig::TypeBool const type)

/**
 **
 ** writes the name of 'type' in 'ostr'
 **
 ** @param	ostr	stream to write in
 ** @param	type	type to write the name of
 **
 ** @return	output stream
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
ostream&
operator<<(ostream& ostr, Aiconfig::TypeUnsigned const type)
{
  ostr << name(type);

  return ostr;
} // ostream& operator<<(ostream& ostr, Aiconfig::TypeUnsigned const type)

/**
 **
 ** writes the name of 'type' in 'ostr'
 **
 ** @param	ostr	stream to write in
 ** @param	type	type to write the name of
 **
 ** @return	output stream
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
ostream&
operator<<(ostream& ostr, Aiconfig::TypeCard const type)
{
  ostr << name(type);

  return ostr;
} // ostream& operator<<(ostream& ostr, Aiconfig::TypeCard const type)

/**********************************************************************
 *
 ** operator<<(ostream& ostr, const Aiconfig& aiconfig)
 *
 ** Parameters:  ostr - ouput stream
 **              aiconfig - aiconfigs
 *
 ** Result:      output stream
 *
 ** Version:     0.4.2
 *
 ** Description: prints the aiconfigs in the ouput stream
 *
 **********************************************************************/
ostream&
operator<<(ostream& ostr, Aiconfig const& aiconfig)
{
  aiconfig.write(ostr);

  return ostr;
} // ostream& operator<<(ostream& ostr, const Aiconfig& aiconfig)


/**********************************************************************
 *
 ** string name(AiType const& type)
 *
 ** Parameters:  aitype - the aitype
 *
 ** Result:  name of the aitype
 *
 ** Version: 0.4.2
 *
 ** Description: -> result
 *
 **********************************************************************/
string
name(AiType const& aitype)
{
  using namespace AITYPE;

  string name;

  switch(aitype) {
  case NO_CHOOSEBESTCARD:
    name = "no choosebestcard";
    break;
  case RANDOM:
    name = "random";
    break;
  case VIRTUAL_GAMES:
    name = "virtual games";
    break;
  case GAMETREE:
    name = "gametree";
    break;
  case GAMETREE_WITH_HEURISTICS:
    name = "gametree with heuristics";
    break;
  case MONTE_CARLO:
    name = "monte carlo";
    break;

  } // switch(aitype)

  return name;
} // string name(AiType const& aitype)


/**********************************************************************
 *
 **    ostream& operator<<(ostream& ostr, AiType const& t)
 *
 **    Parameters:  output stream and AiType to be printed
 *
 **    Result: 
 *
 **    Version: Alpha
 *
 **    Description: 
 *
 **********************************************************************/
ostream&
operator<<(ostream& ostr, AiType const& aitype)
{
  ostr << name(aitype);

  return ostr;
} // ostream operator<<(ostream, aitype);
