/**********************************************************************
 *
 *   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 "player.h"

#include "human/human.h"
#include "ai/ai.h"
#include "ai.dummy/ai.h"
#include "ai.random/ai.h"
#include "../card/hand.h"
#include "../party/party.h"
#include "../party/rule.h"
#include "../game/game_summary.h"
#include "../card/trick.h"
#include "../misc/setting.h"
#include "../ui/ui.h"
#include "playersDb.h"

/**
 **
 ** -> result
 **
 ** @param       type    playertype
 **
 ** @return      pointer to a new player of the given type
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Player*
Player::new_(Type const& type)
{
  Player* player = NULL;

  switch(type) {
  case Player::UNSET:
    DEBUG_ASSERTION(false,
		    "Player::new_(type, player):\n"
		    "  type == UNSET");
    break;
  case Player::HUMAN:
    player = new Human();
    break;
  case Player::AI:
    player = new Ai();
    break;
  case Player::AI_DUMMY:
    player = new AiDummy();
    break;
  case Player::AI_RANDOM:
    player = new AiRandom();
    break;
  } // switch(type)

  return player;
} // Player* Player::new_(Type const& type)

/**
 **
 ** -> result
 **
 ** @param	type	playertype
 ** @param	p	the player to be copied
 **
 ** @return	pointer to a new player of the given type and with data
 **		from 'player'
 **
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Player*
Player::new_(Type const& type, Player const& p)
{
  Player* player = NULL;

  switch(type) {
  case Player::UNSET:
    DEBUG_ASSERTION(false,
		    "Player::new_(type, player):\n"
		    "  type == UNSET");
    break;
  case Player::HUMAN:
#ifdef WORKAROUND
    if (dynamic_cast<Ai const*>(&p) != NULL)
      player = new Human(dynamic_cast<Ai const&>(p));
    else if (dynamic_cast<Aiconfig const*>(&p) != NULL)
      player = new Human(p, dynamic_cast<Aiconfig const&>(p));
    else
      player = new Human(p);
#else
    // see 'AI'
    player = new Human(p);
#endif
    break;

  case Player::AI:
#ifdef WORKAROUND
    if (dynamic_cast<Ai const*>(&p) != NULL)
      player = new Ai(dynamic_cast<Ai const&>(p));
    else if (dynamic_cast<Aiconfig const*>(&p) != NULL)
      player = new Ai(p, dynamic_cast<Aiconfig const&>(p));
    else
      player = new Ai(p);
#else
    // if 'p' is of type 'Human', the GNU C++ compiler calls 'Ai(Player)' but
    // not 'Ai(Ai)' although 'Human' is a child of 'Ai'
    player = new Ai(p);
#endif
    break;
  case Player::AI_DUMMY:
    if (dynamic_cast<Aiconfig const*>(&p) != NULL)
      player = new AiDummy(p, dynamic_cast<Aiconfig const&>(p));
    else
      player = new AiDummy(p);
    break;
  case Player::AI_RANDOM:
    if (dynamic_cast<Aiconfig const*>(&p) != NULL)
      player = new AiRandom(p, dynamic_cast<Aiconfig const&>(p));
    else
      player = new AiRandom(p);
    break;
  } // switch(type)

  return player;
} // Player* Player::new_(Type const& type, Player const& player)

/**
 **
 ** returns a player, created by the infos of the file
 **
 ** @param	filename	file with the player info
 **
 ** @return	pointer to a new player of the given type
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
Player*
Player::new_(string const& filename)
{
  ifstream istr(filename.c_str());
  if (istr.fail())
    return NULL;

  return Player::new_(istr);
} // Player* Player::new_(string const& filename)

/**
 **
 ** returns a player, created by the infos of the stream
 **
 ** @param	istr	stream with the player info
 **
 ** @return	pointer to a new player of the given type
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
Player*
Player::new_(istream& istr)
{
  Player* player = new Player(UNSET);

#ifndef OUTDATED
  // line that has been read
  string line;

  // the first line has the name 'name':
  // Player n: name
  do {
  std::getline(istr, line);
  if (*line.rbegin() == '\r')
    line.erase(line.end() - 1);
  } while (line.empty());
  // 0.6.8    28. 12. 2004
  if ((string(line, 0, strlen("Player:")) == "Player:")
      && istr.good()) {

    // the name of the player
    string name;
    // the rest of the line is the name of the player
    if (line.length() > strlen("Player: "))
      name = string(line, strlen("Player: "), string::npos);
    else
      name = "";

    // the second line is the player type 'type'
    // Player type: 'type'
    std::getline(istr, line);
    if (*line.rbegin() == '\r')
      line.erase(line.end() - 1);
    if ((string(line, 0, strlen("Player type:")) != "Player type:")
	|| istr.fail())
      return NULL;

    // the rest of the line is the type of the player
    string type = string(line, strlen("Player type: "), string::npos);

    // new player
    delete player;
    player = NULL;

    if (type == ::name(HUMAN)) {
      player = new Human(istr);
    } else if (type == ::name(AI)) {
      player = new Ai(istr);
    } else if (type == ::name(AI_DUMMY)) {
      player = new AiDummy(istr);
    } else { // if (type == 'type')
      DEBUG_ASSERTION(false,
		      "Player::new_(istr):\n"
		      "  player type '" << type << "' not known");
    }

    if (player)
      player->name_set(name);

    return player;
  } else {
    if ((string(line, 0, strlen("Name =")) == "Name =")
	&& istr.good()) {

      // the name of the player
      string name;
      // the rest of the line is the name of the player
      if (line.length() > strlen("Name = "))
	name = string(line, strlen("Name = "), string::npos);
      else
	name = "";
      player->name_set(name);
    } else if (line == "{") {
    } else {
      DEBUG_ASSERTION(false,
		      "Player::new_(istream):\n"
		      "first line does not begin with 'Name =':\n"
		      << line);
    }
  }
#endif // #ifndef OUTDATED

  int depth = 0;
  Player::Type type_before = Player::UNSET;
  if (line == "{")
    depth += 1;
  while (istr.good()) {
#ifndef OUTDATED
    // DK: 2005-01-21
    // The player is not included in '{ }', so check, whether the next line
    // is 'Name = ...'
    while ( (istr.peek() == '\n')
	    || (istr.peek() == '\r'))
      istr.get();
    if ((istr.peek() == 'N')
	&& (depth == 0))
      break;
#endif

    Config config;
    istr >> config;

    if (istr.eof())
      break;

    if (istr.fail()) {
#ifndef RELEASE
      cerr << "reading player failed" << endl;
#endif
      return NULL;
    }

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

    if ((config.name == "{")
	&& config.value.empty())
      depth += 1;

    if ((config.name == "}")
	&& config.value.empty()) {
      depth -= 1;
      // finished with the player
      if (depth == -1)
	istr.putback('}');
      if (depth <= 0)
	break;
    }

    if (!player->read(config, istr))
      cerr << "Unknown player line " << config.name << " = " << config.value
	<< endl;

    // if the type is set, change the underlying player
    if (player->type() != type_before) {
      Player* player2 = NULL;
      switch(player->type()) {
      case UNSET:
	DEBUG_ASSERTION(false,
			"Player::new_(istr):\n"
			"  player type is 'UNSET'");
      case HUMAN:
	player2 = Player::new_(HUMAN, *player);
	break;
      case AI:
	player2 = Player::new_(AI, *player);
	break;
      case AI_DUMMY:
	player2 = Player::new_(AI_DUMMY, *player);
	break;
      case AI_RANDOM:
	player2 = Player::new_(AI_RANDOM, *player);
	break;
      } // switch(player->type())
      delete player;
      player = player2;
      type_before = player->type();
    } // if (player->type() != UNSET)
  } // while (istr.good())

  return player;
} // Player* Player::new_(istream& istr)

/**
 **
 ** constructor
 **
 ** @param       type type of the player
 **
 ** @return      -
 **
 ** @version     0.4.4
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 **/
Player::Player(Type const& type)  :
  game_p(NULL),
  type_p(type),
  name_p(),
  no_p(UINT_MAX),
  hand_p(),
  sorted_hand_p(this->hand_p),
  trickpile_(),
  db_( NULL ),
  teaminfo_p(vector<Team>(::party.rule()(Rule::NUMBER_OF_PLAYERS_IN_GAME),
			  TEAM::UNKNOWN))
{
  this->db_ = new PlayersDb();

  return ;
} // Player::Player(Type const& type)  :

