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


#include "constants.h"
#include "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.6.7
 **
 **/
Trick::Trick(Player const& startplayer) :
card_p(),
  game_p(&(startplayer.game())),
  no_(startplayer.game().trick_current_no()),
  startplayer_p(&startplayer),
  winnerplayer_p(NULL),
intrickpile_p(false)
{
  return ;
} // 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())),
  no_(UINT_MAX),
  startplayer_p(),
  winnerplayer_p(NULL),
intrickpile_p(false)
{
  string line;
  getline(istr, line);
  if (DK::Utils::String::word_first(line) != "Startplayer:")
    return ;

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

  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:")

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

/**
 ** constructor
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
Trick::Trick() :
card_p(),
  game_p(NULL),
  no_(UINT_MAX),
  startplayer_p(NULL),
  winnerplayer_p(NULL),
intrickpile_p(false)
{
  return ;
} // Trick::Trick()

/**
 ** destructor
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Trick::~Trick()
{
  return ;
} // Trick::~Trick()

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

/**
 ** copy method
 **
 ** @param	trick	the trick to copy
 **
 ** @return	the trick
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
Trick&
Trick::operator=(Trick const& trick)
{
  this->card_p = trick.card_p;
  this->game_p = trick.game_p;
  this->no_ = trick.no_;
  this->startplayer_p = trick.startplayer_p;
  this->winnerplayer_p = trick.winnerplayer_p;
  this->intrickpile_p = trick.intrickpile_p;

  return *this;
} // Trick& Trick::operator=(Trick const& trick)

/**
 ** self check
 ** when an error is found, an ASSERTION is created
 **
 ** @param	-
 **
 ** @return	wether the self-check was successful (no error)
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
bool
Trick::self_check() const
{
  DEBUG_ASSERTION(this->game_p,
		  "Trick::self_check()\n"
		  "  no game");

  DEBUG_ASSERTION((this->no_ <= this->game_p->trick_current_no()),
		  "Trick::self_check()\n"
		  "  number not valid: " << this->no_);

  DEBUG_ASSERTION((this == &this->game_p->trick(this->no_)),
		  "Trick::self_check()\n"
		  "  Not the trick the number says to be");

  DEBUG_ASSERTION(this->startplayer_p,
		  "Trick::self_check()\n"
		  "  no startplayer");

  DEBUG_ASSERTION((!this->intrickpile_p
		   || this->winnerplayer_p),
		  "Trick::self_check()\n"
		  "  in trickpile but no winnerplayer");

#ifdef POSTPHONED
  DEBUG_ASSERTION((this->game_p == &this->startplayer_p->game()),
		  "Trick::self_check()\n"
		  "  game is not the same as game of the startplayer");

  DEBUG_ASSERTION((this->startplayer_p
		   == &this->game_p->player(this->startplayer_p->no())),
		  "Trick::self_check()\n"
		  "  startplayer is not in the game");

  if (this->winnerplayer_p) {
    DEBUG_ASSERTION((this->game_p == &this->winnerplayer_p->game()),
		    "Trick::self_check()\n"
		    "  game is not the same as game of the winnerplayer");

    DEBUG_ASSERTION((this->winnerplayer_p
		     == &this->game_p->player(this->winnerplayer_p->no())),
		    "Trick::self_check()\n"
		    "  winnerplayer is not in the game");
  } // if (this->winnerplayer_p)
#endif

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

/**
 **
 ** 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
{
  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";

  return 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)
{
  trick.out(ostr);

  return ostr;
} // 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_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);

  return *this;
} // Trick& Trick::operator+=(Card const& c)

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the number of the trick in the game
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
unsigned
Trick::no() const
{

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

/**
 **
 ** -> 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_ASSERTION((c < this->actcardno()),
		  "Trick::card(c):\n"
		  "  'c' is to great (" << c << ">=" << this->actcardno()
		  << ")");

  return this->card_p[c];
} // 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
{
  return ((player.no() >= this->startplayer().no())
		   ? this->card(player.no()
				- this->startplayer().no())
		   : this->card(player.no()
				+ this->game().playerno()
				- this->startplayer().no())
		  );
} // 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
{
  return ((this->startplayer().no() + c
		    < this->game().playerno())
		   ? this->game().player(c + this->startplayer().no())
		   : this->game().player(c + this->startplayer().no()
					 - this->game().playerno())
		  );
} // 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
{
  return ((this->startplayer().no()
		    <= player.no())
		   ? (player.no() - this->startplayer().no())
		   : (player.no()
		      + this->game().playerno()
		      - this->startplayer().no())
		  );
} // 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_ASSERTION(this->game_p,
		  "Trick::game():\n"
		  "  game_p = NULL");

  return *this->game_p;
} // 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_ASSERTION(this->startplayer_p,
		  "Trick::startplayer():\n"
		  "  startplayer_p = NULL");

  return *this->startplayer_p;
} // Player const& Trick::startcard() const

/**
 **
 ** set the startplayer
 **
 ** @param	startplayer	new startplayer
 **
 ** @return	the startplayer
 **
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
void
Trick::startplayer_set(Player const& startplayer)
{
  DEBUG_ASSERTION(!this->startplayer_p,
		  "Trick::startplayer_set(startplayer):\n"
		  "  this->startplayer_p != NULL");
  this->startplayer_p = &startplayer;

  return ;
} // void 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_ASSERTION(!this->isstartcard(),
		  "Trick::startcard():\n"
		  "  trick is empty");

  return this->card_p[0];
} // 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
{
  return (this->actcardno() == 0);
} // 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
{
  return (this->actcardno() == 0);
} // 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
{
  return (this->actcardno() == this->game().playerno());
} // 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
{
  return (this->actcardno() + 1
	  == this->game().playerno());
} // 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
{
  return this->intrickpile_p;
} // bool Trick::intrickpile() const

/**
 **
 ** moves the trick in the trickpile
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 ** @bug	const cast
 **
 **/
void
Trick::move_in_trickpile()
{
  // Bug: const cast
  const_cast<Player&>(this->winnerplayer()).move_in_trickpile(*this);

  this->intrickpile_p = true;

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

  return ;
} // 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
{
  return this->card_p.size();
} // 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
{
  return ((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()
			       )
	 );
} // 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
{
  unsigned points = 0;

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

  return 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
{
  // 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())
    return true;

  // 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()))
    return (this->startcard().tcolor() == card.tcolor());

  // the tcolor of the startcard is not in the hand
  // the player can play any card
  return true;
} // 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
{
  // for the ai (?)
  if (this->winnerplayer_p == NULL)
    return *this->startplayer_p;

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

  return *this->winnerplayer_p;
} // 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
{
  return this->winnerplayer().team();
} // 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
{
  if (this->isempty())
    return Card();

  return this->card_of_player(this->winnerplayer());
} // 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
{
  return this->cardno_of_player(this->winnerplayer());
} // unsigned Trick::winnercardno() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	whether this is the last trick in the game
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
bool
Trick::islast() const
{
  return (this->no() == this->game().trickno() - 1);
} // 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
 **
 ** @todo	compare the number
 **
 **/
bool
operator==(Trick const& trick1, Trick const& trick2)
{
  if ((trick1.game() != trick2.game())
      || (trick1.startplayer() != trick2.startplayer())
      || (trick1.actcardno() != trick2.actcardno())
      || (trick1.isfull() != trick2.isfull()))
    return false;

  for (unsigned c = 0; c < trick1.actcardno(); c++)
    if (trick1.card(c) != trick2.card(c))
      return false;

  if (trick1.isfull()
      && (trick1.winnerplayer() != trick2.winnerplayer()))
    return false;

  return 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)
{
  return !(trick1 == trick2);
} // 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
{
  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));

  return this->specialpoints(this->game().type(), teams, this->islast());
} // 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
{
  return this->specialpoints(gametype, real_team, real_team, islasttrick);
} // 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
{
  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))
    return sp;

  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++) {
    if ( ((local_winnerteam == TEAM::RE)
	  || (local_winnerteam == TEAM::CONTRA))
	 && (local_winnerteam == known_team[this->player_of_card(i).no()]) )
      continue;
    // 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)
  }

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

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	a vector with the cards that made a specialpoint
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
vector<Card>
Trick::specialpoints_cards() const
{
  Specialpointsvector const spv = this->specialpoints();

  vector<Card> cards;

  for (Specialpointsvector::const_iterator sp = spv.begin();
       sp != spv.end();
       ++sp) {
    switch (sp->type) {
    case SPECIALPOINT::NOSPECIALPOINT:
      break;
    case SPECIALPOINT::CAUGHT_FOX:
    case SPECIALPOINT::FOX_LAST_TRICK:
      cards.push_back(Card(this->game().trumpcolor(), Card::ACE));
      break;
    case SPECIALPOINT::CHARLIE:
    case SPECIALPOINT::CAUGHT_CHARLIE:
      cards.push_back(Card::CHARLIE);
      break;
    case SPECIALPOINT::DOLLE_CAUGHT_DOLLE:
      cards.push_back(Card::DOLLE);
      break;
    case SPECIALPOINT::HEART_TRICK:
      cards.push_back(this->winnercard());
      break;
    case SPECIALPOINT::DOPPELKOPF:
      cards.push_back(this->winnercard());
      break;
    case SPECIALPOINT::NO120:
    case SPECIALPOINT::NO90:
    case SPECIALPOINT::NO60:
    case SPECIALPOINT::NO30:
    case SPECIALPOINT::NO0:
    case SPECIALPOINT::NO90_WON:
    case SPECIALPOINT::NO60_WON:
    case SPECIALPOINT::NO30_WON:
    case SPECIALPOINT::NO0_WON:
    case SPECIALPOINT::NO120_SAID:
    case SPECIALPOINT::NO90_SAID:
    case SPECIALPOINT::NO60_SAID:
    case SPECIALPOINT::NO30_SAID:
    case SPECIALPOINT::NO0_SAID:
    case SPECIALPOINT::NO120_REPLY:
    case SPECIALPOINT::NO90_REPLY:
    case SPECIALPOINT::NO60_REPLY:
    case SPECIALPOINT::NO30_REPLY:
    case SPECIALPOINT::NO0_REPLY:
    case SPECIALPOINT::CONTRA_WON:
    case SPECIALPOINT::SOLO:
      break;
    } // switch (sp->type)
  } // for (sp \in spv)

  return cards;
} // vector<Card> Trick::specialpoints_cards() const
