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


#include "constants.h"
#include "hand.h"

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

/**
 **
 ** constructor
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
Hand::Hand() :
  card_p(0),
  card_all_p(0),
  played_p(cardsnumber_all(), UINT_MAX),
requested_position_p(UINT_MAX),
  player_(NULL)
{
  return ;
} // Hand::Hand()

/**
 **
 ** constructor
 **
 ** @param	hand	hand to copy
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
Hand::Hand(Hand const& hand):
  card_p(hand.card_p),
  card_all_p(hand.card_all_p),
  played_p(hand.played_p),
requested_position_p(hand.requested_position()),
  player_(hand.player_)
{
  return ;
} // Hand::Hand(Hand)

/**
 **
 ** 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):
  card_p(hand.card_p),
  card_all_p(hand.card_all_p),
  played_p(hand.played_p),
requested_position_p(hand.requested_position()),
  player_(&player)
{
  return ;
} // Hand::Hand(Player const& player, Hand const& hand)

/**
 **
 ** constructor
 **
 ** @param	cards	cards of the hand
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
Hand::Hand(vector<Card> const& cards) :
  card_p(cards),
  card_all_p(cards),
  played_p(cards.size(), UINT_MAX),
  requested_position_p(UINT_MAX),
  player_(NULL)
{
  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) :
  card_p(cards),
  card_all_p(cards),
  played_p(cards.size(), UINT_MAX),
  requested_position_p(UINT_MAX),
  player_(&player)
{
  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)
{
  this->card_p = hand.card_p;
  this->card_all_p = hand.card_all_p;
  this->played_p = hand.played_p;
  this->requested_position_p = 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) :
  card_p(),
  card_all_p(),
  played_p(),
  requested_position_p(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);

    Card card(card_name);
    if (!card)
      break;
    this->card_p.push_back(card);
    this->card_all_p.push_back(card);

    DK::Utils::String::remove_blanks(line);
    if (line.empty()) {
      // the card has not been played, yet
      this->played_p.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_p.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()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of cards still in the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
unsigned
Hand::cardsnumber() const
{
  return this->card_p.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
 **
 **/
Card 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->card_p[i],
		  "Hand::card(i):\n"
		  "  empty card " << i << ":\n"
		  << *this);

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

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	all (not played) cards
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
vector<Card> const&
Hand::cards() const
{
  return this->card_p;
} // vector<Card> const& Hand::cards() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	all (not played) cards, but only one of multiple same
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.3
 **
 **/
vector<Card>
Hand::cards_single() const
{
  vector<Card> cards;

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

    if (c2 == cards.end())
      cards.push_back(*c);
  } // for (c \in this->card_p)

  return cards;
} // vector<Card> 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->card_all_p.size();
} // unsigned Hand::cardsnumber_all() const

/**
 **
 ** -> result
 **
 ** @param	i	cardnumber
 **
 ** @return	the card number 'i'
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
Card 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->card_all_p[i],
		  "Hand::card_all(i):\n"
		  "  empty card " << i << ":\n"
		  << *this);

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

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	all cards
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
vector<Card> const&
Hand::cards_all() const
{
  return this->card_all_p;
} // vector<Card> const& Hand::cards_all() 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_p[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
 **
 **/
Card const&
Hand::highest_card() const
{
  DEBUG_ASSERTION((this->cardsnumber() > 0),
		  "Hand::highest_card(game):\n"
		  "  Hand is empty");

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

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

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

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

#ifndef 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
 **
 **/
Card const&
Hand::highest_card(Game const& game) const
{
  DEBUG_ASSERTION((this->cardsnumber() > 0),
		  "Hand::highest_card(game):\n"
		  "  Hand is empty");

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

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

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

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

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

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the position of the requested card (to be played next)
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.1
 **
 **/
unsigned
Hand::requested_position() const
{
  return this->requested_position_p;
} // unsigned Hand::requested_position() 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_p = 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_p = UINT_MAX;

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


/**
 **
 ** -> 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 >= cardsnumber())
       || (played_p.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 (!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_p.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 this hand belongs to to 'player'
 **
 ** @param	player	new player
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
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(Card const& c)
{
  this->playcard(getpos(c));

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

/**
 **
 ** 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_p[this->pos_to_pos_all(pos)] = pos;
  } else { //
    this->played_p[this->pos_to_pos_all(pos)]
      = ::party.game().trick_current_no();
  }

  this->card_p.erase(this->card_p.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(Card const& c)
{
  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_p[i] = UINT_MAX;
      unsigned j = 0; // position in 'card_p'
      for (; i > 0; i--)
	if (!this->played(i - 1))
	  j++;

      this->card_p.insert(this->card_p.begin() + j, 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(Card)

/**
 **
 ** adds 'card' to the hand
 **
 ** @param	card	card to add
 **
 ** @return	-
 **
 ** @version	0.4.5
 **
 ** @author	Diether Knof
 **
 **/
void
Hand::add(Card const& card)
{
  this->card_p.push_back(card);
  this->card_all_p.push_back(card);
  this->played_p.push_back(UINT_MAX);

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

  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.5.4
 **
 ** @author	Diether Knof
 **
 **/
void
Hand::add(Hand const& hand)
{
  for (unsigned c = 0; c < hand.cardsnumber_all(); c++) {
    this->card_p.push_back(hand.card_all(c));
    this->card_all_p.push_back(hand.card_all(c));
    this->played_p.push_back(hand.played_trick(c));
  } // for (c < hand.cardsnumber_all())

  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(Card const& card)
{
  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->card_p.erase(this->card_p.begin() + this->pos_all_to_pos(pos_all));
  this->card_all_p.erase(this->card_all_p.begin() + pos_all);
  this->played_p.erase(this->played_p.begin() + pos_all);

  return pos_all;
} // unsigned Hand::remove(Card 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<Card> const& cards)
{
  for (vector<Card>::const_iterator c = cards.begin();
       c != cards.end();
       c++)
    this->remove(*c);

  return ;
} // void Hand::remove(vector<Card> 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<Card>::const_iterator c = hand.cards_all().begin();
       c != hand.cards_all().end();
       ++c)
    this->remove(*c);

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

/**
 **
 ** -> 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<Card>::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	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<Card>::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)