/**
 **
 ** copy constructor
 **
 ** @param       player  player to copy
 **
 ** @return      -
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.6.4
 **
 **/
Player::Player(Player const& player) :
  game_p(player.game_p),
  type_p(Player::UNSET),
  name_p(player.name_p),
  no_p(player.no_p),
  hand_p(*this, player.hand_p),
  sorted_hand_p(player.sorted_hand_p, this->hand_p),
  trickpile_(player.trickpile_),
  db_( (player.db_ == NULL)
       ? NULL
       : new PlayersDb(*(player.db_)) ), // *** DK must use a copy!
  teaminfo_p(player.teaminfo_p)
{
  return ;
} // Player::Player(const Player& player)

/**
 **
 ** destructor
 **
 ** @param       -
 **
 ** @return      -
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.5.3
 **
 **/
Player::~Player()
{
  delete this->db_;

  return ;
} // Player::~Player()

/**
 ** self check
 ** when an error is found, an ASSERTION is created
 **
 ** @param	-
 **
 ** @return	wether the self-check was successful (no error)
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 ** @todo	check the hand
 ** @todo	check the sorted hand
 **
 **/
bool
Player::self_check() const
{
  DEBUG_ASSERTION(this->db_,
		  "Player::self_check()\n"
		  "  no database");
  if (this->game_p) {
    DEBUG_ASSERTION((this == &this->game_p->player(this->no_p)),
		    "Player::self_check()\n"
		    "  number not valid: " << this->no_p);


    // ToDo
    // check the hand
    // check the sorted hand

    for (TrickPile::const_iterator t = this->trickpile_.begin();
	 t != this->trickpile_.end();
	 ++t) {
      if (this->game_p != &(*t)->game()) {
	COUT << "  " << this->game_p << " != " << &(*t)->game() << endl;
	COUT << "  trickpile anz: " << this->trickpile_.size() << endl;
	COUT << "  Player: " << this->no() << endl;
	COUT << "  Trick: " << *t << endl;
	COUT << "  Trick: " << **t << endl;
	DEBUG_ASSERTION((this->game_p == &(*t)->game()),
			"Player::self_check()\n"
			"  Trick " << (*t)->no() << " has not the same game");
      }
    } // for (t \in this->trickpile_)
  } // if (this->game_p)

  return true;
} // virtual bool Player::self_check() const

