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

#include "../basistypes.h"
#include "game.h"
#include "../party/party.h"
#include "../party/rule.h"


// sets the counting team
Specialpoints& counting_team_set(Specialpoints& sp, Team const winner);

/**********************************************************************
 **
 **    GamePoints::GamePoints(Game const& game)
 **
 **    Parameters: 
 **       game   : the game
 **
 **    Result: Standard Initialized GamePoints
 **
 **    Version: 0.3.7
 **
 **    Description: 
 **      
 **
 **********************************************************************/

GamePoints::GamePoints(Game* game) throw (InvalidGameException) :
winnerteam_p(game->winnerteam()),
  points_p(-1),
  team_p(game->playerno()),
  playerspoints_p(game->playerno()),
  gametype_p(game->type()),
  pointsvector_p(),
  highest_announcement_re_p(ANNOUNCEMENT::NOANNOUNCEMENT),
highest_announcement_contra_p(ANNOUNCEMENT::NOANNOUNCEMENT)
{
  DEBUG_CALLING(INFO_GAMEPOINTS && INFO_INIT,"GamePoints::GamePoints()");

  // setting the teams and the playerspoints
  for (unsigned p = 0; p < game->playerno(); p++) {
    this->team_p[p] = game->team(game->player(p));
    this->playerspoints_p[p] = game->points_of_player(game->player(p));
  }

  this->evaluate(*game);

  DEBUG_RETURNING_N(INFO_GAMEPOINTS && INFO_INIT,"GamePoints::GamePoints()");
}

#if 0
/**********************************************************************
 **
 ** GamePoints::GamePoints(int const p = -1,
 **                        vector<Team> const& t = vector<Team>(),
 **                        vector<unsigned> const& pp = vector<unsigned>(), 
 **                        GameType const g = GAMETYPE::NORMAL);
 **
 ** Parameters: 
 **    p   : points of the last game
 **    t   : teams of the players in the last game
 **    pp  : points with tricks of each player
 **    g   : last GameType
 **
 **  Result: Standard Initialized GamePoints
 **
 **  Version: Alpha
 **
 **  Description: 
 **      
 **
 **********************************************************************/
GamePoints::GamePoints(int const p,
		       vector<Team> const& t,
		       vector<unsigned> const& pp, 
		       GameType const g) :
winnerteam_p(TEAM::UNKNOWN),
  points_p(p),
  team_p(t),
  playerspoints_p(pp),
  gametype_p(g),
  highest_announcement_re_p(ANNOUNCEMENT::NOANNOUNCEMENT),
highest_announcement_contra_p(ANNOUNCEMENT::NOANNOUNCEMENT)
{
  DEBUG_CALLING(INFO_GAMEPOINTS && INFO_INIT,"GamePoints::GamePoints()");
  pointsvector_p=Specialpointsvector();
  DEBUG_RETURNING_N(INFO_GAMEPOINTS && INFO_INIT,"GamePoints::GamePoints()");
}
#endif


/**********************************************************************
 **
 **    GamePoints::~GamePoints()
 **
 **    Parameters:  
 **
 **    Result: destroyed GamePoints
 **
 **    Version: Alpha
 **
 **    Description: 
 **      
 **
 **********************************************************************/

GamePoints::~GamePoints()
{
  DEBUG_CALLING(INFO_GAMEPOINTS && INFO_INIT,"GamePoints::~GamePoints()");
  DEBUG_RETURNING_N(INFO_GAMEPOINTS && INFO_INIT,"GamePoints::~GamePoints()");
}


/**********************************************************************
 **
 **    GamePoints& GamePoints::operator=(GamePoints const& g)
 **
 **    Parameters:  GamePoints to copy
 **
 **    Result: copy of g
 **
 **    Version: Alpha
 **
 **    Description: 
 **      
 **
 **********************************************************************/
GamePoints&
GamePoints::operator=(GamePoints const& g)
{
  DEBUG_CALLING(INFO_GAMEPOINTS && INFO_VALUE,
		"GamePoints::operator=");

  this->gametype_p = g.gametype_p;
  this->points_p = g.points_p;

  this->team_p = g.team_p;
  this->playerspoints_p = g.playerspoints_p;

  DEBUG_RETURNING(*this,
		  INFO_GAMEPOINTS && INFO_VALUE,
		  "GamePoints::operator=");
} // GamePoints& GamePoints::operator=(GamePoints const& g)


