/**********************************************************************
 *
 *   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 "../misc/setting.h"
#include "../utils/string.h"

/**
 **
 ** constructor
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.5.4
 **
 ** @author	Diether Knof
 **
 **/
Hand::Hand() :
  card_p(0),
  card_all_p(0),
  played_p(cardsnumber_all(), UINT_MAX),
requested_position_p(UINT_MAX)
#if 0
cardsnumber_p(::party.rule()(Rule::NUMBER_OF_CARDS_ON_HAND)),
  card_p(cardsnumber()),
  cardsnumber_all_p(cardsnumber()),
  card_all_p(cardsnumber_all()),
  played_p(cardsnumber_all(), UINT_MAX),
requested_position_p(UINT_MAX)
#endif
{
  DEBUG_CALLING(INFO_HAND && INFO_INIT,
		"Hand::Hand()");

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_INIT,
		  "Hand::Hand()");
} // Hand::Hand()

/**
 **
 ** constructor
 **
 ** @param	hand	hand to copy
 **
 ** @return	-
 **
 ** @version	0.5.4
 **
 ** @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())
{
  DEBUG_CALLING(INFO_HAND && INFO_INIT,
		"Hand::Hand(Hand)");

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_INIT,
		  "Hand::Hand(Hand)");
} // Hand::Hand(Hand)

/**
 **
 ** copy operator
 **
 ** @param	hand	hand to copy
 **
 ** @return	copied hand
 **
 ** @version	0.5.4
 **
 ** @author	Diether Knof
 **
 **/
Hand&
Hand::operator=(Hand const& hand)
{
  DEBUG_CALLING(INFO_HAND && INFO_OTHER_FUNCTION,
		"Hand::operator=(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();

  DEBUG_RETURNING(*this,
		  INFO_HAND && INFO_OTHER_FUNCTION,
		  "Hand::operator=(hand)");
} // Hand& Hand::operator=(Hand const& hand)

/**
 **
 ** constructor
 **
 ** @param	cardno	number of cards
 **
 ** @return	-
 **
 ** @version	0.5.4
 **
 ** @author	Diether Knof
 **
 **/
Hand::Hand(unsigned const cardno) :
  card_p(cardno),
  card_all_p(cardno),
  played_p(cardno),
requested_position_p(cardno)
{
  DEBUG_CALLING(INFO_HAND && INFO_INIT,
		"Hand::Hand(cardno)");

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_INIT,
		  "Hand::Hand(cardno)");
} // Hand::Hand(unsigned const cardno)

/**
 **
 ** constructor
 **
 ** @param	cards	cards of the hand
 **
 ** @return	-
 **
 ** @version	0.5.4
 **
 ** @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)
{
  DEBUG_CALLING(INFO_HAND && INFO_INIT,
		"Hand::Hand(cards)");

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_INIT,
		  "Hand::Hand(cards)");
} // Hand::Hand(vector<Card> const& cards)

/**
 **
 ** 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)
{
  DEBUG_CALLING(INFO_HAND && INFO_INIT,
		"Hand::Hand(istr)");

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

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_INIT,
		  "Hand::Hand(istr)");
} // Hand::Hand(istream& istr)

/**
 **
 ** destructor
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.5.4
 **
 ** @author	Diether Knof
 **
 **/
Hand::~Hand()
{
  DEBUG_CALLING(INFO_HAND && INFO_INIT,
		"Hand::~Hand()");

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_INIT,
		  "Hand::~Hand()");
} // Hand::~Hand()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of cards still in the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **      
 **
 **/