/**
 **
 ** -> result
 **
 ** @param	player	player to compare with
 **
 ** @return	whether the players are the same
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
Player::is_same(Player const& player) const
{
  return (this == &player);
} // bool Player::is_same(Player const& player) const

/**
 **
 ** -> result
 **
 ** @param	player	player to compare with
 **
 ** @return	whether the players are the equal (value)
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 ** @todo	compare values
 ** @todo	comparing sorted hands
 ** @todo	comparing database
 **
 **/
bool
Player::is_equal(Player const& player) const
{
  if (this->type() != player.type())
    return false;
  if (this->name_p != player.name_p)
    return false;
  if (this->no_p != player.no_p)
    return false;

  if (this->game_p != player.game_p)
    return false;

  if (this->hand_p != player.hand_p)
    return false;
#ifdef POSTPHONED
  if (this->sorted_hand_p != player.sorted_hand_p)
    return false;
#endif
  if (this->trickpile_ != player.trickpile_)
    return false;
#ifdef POSTPHONED
  if (*(this->db_) != *(player.db_))
    return false;
#endif

  if (this->teaminfo_p != player.teaminfo_p)
    return false;

  switch(this->type()) {
  case UNSET:
    return true;
  case HUMAN:
  case AI:
  case AI_DUMMY:
  case AI_RANDOM:
    // ToDo: compare with values
    return this->is_same(player);
  } // switch (this->type())

  DEBUG_ASSERTION(false,
		  "Player::is_equal(player):\n"
		  "  behind the 'case' block");

  return true;
} // bool Player::is_equal(Player const& player) const

/**
 **
 ** clone the player
 **
 ** @param       -
 **
 ** @return      pointer of a clone
 **
 ** @author      Diether Knof
 **
 ** @version     0.5.3
 **
 **/
Player*
Player::clone() const
{  
  return new Player(*this);
} // virtual Player* Player::clone() const

/**
 **
 ** copy operator
 **
 ** @param       player  player to be copied
 **
 ** @return      copy of player
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Player&
Player::operator=(const Player& player)
{  
  // copy the values
  this->game_p = player.game_p;
  this->type_p = player.type_p;
  this->name_p = player.name_p;
  this->no_p = player.no_p;
  this->hand_p = player.hand_p;
  this->hand_p.set_player(*this);
  this->sorted_hand_p = SortedHand(player.sorted_hand_p, this->hand_p);
  this->trickpile_ = player.trickpile_;
  this->teaminfo_p = player.teaminfo_p;
  this->db_        = ((player.db_ == NULL)
		      ? NULL
		      : new PlayersDb(*(player.db_))); // *** DK must use a copy!

  return *this;
} // Player& Player::operator=(const Player& player)

/**
 **
 ** -> result
 **
 ** @param	player1		player 1 to compare
 ** @param	player2	 player 2 to compare
 **
 ** @return	whether the players are equal (they lie in the same memory)
 **
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 ** @todo	compare with values
 **
 **/
bool
operator==(Player const& player1, Player const& player2)
{
  return player1.is_equal(player2);
} // bool operator==(Player const& player1, Player const& player2)

