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

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


/**
 ** constructor
 **
 ** @param	startplayer	the player, who has to play the first card
 **
 ** @return	-
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Trick::Trick(Player const& startplayer) :
card_p(),
  game_p(&(startplayer.game())),
  startplayer_p(&startplayer),
  winnerplayer_p(NULL),
intrickpile_p(false)
{
  DEBUG_CALLING(INFO_TRICK && INFO_INIT,
		"Trick::Trick(startplayer)");

  DEBUG_RETURNING(VOID,
		  INFO_TRICK && INFO_INIT,
		  "Trick::Trick(startplayer)");
} // Trick::Trick(Player const& startplayer)

/**
 ** constructor
 **
 ** @param	istr	the stream to read the trick from
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
Trick::Trick(istream& istr) :
card_p(),
  game_p(&(::party.game())),
  startplayer_p(),
  winnerplayer_p(NULL),
intrickpile_p(false)
{
  DEBUG_CALLING(INFO_TRICK && INFO_INIT,
		"Trick::Trick(istr)");

  string line;
  getline(istr, line);
  if (DK::Utils::String::word_first(line) != "Startplayer:")
    DEBUG_RETURNING(VOID,
		    INFO_TRICK && INFO_INIT,
		    "Trick::Trick(istr) - error");

  DK::Utils::String::word_first_remove(line);
  this->startplayer_p = &(::party.game().player(static_cast<unsigned>(atoi(line.c_str()))));

  while(istr.good()) {
    getline(istr, line);
    if (line.empty())
      break;
    if (DK::Utils::String::word_first(line) == "Winner:")
      break;

    // the line is like: 1: club ace
    DK::Utils::String::word_first_remove(line);
    DK::Utils::String::remove_blanks(line);
    this->card_p.push_back(Card(line));
  } // for (this->actcardno_p)
  if (line.empty()
      || !istr.good())
    DEBUG_RETURNING(VOID,
		    INFO_TRICK && INFO_INIT,
		    "Trick::Trick(istr)");

  if (DK::Utils::String::word_first(line) == "Winner:") {
    DK::Utils::String::word_first_remove(line);
    this->winnerplayer_p = &(this->game().player(static_cast<unsigned>(atoi(line.c_str()))));
  } // if (DK::Utils::String::word_first(line) == "Winner:")

  DEBUG_RETURNING(VOID,
		  INFO_TRICK && INFO_INIT,
		  "Trick::Trick(istr)");
} // Trick::Trick(istream& istr)

/**
 ** constructor
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Trick::Trick() :
card_p(),
  game_p(NULL),
  startplayer_p(NULL),
  winnerplayer_p(NULL),
intrickpile_p(false)
{
  DEBUG_CALLING(INFO_TRICK && INFO_INIT,
		"Trick::Trick()");

  DEBUG_RETURNING(VOID,
		  INFO_TRICK && INFO_INIT,
		  "Trick::Trick()");
} // Trick::Trick()

/**
 ** destructor
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Trick::~Trick()
{
  DEBUG_CALLING(INFO_TRICK && INFO_INIT,
		"Trick::~Trick()");

  DEBUG_RETURNING(VOID,
		  INFO_TRICK && INFO_INIT,
		  "Trick::~Trick()");
} // Trick::~Trick()

/**
 ** copy constructor
 **
 ** @param	trick	the trick to copy
 **
 ** @return	-
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Trick::Trick(Trick const& trick) :
card_p(trick.card_p),
  game_p(trick.game_p),
  startplayer_p(trick.startplayer_p),
  winnerplayer_p(trick.winnerplayer_p),
intrickpile_p(trick.intrickpile_p)
{
  DEBUG_CALLING(INFO_TRICK && INFO_INIT,
		"Trick::Trick(trick)");

  DEBUG_RETURNING(VOID,
		  INFO_TRICK && INFO_INIT,
		  "Trick::Trick(trick)");
} // Trick::Trick(Trick const& trick)

/**
 ** copy method
 **
 ** @param	trick	the trick to copy
 **
 ** @return	the trick
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Trick&
Trick::operator=(Trick const& trick)
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::operator=(Trick const& trick)");

  this->card_p = trick.card_p;
  this->game_p = trick.game_p;
  this->startplayer_p = trick.startplayer_p;
  this->winnerplayer_p = trick.winnerplayer_p;
  this->intrickpile_p = trick.intrickpile_p;

  DEBUG_RETURNING(*this,
		  INFO_TRICK && INFO_VALUE,
		  "Trick::operator=(Trick const& trick)");
} // Trick& Trick::operator=(Trick const& trick)

/**
 **
 ** output of the trick
 **
 ** @param	ostr	output stream
 **
 ** @return	output stream
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
ostream&
Trick::out(ostream& ostr) const
{
  DEBUG_CALLING(INFO_TRICK && INFO_IO,
		"Trick::out(ostream& ostr)");

  ostr << "Startplayer: " << this->startplayer().no() << "\n";
  for(unsigned i = 0; i < this->actcardno(); i++) {
    ostr << this->player_of_card(i).no() << ": "
      << this->card(i) << "\n";
  }

  if (this->isfull())
    ostr << "Winner: " << this->winnerplayer().no() << "\n";

  DEBUG_RETURNING(ostr,
		  INFO_TRICK && INFO_IO,
		  "Trick::out(ostream& ostr)");
} // ostream& Trick::out(ostream& ostr) const

/**
 **
 ** output of the trick
 **
 ** @param	ostr	output stream
 ** @param	trick	Trick to be put in the output stream
 **
 ** @return	output stream
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
ostream&
operator<<(ostream& ostr, Trick const& trick)
{
  DEBUG_CALLING(INFO_TRICK && INFO_IO,
		"operator<<(ostream& ostr, trick)");

  trick.out(ostr);

  DEBUG_RETURNING(ostr,
		  INFO_TRICK && INFO_IO,
		  "operator<<(ostream& ostr, trick)");
} // ostream& operator<<(ostream& ostr, Trick const& trick)

/**
 **
 ** adds the card 'c' to the trick
 **
 ** @param	card	card, which should be added to this trick
 **
 ** @return	trick with c as last card
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Trick&
Trick::operator+=(Card const& card)
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::operator+=(Card const& c)");

  DEBUG_ASSERTION(card,
		  "Trick::operator+=(Card):\n"
		  "  shall add empty card to the trick");

  DEBUG_ASSERTION(!this->isfull(),
		  "Trick::operator+=(Card):\n"
		  "  trick is already full");

  // update the winnerplayer
  if (this->isstartcard()) {
    this->winnerplayer_p = &(this->startplayer());
  } else {
    if (this->winnercard().less(card, this->game())) {
      this->winnerplayer_p = &(this->actplayer());
    }
  } // if !(this->isstartcard())

  // add the card to the trick
  this->card_p.push_back(card);

  DEBUG_RETURNING(*this,
		  INFO_TRICK && INFO_VALUE,
		  "Trick::operator+=(Card const& c)");
} // Trick& Trick::operator+=(Card const& c)



/**
 **
 ** -> result
 **
 ** @param	c	number of card for the result
 **
 ** @return	card c of actual trick
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Card const&
Trick::card(unsigned const c) const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::card(unsigned i)");

  DEBUG_ASSERTION((c < this->actcardno()),
		  "Trick::card(c):\n"
		  "  'c' is to great (" << c << ">=" << this->actcardno());

  DEBUG_RETURNING(this->card_p[c],
		  INFO_TRICK && INFO_VALUE,
		  "Trick::card(unsigned i)");
} // Card const& Trick::card(unsigned const c) const


/**
 **
 ** -> result
 **
 ** @param	player	player whose card is returned
 **
 ** @return	card of 'player' of actual trick
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Card const&
Trick::card_of_player(Player const& player) const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::card_of_player(player)");

  DEBUG_RETURNING(((player.no() >= this->startplayer().no())
		   ? this->card(player.no()
				- this->startplayer().no())
		   : this->card(player.no()
				+ this->game().playerno()
				- this->startplayer().no())
		  ),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::card_of_player(player)");
} // Card const& Trick::card_of_player(Player const& player) const

/**
 **
 ** -> result
 **
 ** @param	c	number of card for the result
 **
 ** @return	the player, who has played the 'c'th card
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Player const&
Trick::player_of_card(unsigned const c) const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::player_of_card(unsigned c)");

  DEBUG_RETURNING(((this->startplayer().no() + c
		    < this->game().playerno())
		   ? this->game().player(c + this->startplayer().no())
		   : this->game().player(c + this->startplayer().no()
					 - this->game().playerno())
		  ),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::player_of_card(unsigned c)");
} // Player const& Trick::player_of_card(unsigned const c) const

/**
 **
 ** -> result
 **
 ** @param	player	player, whose cardno is returnes
 **
 ** @return	the number of the card, the player has played
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
unsigned
Trick::cardno_of_player(Player const& player) const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::cardno_of_player(player)");

  DEBUG_RETURNING(((this->startplayer().no()
		    <= player.no())
		   ? (player.no() - this->startplayer().no())
		   : (player.no()
		      + this->game().playerno()
		      - this->startplayer().no())
		  ),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::cardno_of_player(player)");
} // unsigned Trick::cardno_of_player(Player const& player) const


/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the game the trick is part of
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.5
 **
 **/