unsigned
Hand::cardsnumber() const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::cardsnumber()");

  DEBUG_RETURNING(this->card_p.size(),
		  INFO_HAND && INFO_VALUE,
		  "Hand::cardsnumber()");
} // 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_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::card(i)");     

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

  DEBUG_RETURNING(this->card_p[i],
		  INFO_HAND && INFO_VALUE,
		  "Hand::card(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
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::cards()");     

  DEBUG_RETURNING(this->card_p,
		  INFO_HAND && INFO_VALUE,
		  "Hand::cards()");
} // 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
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::cards_single()");     

  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)

  DEBUG_RETURNING(cards,
		  INFO_HAND && INFO_VALUE,
		  "Hand::cards_single()");
} // 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
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::cardsnumber_all()");

  DEBUG_RETURNING(this->card_all_p.size(),
		  INFO_HAND && INFO_VALUE,
		  "Hand::cardsnumber_all()");
} // 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_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::card_all(i)");

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

  DEBUG_RETURNING(this->card_all_p[i],
		  INFO_HAND && INFO_VALUE,
		  "Hand::card_all(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
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::cards_all()");     

  DEBUG_RETURNING(this->card_all_p,
		  INFO_HAND && INFO_VALUE,
		  "Hand::cards_all()");
} // 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
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::played(i)");

  DEBUG_RETURNING((this->played_trick(i) != UINT_MAX),
		  INFO_HAND && INFO_VALUE,
		  "Hand::played(i)");
} // 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_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::played_trick(unsigned const i)");

  DEBUG_ASSERTION((i < this->cardsnumber_all()),
		  "Hand::played()\n"
		  "  illegal value i = " << i
		  << " (>= " << this->cardsnumber_all() << ")");

  DEBUG_RETURNING(this->played_p[i],
		  INFO_HAND && INFO_VALUE,
		  "Hand::played_trickcardno(unsigned const i)");
} // unsigned Hand::played_trick(i)

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the requested card (to be played next)
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.1
 **
 **/
Card
Hand::requested_card() const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::requested_card()");

  if (this->requested_position() == UINT_MAX)
    DEBUG_RETURNING(Card(),
		    INFO_HAND && INFO_VALUE,
		    "Hand::requested_card()");

  DEBUG_RETURNING(this->card(this->requested_position()),
		  INFO_HAND && INFO_VALUE,
		  "Hand::requested_card()");
} // 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
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::requested_position()");

  DEBUG_RETURNING(this->requested_position_p,
		  INFO_HAND && INFO_VALUE,
		  "Hand::requested_position()");
} // 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)
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::request_position(position)");

  this->requested_position_p = position;

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_VALUE,
		  "Hand::request_position(position)");
} // 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)
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::request_position_all(position_all)");

  this->request_position(this->pos_all_to_pos(position_all));

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_VALUE,
		  "Hand::request_position_all(position_all)");
} // 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_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::request_card(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));

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_VALUE,
		  "Hand::request_card(card)");
} // void Hand::request_card(Card const card)

/**
 **
 ** forget the request
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.4
 **
 **/
void
Hand::forget_request()
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::forget_request()");

  this->requested_position_p = UINT_MAX;

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_VALUE,
		  "Hand::forget_request()");
} // 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
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::pos_to_pos_all(unsigned pos)");

  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 << ")");
    DEBUG_RETURNING(UINT_MAX,INFO_HAND && INFO_VALUE,"Hand::pos_to_pos_all(unsigned pos)");
  }

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

  DEBUG_RETURNING(n - 1,
		  INFO_HAND && INFO_VALUE,
		  "Hand::pos_to_pos_all(unsigned pos)");
} // 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
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,"Hand::pos_all_to_pos(unsigned pos)");

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

  DEBUG_RETURNING(n - 1,
		  INFO_HAND && INFO_VALUE,
		  "Hand::pos_all_to_pos(unsigned pos)");
} // unsigned Hand::pos_all_to_pos(pos)