/**********************************************************************
 **
 **    int GamePoints::points()
 **
 **    Parameters:  
 **
 **    Result: returns points of GamePoints
 **
 **    Version: Alpha
 **
 **    Description: 
 **      
 **
 **********************************************************************/

int GamePoints::points() const
{
  DEBUG_CALLING(INFO_GAMEPOINTS && INFO_VALUE, "GamePoints::points()");
  DEBUG_RETURNING(points_p, INFO_GAMEPOINTS && INFO_VALUE,"GamePoints::points()");
}


/**********************************************************************
 **
 ** unsigned GamePoints::playerspoints(unsigned const p)
 **
 ** Parameters:  p - the playernumber
 **
 ** Result:      the points, the player 'p' has made in his tricks
 **
 ** Version:     0.4.2
 **
 ** Description: -> result
 **
 **********************************************************************/
unsigned
GamePoints::playerspoints(unsigned const p) const
{
  DEBUG_CALLING(INFO_GAMEPOINTS && INFO_VALUE,
		"GamePoints::playerspoints(unsigned const p)");

  DEBUG_ASSERTION(((p < ::party.rule()(Rule::NUMBER_OF_PLAYERS_IN_GAME))
		   && !playerspoints_p.empty()),
		  "GamePoints::playerspoints(p):\n"
		  "  illegal value " << p);

  DEBUG_RETURNING(playerspoints_p[p],
		  INFO_GAMEPOINTS && INFO_VALUE,
		  "GamePoints::playerspoints(unsigned const p)");
} // unsigned GamePoints::playerspoints(unsigned const p) const

/**********************************************************************
 **
 ** unsigned GamePoints::teampoints(unsigned const t)
 **
 ** Parameters:  t - the team
 **
 ** Result:      the points, the team 't' has got in the tricks
 **
 ** Version:     0.4.2
 **
 ** Description: -> result
 **
 **********************************************************************/
unsigned
GamePoints::teampoints(Team const& t) const
{
  DEBUG_CALLING(INFO_GAMEPOINTS && INFO_VALUE,
		"GamePoints::teampoints(Team const& t)");

  unsigned points = 0;

  for (unsigned p = 0; p < ::party.rule()(Rule::NUMBER_OF_PLAYERS_IN_GAME); p++)
    if (this->team(p) == t)
      points += this->playerspoints(p);

  DEBUG_RETURNING(points,
		  INFO_GAMEPOINTS && INFO_VALUE,
		  "GamePoints::teampoints(Team const& t)");
} // unsigned GamePoints::teampoints(Team const& t) const

/**********************************************************************
 **
 **    GameType GamePoints::gametype()
 **
 **    Parameters:  
 **
 **    Result: gametype of last game
 **
 **    Version: Alpha
 **
 **    Description: 
 **      
 **
 **********************************************************************/

GameType GamePoints::gametype() const
{
  DEBUG_CALLING(INFO_GAMEPOINTS && INFO_VALUE, "GamePoints::gametype()");

  DEBUG_RETURNING(gametype_p,
		  INFO_GAMEPOINTS && INFO_VALUE, "GamePoints::gametype()");
}


/**********************************************************************
 **
 **    Team GamePoints::winnerteam()
 **
 **    Parameters:  
 **
 **    Result: Team which wins last game
 **
 **    Version: 0.3.7
 **
 **    Description: 
 **      doesn't take announcements in account
 **
 **********************************************************************/