Game const&
Trick::game() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::game()");

  DEBUG_ASSERTION(this->game_p,
		  "Trick::game():\n"
		  "  game_p = NULL");

  DEBUG_ASSERTION((this->game_p == &(this->startplayer().game())),
		  "Trick::game():\n"
		  "  game_p != startplayer().game()");

  DEBUG_RETURNING(*(this->game_p),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::game()");
} // Game const& Trick::game() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the startplayer
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Player const&
Trick::startplayer() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::startplayer()");

  DEBUG_ASSERTION(this->startplayer_p,
		  "Trick::startplayer():\n"
		  "  startplayer_p = NULL");

  DEBUG_RETURNING(*(this->startplayer_p),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::startplayer()");
} // Player const& Trick::startcard() const

/**
 **
 ** set the startplayer
 **
 ** @param	startplayer	new startplayer
 **
 ** @return	the startplayer
 **
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Player const&
Trick::startplayer_set(Player const& startplayer)
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::startplayer_set(startplayer)");

  this->startplayer_p = &startplayer;

  DEBUG_RETURNING(this->startplayer(),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::startplayer_set(startplayer)");
} // Player const& Trick::startcard_set(Player const& startplayer)

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the startcard
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Card const&
Trick::startcard() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::startcard()");

  DEBUG_ASSERTION(!this->isstartcard(),
		  "Trick::startcard():\n"
		  "  trick is empty");

  DEBUG_RETURNING(this->card_p[0],
		  INFO_TRICK && INFO_VALUE,
		  "Trick::startcard()");
} // Card const& Trick::startcard() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	whether the trick is empty
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
bool
Trick::isstartcard() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::isstartcard()");

  DEBUG_RETURNING((this->actcardno() == 0),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::isstartcard()");
} // bool Trick::isstartcard() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	whether the trick is empty
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
bool
Trick::isempty() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::isempty()");

  DEBUG_RETURNING((this->actcardno() == 0),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::isempty()");
} // bool Trick::isempty() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	whether the trick is full
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
bool
Trick::isfull() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::isfull()");

  DEBUG_RETURNING((this->actcardno()
		   == this->game().playerno()),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::isfull()");
} // bool Trick::isfull() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	whether the trick lacks only one card
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
bool
Trick::islastcard() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::islastcard()");

  DEBUG_RETURNING((this->actcardno() + 1
		   == this->game().playerno()),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::islastcard()");
} // bool Trick::islastcard() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	whether the trick is in a trickpile
 **
 ** @author	Diether Knof
 **
 ** @version	0.4.5
 **
 **/