/**********************************************************************
 *
 **    bool Hand::hastrump()
 *
 **    Parameters:  
 *
 **    Result: true if a trump is still on hand
 **            false otherwise
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/

bool
Hand::hastrump() const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,"Hand::hastrump() ");

  for (unsigned i = 0; i < cardsnumber(); i++)
    if (card(i).istrump())
      DEBUG_RETURNING(true,INFO_HAND && INFO_VALUE,"Hand::hastrump() ");

  DEBUG_RETURNING(false,INFO_HAND && INFO_VALUE,"Hand::hastrump() ");
} // bool Hand::hastrump()


/**********************************************************************
 *
 **    unsigned Hand::numberof(Card::Value)
 *
 **    Parameters:  
 *
 **    Result: number of cards with the given value on hand
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/

unsigned
Hand::numberof(Card::Value const& v) const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"numberof(Card::Value)");

  unsigned res=0;
  for (unsigned i = 0; i < cardsnumber(); i++)
    if (card(i).value() == v)
      res++;

  DEBUG_RETURNING(res,
		  INFO_HAND && INFO_VALUE,
		  "numberof(Card::Value)");
} // unsigned Hand::numberof(Card::Value)


/**********************************************************************
 *
 **    unsigned Hand::numberof(Card::Value, Card::TColor)
 *
 **    Parameters:  
 *
 **    Result: number of cards with the given value on hand
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/

unsigned
Hand::numberof(Card::TColor const& c, Card::Value const& v) const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"numberof(Card::TColor, Card::Value)");

  unsigned res=0;
  for (unsigned i = 0; i < cardsnumber(); i++)
    if ((card(i).tcolor() == c) &&
	(card(i).value() == v))
      res++;

  DEBUG_RETURNING(res,
		  INFO_HAND && INFO_VALUE,
		  "numberof(Card::TColor, Card::Value)");
} // unsigned Hand::numberof(Card::TColor, Card::Value)


/**********************************************************************
 *
 **    unsigned Hand::numberof(Card::TColor)
 *
 **    Parameters:  
 *
 **    Result: number of cards with the given color on hand
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/

unsigned
Hand::numberof(Card::TColor const& c) const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"numberof(Card::TColor)");

  unsigned res = 0;
  for (unsigned i = 0; i < this->cardsnumber(); i++)
    if (this->card(i).tcolor() == c)
      res += 1;

  DEBUG_RETURNING(res,
		  INFO_HAND && INFO_VALUE,
		  "numberof(Card::TColor)");
} // unsigned Hand::numberof(Card::TColor)

/**********************************************************************
 *
 **    unsigned Hand::numberof(Card::Color, gametype t)
 *
 **    Parameters:  
 *
 **    Result: number of cards with the given color on hand for gametype t
 *
 **    Version: 0.3.7
 *
 **    Description: 
 **      
 *
 **********************************************************************/

unsigned
Hand::numberof(Card::Color const& c,GameType const& t) const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"numberof(Card::Color,gametype)");

  unsigned res=0;
  for (unsigned i = 0; i < cardsnumber(); i++)
    if (card(i).color() == c && !card(i).istrump(t))
      res++;

  DEBUG_RETURNING(res,
		  INFO_HAND && INFO_VALUE,
		  "numberof(Card::Color,gametype)");
} // unsigned Hand::numberof(Card::Color)


/**********************************************************************
 *
 **    unsigned Hand::numberof(Card)
 *
 **    Parameters:  
 *
 **    Result: number of cards with the given value on hand
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/

unsigned
Hand::numberof(Card const& c) const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"numberof(Card)");

  unsigned res=0;
  for (unsigned i = 0; i < cardsnumber(); i++)
    if (card(i) == c)
      res++;

  DEBUG_RETURNING(res,
		  INFO_HAND && INFO_VALUE,
		  "numberof(Card)");
} // unsigned Hand::numberof(Card)


/**********************************************************************
 *
 **    unsigned Hand::numberoftrumps()
 *
 **    Parameters:  
 *
 **    Result: number of trumps on hand
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/

unsigned
Hand::numberoftrumps() const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"numberoftrumps()");

  DEBUG_RETURNING(numberof(Card::TRUMP),
		  INFO_HAND && INFO_VALUE,
		  "numberoftrumps()");
} // unsigned Hand::numberoftrumps()


/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of trump aces on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
unsigned
Hand::numberoftrumpaces() const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"numberoftrumpaces()");

  DEBUG_RETURNING(this->numberof(Card::TRUMP, Card::ACE),
		  INFO_HAND && INFO_VALUE,
		  "numberoftrumpaces()");
} // 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
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"numberoftrumpnines()");

  DEBUG_RETURNING(this->numberof(Card::TRUMP, Card::NINE),
		  INFO_HAND && INFO_VALUE,
		  "numberoftrumpnines()");
} // unsigned Hand::numberoftrumpnines() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of trump kings on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
unsigned
Hand::numberoftrumpkings() const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"numberoftrumpkings()");

  DEBUG_RETURNING(this->numberof(Card::TRUMP, Card::KING),
		  INFO_HAND && INFO_VALUE,
		  "numberoftrumpkings()");
} // unsigned Hand::numberoftrumpkings() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of nines on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
unsigned
Hand::numberofnines() const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"numberofnines()");

  DEBUG_RETURNING(this->numberof(Card::NINE),
		  INFO_HAND && INFO_VALUE,
		  "numberofnines()");
} // unsigned Hand::numbernines()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of kings on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
unsigned
Hand::numberofkings() const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"numberofkings()");

  DEBUG_RETURNING(this->numberof(Card::KING),
		  INFO_HAND && INFO_VALUE,
		  "numberofkings()");
} // unsigned Hand::numberkings()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of club queens on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
unsigned
Hand::numberofclubqueens() const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"numberofclubqueens()");

  DEBUG_RETURNING(this->numberof(Card::CLUB_QUEEN),
		  INFO_HAND && INFO_VALUE,
		  "numberofclubqueens()");
} // unsigned Hand::numberofclubqueens()

/**********************************************************************
 *
 **    bool Hand::existstcolor(Card::TColor tcolor)
 *
 **    Parameters:  Card::TColor for which should be checked if 
 **                 an card of this color is on this hand
 *
 **    Result: 
 **      true : if one card one hand has the same Card::TColor as 'tcolor'
 *
 **      false: otherwise 
 *
 **    Version: Alpha
 *
 **    Description: 
 *
 **********************************************************************/