Team GamePoints::winnerteam() const throw (InvalidGameException)
{
  DEBUG_CALLING(INFO_GAMEPOINTS && INFO_VALUE, "GamePoints::winnerteam()");

  unsigned repoints=0;
  unsigned contrapoints=0;

  for ( unsigned i = 0; i< ::party.game().playerno(); i++)
  {
    if (team_p[i]==TEAM::RE)
      repoints+=playerspoints_p[i];
    else if (team_p[i]==TEAM::CONTRA)
      contrapoints+=playerspoints_p[i];
    else {
      DEBUG_ASSERTION(false,
		      "GamePoints::winnerteam():\n"
		      "  'there exists a player without a team");
    }
  }

  // ToDo: Rule 'POINTS_IN_GAME'
  if (repoints + contrapoints
      != 120 * ::party.game().rule()(Rule::NUMBER_OF_SAME_CARDS))
    DEBUG_THROW( InvalidGameException, InvalidGameException() );

  DEBUG_ASSERTION((   ( this->winnerteam_p == TEAM::RE )
		      || ( this->winnerteam_p == TEAM::CONTRA )
		      || ( this->winnerteam_p == TEAM::NOTEAM )),
		  "GamePoints::winnerteam():" << endl
		  << "  wrong team at end: " << this->winnerteam_p);

  DEBUG_RETURNING(this->winnerteam_p,
		  INFO_GAMEPOINTS && INFO_VALUE,
		  "GamePoints::winnerteam()");
}


/**********************************************************************
 **
 **    Team GamePoints::team(unsigned i)
 **
 **    Parameters:  number of the player, whose team should be
 **                 reuslt of this method
 **
 **    Result: Team of player i, if i is legal
 **            otherwise NOTEAM
 **
 **    Version: Alpha
 **
 **    Description: 
 **      
 **
 **********************************************************************/

Team GamePoints::team(unsigned const i) const
{
  DEBUG_CALLING(INFO_GAMEPOINTS && INFO_VALUE, "GamePoints::team(int const i)");

  using namespace TEAM;

  if ((i < ::party.game().playerno()) && (!team_p.empty()))
  {
    DEBUG_RETURNING(team_p[i],INFO_GAMEPOINTS && INFO_VALUE, "GamePoints::team(int const i)");
  } else
  {
    DEBUG_ASSERTION(false,
		    "Error: file " << __FILE__ << ", line " << __LINE__ << ", "
		    << "function GamePoints::team()\n"
		    << "  illegal value " << i
		    << endl);

    DEBUG_RETURNING(NOTEAM,INFO_GAMEPOINTS && INFO_VALUE, "GamePoints::team(int const i)");
  }
}


/**********************************************************************
 **
 **    const Specialpointsvector& GamePoints::pointlist() const
 **
 **    Parameters:  
 **
 **    Result: returns a vector consisting of all points of
 **            the last game
 **
 **    Version: Alpha
 **
 **    Description: 
 **      
 **
 **********************************************************************/

const Specialpointsvector&
GamePoints::pointlist() const
{
  DEBUG_CALLING(INFO_GAMEPOINTS && INFO_VALUE,"GamePoints::pointlist()");
  DEBUG_RETURNING(pointsvector_p,INFO_GAMEPOINTS && INFO_VALUE,"GamePoints::pointlist()");
}



/**********************************************************************
 **
 **    void GamePoints::evaluate(Game const& g)
 **
 **    Parameters:  last game g
 **
 **    Result: 
 **
 **    Version: 0.4.4
 **
 **    Description: 
 **      caculates the gamespointsvector, highestannouncements and points
 **      of game
 **
 **********************************************************************/ 