/**
 **
 ** -> result
 **
 ** @param       player1 player 1 to compare
 ** @param       player2 player 2 to compare
 **
 ** @return      whether the players are not equal
 **              (they don't lie in the same memory)
 **
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
bool
operator!=(Player const& player1, Player const& player2)
{
  return !(player1 == player2);
} // bool operator!=(Player const& player1, Player const& player2)

/**
 **
 ** save the player in the file 'filename'
 **
 ** @param	filename    file the player shall be saved
 **
 ** @return	whether the saving was sucessful
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
bool
Player::save(string const& filename) const
{
  ofstream ostr(filename.c_str());
  if (ostr.fail())
    return false;

  this->write(ostr);

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

/**
 **
 ** write the player in the stream
 **
 ** @param       ostr    output stream
 **
 ** @return      output stream
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
ostream&
Player::write(ostream& ostr) const
{
  ostr << "Name = " << this->name() << "\n"
    << "Type = " << this->type() << "\n"
    << '\n'
    << "Database\n"
    << "{\n"
    << this->db()
    << "}\n";

#if 0
  if (::game_status & GAMESTATUS::GAME) {
    ostr << "Team" << ": " << this->team() << "\n"
      << "Announcement" << ": " << this->announcement()
      << "\n"
      << this->hand()
      << "Teaminfo" << ": \n";
    for(vector<Player*>::const_iterator player = this->game().player_begin();
	player != this->game().player_end();
	player++)
      ostr << (*player)->no() << ": " << this->teaminfo(**player) << "\n";

  } // if (::gamestatus & GAMESTATUS::GAME)
#endif

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

/**
 **
 ** output of the player
 **
 ** @param       ostr    output stream
 ** @param       player  player to be put in the stream
 **
 ** @return      output stream
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
ostream&
operator<<(ostream& ostr, const Player& player)
{
  player.write(ostr);

  return ostr;
} // ostream& operator<<(ostream& ostr, const Player& player)

/**
 **
 ** read the config of the player
 **
 ** @param	config		configuration to read
 ** @param	istr		input stream
 **
 ** @return	whether the configuration was valid
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
bool
Player::read(Config const& config, istream& istr)
{
  if (config.separator) {
    if (config.name == "Name") {
      this->name_set(config.value);
      return true;
    } else if (config.name == "Type") {
      if (this->type() != UNSET) {
	cerr << "Type already set, ignoring further one" << endl;
	return true;
      }
      if (config.value == ::name(HUMAN)) {
	this->type_set(HUMAN);
      } else if (config.value == ::name(AI)) {
	this->type_set(AI);
      } else if (config.value == ::name(AI_DUMMY)) {
	this->type_set(AI_DUMMY);
      } else { // if (config.value == 'type')
	DEBUG_ASSERTION(false,
			"Player::read(config, istr):\n"
			"  player type '" << config.value << "' not known");
      }
      return true;
      // I know the type, so I can create the player
    }
  } else { // if (config.separator)
    if (config.name == "Database") {
      this->db_->read(istr);
      return true;
    }
  } // if (config.separator)

  return false;
} // virtual bool Player::read(Config config, istream& istr)

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      game the player is playing
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Game&
Player::game()
{
  DEBUG_ASSERTION(this->game_p,
		  "Player::game(): 'game_p' is a NULL-pointer\n"
		  "  this = " << this);

  return *(this->game_p);
} // Game& Player::game()

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      game the player is playing
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Game const&
Player::game() const
{
  DEBUG_ASSERTION(this->game_p != NULL,
		  "Player::game(): 'game_p' is a NULL-pointer\n"
		  "  this = " << this);

  return *(this->game_p);
} // Game const& Player::game() const

/**
 **
 ** set the game
 **
 ** @param       game    new game
 **
 ** @return      -
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.6.7
 **
 **/
void
Player::game_set(Game& game)
{
  this->game_p = &game;

  for (TrickPile::iterator t = this->trickpile_.begin();
       t != this->trickpile_.end();
       ++t)
    *t = &game.trick((*t)->no());

  return ;
} // void Player::game_set(Game& game)

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      type
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Player::Type const&
Player::type() const
{
  return this->type_p;
} // Player::Type const& Player::type() const

/**
 **
 ** sets the type
 **
 ** @param       type - new player type
 **
 ** @return      new type
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Player::Type const&
Player::type_set(Type const& type)
{
  this->type_p = type;

  return this->type();
} // Player::Type const& Player::type_set(Type const& type)

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      name of the player
 **              if it is empty, take a default
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
string const
Player::name() const
{
  if (this->name_p.empty())
    return Player::default_name(this->type());


  return this->name_p;
} // string const Player::name() const

/**
 **
 ** sets the name
 **
 ** @param       name    new name
 **
 ** @return      name
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
string const
Player::name_set(string const& name)
{
  if (Player::default_name(this->type()) == name)
    this->name_p = "";
  else
    this->name_p = name;

  return this->name();
} // string const Player::name_set(string const& name)

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      value of the name of the player
 **
 ** @author      Diether Knof
 **
 ** @version     0.5.3
 **
 **/
string const&
Player::name_value() const
{
  return this->name_p;
} // string const& Player::name_value() const

/**
 **
 ** -> result
 **
 ** @param       type    the type
 **
 ** @return      default name of the type
 **
 ** @author      Diether Knof
 **
 ** @version     0.5.3
 **
 **/