bool
Hand::existstcolor(Card::TColor const& tcolor) const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"existstcolor()");

  DEBUG_RETURNING((numberof(tcolor) > 0),
		  INFO_HAND && INFO_VALUE,
		  "existstcolor()");
} // bool Hand::existscolor(Card::TColor)


/**********************************************************************
 *
 **    unsigned Hand::getpos(Card const&)
 *
 **    Parameters:  card, that is searched in the remaining cards of the hand
 *
 **    Result:  Number of the card, if it is in the hand
 **             otherwise UINT_MAX
 *
 **    Version: Alpha
 *
 **    Description: see 'result'
 **      
 *
 **********************************************************************/
unsigned
Hand::getpos(Card const& c) const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::getpos(Card const& c)");

  // if the card is in the requested position, take that
  if ((this->requested_position() < this->cardsnumber())
      && (this->card(requested_position()) == c)
     )
    DEBUG_RETURNING(this->requested_position(),
		    INFO_HAND && INFO_VALUE,
		    "Hand::getpos(Card const& c)");

  // search the card
  for (unsigned i = 0; i < this->cardsnumber(); i++)
    if (c == this->card(i))
      // the card has been found 
      DEBUG_RETURNING(i,
		      INFO_HAND && INFO_VALUE,
		      "Hand::getpos(Card const& c)");

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

  // the card is not in the hand
  DEBUG_RETURNING(UINT_MAX,
		  INFO_HAND && INFO_VALUE,
		  "Hand::getpos(Card const& c)");
} // unsigned Hand::getpos(Card)


/**********************************************************************
 *
 **    unsigned Hand::getpos_all(Card const&)
 *
 **    Parameters:  card, that is searched in all cards of the hand
 *
 **    Result:  Number of the card, if it is in the hand
 **             otherwise UINT_MAX
 *
 **    Version: Alpha
 *
 **    Description: see 'result'
 **      
 *
 **********************************************************************/
