/**********************************************************************
 *
 *   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 "heuristicsmap.h"
#include "player.h"
#include "../game/game.h"
#include "../party/rule.h"
#include "../basistypes.h"

#include "../misc/bug_report.h"

/**
 **
 ** -> result
 **
 ** @param	game	game
 **
 ** @return	group of the gametype
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **   
 ** @version	0.6.6
 **
 **/
HeuristicsMap::GametypeGroup
HeuristicsMap::group(Game const& game)
{
  GametypeGroup group = DEFAULT;

  switch(game.type()) {
  case GAMETYPE::NORMAL:
    group = NORMAL;
    break;
  case GAMETYPE::FIVE_NINES:
  case GAMETYPE::SIX_KINGS:
  case GAMETYPE::FOX_HIGHEST_TRUMP:
    DEBUG_ASSERT(false);
    break;
  case GAMETYPE::POVERTY:
    group = POVERTY;
    break;
  case GAMETYPE::GENSCHER:
    group = NORMAL;
    break;
  case GAMETYPE::MARRIAGE:
    if (game.marriage_selector() == MARRIAGE_SELECTOR::TEAM_SET)
      group = NORMAL;
    else
      group = MARRIAGE_UNDETERMINED;
    break;
  case GAMETYPE::MARRIAGE_SOLO:
    group = SOLI_COLOR;
    break;
  case GAMETYPE::MARRIAGE_SILENT:
    group = MARRIAGE_SILENT;
    break;
  case GAMETYPE::SOLO_JACK:
  case GAMETYPE::SOLO_QUEEN:
  case GAMETYPE::SOLO_KING:
    group = SOLI_SINGLE_PICTURE;
    break;
  case GAMETYPE::SOLO_QUEEN_JACK:
  case GAMETYPE::SOLO_KING_JACK:
  case GAMETYPE::SOLO_KING_QUEEN:
    group = SOLI_DOUBLE_PICTURE;
    break;
  case GAMETYPE::SOLO_KOEHLER:
    group = SOLO_KOEHLER;
    break;
  case GAMETYPE::SOLO_CLUB:
  case GAMETYPE::SOLO_SPADE:
  case GAMETYPE::SOLO_HEART:
  case GAMETYPE::SOLO_DIAMOND:
    group = SOLI_COLOR;
    break;
  case GAMETYPE::SOLO_MEATLESS:
    group = SOLO_MEATLESS;
    break;
  } // switch(game.type())

  DEBUG_ASSERT(group != DEFAULT);

  return group;
} // HeuristicsMap::GametypeGroup HeuristicsMap::group(Game const& game)

/**
 **
 ** -> result
 **
 ** @param	player	player
 **
 ** @return	group of the player
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **   
 ** @version	0.6.6
 **
 **/
HeuristicsMap::PlayerTypeGroup
HeuristicsMap::group(Player const& player)
{
  PlayerTypeGroup group;

  switch(player.team()) {
  case TEAM::RE:
    group = RE;
    break;
  case TEAM::CONTRA:
  case TEAM::MAYBE_CONTRA:
    group = CONTRA;
    break;
  default:
#ifndef RELEASE
    cerr << "HeuristicsMap::group(player):\n"
      <<"  wrong team " << player.team()
      << endl;
#if 0
    ::bug_report.report("HeuristicsMap::group(player):\n"
			"  wrong team " + ::name(player.team()));
#endif
    group = CONTRA;
    break;
#endif
#ifdef POSTPHONED
    DEBUG_ASSERTION(false,
		    "HeuristicsMap::group(player):\n"
		    "  wrong team " << player.team());
#else
    group = CONTRA;
#endif
    break;
  } // switch(gametype)

  // special types

  // poverty
  if ( (player.game().type() == GAMETYPE::POVERTY)
       && player.is_same(player.game().soloplayer()) )
    group = SPECIAL;

  // genscher
  if ( (player.game().type() == GAMETYPE::NORMAL)
       && player.game().rule()(Rule::GENSCHER)
       && (player.hand().numberoftrumpkings()
	   == player.game().rule()(Rule::NUMBER_OF_SAME_CARDS)) )
    group = SPECIAL;

  return group;
} // HeuristicsMap::PlayerTypeGroup HeuristicsMap::group(Player const& player)

/**
 **
 ** -> result
 **
 ** @param	player	player
 **
 ** @return	group of the player
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **   
 ** @version	0.6.6
 **
 **/
HeuristicsMap::Key
HeuristicsMap::key(Player const& player)
{
  Key key;

  key.gametype_group = group(player.game());
  key.playertype_group = group(player);

  return key;
} // HeuristicsMap::Key HeuristicsMap::key(Player const& player)

/**
 **
 ** -> result
 **
 ** @param	a	first key
 ** @param	b	second key
 **
 ** @return	whether 'a' is less than 'b'
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **   
 ** @version	0.6.6
 **
 **/
bool
HeuristicsMap::operator<(HeuristicsMap::Key const& a,
			 HeuristicsMap::Key const& b)
{
  return ((a.gametype_group < b.gametype_group)
	  || ((a.gametype_group == b.gametype_group)
	      && (a.playertype_group < b.playertype_group)));
} // bool HeuristicsMap::operator<(HeuristicsMap::Key const& a, HeuristicsMap::Key const& b)
