/**********************************************************************
 *
 *   FreeDoko a Doppelkopf-Game
 *    
 *   Copyright (C) 2001-2006  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 "cards_information.of_player.weighting.heuristics.h"

#include "cards_information.of_player.h"

#include "../../card/hand_card.h"
#include "../../card/trick.h"
#include "ai.h"

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

// For configuration values search for '*Value*'

// whether to output the changes of the weighting
#define INFO_WEIGHTING_CHANGE

// the ai whose information are written
// (what the ai assumes of the other players)
#define DEBUG_AI 0

#ifdef INFO_WEIGHTING_CHANGE
#define CHANGE_WEIGHTING(card, value) \
  (((ai.no() == DEBUG_AI) && !ai.game().isvirtual()) \
   ? (cout << "weighting change: " << player.no() << ": " << card << ": " << value << "\n") \
   : cout), \
  (weighting[card] += value);
#else
#define CHANGE_WEIGHTING(card, value) \
  weighting[card] += value;
#endif

namespace CardsInformationOfPlayerWeightingHeuristics {

/* Further ideas
 *
 *
 */

  /**
   ** a player has not started with a color ace
   ** If the player is startplayer and has not started with a color ace,
   ** it is assumed that he does not have one.
   ** Problem: He has so many cards of the color so that he knows he cannot
   **          get the trick
   **
   ** @param	played_card   the card played by the player
   ** @param	trick         the current trick
   ** @param	ai            the ai that analyses
   ** @param    weighting     the card weightings
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.7.3
   **
   ** @todo     marriage
   **/
  void
    no_color_ace(HandCard const& played_card,
		 Trick const& trick,
		 Ai const& ai,
		 map<Card, int>& weighting)
    {
      /* Idea
       *
       * A player starts with a color ace.
       */

      // the player of the card
      Player const& player = played_card.player();
      // the game
      Game const& game = player.game();

      // a normal game or a marriage
      if (!(   (game.type() == GAMETYPE::NORMAL)
	    || (game.type() == GAMETYPE::GENSCHER)
	    || (game.type() == GAMETYPE::MARRIAGE)))
	return ;

      // startplayer
      if (!(trick.startplayerno() == player.no()))
	return ;

      // has not played a color ace
      if (!(   (played_card.value() != Card::ACE)
	    || played_card.istrump()))
	return ;

      // For all colors which have not run, yet, the player is assumed to not
      // have the ace.
      // ToDo: check also, that noone has thrown the color
      for (vector<Card::Color>::const_iterator
	   c = ai.game().rule().valid_card_colors().begin();
	   c != ai.game().rule().valid_card_colors().end();
	   ++c)
	if (!Card(*c, Card::ACE).istrump(game))
	  if (ai.color_runs(*c) == 0)
	    CHANGE_WEIGHTING(Card(*c, Card::ACE), -5); // *Value*


      return ;
    } // void no_color_ace(...)

  /**
   ** a player has served a color trick
   ** if the winnerplayer is not of the own team and there is no player in
   ** the own team, the player does have no card below the played one
   **
   ** @param	played_card   the card played by the player
   ** @param	trick         the current trick
   ** @param	ai            the ai that analyses
   ** @param    weighting     the card weightings
   **
   ** @return	-
   **
   ** @author	Diether Knof
   **
   ** @version	0.7.3
   **
   ** @todo     other gametypes
   **/
  void
    served_color(HandCard const& played_card,
		 Trick const& trick,
		 Ai const& ai,
		 map<Card, int>& weighting)
    {
      /* Idea:
       * If no team is known, the player plays the lowest card in a color trick
       */

      // the player of the card
      Player const& player = played_card.player();
      // the game
      Game const& game = player.game();

      // not startplayer
      if (trick.startplayerno() == player.no())
	return ;

      // color trick
      if (trick.startcard().istrump())
	return ;
      // color trick served
      if (played_card.tcolor() != trick.startcard().tcolor())
	return ;

      // it is not the winnerplayer
      if (trick.winnerplayer().no() == player.no())
	return ;
      // the winnerplayer is not of the team as the plaer
      // note: 'TeamInfo' makes the opposite assumption:
      //         a high card played is a sign for the same team
      if (ai.teaminfo(trick.winnerplayer()) != ::TEAM::UNKNOWN)
	if (maybe_to_team(ai.teaminfo(trick.winnerplayer()))
	    == maybe_to_team(ai.teaminfo(player)))
	  return ;

      // the own team cannot jab the trick
      for (unsigned c = game.playerno() - 1; c > trick.actcardno(); --c) {
	if (ai.teaminfo(trick.player_of_card(c)) != ai.team()) {
	  // test whether the opponent can jab
	  if (!ai.handofplayer(trick.player_of_card(c)).existstcolor(trick.startcard().tcolor()))
	    break;
	} else { // if !(opposite team)
	  // test whether the partner can jab the trick
	  if (!ai.handofplayer(trick.player_of_card(c)).existstcolor(trick.startcard().tcolor()))
	    return ;
	} // if !(opposite team)
      } // for (c > trick.actacardno())

      switch (game.type()) {
      case GAMETYPE::NORMAL:
      case GAMETYPE::POVERTY:
      case GAMETYPE::GENSCHER:
      case GAMETYPE::MARRIAGE:
      case GAMETYPE::MARRIAGE_SOLO:
      case GAMETYPE::MARRIAGE_SILENT:
      case GAMETYPE::SOLO_CLUB:
      case GAMETYPE::SOLO_HEART:
      case GAMETYPE::SOLO_SPADE:
      case GAMETYPE::SOLO_DIAMOND:
	switch (played_card.value()) {
	case Card::ACE:
	  CHANGE_WEIGHTING(Card(played_card.color(), Card::TEN), -5); // *Value*
	  CHANGE_WEIGHTING(Card(played_card.color(), Card::KING), -9); // *Value*
	  if (game.rule()(Rule::WITH_NINES))
	    CHANGE_WEIGHTING(Card(played_card.color(), Card::NINE), -12); // *Value*
	  break;
	case Card::TEN:
	  CHANGE_WEIGHTING(Card(played_card.color(), Card::KING), -8); // *Value*
	  if (game.rule()(Rule::WITH_NINES))
	    CHANGE_WEIGHTING(Card(played_card.color(), Card::NINE), -11); // *Value*
	  break;
	case Card::KING:
	  if (game.rule()(Rule::WITH_NINES))
	    CHANGE_WEIGHTING(Card(played_card.color(), Card::NINE), -5); // *Value*
	  break;
	default:
	  break;
	} // switch (played_card.value())
	break;

      default:
	// ToDo
	break;
      } // switch (game.type())

      return ;
    } // void served_color(...)


} // namespace CardsInformationOfPlayerWeightingHeuristics
