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

#include "trick.h"
#include "../player/player.h"
#include "../game/game.h"
#include "../party/rule.h"
#include "../utils/string.h"

/**
 **
 ** constructor
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
Hand::Hand() :
  cards_(),
  cards_all_(),
  played_(),
  requested_position_(UINT_MAX),
  player_(NULL)
{
  return ;
} // Hand::Hand()

/**
 **
 ** constructor
 **
 ** @param	player	player this hand belongs to
 **
 ** @return	-
 **
 ** @version	0.6.8
 **
 ** @author	Diether Knof
 **
 **/
Hand::Hand(Player const& player):
  cards_(),
  cards_all_(),
  played_(),
  requested_position_(UINT_MAX),
  player_(&player)
{
  return ;
} // Hand::Hand(Player const& player)

/**
 **
 ** constructor
 **
 ** @param	player	player this hand belongs to
 ** @param	hand	hand to copy
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
Hand::Hand(Player const& player, Hand const& hand):
  cards_(),
  cards_all_(),
  played_(),
  requested_position_(hand.requested_position()),
  player_(&player)
{
  this->add(hand);
  return ;
} // Hand::Hand(Player const& player, Hand const& hand)

/**
 **
 ** constructor
 **
 ** @param	hand	hand to copy
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
Hand::Hand(Hand const& hand):
  cards_(),
  cards_all_(),
  played_(),
  requested_position_(hand.requested_position()),
  player_(hand.player_)
{
  this->add(hand);
  return ;
} // Hand::Hand(Hand)

/**
 **
 ** constructor
 **
 ** @param	cards	cards of the hand
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
Hand::Hand(vector<Card> const& cards) :
  cards_(),
  cards_all_(),
  played_(),
  requested_position_(UINT_MAX),
  player_(NULL)
{
  this->add(cards);
  return ;
} // Hand::Hand(vector<Card> const& cards) :

/**
 **
 ** constructor
 **
 ** @param	player	the player who owns the hand
 ** @param	cards	cards of the hand
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
Hand::Hand(Player const& player, vector<Card> const& cards) :
  cards_(),
  cards_all_(),
  played_(),
  requested_position_(UINT_MAX),
  player_(&player)
{
  this->add(cards);
  return ;
} // Hand::Hand(vector<Card> const& cards)

/**
 **
 ** constructor
 **
 ** @param	player	the player who owns the hand
 ** @param	cards	cards of the hand
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
Hand::Hand(Player const& player, vector<HandCard> const& cards) :
  cards_(),
  cards_all_(),
  played_(),
  requested_position_(UINT_MAX),
  player_(&player)
{
  this->add(Card::simple_cards(cards));
  return ;
} // Hand::Hand(vector<Card> const& cards)

/**
 **
 ** copy operator
 **
 ** @param	hand	hand to copy
 **
 ** @return	copied hand
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
Hand&
Hand::operator=(Hand const& hand)
{
  if (this == &hand)
    return *this;

  this->cards_.clear();
  this->cards_all_.clear();
  this->played_.clear();
  this->add(hand);
  this->requested_position_ = hand.requested_position();
  this->player_ = hand.player_;

  return *this;
} // Hand& Hand::operator=(Hand const& hand)

/**
 **
 ** constructor:
 ** read the hand from the stream
 **
 ** @param	istr	Stream with the info
 **
 ** @return	-
 **
 ** @version	0.5.4
 **
 ** @author	Diether Knof
 **
 **/