bool
Trick::intrickpile() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::intrickpile()");

  DEBUG_RETURNING(this->intrickpile_p,
		  INFO_TRICK && INFO_VALUE,
		  "Trick::intrickpile()");
} // bool Trick::intrickpile() const

/**
 **
 ** moves the trick in the trickpile
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.4.5
 **
 **/
void
Trick::move_in_trickpile()
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::move_in_trickpile()");

  this->intrickpile_p = true;

  if (this->game() == ::party.game())
    ::ui->trick_move_in_pile(*this);

  DEBUG_RETURNING(VOID,
		  INFO_TRICK && INFO_VALUE,
		  "Trick::move_in_trickpile()");
} // void Trick::move_in_trickpile()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the number of the acting card
 **		(that is, how many cards there are in the tricks)
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
unsigned
Trick::actcardno() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::actcardno()");

  DEBUG_RETURNING(this->card_p.size(),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::actcardno()");
} // unsigned Trick::actcardno() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the acting player
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Player const&
Trick::actplayer() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::actplayer()");

  DEBUG_RETURNING(((this->startplayer().no() + this->actcardno()
		    < this->game().playerno())
		   ? this->game().player(this->startplayer().no()
					 + this->actcardno()
					)
		   : this->game().player(this->startplayer().no()
					 + this->actcardno()
					 - this->startplayer().game().playerno()
					)
		  ),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::actplayer()");
} // Player const& Trick::actplayer() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the points in the trick
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
unsigned
Trick::points() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::points()");

  unsigned points = 0;

  for (unsigned c = 0; c < this->actcardno(); c++)
    points += this->card(c).points();

  DEBUG_RETURNING(points,
		  INFO_TRICK && INFO_VALUE,
		  "Trick::points()");
} // unsigned Trick::points() const