void GamePoints::evaluate(Game const& g) throw (InvalidGameException)
{
  DEBUG_CALLING(INFO_GAMEPOINTS && INFO_GAMEPLAY,
		"GamePoints::evaluate(Game g)");
  unsigned i;
  vector<Team> t(g.playerno());

  for( i = 0; i < g.playerno(); i++ )
    t[ i ] = g.team( g.player( i ) );

  // calculate highest announcements
  vector<unsigned> re_announcement_player(ANNOUNCEMENT::NUMBER, UINT_MAX);
  vector<unsigned> contra_announcement_player(ANNOUNCEMENT::NUMBER, UINT_MAX);
  Announcement reply_announcement = ANNOUNCEMENT::NOANNOUNCEMENT;
  unsigned reply_player;
  for( i = 0; i < g.playerno(); i++ ) {
    Player const& pl = g.player( i );
    vector<Game::AnnouncementWithTrickno> const& announcements
      = g.announcements_of_player(pl);

    if (is_reply(announcements.back().announcement)) {
      reply_announcement = announcements.back().announcement;
      reply_player = i;
    }

    if( g.team( g.player( i ) ) == TEAM::RE )
    {
      if( pl.announcement() > highest_announcement_re_p )
	highest_announcement_re_p = pl.announcement();

      for (unsigned a = 0; a < announcements.size(); a++)
	re_announcement_player[announcements[a].announcement] = pl.no();
    }

    if( g.team( g.player( i ) ) == TEAM::CONTRA )
    {
      if( pl.announcement() > highest_announcement_contra_p )
	highest_announcement_contra_p = pl.announcement();

      for (unsigned a = 0; a < announcements.size(); a++)
	contra_announcement_player[announcements[a].announcement] = pl.no();
    }
  }

  // Order of the points
  // * re no 0
  // * contra no 0
  // * no 0 reply
  // * re no 0 said
  // * contra no 0 said
  // * re no 30
  // * contra no 30
  // * no 30 reply
  // * re no 30 said
  // * contra no 30 said
  // * re no 60
  // * contra no 60
  // * no 60 reply
  // * re no 60 said
  // * contra no 60 said
  // * re no 90
  // * contra no 90
  // * no 90 reply
  // * re no 90 said
  // * contra no 90 said
  // * re won && re > 120 points
  // * re won && re 120 points && re no announcement && contra no announcement
  // * contra won && contra > 120 points
  // * consta won && contra 120 points && contra no announcement
  // * no 120 reply
  // * contra no 0 said && re > 30 points
  // * contra no 30 said && re > 60 points
  // * contra no 60 said && re > 90 points
  // * contra no 90 said && re > 120 points
  // * re no 0 said && contra > 30 points
  // * re no 30 said && contra > 60 points
  // * re no 60 said && contra > 90 points
  // * re no 90 said && contra > 120 points
  // * re no 120 said
  // * contra no 120 said
  // * against club queen
  // * specialpoints


  // re no 0
  if (( !g.hastrick(TEAM::RE))
      && (g.winnerteam() != TEAM::RE))
  {
    Specialpoints sp(SPECIALPOINT::NO0, TEAM::CONTRA);
    pointsvector_p.push_back(sp);
  }
  // contra no 0
  if (( !g.hastrick( TEAM::CONTRA ) )
      && (g.winnerteam() != TEAM::CONTRA))
  {
    Specialpoints sp(SPECIALPOINT::NO0, TEAM::RE);
    pointsvector_p.push_back( sp );
  }
  // re 0 got
  if ( highest_announcement_contra_p == ANNOUNCEMENT::NO0 &&
       g.hastrick( TEAM::RE ) )
  {
    Specialpoints sp(SPECIALPOINT::NO0_WON, TEAM::RE);
    pointsvector_p.push_back( sp );
  }
  // contra 0 got
  if ( highest_announcement_re_p == ANNOUNCEMENT::NO0 &&
       g.hastrick( TEAM::CONTRA ) )
  {
    Specialpoints sp(SPECIALPOINT::NO0_WON, TEAM::CONTRA);
    pointsvector_p.push_back( sp );
  }
  // no 0 reply
  if( reply_announcement == ANNOUNCEMENT::NO0_REPLY )
  {
    Specialpoints sp( SPECIALPOINT::NO0_REPLY,
		      g.player(reply_player).team(), g.winnerteam());
    sp.player_of_no = reply_player;
    pointsvector_p.push_back( sp );      
  }
  // re no 0 announced
  if (is_real(highest_announcement_re_p)
      && ( highest_announcement_re_p >= ANNOUNCEMENT::NO0 )
      && (g.winnerteam() != TEAM::NOTEAM))
  {
    Specialpoints sp(SPECIALPOINT::NO0_SAID, TEAM::RE, g.winnerteam());
    sp.player_of_no = re_announcement_player[ANNOUNCEMENT::NO0];
    pointsvector_p.push_back( sp );
  }
  // contra no 0 announced
  if (is_real(highest_announcement_contra_p)
      && ( highest_announcement_contra_p >= ANNOUNCEMENT::NO0 )
      && (g.winnerteam() != TEAM::NOTEAM))
  {
    Specialpoints sp(SPECIALPOINT::NO0_SAID, TEAM::CONTRA, g.winnerteam());
    sp.player_of_no = contra_announcement_player[ANNOUNCEMENT::NO0];
    pointsvector_p.push_back( sp );
  }

  // re no 30
  if (( g.points_of_team(TEAM::RE) < 30)
      && (g.winnerteam() != TEAM::RE))
  {
    Specialpoints sp(SPECIALPOINT::NO30, TEAM::CONTRA);
    pointsvector_p.push_back(sp);
  }
  // contra no 30
  if (( g.points_of_team( TEAM::CONTRA ) < 30 )
      && (g.winnerteam() != TEAM::CONTRA))
  {
    Specialpoints sp(SPECIALPOINT::NO30, TEAM::RE);
    pointsvector_p.push_back( sp );
  }
  // re 30 got
  if ( highest_announcement_contra_p == ANNOUNCEMENT::NO30 &&
       g.points_of_team( TEAM::RE ) >= 30 )
  {
    Specialpoints sp(SPECIALPOINT::NO30_WON, TEAM::RE);
    pointsvector_p.push_back( sp );
  }
  // contra 30 got
  if ( highest_announcement_re_p == ANNOUNCEMENT::NO30 &&
       g.points_of_team( TEAM::CONTRA ) >= 30 )
  {
    Specialpoints sp(SPECIALPOINT::NO30_WON, TEAM::CONTRA);
    pointsvector_p.push_back( sp );
  }
  // no 30 reply
  if( reply_announcement == ANNOUNCEMENT::NO30_REPLY )
  {
    Specialpoints sp( SPECIALPOINT::NO30_REPLY,
		      g.player(reply_player).team(), g.winnerteam());
    sp.player_of_no = reply_player;
    pointsvector_p.push_back( sp );      
  }
  // re no 30 announced
  if (is_real(highest_announcement_re_p)
      && ( highest_announcement_re_p >= ANNOUNCEMENT::NO30 )
      && (g.winnerteam() != TEAM::NOTEAM))
  {
    Specialpoints sp(SPECIALPOINT::NO30_SAID, TEAM::RE, g.winnerteam());
    sp.player_of_no = re_announcement_player[ANNOUNCEMENT::NO30];
    pointsvector_p.push_back( sp );
  }
  // contra no 30 announced
  if (is_real(highest_announcement_contra_p)
      && ( highest_announcement_contra_p >= ANNOUNCEMENT::NO30 )
      && (g.winnerteam() != TEAM::NOTEAM))
  {
    Specialpoints sp(SPECIALPOINT::NO30_SAID, TEAM::CONTRA, g.winnerteam());
    sp.player_of_no = contra_announcement_player[ANNOUNCEMENT::NO30];

    pointsvector_p.push_back( sp );
  }

  // re no 60
  if (( g.points_of_team( TEAM::RE ) < 60 )
      && (g.winnerteam() != TEAM::RE))
  {
    Specialpoints sp(SPECIALPOINT::NO60, TEAM::CONTRA);

    pointsvector_p.push_back( sp );
  }
  // contra no 60
  if (( g.points_of_team( TEAM::CONTRA ) < 60 )
      && (g.winnerteam() != TEAM::CONTRA))
  {
    Specialpoints sp(SPECIALPOINT::NO60, TEAM::RE);

    pointsvector_p.push_back( sp );
  }
  // re 60 got
  if ( highest_announcement_contra_p == ANNOUNCEMENT::NO60 &&
       g.points_of_team( TEAM::RE ) >=60 )
  {
    Specialpoints sp(SPECIALPOINT::NO60_WON, TEAM::RE);
    pointsvector_p.push_back( sp );
  }
  // no 60 reply
  if( reply_announcement == ANNOUNCEMENT::NO60_REPLY )
  {
    Specialpoints sp( SPECIALPOINT::NO60_REPLY,
		      g.player(reply_player).team(), g.winnerteam());
    sp.player_of_no = reply_player;
    pointsvector_p.push_back( sp );      
  }
    // contra 60 got
  if ( highest_announcement_re_p == ANNOUNCEMENT::NO60 &&
       g.points_of_team( TEAM::CONTRA ) >=60 )
  {
    Specialpoints sp(SPECIALPOINT::NO60_WON, TEAM::CONTRA);
    pointsvector_p.push_back( sp );
  }
  // re no 60 announced
  if (is_real(highest_announcement_re_p)
      && ( highest_announcement_re_p >= ANNOUNCEMENT::NO60 )
      && (g.winnerteam() != TEAM::NOTEAM))
  {
    Specialpoints sp(SPECIALPOINT::NO60_SAID, TEAM::RE, g.winnerteam());
    sp.player_of_no = re_announcement_player[ANNOUNCEMENT::NO60];

    pointsvector_p.push_back( sp );
  }
  // contra no 60 announced
  if (is_real(highest_announcement_contra_p)
      && ( highest_announcement_contra_p >= ANNOUNCEMENT::NO60 )
      && (g.winnerteam() != TEAM::NOTEAM))
  {
    Specialpoints sp(SPECIALPOINT::NO60_SAID, TEAM::CONTRA, g.winnerteam());
    sp.player_of_no = contra_announcement_player[ANNOUNCEMENT::NO60];

    pointsvector_p.push_back( sp );
  }

  // re no 90
  if (( g.points_of_team(TEAM::RE) < 90 )
      && (g.winnerteam() != TEAM::RE))
  {
    Specialpoints sp(SPECIALPOINT::NO90, TEAM::CONTRA);

    pointsvector_p.push_back( sp );
  }
  // contra no 90
  if (( g.points_of_team( TEAM::CONTRA ) < 90 )
      && (g.winnerteam() != TEAM::CONTRA))
  {
    Specialpoints sp(SPECIALPOINT::NO90, TEAM::RE);

    pointsvector_p.push_back( sp );
  }
  // re 90 got
  if ( highest_announcement_contra_p == ANNOUNCEMENT::NO90 &&
       g.points_of_team( TEAM::RE ) >= 90 )
  {
    Specialpoints sp(SPECIALPOINT::NO90_WON, TEAM::RE);
    pointsvector_p.push_back( sp );
  }
  // contra 90 got
  if ( highest_announcement_re_p == ANNOUNCEMENT::NO90 &&
       g.points_of_team( TEAM::CONTRA ) >= 90 )
  {
    Specialpoints sp(SPECIALPOINT::NO90_WON, TEAM::CONTRA);
    pointsvector_p.push_back( sp );
  }
  // no 90 reply
  if( reply_announcement == ANNOUNCEMENT::NO90_REPLY )
  {
    Specialpoints sp( SPECIALPOINT::NO90_REPLY,
		      g.player(reply_player).team(), g.winnerteam());
    sp.player_of_no = reply_player;
    pointsvector_p.push_back( sp );      
  }
  // re no 90 announced
  if (is_real(highest_announcement_re_p)
      && ( highest_announcement_re_p >= ANNOUNCEMENT::NO90 )
      && (g.winnerteam() != TEAM::NOTEAM))
  {    
    Specialpoints sp(SPECIALPOINT::NO90_SAID, TEAM::RE, g.winnerteam());
    sp.player_of_no = re_announcement_player[ANNOUNCEMENT::NO90];
    pointsvector_p.push_back( sp );
  }
  // contra no 90 announced
  if (is_real(highest_announcement_contra_p)
      && ( highest_announcement_contra_p >= ANNOUNCEMENT::NO90 )
      && (g.winnerteam() != TEAM::NOTEAM))
  {
    Specialpoints sp(SPECIALPOINT::NO90_SAID, TEAM::CONTRA, g.winnerteam());
    sp.player_of_no = contra_announcement_player[ANNOUNCEMENT::NO90];
    pointsvector_p.push_back( sp );
  }

  // re no 120
  if ( g.winnerteam() == TEAM::CONTRA ) {     
    if ( ( g.points_of_team( TEAM::RE ) < 120 )
	 || ( ( g.points_of_team(TEAM::RE) == 120 )
	      && ( highest_announcement_contra_p == ANNOUNCEMENT::NOANNOUNCEMENT ) 
	    ) 
       )
    {
      Specialpoints sp(SPECIALPOINT::NO120, TEAM::CONTRA);
      pointsvector_p.push_back( sp );
    }
  } // if ( g.winnerteam() == TEAM::CONTRA )
  // contra no 120
  if (g.winnerteam() == TEAM::RE) {
    if ( ( g.points_of_team( TEAM::CONTRA ) < 120 )
	 || ( ( g.points_of_team(TEAM::CONTRA) == 120 )
	      && ( highest_announcement_re_p == ANNOUNCEMENT::NOANNOUNCEMENT )
	      && ( highest_announcement_contra_p > ANNOUNCEMENT::NOANNOUNCEMENT ) 
	    ) 
       )
    {
      Specialpoints sp(SPECIALPOINT::NO120, TEAM::RE);
      pointsvector_p.push_back( sp );
    }
  } // if (g.winnerteam() == TEAM::RE)
  // no 120 reply
  if( reply_announcement == ANNOUNCEMENT::NO120_REPLY )
  {
    Specialpoints sp( SPECIALPOINT::NO120_REPLY,
		      g.player(reply_player).team(), g.winnerteam());
    sp.player_of_no = reply_player;
    pointsvector_p.push_back( sp );      
  }
  // re no 120 announced
  if (is_real(highest_announcement_re_p)
      && ( highest_announcement_re_p >= ANNOUNCEMENT::NO120 )
      && (g.winnerteam() != TEAM::NOTEAM))
  {
    Specialpoints sp(SPECIALPOINT::NO120_SAID, TEAM::RE, g.winnerteam());
    sp.player_of_no = re_announcement_player[ANNOUNCEMENT::NO120];
    pointsvector_p.push_back( sp );
  }
  // contra no 120 announced
  if (is_real(highest_announcement_contra_p)
      && ( highest_announcement_contra_p >= ANNOUNCEMENT::NO120 )
      && (g.winnerteam() != TEAM::NOTEAM))
  {
    Specialpoints sp(SPECIALPOINT::NO120_SAID, TEAM::CONTRA, g.winnerteam());
    sp.player_of_no = contra_announcement_player[ANNOUNCEMENT::NO120];
    pointsvector_p.push_back( sp );
  }

  // against club queens
  if ( g.winnerteam() == TEAM::CONTRA )
  {     
    if ( !GAMETYPE::is_solo( this->gametype() ) ) 
    {
      Specialpoints sp(SPECIALPOINT::CONTRA_WON, TEAM::CONTRA);
      pointsvector_p.push_back( sp );
    }
  }
  // last collect all specialpoints of each trick
  for (i=0; i < g.trick_current_no(); i++ ) {
    Specialpointsvector const spv
      = g.trick(i).specialpoints( g.type(), t,
				  ( ( i + 1 ) == g.trick_current_no() ) );
    for (Specialpointsvector::const_iterator s = spv.begin();
	 s != spv.end();
	 s++)
      if (s->is_valid(t))
	pointsvector_p.push_back(*s);
  }

  // calculating the main game points
  points_p=Sum_of_Specialpoints(pointsvector_p,g.winnerteam(),g);

  DEBUG_ASSERTION((   ( this->winnerteam() == TEAM::RE )
		      || ( this->winnerteam() == TEAM::CONTRA )
		      || ( this->winnerteam() == TEAM::NOTEAM )),
		  "GamePoints::evaluate(Game):" << endl
		  << "  wrong team at end: " << this->winnerteam());

  DEBUG_RETURNING_N(INFO_GAMEPOINTS && INFO_GAMEPLAY,
		    "GamePoints::evaluate(Game g)");
}