unsigned
Hand::getpos_all(Card const& c) const
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"Hand::getpos_all(Card const& c)");

  // if the card is in the requested position, take that
  if ( (requested_position() < cardsnumber())
       && (card_all(requested_position()) == c)
     )
    DEBUG_RETURNING(requested_position(),
		    INFO_HAND && INFO_VALUE,
		    "Hand::getpos_all(Card const& c)");

  // 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
	DEBUG_RETURNING(i,
			INFO_HAND && INFO_VALUE,
			"Hand::getpos_all(Card const& c)");

  // search the card
  for (unsigned i = 0; i < cardsnumber_all(); i++)
    if (c == card_all(i))
      // the card has been found
      DEBUG_RETURNING(i,
		      INFO_HAND && INFO_VALUE,
		      "Hand::getpos_all(Card const& c)");

  // the card is not in the hand
  DEBUG_RETURNING(UINT_MAX,
		  INFO_HAND && INFO_VALUE,
		  "Hand::getpos_all(Card const& c)");
} // 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)
{
  DEBUG_CALLING(INFO_HAND && INFO_GAMEPLAY,
		"Hand::playcard(Card const& c)");

  this->playcard(getpos(c));

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_GAMEPLAY,
		  "Hand::playcard(Card const& c)");
} // 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_CALLING(INFO_HAND && INFO_GAMEPLAY,"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);

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_GAMEPLAY,
		  "Hand::playcard(unsigned pos)");
} // 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)
{
  DEBUG_CALLING(INFO_HAND && INFO_GAMEPLAY,
		"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);

      DEBUG_RETURNING(VOID,
		      INFO_HAND && INFO_GAMEPLAY,
		      "Hand::playcard(Card const& c)");
    } // card found
  } // for (i)

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

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_GAMEPLAY,
		  "Hand::unplaycard(Card const& c)");
} // 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)
{
  DEBUG_CALLING(INFO_HAND && INFO_GAMEPLAY,
		"Hand::add(Card)");

  this->card_p.push_back(card);
  this->card_all_p.push_back(card);
  this->played_p.push_back(UINT_MAX);

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_GAMEPLAY,
		  "Hand::add(Card)");
} // 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)
{
  DEBUG_CALLING(INFO_HAND && INFO_GAMEPLAY,
		"Hand::add(cards)");

  for (vector<Card>::const_iterator c = cards.begin();
       c != cards.end();
       c++)
    this->add(*c);

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_GAMEPLAY,
		  "Hand::add(cards)");
} // 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)
{
  DEBUG_CALLING(INFO_HAND && INFO_GAMEPLAY,
		"Hand::add(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())

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_GAMEPLAY,
		  "Hand::add(hand)");
} // 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)
{
  DEBUG_CALLING(INFO_HAND && INFO_GAMEPLAY,
		"Hand::remove(Card)");

  unsigned const pos_all = this->getpos_all(card);
  if ((pos_all == UINT_MAX)
      && !card)
    DEBUG_RETURNING(UINT_MAX,
		    INFO_HAND && INFO_GAMEPLAY,
		    "Hand::remove(Card)");

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

  DEBUG_RETURNING(pos_all,
		  INFO_HAND && INFO_GAMEPLAY,
		  "Hand::remove(Card)");
} // 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)
{
  DEBUG_CALLING(INFO_HAND && INFO_GAMEPLAY,
		"Hand::remove(cards)");

  for (vector<Card>::const_iterator c = cards.begin();
       c != cards.end();
       c++)
    this->remove(*c);

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_GAMEPLAY,
		  "Hand::remove(cards)");
} // void Hand::remove(vector<Card> const& cards)

/**
 **
 ** removes the cards from 'hand' from the hand
 **
 ** @param	hand	cards to be removeed
 **
 ** @return	-
 **
 ** @version	0.5.4
 **
 ** @author	Diether Knof
 **
 **/
void
Hand::remove(Hand const& hand)
{
  DEBUG_CALLING(INFO_HAND && INFO_GAMEPLAY,
		"Hand::remove(hand)");

  for (unsigned c = 0; c < hand.cardsnumber_all(); c++)
    this->remove(hand.card_all(c));

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_GAMEPLAY,
		  "Hand::remove(hand)");
} // void Hand::remove(Hand const& hand)

#ifdef OUTDATED
/**
 **
 ** sorts the cards (as set in the settings)
 **
 ** @param	-
 **
 ** @return	whether the order has benn changed
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.4
 **
 ** @todo	update the requested position
 **
 **/
bool
Hand::sort()
{
  DEBUG_CALLING(INFO_HAND && INFO_OTHER_FUNCTION,
		"Hand::sort()");

  bool changed = false;

  if (::setting(Setting::CARDS_ORDER).sorted()) {
    // DK: a bad bubble sort, but we have at max 12 cards

    for (unsigned c1 = 0; c1 < this->cardsnumber_all(); c1++)
      for (unsigned c2 = c1 + 1; c2 < this->cardsnumber_all(); c2++)
	if (Card::relative_position(this->card_all(c1), this->card_all(c2))
	    > 0) {
	  std::swap(this->card_all_p[c1], this->card_all_p[c2]);
	  std::swap(this->played_p[c1], this->played_p[c2]);
	  changed = true;
	} // card 1 < card 2

    // make the cards on the hand sorted
    this->card_p.clear();
    for (unsigned c = 0; c < this->card_all_p.size(); ++c)
      if (this->played_p[c] == UINT_MAX)
	this->card_p.push_back(this->card_all_p[c]);

    // forget the requested position
    this->requested_position_p = UINT_MAX;
  } // bubble sort over all cards

  DEBUG_RETURNING(changed,
		  INFO_HAND && INFO_OTHER_FUNCTION,
		  "Hand::sort()");
} // bool Hand::sort()