/**
 **
 ** -> result
 **
 ** @param	card	card which is checked
 ** @param	hand	hand of the player
 **
 ** @return	whether it is valid to play 'card' with the hand 'hand'
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
bool
Trick::isvalid(Card const& card, Hand const& hand) const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::isvalid(card, hand)");

  // test the card
  DEBUG_ASSERTION(card,
		  "Trick::isvalid(Card, Hand):\n"
		  "  empty Card");

  // test whether the card is in the hand
  DEBUG_ASSERTION(hand.getpos(card) != UINT_MAX,
		  "Trick::isvalid(Card, Hand):\n"
		  "  Card is not in the hand"
		  ": " << card << "\n" << hand);

  // The first person can play all cards
  if (this->isstartcard()) {
    DEBUG_RETURNING(true,
		    INFO_TRICK && INFO_VALUE,
		    "Trick::isvalid(card, hand)");
  }

  // if there is a card with the same tcolor on the hand as the startcard,
  // the card has to have the same tcolor
  if (hand.existstcolor(this->startcard().tcolor()))
    DEBUG_RETURNING((this->startcard().tcolor() == card.tcolor()),
		    INFO_TRICK && INFO_VALUE,
		    "Trick::isvalid(card, hand)");

  // the tcolor of the startcard is not in the hand
  // the player can play any card
  DEBUG_RETURNING(true,
		  INFO_TRICK && INFO_VALUE,
		  "Trick::isvalid(card, hand)");
} // bool Trick::isvalid(Card const& card, Hand const& hand) const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the player which wins this trick
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.5
 **
 **/