string
Player::default_name(Type const& type)
{
  switch(type) {
  case HUMAN:
    return ::setting(Setting::NAME);
    break;
  default:
    return ::name(type);
    break;
  } // switch(this->type())
} // string Player::default_name(const Player::Type& type)

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      the number of the player in the game
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
unsigned
Player::no() const
{
#ifdef POSTPHONED
  DEBUG_ASSERTION((::game_status & GAMESTATUS::GAME),
		  "Player::no():\n"
		  "  game_status is not GAME");
#endif

#ifdef POSTPHONED
  return this->game().no_of_player(*this);
#else
  DEBUG_ASSERTION((this->no_p != UINT_MAX),
		  "Player::no():\n"
		  "  no not set (use Player::no_set(unsigned))");

  return this->no_p;
#endif
} // unsigned Player::no() const

/**
 **
 ** sets the playernumber
 **
 ** @param       no      new playernumber
 **
 ** @return      the playernumber
 **
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
unsigned
Player::no_set(unsigned const no)
{
#ifdef POSTPHONED
  DEBUG_ASSERTION((::game_status & GAMESTATUS::GAME),
		  "Player::no_set():\n"
		  "  game_status is not GAME");

  DEBUG_ASSERTION((no < this->game().playerno()),
		  "Player::no_set():\n"
		  "  no is too great");
#else
  DEBUG_ASSERTION((no < ::party.playerno()),
		  "Player::no_set():\n"
		  "  no is too great");
#endif

  this->no_p = no;

  return this->no();
} // unsigned Player::no() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      the database
 **
 ** @author      Borg Enders
 **
 ** @version     0.6.2
 **
 **/
PlayersDb const&
Player::db() const
{
  DEBUG_ASSERTION(this->db_,
		  "Playe::db():\n"
		  "  'this->db_' == NULL");

  return *(this->db_);
} // PlayersDb const& Player::db() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      the database
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.6
 **
 **/
PlayersDb&
Player::db()
{
  DEBUG_ASSERTION(this->db_,
		  "Playe::db():\n"
		  "  'this->db_' == NULL");

  return *(this->db_);
} // PlayersDb& Player::db()

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      hand
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Hand const&
Player::hand() const
{
  return this->hand_p;
} // Hand const& Player::hand() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      hand
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Hand&
Player::hand()
{
  return this->hand_p;
} // Hand& Player::hand()


/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      sorted hand
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.4
 **
 **/
SortedHand const&
Player::sorted_hand() const
{
  return this->sorted_hand_p;
} // SortedHand const& Player::sorted_hand() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      hand
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.4
 **
 **/
SortedHand&
Player::sorted_hand()
{
  return this->sorted_hand_p;
} // SortedHand& Player::hand()


/**
 **
 ** sort the hand
 **
 ** @param       -
 **
 ** @return      sorted hand
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.5.4
 **
 **/
Hand const&
Player::hand_sort()
{
  if (::setting(Setting::CARDS_ORDER).sorted()
      && (this->game_p != NULL)
      && !(this->game().isvirtual())) {
    bool const changed = this->sorted_hand().sort();
    if (changed)
      ::ui->hand_update(*this);
  } // if (::setting(Setting::CARDS_ORDER).sorted())

  return this->hand();
} // Hand const& Player::hand_sort()

/**
 **
 ** mixes the hand
 **
 ** @param       -
 **
 ** @return      mixed hand
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.5.4
 **
 **/
Hand const&
Player::hand_mix()
{
  if (!::setting(Setting::CARDS_ORDER).sorted()) {
    this->sorted_hand().mix();
    if ((this->game_p != NULL)
	&& (!this->game().isvirtual()))
      ::ui->hand_update(*this);
  } // if (!::setting(Setting::CARDS_ORDER).sorted())

  return this->hand();
} // Hand const& Player::hand_mix()


/**
 **
 ** set the hand
 **
 ** @param       hand    new hand
 **
 ** @return      player with hand h
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.6.7
 **
 **/
Hand const&
Player::hand_set(Hand const& hand)
{
  this->hand_p = hand;
  this->hand_p.set_player(*this);

  if (!this->game().isvirtual()
      && (*this == this->game().player(this->no())) )
    // In virtual games the hand is not shown, so it does not have to be sorted.
    if (::setting(Setting::CARDS_ORDER).sorted())
      this->hand_sort();
    else
      this->hand_mix();

  return this->hand();
} // Hand const& Player::hand_set(Hand const& hand)


/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      whether the player is re
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
bool
Player::isre() const
{
  return (this->teaminfo(*this) == TEAM::RE);
} // bool Player::isre() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      whether the player has swines
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.5
 **
 **/
bool
Player::swines_has() const
{
  if (this->game().swines_announced()
      && (this == this->game().swines_owner())) {
    if ((::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)
	&& (*this == this->game().soloplayer()))
      return true;
    // search a swine in all cards of the hand
    for (unsigned c = 0; c < hand().cardsnumber_all(); c++)
      if (hand().card_all(c).isswine())
	return true;
  } // if (this->game().swines_announced())

  return false;
} // bool Player::swines_has() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      whether the player has hyperswines
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.5
 **
 **/