Hand::Hand(istream& istr) :
  cards_(),
  cards_all_(),
  played_(),
  requested_position_(UINT_MAX),
  player_()
{
  string line;
  while (istr.good()) {
    // read the lines until there is an empty line or eof
    getline(istr, line);
    if (line.empty())
      break;

    // the line is as followed:
    // 0  diamond king		(played 2)
    // (number of the card, card)
    DK::Utils::String::word_first_remove(line);

    string card_name;
    card_name = DK::Utils::String::word_first(line);
    DK::Utils::String::word_first_remove(line);
    card_name += " ";
    card_name += DK::Utils::String::word_first(line);
    DK::Utils::String::word_first_remove(line);

    HandCard card(*this, card_name);
    if (!card)
      break;
    this->cards_.push_back(card);
    this->cards_all_.push_back(card);

    DK::Utils::String::remove_blanks(line);
    if (line.empty()) {
      // the card has not been played, yet
      this->played_.push_back(UINT_MAX);
    } else { // if (line.empty())
      // the card has been played
      // the line is now like: (played 1)
      if (DK::Utils::String::word_first(line) != "(played")
	break;
      DK::Utils::String::word_first_remove(line);
      DK::Utils::String::remove_blanks(line);

      this->played_.push_back(static_cast<unsigned>(atoi(line.c_str())));
    } // if !(line.empty())

  } // while (istr.good())

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

/**
 **
 ** destructor
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
Hand::~Hand()
{
  return ;
} // Hand::~Hand()

/**
 **
 ** 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.8
 **
 **/
bool
Hand::self_check() const
{
  { // check the cards with cards_all
    unsigned c = 0;
    for (unsigned ca = 0; ca < this->cardsnumber_all(); ++ca) {
      if (!this->played(ca)) {
	DEBUG_ASSERTION((this->card(c) == this->card_all(ca)),
			"Hand::self_check():\n"
			"  card '" << this->card(c) << "' on position " << c
			<< " is not the same as card all '"
			<< this->card_all(ca) << "' at position " << ca << "\n"
			<< *this);
	c += 1;
      } // if (!this->played(ca))
    }
  } // check the cards with cards_all

  { // check the hand of the cards
    for (vector<HandCard>::const_iterator c = this->cards_.begin();
	 c != this->cards_.end();
	 ++c)
      DEBUG_ASSERTION((&c->hand() == this),
		      "Hand::self_check():\n"
		      "  card '" << *c << "' does not belong to this hand.\n"
		      << *this);
    for (vector<HandCard>::const_iterator c = this->cards_all_.begin();
	 c != this->cards_all_.end();
	 ++c)
      DEBUG_ASSERTION((&c->hand() == this),
		      "Hand::self_check():\n"
		      "  card_all '" << *c
		      << "' does not belong to this hand.\n"
		      << *this);
  } // check the hand of the cards

  return true;
} // bool Hand::self_check() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of cards still in the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
unsigned
Hand::cardsnumber() const
{
  return this->cards_.size();
} // unsigned Hand::cardsnumber() const

/**
 **
 ** -> result
 **
 ** @param	i	number of card
 **
 ** @return	card i of the hand (with remaining cards)
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
HandCard const&
Hand::card(unsigned const i) const
{
  DEBUG_ASSERTION((i < this->cardsnumber()),
		  "Hand::card(i):\n"
		  "  invalid value 'i' = " << i
		  << " (max = " << this->cardsnumber() << ")\n"
		  "Hand: "
		  << *this);

  DEBUG_ASSERTION(this->cards_[i],
		  "Hand::card(i):\n"
		  "  empty card " << i << ":\n"
		  << *this);

  return this->cards_[i];
} // HandCard const& Hand::card(unsigned const i) const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	all (not played) cards, but only one of multiple same
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.3
 **
 **/
Hand
Hand::cards_single() const
{
  Hand cards_single;
  if (this->player_)
    cards_single.set_player(this->player());

  for (vector<HandCard>::const_iterator c = this->cards_.begin();
       c != this->cards_.end();
       ++c) {
    // search the card in the til now selected cards
    vector<HandCard>::const_iterator c2 = cards_single.cards().begin();
    for ( ; c2 != cards_single.cards().end(); ++c2)
      if (*c2 == *c)
	break;

    if (c2 == cards_single.cards().end())
      cards_single.add(*c);
  } // for (c \in this->cards_)

  return cards_single;
} // Hand Hand::cards_single() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of all cards in the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **      
 **
 **/
unsigned
Hand::cardsnumber_all() const
{
  return this->cards_all_.size();
} // unsigned Hand::cardsnumber_all() const

/**
 **
 ** -> result
 **
 ** @param	i	cardnumber
 **
 ** @return	the card number 'i'
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
HandCard const&
Hand::card_all(unsigned const i) const
{
  DEBUG_ASSERTION((i < this->cardsnumber_all()),
		  "Error: file " << __FILE__ << ", line " << __LINE__ << ", "
		  << "function Hand::card_all()\n"
		  << "  illegal value " << i
		  << " (maximal value is: " << this->cardsnumber_all() - 1 << ")");


  DEBUG_ASSERTION(this->cards_all_[i],
		  "Hand::card_all(i):\n"
		  "  empty card " << i << ":\n"
		  << *this);

  return this->cards_all_[i];
} // HandCard const& Hand::card(unsigned const i) const

/**
 **
 ** -> result
 **
 ** @param	i	cardnumber
 **
 ** @return	whether the card 'i' has been played
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
bool
Hand::played(unsigned const i) const
{
  return (this->played_trick(i) != UINT_MAX);
} // bool Hand::played(unsigned const i) const

/**
 **
 ** -> result
 **
 ** @param	i	number of card
 **
 ** @return	in which trick the card has been played
 **		(UINT_MAX, if not played, yet)
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
unsigned
Hand::played_trick(unsigned const i) const
{
  DEBUG_ASSERTION((i < this->cardsnumber_all()),
		  "Hand::played()\n"
		  "  illegal value i = " << i
		  << " (>= " << this->cardsnumber_all() << ")");

  return this->played_[i];
} // unsigned Hand::played_trick(i)

/**
 **
 ** -> result
 **
 ** @param	i	number of card
 **
 ** @return	in which trick the card has been played
 **		(UINT_MAX, if not played, yet)
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
HandCard const&
Hand::highest_card() const
{
  DEBUG_ASSERTION((this->cardsnumber() > 0),
		  "Hand::highest_card():\n"
		  "  Hand is empty");

  DEBUG_ASSERTION(this->player_,
		  "Hand::highest_card():\n"
		  "  hand does not belongs to a player");

  vector<HandCard>::const_iterator highest_card = this->cards().begin();

  for (vector<HandCard>::const_iterator c = this->cards().begin() + 1;
       c != this->cards().end();
       ++c) {
    if (highest_card->less(*c))
      highest_card = c;
  } // for (c)

  return *highest_card;
} // HandCard const& Hand::highest_card() const

#ifdef OUTDATED
// 0.6.7 by Hand::highest_card()
/**
 **
 ** -> result
 **
 ** @param	i	number of card
 **
 ** @return	in which trick the card has been played
 **		(UINT_MAX, if not played, yet)
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
HandCard const&
Hand::highest_card(Game const& game) const
{
  DEBUG_ASSERTION((this->cardsnumber() > 0),
		  "Hand::highest_card(game):\n"
		  "  Hand is empty");

  vector<HandCard>::const_iterator highest_card = this->cards().begin();

  for (vector<HandCard>::const_iterator c = this->cards().begin() + 1;
       c != this->cards().end();
       ++c) {
    if (highest_card->less(*c))
      highest_card = c;
  } // for (c)

  return *highest_card;
} // HandCard const& Hand::highest_card(Game const& game) const
#endif

/**
 **
 ** -> result
 ** The pos of the argument is the pos in the remaining cards.
 ** It is searched, what position in all cards 'pos' stands for.
 **
 ** @param	pos	position in the unplayed card
 **
 ** @return	position the played cards
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.4
 **
 **/
unsigned
Hand::pos_to_pos_all(unsigned pos) const
{
  if ( (pos >= this->cardsnumber())
       || (this->played_.empty()) ) {
    DEBUG_ASSERTION(false,
		    "Error: file " << __FILE__ << ", line " << __LINE__ << ", "
		    << "function Hand::pos_to_pos_all(" << pos << ")\n"
		    << "  illegal value " << pos
		    << " (max value is: " << cardsnumber() - 1 << ")");
    return UINT_MAX;
  }

  unsigned n;
  // translate the position
  for (n = 0, pos += 1; pos > 0; n++)
    if (!this->played(n))
      pos--;

  return (n - 1);
} // unsigned Hand::pos_to_pos_all(pos)


/**
 **
 ** -> result
 ** The pos of the argument is the pos in all cards.
 ** It is searched, what position in the remaining cards 'pos' stands for.
 **
 ** @param	pos	position in all card
 **
 ** @return	position in the unplayed cards
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.4
 **
 **/
unsigned
Hand::pos_all_to_pos(unsigned pos) const
{
  if ( (pos >= cardsnumber_all())
       || (played_.empty()) ) {
    DEBUG_ASSERTION(false,
		    "Error: file " << __FILE__ << ", line " << __LINE__ << ", "
		    << "function Hand::pos_all_to_pos(" << pos << ")\n"
		    << "  illegal value " << pos
		    << " (max value is: " << cardsnumber_all() - 1 << ")");
  }

  unsigned n;
  // translate the position
  for (n = 0, pos += 1; pos > 0; pos--)
    if (!played(pos - 1))
      n++;

  return (n - 1);
} // unsigned Hand::pos_all_to_pos(pos)

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the player this hand belongs to
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
Player const&
Hand::player() const
{
  DEBUG_ASSERTION(this->player_,
		  "Hand::player():\n"
		  "  this->player_ == NULL");

  return *this->player_;
} // Player const& Hand::player() const

/**
 **
 ** sets the player
 **
 ** @param	player	player of this hand
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
void
Hand::set_player(Player const& player)
{
  this->player_ = &player;

  return ;
} // void Hand::set_player(Player const& player)

/**
 **
 ** -> result
 **
 ** @param	c	card to search
 **
 ** @return	position in the unplayed cards of 'c'
 **		if 'c' is the requested card, its position is returned
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.4
 **
 **/
unsigned
Hand::getpos(Card const& c) const
{
  // if the card is in the requested position, take that
  if ((this->requested_position() < this->cardsnumber())
      && (this->card(requested_position()) == c)
     )
    return this->requested_position();

  // search the card
  for (unsigned i = 0; i < this->cardsnumber(); i++)
    if (c == this->card(i))
      // the card has been found 
      return i;

  DEBUG_ASSERTION(false,
		  "Hand::getpos(Card):\n"
		  "  card is not in the hand: " << c << '\n'
		  << *this);

  // the card is not in the hand
  return UINT_MAX;
} // unsigned Hand::getpos(Card)

/**
 **
 ** -> result
 **
 ** @param	c	card to search
 **
 ** @return	position in all cards of 'c'
 **		if 'c' is the requested card, its position is returned
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.4
 **
 **/
unsigned
Hand::getpos_all(Card const& c) const
{
  // if the card is in the requested position, take that
  if ( (requested_position() < cardsnumber())
       && (card_all(requested_position()) == c)
     )
    return requested_position();

  // search the card (in played form)
  for (unsigned i = 0; i < cardsnumber_all(); i++)
    if (this->played(i))
      if (c == card_all(i))
	// the card has been found
	return i;

  // search the card
  for (unsigned i = 0; i < cardsnumber_all(); i++)
    if (c == card_all(i))
      // the card has been found
      return i;

  // the card is not in the hand
  return UINT_MAX;
} // unsigned Hand::getpos_all(Card)

/**
 **
 ** marks card 'c' as played
 **
 ** @param	c	card to play
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.4
 **
 **/
void
Hand::playcard(HandCard const& c)
{
  DEBUG_ASSERTION((this == &c.hand()),
		  "Hand::playcard(c):\n"
		  "  the card does not belong to the hand");

  this->playcard(this->getpos(c));

  return ;
} // void Hand::playcard(HandCard c)

/**
 **
 ** marks card at 'pos' as played
 **
 ** @param	pos	position of the card to play
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.4
 **
 **/
void
Hand::playcard(unsigned pos)
{
  DEBUG_ASSERTION((pos != UINT_MAX),
		  "function Hand::playcard(pos)\n"
		  "  illegal position 'UINT_MAX'"
		  << *this);


  DEBUG_ASSERTION((pos < this->cardsnumber()),
		  "function Hand::playcard(" << pos << ")\n"
		  << "  illegal position"
		  << " (maximal value is " << cardsnumber() << ")");

  DEBUG_ASSERTION(this->card(pos),
		  "Hand::playcard(" << pos << ")\n"
		  << "  empty card: " << card(pos));

  // mark the card as being played
  if (::game_status == GAMESTATUS::GAME_POVERTY_SHIFT) {
    this->played_[this->pos_to_pos_all(pos)] = pos;
  } else { //
    this->played_[this->pos_to_pos_all(pos)]
      = this->player().game().trick_current_no();
  }

  this->cards_.erase(this->cards_.begin() + pos);

  return ;
} // void Hand::playcard(pos)

/**
 **
 ** marks a played 'card' as not played
 **
 ** @param	c card to unmark
 **
 ** @return	-
 **
 ** @version	0.5
 **
 ** @author	Diether Knof
 **
 **/
void
Hand::unplaycard(HandCard const& c)
{
  DEBUG_ASSERTION((this == &c.hand()),
		  "Hand::playcard(c):\n"
		  "  the card does not belong to the hand");

  for (unsigned i = 0; i < this->cardsnumber_all(); i++) {
    if ((this->card_all(i) == c)
	&& (this->played(i))) {
      // card found:
      // unmark the card and add it to the hand
      this->played_[i] = UINT_MAX;
      unsigned j = 0; // position in 'cards_'
      for (; i > 0; i--)
	if (!this->played(i - 1))
	  j++;

      this->cards_.insert(this->cards_.begin() + j, HandCard(*this, c));

      return ;
    } // card found
  } // for (i)

  // the card has not been found
  DEBUG_ASSERTION(false,
		  "Hand::unplaycard(" << c << "):\n"
		  "  card not found:\n"
		  << *this);

  return ;
} // void Hand::unplaycard(HandCard)

/**
 **
 ** adds 'card' to the hand
 **
 ** @param	card	card to add
 **
 ** @return	-
 **
 ** @version	0.6.8
 **
 ** @author	Diether Knof
 **
 **/
void
Hand::add(Card const& card)
{
  this->cards_.push_back(HandCard(*this, card));
  this->cards_all_.push_back(HandCard(*this, card));
  this->played_.push_back(UINT_MAX);

  this->self_check();

  return ;
} // void Hand::add(Card const& card)

/**
 **
 ** adds the cards 'cards' to the hand
 **
 ** @param	cards	cards to be added
 **
 ** @return	-
 **
 ** @version	0.4.5
 **
 ** @author	Diether Knof
 **
 **/
void
Hand::add(vector<Card> const& cards)
{
  for (vector<Card>::const_iterator c = cards.begin();
       c != cards.end();
       c++)
    this->add(*c);

  this->self_check();

  return ;
} // void Hand::add(vector<Card> const& cards)

/**
 **
 ** adds the cards from 'hand' to the hand
 **
 ** @param	hand	hand to be added
 **
 ** @return	-
 **
 ** @version	0.6.8
 **
 ** @author	Diether Knof
 **
 **/
void
Hand::add(Hand const& hand)
{
  for (unsigned c = 0; c < hand.cardsnumber_all(); c++) {
    if (!hand.played(c))
      this->cards_.push_back(HandCard(*this, hand.card_all(c)));
    this->cards_all_.push_back(HandCard(*this, hand.card_all(c)));
    this->played_.push_back(hand.played_trick(c));
  } // for (c < hand.cardsnumber_all())

  this->self_check();

  return ;
} // void Hand::add(Hand const& hand)

/**
 **
 ** removes 'card' from the hand
 **
 ** @param	card	card to remove
 **
 ** @return	position of the removed card
 **
 ** @version	0.6.4
 **
 ** @author	Diether Knof
 **
 **/
unsigned
Hand::remove(HandCard const& card)
{
  DEBUG_ASSERTION((this->player_ == card.hand().player_),
		  "Hand::remove(card):\n"
		  "  the card does not belong to the same player: " << card << '\n'
		  << *this);

  unsigned const pos_all = this->getpos_all(card);
  if ((pos_all == UINT_MAX)
      && !card)
    return UINT_MAX;

  DEBUG_ASSERTION((pos_all != UINT_MAX),
		  "Hand::remove(card):"
		  "  card '" << card << "' not in the hand: \n"
		  << *this);

  if (!this->played(pos_all))
    this->cards_.erase(this->cards_.begin() + this->pos_all_to_pos(pos_all));
  this->cards_all_.erase(this->cards_all_.begin() + pos_all);
  this->played_.erase(this->played_.begin() + pos_all);

  this->self_check();

  return pos_all;
} // unsigned Hand::remove(HandCard const& card)

/**
 **
 ** removes the cards 'cards' from the hand
 **
 ** @param	cards	cards to be removeed
 **
 ** @return	-
 **
 ** @version	0.4.5
 **
 ** @author	Diether Knof
 **
 **/
void
Hand::remove(vector<HandCard> const& cards)
{
  for (vector<HandCard>::const_iterator c = cards.begin();
       c != cards.end();
       c++)
    this->remove(*c);

  this->self_check();

  return ;
} // void Hand::remove(vector<HandCard> const& cards)

/**
 **
 ** removes the cards from 'hand' from the hand
 **
 ** @param	hand	cards to be removeed
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
Hand::remove(Hand const& hand)
{
  for (vector<HandCard>::const_iterator c = hand.cards_all().begin();
       c != hand.cards_all().end();
       ++c)
    this->remove(HandCard(*this, *c));

  this->self_check();

  return ;
} // void Hand::remove(Hand const& hand)

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the requested card (to be played next)
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.1
 **
 **/
HandCard
Hand::requested_card() const
{
  if (this->requested_position() == UINT_MAX)
    return HandCard(*this, Card());

  return this->card(this->requested_position());
} // HandCard Hand::requested_card() const

/**
 **
 ** request the card in 'position' to be played next
 **
 ** @param	position	position of the requested card
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.1
 **
 **/
void
Hand::request_position(unsigned const position)
{
  this->requested_position_ = position;

  return ;
} // void Hand::request_position(unsigned const position)

/**
 **
 ** request the card in 'position_all' of all cards to be played next
 **
 ** @param	position_all	position (of all cards) of the requested card
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.1
 **
 **/
void
Hand::request_position_all(unsigned const position_all)
{
  if (!this->played(position_all))
    this->request_position(this->pos_all_to_pos(position_all));

  return ;
} // void Hand::request_position_all(unsigned const position_all)

/**
 **
 ** request the card 'card' to be played next
 **
 ** @param	card	card to be requested
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.1
 **
 **/
void
Hand::request_card(Card const card)
{
  DEBUG_ASSERTION((this->numberof(card) > 0),
		  "Hand::request_card(card):\n"
		  "  'card' " << card << " is not in the hand:\n"
		  << *this);

  this->request_position(this->getpos(card));

  return ;
} // void Hand::request_card(Card const card)

/**
 **
 ** forget the request
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.4
 **
 **/
void
Hand::forget_request()
{
  this->requested_position_ = UINT_MAX;

  return ;
} // void Hand::forget_request()

/**
 **
 ** -> result:
 ** 
 ** @param	trick	trick
 ** 
 ** @return	all cards that are valid to play in the trick
 ** 
 ** @author	Diether Knof 
 ** 
 ** @version	0.6.7
 ** 
 **/
Hand
Hand::validcards(Trick const& trick) const
{
  DEBUG_ASSERTION((this->cardsnumber() > 0),
		  "Hand::validcards(trick):\n"
		  "  The hand has no cards");

  vector<Card> hand_new; // cards for the new hand

  for (vector<HandCard>::const_iterator c = this->cards().begin();
       c != this->cards().end();
       ++c)
    if (trick.isvalid(*c, *this))
      if (std::find(hand_new.begin(),
		    hand_new.end(),
		    *c)
	  == hand_new.end())
	hand_new.push_back(*c);

  DEBUG_ASSERTION((hand_new.size() > 0),
		  "Hand::validcards(trick):\n"
		  "  The new hand has no cards");

#ifndef OUTDATED
  if (!this->player_)
    return Hand(hand_new);
#endif
  return Hand(this->player(), hand_new);
} // Hand Hand::validcards(trick)

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	whether there is a trump still on the hand
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
bool
Hand::hastrump() const
{
  for (vector<HandCard>::const_iterator c = this->cards().begin();
       c != this->cards().end();
       ++c)
    if (c->istrump())
      return true;

  return false;
} // bool Hand::hastrump()

/**
 **
 ** -> result
 **
 ** @param	tcolor	trump-color to search for
 **
 ** @return	whether there is a card with trump-color 'tcolor' on the hand
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
bool
Hand::existstcolor(Card::TColor const& tcolor) const
{
  for (vector<HandCard>::const_iterator c = this->cards().begin();
       c != this->cards().end();
       ++c)
    if (c->tcolor() == tcolor)
      return true;

  return false;
} // bool Hand::existstcolor(Card::TColor const& tcolor)

/**
 **
 ** -> result
 **
 ** @param	value	value to count
 **
 ** @return	number of cards with the value 'value'
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
unsigned
Hand::numberof(Card::Value const& value) const
{
  unsigned number = 0;

  for (vector<HandCard>::const_iterator c = this->cards().begin();
       c != this->cards().end();
       ++c)
    if (c->value() == value)
      number += 1;

  return number;
} // unsigned Hand::numberof(Card::Value const& value)

/**
 **
 ** -> result
 **
 ** @param	tcolor	trump-color to count
 **
 ** @return	number of cards with the trump-color 'tcolor'
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
unsigned
Hand::numberof(Card::TColor const& tcolor) const
{
  unsigned number = 0;

  for (vector<HandCard>::const_iterator c = this->cards().begin();
       c != this->cards().end();
       ++c)
    if (c->tcolor() == tcolor)
      number += 1;

  return number;
} // unsigned Hand::numberof(Card::TColor const& tcolor)

/**
 **
 ** -> result
 **
 ** @param	card	card to count
 **
 ** @return	number of cards 'card'
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
unsigned
Hand::numberof(Card const& card) const
{
  unsigned number = 0;

  for (vector<HandCard>::const_iterator c = this->cards().begin();
       c != this->cards().end();
       ++c)
    if (*c == card)
      number += 1;

  return number;
} // unsigned Hand::numberof(Card const& card) const

/**
 **
 ** -> result
 ** Note: 'Hand::numberof(Card)' does not cover the case (TRUMP, ACE)
 **
 ** @param	tcolor	trump-color of the card
 ** @param	value	value of the card
 **
 ** @return	number of cards with trump-color 'tcolor' and value 'value'
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
unsigned
Hand::numberof(Card::TColor const& tcolor, Card::Value const& value) const
{
  unsigned number = 0;

  for (vector<HandCard>::const_iterator c = this->cards().begin();
       c != this->cards().end();
       ++c)
    if ( (c->tcolor() == tcolor)
	 && (c->value() == value) )
      number += 1;

  return number;
} // unsigned Hand::numberof(Card::TColor, Card::Value)

/**
 **
 ** -> result
 ** Note: 'Hand::numberof(Card)' does not cover the case (TRUMP, ACE)
 **
 ** @param	color	color to count
 ** @param	game	game
 **
 ** @return	number of cards with color 'color' given the gametype 'gt'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
unsigned
Hand::numberof(Card::Color const& color, Game const& game) const
{
  return this->numberof(color, game.type(), game.rule()(Rule::DOLLEN));
} // unsigned Hand::numberof(Card::Color color, Game game) const

/**
 **
 ** -> result
 ** Note: 'Hand::numberof(Card)' does not cover the case (TRUMP, ACE)
 **
 ** @param	color		color to count
 ** @param	gametype	the gametype
 ** @param	dollen		whether dollen are allowed
 **
 ** @return	number of cards with color 'color' given the gametype and the dollen rule
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
unsigned
Hand::numberof(Card::Color const& color,
	       GameType const gametype, bool const dollen) const
{
  unsigned number = 0;

  for (vector<HandCard>::const_iterator c = this->cards().begin();
       c != this->cards().end();
       ++c)
    if ((c->color() == color)
	&& !c->Card::istrump(gametype, dollen))
      number += 1;

  return number;
} // unsigned Hand::numberof(Card::Color color, GameType gametype, bool dollen) const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of trumps on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
unsigned
Hand::numberoftrumps() const
{
  return this->numberof(Card::TRUMP);
} // unsigned Hand::numberoftrumps() const

/**
 **
 ** -> result
 **
 ** @param	tcolor	card tcolor
 ** @param	value	card value
 **
 ** @return	number of 'Card(tcolor, value)' on the hand with all cards
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
unsigned
Hand::numberofall(Card::TColor const& tcolor, Card::Value const& value) const
{
  unsigned res=0;

  for (unsigned i = 0; i < this->cardsnumber_all(); i++)
    if ((this->card_all(i).tcolor() == tcolor)
	&& (this->card_all(i).value() == value))
      ++res;

  return res;
} // unsigned Hand::numberofall(Card::TColor const& tcolor, Card::Value const& value) const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of trump aces on the hand with all cards
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
unsigned
Hand::numberofalltrumpaces() const
{
  return this->numberofall(Card::TRUMP, Card::ACE);
} // unsigned Hand::numberofalltrumpaces() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of trump kings on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
unsigned
Hand::numberoftrumpkings() const
{
  return this->numberof(Card::TRUMP, Card::KING);
} // unsigned Hand::numberoftrumpkings() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of nines on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
unsigned
Hand::numberofnines() const
{
  return this->numberof(Card::NINE);
} // unsigned Hand::numbernines()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of kings on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
unsigned
Hand::numberofkings() const
{
  return this->numberof(Card::KING);
} // unsigned Hand::numberkings()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of club queens on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
unsigned
Hand::numberofclubqueens() const
{
  return this->numberof(Card::CLUB_QUEEN);
} // unsigned Hand::numberofclubqueens()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of trump aces on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
unsigned
Hand::numberoftrumpaces() const
{
  return this->numberof(Card::TRUMP, Card::ACE);
} // unsigned Hand::numberoftrumpaces() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of trump nines on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
unsigned
Hand::numberoftrumpnines() const
{
  return this->numberof(Card::TRUMP, Card::NINE);
} // unsigned Hand::numberoftrumpnines() const

/**
 **
 ** -> result:
 ** 
 ** @param	hand	hand to compare with
 ** 
 ** @return	whether all cards of 'hand' are contained in 'this'
 ** 
 ** @author	Diether Knof 
 ** 
 ** @version	0.6.7
 ** 
 **/
bool
Hand::contains(Hand const& hand) const
{
  for (vector<HandCard>::const_iterator c = hand.cards().begin();
       c != hand.cards().end();
       ++c)
    if (this->numberof(*c) < hand.numberof(*c))
      return false;

  return true;
} // bool Hand::contains(Hand const& hand) const

/**
 **
 ** -> result:
 ** 
 ** @param	hand	hand to compare with
 ** 
 ** @return	the cards which are in 'hand' but not in 'this'
 ** 
 ** @author	Diether Knof 
 ** 
 ** @version	0.6.6
 ** 
 **/
Hand
Hand::missing_cards(Hand const& hand) const
{
  vector<Card> cards;
  for (unsigned c = 0; c < hand.cardsnumber(); ++c)
    if (this->numberof(hand.card(c)) < hand.numberof(hand.card(c)))
      cards.push_back(hand.card(c));

  return Hand(this->player(), cards);
} // Hand Hand::missing_cards(Hand const& hand) const

/**
 **
 ** -> result:
 ** compares the hands.
 ** The order of the cards is ignored.
 ** 
 ** @param	hand1	first hand
 ** @param	hand2	second hand
 ** 
 ** @return	whether the two hands are equal
 ** 
 ** @author	Diether Knof 
 ** 
 ** @version	0.6.7
 ** 
 ** @todo	compare the players
 ** 
 **/
bool
operator==(Hand const& hand1, Hand const& hand2)
{
  if ((hand1.cardsnumber_all() != hand2.cardsnumber_all())
      || (hand1.cardsnumber() != hand2.cardsnumber()))
    return false;

  vector<bool>found(hand1.cardsnumber_all(), false);

  for (unsigned c = 0; c < hand1.cardsnumber_all(); c++) {
    unsigned d;
    for (d = 0; d < hand2.cardsnumber_all(); d++) {
      if (!found[d]
	  && (hand1.card_all(c) == hand2.card_all(d))
	  && (hand1.played_trick(c) == hand2.played_trick(d)))
	break;
    } // for (d < hand2.cardsnumber_all())
    if (d < hand2.cardsnumber_all())
      found[d] = true;
    else
      return false;
  } // for (c < hand1.cardsnumber_all())

  return true;
} // bool operator==(Hand const& hand1; Hand const& hand2)

/**
 **
 ** -> result:
 ** compares the hands.
 ** The order of the cards is ignored.
 ** 
 ** @param	hand1	first hand
 ** @param	hand2	second hand
 ** 
 ** @return	whether the two hands are different
 ** 
 ** @author	Diether Knof 
 ** 
 ** @version	0.5.4
 ** 
 **/
bool
operator!=(Hand const& hand1, Hand const& hand2)
{
  return !(hand1 == hand2);
} // bool operator!=(Hand const& hand1; Hand const& hand2)

/**
 **
 ** write the hand on 'ostr'
 **
 ** @param	ostr	stream to write the hand to
 ** @param	hand	hand to write
 **
 ** @return	output stream
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
ostream&
operator<<(ostream& ostr, Hand const& hand)
{
  for(unsigned i = 0; i < hand.cardsnumber_all(); i++) {
    ostr << hex << i << dec << "  " << hand.card_all(i);
    if (hand.played(i))
      ostr << "\t(played " << setw(2) << hand.played_trick(i) << ")";
    ostr << "\n";
  } // for (i < hand.cardsnumber_all())

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