/**
 **
 ** mix the (order of the) cards
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.2
 **
 ** @todo	update the requested position
 **
 **/
void
Hand::mix()
{
  DEBUG_CALLING(INFO_HAND && INFO_OTHER_FUNCTION,"Hand::mix()");

  if (::setting(Setting::CARDS_ORDER).mixed()) {
    unsigned r; // random number
    for (unsigned c = 0; c < this->cardsnumber_all(); c++) {
      r = RAND(c);
      swap(this->card_all_p[c], this->card_all_p[r]);
      swap(this->played_p[c], this->played_p[r]);
    } // for (c)

    // make the cards on the hand mixed
    this->card_p.clear();
    for (unsigned c = 0; c < this->card_all_p.size(); ++c)
      if (this->played_p[c] == UINT_MAX)
	this->card_p.push_back(this->card_all_p[c]);

    // forget the requested position
    this->requested_position_p = UINT_MAX;
  } // if (::setting(Setting::CARDS_ORDER).mixed())

  DEBUG_RETURNING(VOID,
		  INFO_HAND && INFO_OTHER_FUNCTION,
		  "Hand::mix()");
} // void Hand::mix()
#endif

/**********************************************************************
 *
 **    Hand Hand::validcards()
 *
 **    Parameters: trick, for which the valid cards are selected
 *
 **    Result: new hand with the valid cards
 *
 **    Version: Alpha
 *
 **    Description: selects the valid cards for the trick from the hand
 *
 *
 *
 **********************************************************************/
Hand
Hand::validcards(Trick const& trick) const
{
  DEBUG_CALLING(INFO_HAND && INFO_GAMEPLAY,
		"Hand::validcards(Trick const& trick)");

  DEBUG_ASSERTION((this->cardsnumber() > 0),
		  "Hand::validcards(trick):\n"
		  "  The hand has no cards");

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

  for (unsigned i = 0; i < this->cardsnumber(); i++)
    if (trick.isvalid(this->card(i), *this))
      if (std::find(hand_new.begin(),
		    hand_new.end(),
		    card(i))
	  == hand_new.end())
	hand_new.push_back(card(i));

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

  DEBUG_RETURNING(Hand(hand_new),
		  INFO_HAND && INFO_GAMEPLAY,
		  "Hand::validcards(Trick const& trick)");
} // Hand Hand::validcards(trick)

/**
 **
 ** -> 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.5.4
 ** 
 **/
bool
operator==(Hand const& hand1, Hand const& hand2)
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"operator==(Hand, Hand)");

  if ((hand1.cardsnumber_all() != hand2.cardsnumber_all())
      || (hand1.cardsnumber() != hand2.cardsnumber()))
    DEBUG_RETURNING(false,
		    INFO_HAND && INFO_VALUE,
		    "operator==(Hand, Hand) = 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
      DEBUG_RETURNING(false,
		      INFO_HAND && INFO_VALUE,
		      "operator==(Hand, Hand) = false");
  } // for (c < hand1.cardsnumber_all())

  DEBUG_RETURNING(true,
		  INFO_HAND && INFO_VALUE,
		  "operator==(Hand, Hand) = 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)
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"operator!=(Hand, Hand)");

  DEBUG_RETURNING(!(hand1 == hand2),
		  INFO_HAND && INFO_VALUE,
		  "operator!=(Hand, Hand)");
} // bool operator!=(Hand const& hand1; Hand const& hand2)

/**********************************************************************
 *
 **    ostream& operator<<(ostream& ostr, THand const& hand)
 *
 **    Parameters:  output stream nad to be printed
 *
 **    Result: 
 *
 **    Version: Alpha
 *
 **    Description: 
 **      
 *
 **********************************************************************/
ostream&
operator<<(ostream& ostr, Hand const& hand)
{
  DEBUG_CALLING(INFO_HAND && INFO_IO,
		"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())

  DEBUG_RETURNING(ostr,
		  INFO_HAND && INFO_IO,
		  "operator<<(ostream& ostr, Hand const& hand)");
} // ostream operator<<(ostream, Hand)