bool
Player::hyperswines_has() const
{
  if (this->game().hyperswines_announced()
      && (this == this->game().hyperswines_owner())) {
    // search a hyperswine in all cards of the hand
    for (unsigned c = 0; c < hand().cardsnumber_all(); c++)
      if (hand().card_all(c).ishyperswine())
	return true;
  } // if (this->game().hyperswines_announced())

  return false;
} // bool Player::hyperswines_has() const


/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      the trickpile of the player
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.4
 **
 **/
TrickPile const&
Player::trickpile() const
{
  return this->trickpile_;
} // TrickPile const& Player::trickpile() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      team of the player
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Team
Player::team() const
{
  return this->teaminfo(*this);
} // Team Player::team() const

/**
 **
 ** -> result
 **
 ** @param       player whose teaminfo is returned
 **
 ** @return      the team of the given player, as far as this player knows it
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Team const&
Player::teaminfo(Player const& player) const
{
  DEBUG_ASSERTION((player.no() < this->teaminfo_p.size()),
		  "Player::teaminfo(player):\n"
		  "  player.no() too great");

  return this->teaminfo_p[player.no()];
} // Team const& Player::teaminfo(Player const& player) const


/**
 **
 ** updates the information of the teams (uses the current trick)
 **
 ** @param       -
 **
 ** @return      the known teams
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 ** @todo	two contra + 1 re without trump
 **
 **/
void
Player::teaminfo_update()
{
  using namespace TEAM;

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

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

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

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

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

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

  return ;
} // void Player::teaminfo_update()

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      announcment of this player (taken from 'game')
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Announcement const&
Player::announcement() const
{
  return this->game().announcement_of_player(*this).announcement;
} // Announcement const& Player::announcement() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      the number of tricks the player has (taken from 'game')
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.0
 **
 **/
unsigned
Player::number_of_tricks() const
{
  DEBUG_ASSERTION((this->game_p != NULL),
		  "Player::number_of_tricks():\n"
		  "  'this->game' == NULL");

  return this->game().numberoftricks_of_player(*this);
} // unsigned Player::number_of_tricks() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      the points of the tricks the player has (taken from 'game')
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.0
 **
 **/
unsigned
Player::points_in_trickpile() const
{
  DEBUG_ASSERTION((this->game_p != NULL),
		  "Player::points_in_trickpile():\n"
		  "  'this->game' == NULL");

  return this->game().points_of_player(*this);
} // unsigned Player::points_in_trickpile() const

/**
 **
 ** the game 'game' is opened
 **
 ** @param       game    opened game
 **
 ** @return      -
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.7
 **
 **/
void
Player::game_open(Game& game)
{
  this->game_p = &game;
  this->hand_p = Hand();

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

  return ;
} // void Player::game_open(Game& game)

/**
 **
 ** the game 'game' is closed
 **
 ** @param       game    closed game
 **
 ** @return      -
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.7
 **
 **/
void
Player::game_close(Game& game)
{
  DEBUG_ASSERTION((this->game_p == &game),
		  "Player::game_close(game):\n"
		  "  wrong game is closed");

  this->trickpile_.clear();
  this->game_p = NULL;

  return ;
} // void Player::game_close(Game& game)

/**
 **
 ** the player can make an announcement
 **
 ** @param       -
 **
 ** @return      announcement of the player
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Announcement
Player::announcement_request() const
{
  return ANNOUNCEMENT::NOANNOUNCEMENT;
} // Announcement Player::announcement_request() const

/**
 **
 ** the given player has made the given announcement
 **
 ** @param       announcement    the announcement
 ** @param       player          the player, who has made the announcement
 **
 ** @return      -
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
void
Player::announcement_made(Announcement const& announcement,
			  Player const& player)
{
  return ;
} // void Player::announcement_made(Announcement const& announcement, Player const& player)

/**
 **
 ** 'player' shifts 'cardno' cards
 **
 ** @param      player  the player who shifts the cards
 ** @param      cardno  the number of cards that are shifted
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.4.5
 **
 **/
void
Player::poverty_shift(Player const& player, unsigned const cardno)
{ 
  return ;
} // void Player::poverty_shift(Player const& player, unsigned const cardno)

/**
 **
 ** 'player' denied to take the shifted cards
 **
 ** @param      player  the player who has denied to take the cards
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.4.5
 **
 **/
void
Player::poverty_take_denied(Player const& player)
{ 
  return ;
} // void Player::poverty_take_denied(Player const& player)

/**
 **
 ** all players have denied to take the cards
 **
 ** @param      -
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.4.5
 **
 **/
void
Player::poverty_take_denied_by_all()
{ 
  return ;
} // void Player::poverty_take_denied_by_all()

/**
 **
 ** 'player' accepts to take the shifted cards
 ** and returns 'cardno' cards with 'trumpno' trumps
 **
 ** @param      player  the player who has accepted to take the cards
 ** @param      cardno  number of cards that are given back
 ** @param      trumpno number of trumps of the cards
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.4.5
 **
 **/