Player const&
Trick::winnerplayer() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::winnerplayer()");

  // for the ai (?)
  if (this->winnerplayer_p == NULL)
    DEBUG_RETURNING(*(this->startplayer_p),
		    INFO_TRICK && INFO_VALUE,
		    "Trick::winnerplayer()");

  DEBUG_ASSERTION(this->winnerplayer_p,
		  "Trick::winnerplayer():\n"
		  "  winnerplayer_p == NULL");

  DEBUG_RETURNING(*(this->winnerplayer_p),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::winnerplayer()");
} // Player const& Trick::winnerplayer() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the team which wins the trick
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Team
Trick::winnerteam() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::winnerteam()"); 

  DEBUG_RETURNING(this->winnerplayer().team(),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::winnerteam()"); 
} // Team Trick::winnerteam() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	card that `makes` the trick
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Card
Trick::winnercard() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::winnercard() ");

  if (this->isempty())
    DEBUG_RETURNING(Card(),
		    INFO_TRICK && INFO_VALUE,
		    "Trick::winnercard() ");

  DEBUG_RETURNING(this->card_of_player(this->winnerplayer()),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::winnercard() ");
} // Card Trick::winnercard() const


/**
 **
 ** returns the number of the winnercard
 **
 ** @param	-
 **
 ** @return	cardno that `makes` the trick
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
unsigned
Trick::winnercardno() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::winnercardno() ");

  DEBUG_RETURNING(this->cardno_of_player(this->winnerplayer()),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::winnercardno() ");
} // unsigned Trick::winnercardno() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	whether this is the last trick in the game
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.1
 **
 **/
bool
Trick::islast() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::islast() ");

  DEBUG_RETURNING((this->game().tricks_remaining_no() == 0),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::islast() ");
#ifdef OUTDATED
  DEBUG_RETURNING(((this->game().tricks_remaining_no() <= 1)
		   && !this->game().trick_current().isfull()
		   && (this->game().trick(this->game().trickno() - 1)
		       == *this)),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::islast() ");
#endif
} // bool Trick::islast() const

/**
 ** comparison of two tricks
 **
 ** @param	trick1	first trick to compare
 ** @param	trick2	second trick to compare
 **
 ** @return	whether the tricks are equal
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
bool
operator==(Trick const& trick1, Trick const& trick2)
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"operator==(Trick, Trick)");

  if ((trick1.game() != trick2.game())
      || (trick1.startplayer() != trick2.startplayer())
      || (trick1.actcardno() != trick2.actcardno())
      || (trick1.isfull() != trick2.isfull()))
    DEBUG_RETURNING(false,
		    INFO_TRICK && INFO_VALUE,
		    "operator==(Trick, Trick) = false");

  for (unsigned c = 0; c < trick1.actcardno(); c++)
    if (trick1.card(c) != trick2.card(c))
      DEBUG_RETURNING(false,
		      INFO_TRICK && INFO_VALUE,
		      "operator==(Trick, Trick) = false");

  if (trick1.isfull()
      && (trick1.winnerplayer() != trick2.winnerplayer()))
    DEBUG_RETURNING(false,
		    INFO_TRICK && INFO_VALUE,
		    "operator==(Trick, Trick) = false");

  DEBUG_RETURNING(true,
		  INFO_TRICK && INFO_VALUE,
		  "operator==(Trick, Trick) = true");
} // bool operator==(Trick const& trick1, Trick const& trick2)

/**
 ** comparison of two tricks
 **
 ** @param	trick1	first trick to compare
 ** @param	trick2	second trick to compare
 **
 ** @return	whether the tricks are different
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
bool
operator!=(Trick const& trick1, Trick const& trick2)
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"operator!=(Trick, Trick)");

  DEBUG_RETURNING(!(trick1 == trick2),
		  INFO_TRICK && INFO_VALUE,
		  "operator!=(Trick, Trick)");
} // bool operator!=(Trick const& trick1, Trick const& trick2)

/**
 **
 ** counts all points witch are turned on in rules and determines
 ** team which has won this point.
 ** takes all inforation from the game the trick belongs to.
 **
 ** @param	-
 **
 ** @return	a vector with names of specialpoints and type of them
 **		for solo games return value is an empty vector
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.1
 **
 **/
Specialpointsvector
Trick::specialpoints() const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::specialpoints()");

  vector<Team> teams;

  for (vector<Player*>::const_iterator p = this->game().player_begin();
       p != this->game().player_end();
       p++)
    teams.push_back(this->game().teaminfo(**p));

  DEBUG_RETURNING(this->specialpoints(this->game().type(),
				      teams,
				      this->islast()),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::specialpoints()");
} // Specialpointsvector Trick::specialpoints() const

/**
 **
 ** counts all points witch are turned on in rules and determines
 ** team which has won this point
 **
 ** @param	gametype	the gametype
 ** @param	real_team	the real teams of the players
 ** @param	islasttrick	whether this is the last trick
 **
 ** @return	a vector with names of specialpoints and type of them
 **		for solo games return value is an empty vector
 **
 ** @author	Borg Enders
 **
 ** @version	0.4.4
 **
 **/
Specialpointsvector
Trick::specialpoints(GameType const gametype,
		     vector<Team> const& real_team,
		     bool const islasttrick) const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::specialpoints()");

  DEBUG_RETURNING(this->specialpoints(gametype, real_team, real_team,
				      islasttrick),
		  INFO_TRICK && INFO_VALUE,
		  "Trick::specialpoints()");
} // Specialpointsvector Trick::specialpoints(GameType const gametype, vector<Team> const& real_team, bool const islasttrick) const