/**********************************************************************
 **
 **    ostream& operator<<(ostream& ostr, GamePoints const& gv)
 **
 **    Parameters: output stream, gamepoints to be printed  
 **
 **    Result: output of gv
 **
 **    Version: Alpha
 **
 **    Description: 
 **      
 **
 **********************************************************************/

ostream&
operator<<(ostream& ostr, GamePoints const& gv)
{
  DEBUG_CALLING(INFO_GAMEPOINTS && INFO_OTHER_FUNCTION,
		"operator<<(ostream& ostr, GamePoints& gv)");

  for (unsigned i = 0; i < ::party.game().playerno(); i++)
  {
    ostr << "points of player " << i << ": " << setw(3) << gv.playerspoints(i)
      << ", team: " << gv.team(i) << endl;
  }
  ostr << "winnerteam: " << gv.winnerteam() << "\n"
    << "gametype: " << gv.gametype() << "\n"
    << "points for the winner: " << gv.points() << "\n"
    << "sum of specialpoints: " <<"*****"
    //       << Sum_of_Specialpoints(gv.pointlist(), gv.winnerteam(), g)
    << "\n"
    << endl;

  DEBUG_RETURNING(ostr,INFO_GAMEPOINTS && INFO_OTHER_FUNCTION,"operator<<(ostream& ostr, GamePoints& gv)");
}