void
Player::poverty_take_accepted(Player const& player,
			      unsigned const cardno, unsigned const trumpno)
{ 
  return ;
} // void Player::poverty_take_accepted(Player const& player, unsigned const cardno, unsigned const trumpno)

/**
 **
 ** returns which cards the player shifts
 **
 ** @param      -
 **
 ** @return     the cards that are to be shifted
 **
 ** @author     Diether Knof
 **
 ** @version    0.4.5
 **
 **/
HandCards
Player::poverty_shift()
{ 
  cerr << "call of Player::poverty shift()"
    << endl;

  return HandCards();
} // HandCards Player::poverty_shift(Player const& player)

/**
 **
 ** returns whether 'player' accepts the shifted cards
 **
 ** @param      cardno  the number of shifted cards
 **
 ** @return     whether to accept the cards
 **
 ** @author     Diether Knof
 **
 ** @version    0.4.5
 **
 **/
bool
Player::poverty_take_accept(unsigned const cardno)
{ 
  cerr << "call of Player::poverty_take_accept(cardno)"
    << endl;

  return false;
} // void Player::poverty_take_accept(unsigned const cardno)

/**
 **
 ** changes the cards from the poverty-player
 **
 ** @param      cards   the cards that are given to the player
 **
 ** @return     the cards that are returned to the poverty-player
 **
 ** @author     Diether Knof
 **
 ** @version    0.4.5
 **
 **/
HandCards
Player::poverty_cards_change(HandCards const& cards)
{ 
  cerr << "call of Player::poverty_cards_change(cards)"
    << endl;

  return HandCards();
} // HandCards Player::poverty_cards_change(HandCards const& cards)

/**
 **
 ** gets the cards from the partner and add them to the hand
 **
 ** @param	cards	the cards that are given to the player
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.5
 **
 **/
void
Player::poverty_cards_get_back(HandCards const& cards)
{ 
  this->sorted_hand().add(cards);
  this->hand_sort();

  return ;
} // void Player::poverty_cards_get_back(HandCards const& cards)

/**
 **
 ** genscher: -> result
 **
 ** @param	-
 **
 ** @return	pointer to the new teammate,
 **		NULL if the genscher is not to be announced
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
Player const*
Player::genscher_partner()
{ 
  return NULL;
} // Player const* Player::genscher_partner()

/**
 **
 ** genscher: Information of the new team
 **
 ** @param	player	genscher player
 ** @param	partner	partner of the gensher player
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
void
Player::genscher(Player const& player,
		 Player const& partner)
{ 
  return ;
} // void Player::genscher(Player const& player, Player const& partner)

/**
 **
 ** a new game has started - init the player:
 ** empty the hand,
 ** set the teaminfo to the teaminfo of the game
 **
 ** @param       game    the game
 **
 ** @return      -
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
void
Player::new_game(Game& game)
{ 
  this->game_p = &game;
  this->hand_p = Hand();

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

  return ;
} // void Player::new_game()

/**
 **
 ** the player makes his reservation
 **
 ** @param       isDuty ?
 **
 ** @return      reservation of the player
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 ** @todo	isDuty documentation
 **
 **/
Reservation
Player::reservation_get( bool isDuty ) 
{ 
  DEBUG_ASSERTION(false,
		  "Player::reservation_get():\n"
		  "  call of this function");

  return this->reservation_get_default();
} // Reservation Player::reservation_get() const

/**
 **
 ** -> result
 ** that is swines and hyperswines, if the player has them,
 ** poverty (nines, kings, trump), marriage
 **
 ** @param	-
 **
 ** @return	default reservation of the player
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.0
 **
 **/