/**
 **
 ** counts all points witch are turned on in rules and determines
 **		team which has won this point
 **
 ** @param	gametype	the gametype
 ** @param	real_team	the real teams of the players
 ** @param	known_team	the teams known by the caller
 ** @param	islasttrick	whether this is the last trick
 **
 ** @return	a vector with names of specialpoints and type of them
 **		for solo games return value is an empty vector
 **
 ** @author	Borg Enders
 **
 ** @version	0.4.4
 **
 **/
Specialpointsvector
Trick::specialpoints(GameType const gametype,
		     vector<Team> const& real_team,
		     vector<Team> const& known_team,
		     bool const islasttrick) const
{
  DEBUG_CALLING(INFO_TRICK && INFO_VALUE,
		"Trick::specialpoints()");

  Specialpointsvector sp=Specialpointsvector();

  Team const local_winnerteam = known_team[this->winnerplayer().no()];

  // if this game is a solo there are no specialspoints
  if (GAMETYPE::is_solo(gametype))
    DEBUG_RETURNING(sp,
		    INFO_TRICK && INFO_VALUE,
		    "Trick::specialpoints()");

  unsigned dollen=0;
  unsigned hearts=0;

  // doppelkopf
  if (this->points() >= 40) {
    Specialpoints s(SPECIALPOINT::DOPPELKOPF, local_winnerteam);
    s.player_get_no = this->winnerplayer().no();

    sp.push_back(s);
  }


  bool fl_caught_charlie=false;
  for(unsigned i=0; i<this->actcardno();i++) {
    // fox caught
    if (this->card(i).isfox()
	&& party.rule()(Rule::EXTRAPOINT_CATCH_FOX)
	&& (this->winnerplayer() != this->player_of_card(i)))
    {
      Specialpoints s(SPECIALPOINT::CAUGHT_FOX, local_winnerteam);
      s.player_get_no = this->winnerplayer().no();
      s.player_of_no = this->player_of_card(i).no();

      sp.push_back(s);
    }



   

    // Charlie caught
    if (islasttrick && card(i)==Card::CHARLIE && !fl_caught_charlie
	&& party.rule()(Rule::EXTRAPOINT_CATCH_CHARLIE)
	&& (this->winnerplayer() != this->player_of_card(i)))
    {

      fl_caught_charlie=true;

      Specialpoints s(SPECIALPOINT::CAUGHT_CHARLIE, local_winnerteam);
      s.player_get_no = this->winnerplayer().no();
      s.player_of_no = this->player_of_card(i).no();
      sp.push_back(s);
      // check for double charlies caught
      if (party.rule()(Rule::EXTRAPOINT_CATCH_DOUBLE_CHARLIE))
	for (unsigned n=i+1; n<actcardno(); n++)
	{
	  if(card(n)==Card::CHARLIE &&
	     real_team[n]!=s.team)
	  {
	  	
	    Specialpoints s(SPECIALPOINT::CAUGHT_CHARLIE,
			    local_winnerteam);
	    s.player_get_no = this->winnerplayer().no();
	    s.player_of_no = this->player_of_card(n).no();
	    sp.push_back(s);
	  }
	}

    } // if (charlie caught)


    // counting of dollen in this trick
    if (card(i).isdolle())
      dollen++;

    // counting of heart  
    if (!card(i).istrump() && card(i).tcolor() == Card::HEART )
      hearts++;


  } // for (i < this->actcardno())

  if(party.rule()(Rule::EXTRAPOINT_DOLLE_JABS_DOLLE)
     && (dollen > 1)
     && winnercard() == Card::DOLLE) {
    for (unsigned c = 0; c < this->actcardno(); c++)
      if (this->card(c) == Card::DOLLE)
	if (real_team[player_of_card(c).no()] != local_winnerteam) {
	  Specialpoints s(SPECIALPOINT::DOLLE_CAUGHT_DOLLE,
			  local_winnerteam);
	  s.player_get_no = this->winnerplayer().no();
	  s.player_of_no = this->player_of_card(c).no();

	  sp.push_back(s);
	} // if (dolle caught of opposite team)
  }

  if (this->game().rule()(Rule::EXTRAPOINT_HEART_TRICK)
      && (GAMETYPE::is_normal(this->game().type()))
      && hearts == 4 ) {
    Specialpoints s(SPECIALPOINT::HEART_TRICK,
		    local_winnerteam);
    s.player_get_no = this->winnerplayer().no();

    sp.push_back(s);
  } // if (heart trick)

  // check for foxes who are winning the last trick
  if (islasttrick
      && (winnercard().isfox())
      && party.rule()(Rule::EXTRAPOINT_FOX_LAST_TRICK))
  {
    Specialpoints s(SPECIALPOINT::FOX_LAST_TRICK,
		    local_winnerteam);
    s.player_get_no = this->winnerplayer().no();
    //s.player_of_no = this->winnerplayer().no();
    sp.push_back(s);

    // check for double fox winning
    if (party.rule()(Rule::EXTRAPOINT_DOUBLE_FOX_LAST_TRICK))
      for (unsigned n=winnercardno()+1; n<actcardno(); n++)
      {
	if(card(n).isfox() &&
	   real_team[n]==s.team)
	{
	  Specialpoints s(SPECIALPOINT::FOX_LAST_TRICK,
			  local_winnerteam);
	  s.player_get_no = this->winnerplayer().no();
	  //s.player_of_no = this->player_of_card(n).no();
	  sp.push_back(s);
	}
      }
  }


  // check for charlies in lasttrick
  if (islasttrick) {
    if ((winnercard()==Card::CHARLIE)
	&& party.rule()(Rule::EXTRAPOINT_CHARLIE))
    {
 
      Specialpoints s(SPECIALPOINT::CHARLIE,
		      local_winnerteam);
      s.player_get_no = this->winnerplayer().no();
      //s.player_of_no = this->winnerplayer().no();
      sp.push_back(s);

      // check for double charlies
      if (party.rule()(Rule::EXTRAPOINT_DOUBLE_CHARLIE))
	for (unsigned n=winnercardno()+1; n<actcardno(); n++)
	{
	  if(card(n)==Card::CHARLIE &&
	     real_team[n]==s.team)
	  {
	    Specialpoints s(SPECIALPOINT::CHARLIE,
			    local_winnerteam);
	    s.player_get_no = this->winnerplayer().no();
	    //s.player_of_no = this->player_of_card(n).no();

	    sp.push_back(s);
	  }
	}
    } // if (charlie)
  }

  DEBUG_RETURNING(sp,
		  INFO_TRICK && INFO_VALUE,
		  "Trick::specialpoints()");
} // Specialpointsvector Trick::specialpoints(GameType const gametype, vector<Team> const& real_team, vector<Team> const& known_team, bool const islasttrick) const