Reservation
Player::reservation_get_default() const
{ 
  Reservation reservation;

  if (this->hand().numberofclubqueens()
      == this->game().rule()(Rule::NUMBER_OF_SAME_CARDS)) {
    reservation.game_type = GAMETYPE::MARRIAGE;
    if (this->game().rule()(MARRIAGE_SELECTOR::FIRST_FOREIGN))
      reservation.marriage_selector = MARRIAGE_SELECTOR::FIRST_FOREIGN;
    else if (this->game().rule()(MARRIAGE_SELECTOR::FIRST_COLOR))
      reservation.marriage_selector = MARRIAGE_SELECTOR::FIRST_COLOR;
    else if (this->game().rule()(MARRIAGE_SELECTOR::FIRST_TRUMP))
      reservation.marriage_selector = MARRIAGE_SELECTOR::FIRST_TRUMP;
    else if (this->game().rule()(MARRIAGE_SELECTOR::FIRST_CLUB))
      reservation.marriage_selector = MARRIAGE_SELECTOR::FIRST_CLUB;
    else if (this->game().rule()(MARRIAGE_SELECTOR::FIRST_SPADE))
      reservation.marriage_selector = MARRIAGE_SELECTOR::FIRST_SPADE;
    else if (this->game().rule()(MARRIAGE_SELECTOR::FIRST_HEART))
      reservation.marriage_selector = MARRIAGE_SELECTOR::FIRST_HEART;
    else
      DEBUG_ASSERTION(false,
		      "Player::reservation_get_default():\n"
		      "  no marriage selector valid.\n"
		      "  Ruleset:"
		      << this->game().rule());
  }

  reservation.swines
    = (this->game().rule()(Rule::SWINES)
       && this->game().rule()(Rule::SWINES_ANNOUNCEMENT_BEGIN)
       && (this->hand().numberoftrumpaces()
	   == this->game().rule()(Rule::NUMBER_OF_SAME_CARDS)));

  reservation.hyperswines
    = (this->game().rule()(Rule::HYPERSWINES)
       && this->game().rule()(Rule::HYPERSWINES_ANNOUNCEMENT_BEGIN)
       && (this->hand().numberoftrumpnines()
	   == this->game().rule()(Rule::NUMBER_OF_SAME_CARDS)));


  if (this->game().rule()(Rule::POVERTY)
      && (this->hand().numberoftrumps()
	  <= Rule::MAX_NUMBER_OF_POVERTY_TRUMPS))
    reservation.game_type = GAMETYPE::POVERTY;

  if (this->game().rule()(Rule::THROW_WHEN_FOX_HIGHEST_TRUMP)) {
    unsigned c;
    for (c = 0; c < this->hand().cardsnumber(); ++c)
      if (Card(Card::DIAMOND, Card::ACE).less(this->hand().card(c)))
	break;

    if (c == this->hand().cardsnumber())
      reservation.game_type = GAMETYPE::FOX_HIGHEST_TRUMP;
  } // test fox highest trump

  if (this->game().rule()(Rule::THROW_WITH_FIVE_NINES)
      && (this->hand().numberofnines()
	  >= Rule::MIN_NUMBER_OF_THROWING_NINES))
    reservation.game_type = GAMETYPE::FIVE_NINES;

  if (this->game().rule()(Rule::THROW_WITH_SIX_KINGS)
      && (this->hand().numberofkings()
	  >= Rule::MIN_NUMBER_OF_THROWING_KINGS))
    reservation.game_type = GAMETYPE::SIX_KINGS;

  return reservation;
} // Reservation Player::reservation_get_default() const

/**
 **
 ** the game is started
 **
 ** @param       -
 **
 ** @return      -
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.6
 **
 **/
void
Player::game_start() 
{ 
  // last time for swines announcements

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

/**
 **
 ** the player plays a card
 **
 ** @param       -
 **
 ** @return      card of the player
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
HandCard
Player::card_get()
{ 
  DEBUG_ASSERTION(false,
		  "Player::card_get():\n"
		  "  call of this function");

  return this->hand().card(0);
} // HandCard Player::card_get()

/**
 **
 ** 'player' has played the card 'card'
 **
 ** @param       card    played card
 **
 ** @return      -
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
void
Player::card_played(HandCard const& card, bool count )
{ 
  return ;
} // void Player::card_played(HandCard const& card)

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

/**
 **
 ** move the trick in the trickpile
 **
 ** @param      trick   trick
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.6.7
 **
 **/
void
Player::move_in_trickpile(Trick const& trick)
{ 
  DEBUG_ASSERTION((&trick.game() == this->game_p),
		  "Player::move_in_trickpile(trick)"
		  "  trick.game != this->game");

  this->trickpile_.push_back(&trick);

  return ;
} // void Player::move_in_trickpile(Trick const& trick)

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

/**
 **
 ** 'player' has announce swines
 **
 ** @param      player	player that has announced the swines
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.6.6
 **
 **/
void
Player::swines_announced(Player const& player)
{ 
  return ;
} // void Player::swines_announced(Player const& player)

/**
 **
 ** evaluation of game for playersDb
 **
 ** @param      game_summary	game summary
 **
 ** @return     -
 **
 ** @author     Borg Enders
 ** @author     Diether Knof
 **
 ** @version    0.6.7
 **
 **/
void
Player::evaluate(GameSummary const& game_summary)
{
  this->db_->evaluate( *this, game_summary );
  return ;
}

/**
 **
 ** -> result
 **
 ** @param       type    the type
 **
 ** @return      name of the type
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
string
name(const Player::Type& type)
{
  string name;

  switch(type) {
  case Player::UNSET:
    name = "player type unset";
    break;
  case Player::HUMAN:
    name = "human";
    break;
  case Player::AI:
    name = "ai";
    break;
  case Player::AI_DUMMY:
    name = "dummy ai";
    break;
  case Player::AI_RANDOM:
    name = "random ai";
    break;
  } // switch(type)

  return name;
} // string name(const Player::Type& type)

/**
 **
 ** output of the name of 'type'
 **
 ** @param       ostr    output stream
 ** @param       type    player type
 **
 ** @return      output stream
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
ostream&
operator<<(ostream& ostr, const Player::Type& type)
{
  ostr << name(type);

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