/********************************************************************** * * FreeDoko a Doppelkopf-Game * * Copyright (C) 2001-2007 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 "aiconfig.h" #include "../party/party.h" #include "../party/rule.h" #include "../misc/setting.h" unsigned const AITYPE::NUMBER = (AITYPE::AITYPE_FIRST - AITYPE::AITYPE_LAST + 1); unsigned const Aiconfig::HEURISTIC_NUMBER = (Aiconfig::HEURISTIC_LAST - Aiconfig::HEURISTIC_FIRST + 1); unsigned const Aiconfig::BOOL_NUMBER = (Aiconfig::BOOL_LAST - Aiconfig::BOOL_FIRST + 1); unsigned const Aiconfig::UNSIGNED_NUMBER = (Aiconfig::UNSIGNED_LAST - Aiconfig::UNSIGNED_FIRST + 1); unsigned const Aiconfig::CARD_NUMBER = (Aiconfig::CARD_LAST - Aiconfig::CARD_FIRST + 1); bool Aiconfig::write_standard_type = true; /** ** -> result ** ** @param difficulty difficulty of the returned ai ** ** @return the preset aiconfig of the given difficulty ** ** @author Diether Knof ** ** @version 0.7.2 **/ Aiconfig const& Aiconfig::preset(Difficulty const difficulty) { DEBUG_ASSERTION( (difficulty != CUSTOM), "Aiconfig::preset(difficulty)\n" " difficulty is 'CUSTOM'"); // just to get a warning when a new difficulty has been added switch (difficulty) { case CUSTOM: case NOVICE: case STANDARD_DEFENSIVE: case STANDARD_OFFENSIVE: case PROFI: case PROFI_UNFAIR: break; } // switch (difficulty) static vector aiconfigs; if (aiconfigs.empty()) { { // NOVICE #include "aiconfigs.preset/novice" istringstream istr(novice); aiconfigs.push_back(new Aiconfig(istr)); } // NOVICE { // STANDARD_DEFENSIVE // this is the hardcoded configuration aiconfigs.push_back(new Aiconfig(UINT_MAX)); } // STANDARD_DEFENSIVE { // STANDARD_OFFENSIVE #include "aiconfigs.preset/standard.offensive" istringstream istr(standard_offensive); aiconfigs.push_back(new Aiconfig(istr)); } // STANDARD_OFFENSIVE { // PROFI #include "aiconfigs.preset/profi" istringstream istr(profi); aiconfigs.push_back(new Aiconfig(istr)); } // PROFI { // PROFI_UNFAIR #include "aiconfigs.preset/profi.unfair" istringstream istr(profi_unfair); aiconfigs.push_back(new Aiconfig(istr)); } // PROFI_UNFAIR { // CUSTOM aiconfigs.push_back(NULL); } // CUSTOM } // if (aiconfigs.empty()) return *aiconfigs[difficulty]; } // static Aiconfig const& Aiconfig::preset(Difficulty difficulty); /** ** -> result ** ** @param - ** ** @return the (interesting) keys for the heuristic configuration ** ** @author Diether Knof ** ** @version 0.7.4 **/ list const& Aiconfig::keys() { static list keys; if (keys.empty()) { keys.push_back(HeuristicsMap::Key(HeuristicsMap::DEFAULT, HeuristicsMap::RE)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::DEFAULT, HeuristicsMap::CONTRA)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::MARRIAGE_UNDETERMINED, HeuristicsMap::RE)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::MARRIAGE_UNDETERMINED, HeuristicsMap::CONTRA)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::MARRIAGE_SILENT, HeuristicsMap::RE)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::MARRIAGE_SILENT, HeuristicsMap::CONTRA)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::POVERTY, HeuristicsMap::SPECIAL)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::POVERTY, HeuristicsMap::RE)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::POVERTY, HeuristicsMap::CONTRA)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::SOLI_COLOR, HeuristicsMap::RE)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::SOLI_COLOR, HeuristicsMap::CONTRA)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::SOLI_SINGLE_PICTURE, HeuristicsMap::RE)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::SOLI_SINGLE_PICTURE, HeuristicsMap::CONTRA)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::SOLI_DOUBLE_PICTURE, HeuristicsMap::RE)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::SOLI_DOUBLE_PICTURE, HeuristicsMap::CONTRA)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::SOLO_KOEHLER, HeuristicsMap::RE)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::SOLO_KOEHLER, HeuristicsMap::CONTRA)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::SOLO_MEATLESS, HeuristicsMap::RE)); keys.push_back(HeuristicsMap::Key(HeuristicsMap::SOLO_MEATLESS, HeuristicsMap::CONTRA)); } // if (keys.empty()) return keys; } // static list const& Aiconfig::keys() /** ** -> result ** ** @param type aitype ** ** @return whether the aitype has support for the rating ** ** @author Diether Knof ** ** @version 0.7.3 **/ bool supports_rating(AiType const type) { switch(type) { case AITYPE::NO_CHOOSEBESTCARD: case AITYPE::RANDOM: case AITYPE::VIRTUAL_GAMES: return false; case AITYPE::GAMETREE: case AITYPE::GAMETREE_WITH_HEURISTICS: case AITYPE::GAMETREE_FOR_TEAM: case AITYPE::MONTE_CARLO: return true; }; // switch (type) DEBUG_ASSERTION(false, "::support_rating(type)\n" " unsupported type '" << type << "'"); return false; } // bool supports_rating(AiType const type) /** ** -> return ** ** @param heuristic the heuristic type ** ** @return whether 'heuristic' is a real heuristic ** ** @author Diether Knof ** ** @version 0.7.3 **/ bool Aiconfig::is_real(Aiconfig::Heuristic const heuristic) { return ( (heuristic != Aiconfig::NO_HEURISTIC) && (heuristic != Aiconfig::MANUAL) && (heuristic != Aiconfig::BUG_REPORT) && (heuristic != Aiconfig::NETWORK) && (heuristic != Aiconfig::ONLY_VALID_CARD) && (heuristic != Aiconfig::CHOOSE_BEST_CARD)); } // static bool Aiconfig::is_real(Aiconfig::Heuristic heuristic) /** ** -> return ** ** @param h the heuristic type ** ** @return whether 'h' is a general heuristic ** ** @author Diether Knof ** ** @version 0.6.6 **/ bool Aiconfig::is_general(Aiconfig::Heuristic const h) { return ( Aiconfig::is_real(h) && !Aiconfig::is_solo(h) && !Aiconfig::is_poverty(h) ); } // static bool Aiconfig::is_general(Aiconfig::Heuristic const h) /** ** -> return ** ** @param h the heuristic type ** ** @return whether 'h' was made for a poverty ** ** @author Diether Knof ** ** @version 0.7.3 **/ bool Aiconfig::is_poverty(Aiconfig::Heuristic const h) { return ( (h == Aiconfig::CHOOSE_PFUND_POVERTY) || ( (h >= Aiconfig::HEURISTIC_POVERTY_FIRST) && (h <= Aiconfig::HEURISTIC_POVERTY_LAST) ) ); } // static bool Aiconfig::is_poverty(Aiconfig::Heuristic const h) /** ** -> return ** ** @param h the heuristic type ** ** @return whether 'h' was made for a solo ** ** @author Diether Knof ** ** @version 0.6.6 **/ bool Aiconfig::is_solo(Aiconfig::Heuristic const h) { return ( Aiconfig::is_solo_color(h) || Aiconfig::is_solo_picture(h) || Aiconfig::is_solo_meatless(h)); } // static bool Aiconfig::is_solo(Aiconfig::Heuristic const h) /** ** -> return ** ** @param h the heuristic type ** ** @return whether 'h' was made for a color solo ** ** @author Diether Knof ** ** @version 0.6.6 **/ bool Aiconfig::is_solo_color(Aiconfig::Heuristic const h) { switch (h) { case COLOR_CHOOSE_ACE: case COLOR_BEST_WINNING: case COLOR_JAB_FOR_ACE: case COLOR_LOW_HIGH: return true; default: return false; }; // switch(h) #ifdef WORKAROUND // g++ 4.0 -O3 return false; #endif } // static bool Aiconfig::is_solo_color(Aiconfig::Heuristic const h) /** ** -> return ** ** @param h the heuristic type ** ** @return whether 'h' was made for a picture solo ** ** @author Diether Knof ** ** @version 0.6.6 **/ bool Aiconfig::is_solo_picture(Aiconfig::Heuristic const h) { switch (h) { case PICTURE_SECONDBESTTRUMP: return true; default: return false; }; // switch(h) #ifdef WORKAROUND // g++ 4.0 -O3 return false; #endif } // static bool Aiconfig::is_solo_picture(Aiconfig::Heuristic const h) /** ** -> return ** ** @param h the heuristic type ** ** @return whether 'h' was made for a meatless solo ** ** @author Diether Knof ** ** @version 0.6.6 **/ bool Aiconfig::is_solo_meatless(Aiconfig::Heuristic const h) { switch (h) { case MEATLESS_PLAYHIGHESTCOLOR: return true; default: return false; }; // switch(h) #ifdef WORKAROUND // g++ 4.0 -O3 return false; #endif } // static bool Aiconfig::is_solo_meatless(Aiconfig::Heuristic const h) /** ** constructor ** ** @param no number of the player ** ** @result - ** ** @author Borg Enders ** @author Diether Knof ** ** @version 0.7.4 **/ Aiconfig::Aiconfig(unsigned const no) : aitype_p(::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME)), rating_p(::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME)), future_limit_p(::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME)), heuristic_states_(), bool_p(BOOL_NUMBER), unsigned_p(UNSIGNED_NUMBER), card_p(CARD_NUMBER) { this->reset_to_hardcoded(); #if 0 switch (no) { case UINT_MAX: this->reset_to_hardcoded(); break; case 0: case 1: this->set_to_difficulty(STANDARD_DEFENSIVE); break; case 2: this->set_to_difficulty(STANDARD_OFFENSIVE); break; case 3: this->set_to_difficulty(STANDARD_DEFENSIVE); break; default: this->set_to_difficulty(STANDARD_DEFENSIVE); break; } // switch (no) #endif return ; } // Aiconfig::Aiconfig() /** ** constructor ** ** @param istr stream with the infos ** ** @return - ** ** @author Diether Knof ** ** @version 0.5.2 **/ Aiconfig::Aiconfig(istream& istr) : aitype_p(::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME)), rating_p(::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME)), future_limit_p(::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME)), heuristic_states_(), bool_p(BOOL_NUMBER), unsigned_p(UNSIGNED_NUMBER), card_p(CARD_NUMBER) { (void)this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::DEFAULT, HeuristicsMap::RE)]; #ifdef WORKAROUND this->init_heuristic_states(); #endif this->read(istr); return ; } // Aiconfig::Aiconfig(istream& istr) /** ** copy constructor ** ** @param aiconfig aiconfig to copy ** ** @return - ** ** @author Diether Knof ** ** @version 0.4.2 **/ Aiconfig::Aiconfig(Aiconfig const& aiconfig) : aitype_p(aiconfig.aitype_p), rating_p(aiconfig.rating_p), future_limit_p(aiconfig.future_limit_p), heuristic_states_(aiconfig.heuristic_states_), bool_p(aiconfig.bool_p), unsigned_p(aiconfig.unsigned_p), card_p(aiconfig.card_p) { } /** ** copy operator ** ** @param aiconfig aiconfig to copy ** ** @return aiconfig ** ** @author Diether Knof ** ** @version 0.7.3 **/ Aiconfig& Aiconfig::operator=(Aiconfig const& aiconfig) { if (this == &aiconfig) return *this; for (unsigned t = 0; t < ::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME); ++t) { this->set_aitype(t, aiconfig.aitype(t)); this->set_rating(t, aiconfig.rating(t)); this->set_future_limit(t, aiconfig.future_limit(t)); } this->heuristic_states_ = aiconfig.heuristic_states_; for (unsigned i = BOOL_FIRST; i <= BOOL_LAST; i++) this->set(TypeBool(i), aiconfig.value(TypeBool(i))); for (unsigned i = UNSIGNED_FIRST; i <= UNSIGNED_LAST; i++) this->set(TypeUnsigned(i), aiconfig.value(TypeUnsigned(i))); for (unsigned i = CARD_FIRST; i <= CARD_LAST; i++) this->set(TypeCard(i), aiconfig.value(TypeCard(i))); return *this; } // Aiconfig& Aiconfig::operator=(Aiconfig const& aiconfig) const /** ** destructor ** ** @param - ** ** @return - ** ** @author Diether Knof ** ** @version 0.4.2 **/ Aiconfig::~Aiconfig() { } /** ** resets the aiconfig to the default values ** ** @param no number of the player ** default: 'UINT_MAX' ** ** @return - ** ** @author Diether Knof ** ** @version 0.7.3 **/ void Aiconfig::reset_to_hardcoded(unsigned const no) { switch (no) { case UINT_MAX: break; case 0: case 1: this->set_to_difficulty(STANDARD_DEFENSIVE); return ; case 2: this->set_to_difficulty(STANDARD_OFFENSIVE); return ; case 3: this->set_to_difficulty(STANDARD_DEFENSIVE); return ; default: this->set_to_difficulty(STANDARD_DEFENSIVE); return ; } // switch (no) this->set(TRUSTING, false); this->set(FAIRPLAYHANDS, true); this->set(FAIRPLAYTEAMS, true); this->set(FEHLCREATIONONFIRSTCARD, true); this->set(REMEMBERTRICKS, 9); this->set(LIMIT_THROW_FEHL, 0); this->set(LIMITQUEEN, 12); this->set(LIMITDOLLE, 20); this->set(LASTFEHLCREATION, 3); this->set(LAST_TRICKS_WITHOUT_HEURISTICS, 3); this->set(FIRST_TRICK_FOR_TRUMP_POINTS_OPTIMIZATION, 4); this->set(ANNOUNCELIMIT, 13); this->set(ANNOUNCELIMITDEC, 1); this->set(ANNOUNCECONFIG, 1); this->set(ANNOUNCELIMITREPLY, 11); this->set(ANNOUNCECONFIGREPLY, 1); this->set(TAKEPOVERTY, 15); this->set(SINGLESOLO, 20); this->set(DOUBLESOLO, 54); this->set(TRIPLESOLO, 108); this->set(COLORSOLO, 30); this->set(MEATLESS, 28); this->set(LIMITTHROWING, Card(Card::DIAMOND, Card::QUEEN)); this->set(TRUMPLIMIT_SOLOCOLOR, Card(Card::DIAMOND, Card::QUEEN)); this->set(TRUMPLIMIT_SOLOJACK, Card(Card::DIAMOND, Card::JACK)); this->set(TRUMPLIMIT_SOLOQUEEN, Card(Card::DIAMOND, Card::QUEEN)); this->set(TRUMPLIMIT_SOLOKING, Card(Card::DIAMOND, Card::KING)); this->set(TRUMPLIMIT_SOLOJACKKING, Card(Card::CLUB, Card::JACK)); this->set(TRUMPLIMIT_SOLOJACKQUEEN, Card(Card::CLUB, Card::JACK)); this->set(TRUMPLIMIT_SOLOQUEENKING, Card(Card::CLUB, Card::QUEEN)); this->set(TRUMPLIMIT_SOLOKOEHLER, Card(Card::CLUB, Card::QUEEN)); this->set(TRUMPLIMIT_MEATLESS, Card(Card::DIAMOND, Card::TEN)); this->set(TRUMPLIMIT_NORMAL, Card(Card::HEART, Card::QUEEN)); this->set(LOWEST_TRUMPLIMIT_SOLOCOLOR, Card(Card::HEART, Card::JACK)); this->set(LOWEST_TRUMPLIMIT_SOLOJACK, Card(Card::HEART, Card::JACK)); this->set(LOWEST_TRUMPLIMIT_SOLOQUEEN, Card(Card::HEART, Card::QUEEN)); this->set(LOWEST_TRUMPLIMIT_SOLOKING, Card(Card::HEART, Card::KING)); this->set(LOWEST_TRUMPLIMIT_SOLOJACKKING, Card(Card::SPADE, Card::JACK)); this->set(LOWEST_TRUMPLIMIT_SOLOJACKQUEEN, Card(Card::SPADE, Card::JACK)); this->set(LOWEST_TRUMPLIMIT_SOLOQUEENKING, Card(Card::SPADE, Card::QUEEN)); this->set(LOWEST_TRUMPLIMIT_SOLOKOEHLER, Card(Card::SPADE, Card::QUEEN)); this->set(LOWEST_TRUMPLIMIT_MEATLESS, Card(Card::DIAMOND, Card::QUEEN)); this->set(LOWEST_TRUMPLIMIT_NORMAL, Card(Card::DIAMOND, Card::JACK)); this->set(LIMITHIGH, Card(Card::HEART, Card::QUEEN)); this->aitype_p[ 0] = AITYPE::MONTE_CARLO; this->aitype_p[ 1] = AITYPE::MONTE_CARLO; this->aitype_p[ 2] = AITYPE::VIRTUAL_GAMES; this->aitype_p[ 3] = AITYPE::VIRTUAL_GAMES; this->aitype_p[ 4] = AITYPE::VIRTUAL_GAMES; this->aitype_p[ 5] = AITYPE::VIRTUAL_GAMES; this->aitype_p[ 6] = AITYPE::VIRTUAL_GAMES; this->aitype_p[ 7] = AITYPE::VIRTUAL_GAMES; this->aitype_p[ 8] = AITYPE::GAMETREE; this->aitype_p[ 9] = AITYPE::GAMETREE; this->aitype_p[10] = AITYPE::GAMETREE; this->aitype_p[11] = AITYPE::GAMETREE; this->rating_p[ 0] = Rating::AVERAGE; this->rating_p[ 1] = Rating::AVERAGE; this->rating_p[ 2] = Rating::AVERAGE; this->rating_p[ 3] = Rating::AVERAGE; this->rating_p[ 4] = Rating::AVERAGE; this->rating_p[ 5] = Rating::AVERAGE; this->rating_p[ 6] = Rating::AVERAGE; this->rating_p[ 7] = Rating::AVERAGE; this->rating_p[ 8] = Rating::MAX; this->rating_p[ 9] = Rating::MAX; this->rating_p[10] = Rating::MAX; this->rating_p[11] = Rating::MAX; this->future_limit_p[ 0] = 10000; this->future_limit_p[ 1] = 10000; this->future_limit_p[ 2] = 10000; this->future_limit_p[ 3] = 10000; this->future_limit_p[ 4] = 10000; this->future_limit_p[ 5] = 10000; this->future_limit_p[ 6] = 10000; this->future_limit_p[ 7] = 10000; this->future_limit_p[ 8] = 10000; this->future_limit_p[ 9] = 10000; this->future_limit_p[10] = 10000; this->future_limit_p[11] = 10000; this->init_heuristic_states(); return ; } // void Aiconfig::reset_to_hardcoded(unsigned no = UINT_MAX) /** ** sets the aiconfig to the preset difficulty ** ** @param difficulty difficulty to set to ** ** @return - ** ** @author Diether Knof ** ** @version 0.7.2 **/ void Aiconfig::set_to_difficulty(Difficulty const difficulty) { if (difficulty == CUSTOM) return ; Aiconfig const& preset = Aiconfig::preset(difficulty); this->aitype_p = preset.aitype_p; this->future_limit_p = preset.future_limit_p; this->rating_p = preset.rating_p; this->heuristic_states_ = preset.heuristic_states_; this->bool_p = preset.bool_p; this->unsigned_p = preset.unsigned_p; this->card_p = preset.card_p; return ; } // void Aiconfig::set_to_difficulty(Difficulty const difficulty) /** ** comparison with the aiconfig ** ** @param aiconfig aiconfig to compare with ** ** @return whether aiconfig has the same values as the argument ** ** @author Diether Knof ** ** @version 0.7.3 **/ bool Aiconfig::equal(Aiconfig const& aiconfig) const { return ( (this->aitype_p == aiconfig.aitype_p) && (this->future_limit_p == aiconfig.future_limit_p) && (this->rating_p == aiconfig.rating_p) && (this->heuristic_states_ == aiconfig.heuristic_states_) && (this->bool_p == aiconfig.bool_p) && (this->unsigned_p == aiconfig.unsigned_p) && (this->card_p == aiconfig.card_p) ); } // bool Aiconfig::equal(Aiconfig aiconfig) const /** ** -> result ** the result is taken by comparison, so this is slow! ** ** @param - ** ** @return the difficulty of the aiconfig ** 'CUSTOM' if it does not match a predefined difficulty ** ** @author Diether Knof ** ** @version 0.7.2 **/ Aiconfig::Difficulty Aiconfig::difficulty() const { for (int d = DIFFICULTY_FIRST; d <= DIFFICULTY_LAST; ++d) if ( (d != CUSTOM) && this->equal(Aiconfig::preset(static_cast(d)))) return static_cast(d); return CUSTOM; } // Aiconfig::Difficulty Aiconfig::difficulty() const /** ** -> result ** ** @param trickno trick number ** ** @return the aitype for trick 'trickno' ** ** @author Diether Knof ** ** @version 0.6.7 **/ AiType const& Aiconfig::aitype(unsigned const trickno) const { return this->aitype_p[trickno]; } // AiType const& Aiconfig::aitye(unsigned const trickno) const; /** ** sets the aitype for trick 'trickno' ** ** @param trickno trick number ** @param aitype new aitype ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.7 **/ void Aiconfig::set_aitype(unsigned const trickno, AiType const& aitype) { #ifdef WORKAROUND if (trickno >= this->future_limit_p.size()) { return ; } #endif this->aitype_p[trickno] = aitype; return ; } // void Aiconfig::set_aitype(unsigned const trickno, AiType const& aitype) const /** ** sets the aitype for all tricks ** ** @param aitype new aitype ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.7 **/ void Aiconfig::set_aitype_for_all_tricks(AiType const& aitype) { for (unsigned i = 0; i < this->aitype_p.size(); ++i) this->set_aitype(i, aitype); return ; } // void Aiconfig::set_aitype_for_all_tricks(AiType const& aitype) const /** ** -> result ** ** @param trickno trick number ** ** @return the future limit for trick 'trickno' ** ** @author Diether Knof ** ** @version 0.7.3 **/ unsigned const Aiconfig::future_limit(unsigned const trickno) const { return this->future_limit_p[trickno]; } // unsigned const Aiconfig::future_limit(unsigned trickno) const /** ** sets the future limit for trick 'trickno' ** ** @param trickno trick number ** @param future_limit new future limit ** ** @return - ** ** @author Diether Knof ** ** @version 0.7.3 **/ void Aiconfig::set_future_limit(unsigned const trickno, unsigned const future_limit) { #ifdef WORKAROUND if (trickno >= this->future_limit_p.size()) { return ; } #endif this->future_limit_p[trickno] = future_limit; return ; } // void Aiconfig::set_future_limit(unsigned trickno, unsigned future_limit) /** ** sets the future limit for all tricks ** ** @param future_limit new future limit ** ** @return - ** ** @author Diether Knof ** ** @version 0.7.3 **/ void Aiconfig::set_future_limit_for_all_tricks(unsigned const future_limit) { for (unsigned i = 0; i < this->future_limit_p.size(); ++i) this->set_future_limit(i, future_limit); return ; } // void Aiconfig::set_future_limit_for_all_tricks(unsigned future_limit) /** ** -> result ** ** @param trickno trick number ** ** @return the rating for trick 'trickno' ** ** @author Diether Knof ** ** @version 0.7.3 **/ Rating::Type const& Aiconfig::rating(unsigned const trickno) const { return this->rating_p[trickno]; } // Rating::Type const Aiconfig::rating(unsigned trickno) const /** ** sets the rating for trick 'trickno' ** ** @param trickno trick number ** @param rating new rating ** ** @return - ** ** @author Diether Knof ** ** @version 0.7.3 **/ void Aiconfig::set_rating(unsigned const trickno, Rating::Type const& rating) { #ifdef WORKAROUND if (trickno >= this->rating_p.size()) { return ; } #endif this->rating_p[trickno] = rating; return ; } // void Aiconfig::set_future_limit(unsigned trickno, Rating::Type rating) /** ** sets the rating for all tricks ** ** @param rating new rating for all tricks ** ** @return - ** ** @author Diether Knof ** ** @version 0.7.3 **/ void Aiconfig::set_rating_for_all_tricks(Rating::Type const& rating) { for (unsigned i = 0; i < this->rating_p.size(); ++i) this->set_rating(i, rating); return ; } // void Aiconfig::set_rating_for_all_tricks(Rating::Type rating) /** ** -> result ** ** @param key the key ** ** @return the heuristic states for the given key ** ** @author Diether Knof ** ** @version 0.7.3 **/ vector const& Aiconfig::heuristic_states(HeuristicsMap::Key const& key) const { map >::const_iterator states = this->heuristic_states_.find(key); // if there is no special take a default one if ( (states == this->heuristic_states_.end()) || states->second.empty()) { if ( (key.gametype_group == HeuristicsMap::SOLO_MEATLESS) && (key.playertype_group == HeuristicsMap::CONTRA) ) return this->heuristic_states(HeuristicsMap::SOLO_MEATLESS, HeuristicsMap::RE); if (key.gametype_group == HeuristicsMap::DEFAULT) return this->heuristic_states(HeuristicsMap::DEFAULT, HeuristicsMap::RE); return this->heuristic_states(HeuristicsMap::DEFAULT, key.playertype_group); } // if (states.empty()) return states->second; } // vector Aiconfig::heuristic_states(HeuristicsMap::Key key) const /** ** -> result ** ** @param gametype_group the game type group ** @param playertype_group the player type group ** ** @return the heuristic states for the given groups ** ** @author Diether Knof ** ** @version 0.7.3 **/ vector const& Aiconfig::heuristic_states(HeuristicsMap::GametypeGroup const gametype_group, HeuristicsMap::PlayerTypeGroup const playertype_group ) const { return this->heuristic_states(HeuristicsMap::Key(gametype_group, playertype_group)); } // vector Aiconfig::heuristic_states(HeuristicsMap::GametypeGroup gametype_group, HeuristicsMap::PlayerTypeGroup playertype_group) const /** ** -> result ** ** @param key the key ** ** @return the heuristic states for the given key ** ** @author Diether Knof ** ** @version 0.7.3 **/ vector& Aiconfig::heuristic_states(HeuristicsMap::Key const& key) { map >::iterator states = this->heuristic_states_.find(key); // if there is no special take a default one if (states == this->heuristic_states_.end()) { if ( (key.gametype_group == HeuristicsMap::SOLO_MEATLESS) && (key.playertype_group == HeuristicsMap::CONTRA) ) return this->heuristic_states(HeuristicsMap::SOLO_MEATLESS, HeuristicsMap::RE); if (key.gametype_group == HeuristicsMap::DEFAULT) return this->heuristic_states(HeuristicsMap::DEFAULT, HeuristicsMap::RE); return this->heuristic_states(HeuristicsMap::DEFAULT, key.playertype_group); } // if (states.empty()) return states->second; } // vector Aiconfig::heuristic_states(HeuristicsMap::Key key) const /** ** -> result ** ** @param gametype_group the game type group ** @param playertype_group the player type group ** ** @return the heuristic states for the given groups ** ** @author Diether Knof ** ** @version 0.7.3 **/ vector& Aiconfig::heuristic_states(HeuristicsMap::GametypeGroup const gametype_group, HeuristicsMap::PlayerTypeGroup const playertype_group ) { return this->heuristic_states(HeuristicsMap::Key(gametype_group, playertype_group)); } // vector& Aiconfig::heuristic_states(HeuristicsMap::GametypeGroup gametype_group, HeuristicsMap::PlayerTypeGroup playertype_group) /** ** -> result ** ** @param gametype_group the game type group ** @param playertype_group the player type group ** ** @return the heuristics for the given groups ** ** @author Diether Knof ** ** @version 0.7.3 **/ vector Aiconfig::heuristics(HeuristicsMap::GametypeGroup const gametype_group, HeuristicsMap::PlayerTypeGroup const playertype_group ) const { vector const& states = this->heuristic_states(gametype_group, playertype_group); vector heuristics; heuristics.push_back(ONLY_VALID_CARD); for (vector::const_iterator s = states.begin(); s != states.end(); ++s) if (s->active) heuristics.push_back(s->heuristic); heuristics.push_back(CHOOSE_BEST_CARD); return heuristics; } // vector Aiconfig::heuristics(HeuristicsMap::GametypeGroup gametype_group, HeuristicsMap::PlayerTypeGroup playertype_group) const /** ** -> result ** ** @param player player ** ** @return the heuristics for the player ** ** @author Diether Knof ** ** @version 0.7.3 **/ vector Aiconfig::heuristics(Player const& player) const { return this->heuristics(HeuristicsMap::group(player.game()), HeuristicsMap::group(player)); } // vector Aiconfig::heuristics(Player player) const /** ** initializes the heuristic states ** ** @param - ** ** @return - ** ** @author Diether Knof ** ** @version 0.7.3 **/ void Aiconfig::init_heuristic_states() { this->heuristic_states_.clear(); (void)this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::DEFAULT, HeuristicsMap::RE)]; { // normal vector& states = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::DEFAULT, HeuristicsMap::RE)]; states.push_back(HeuristicState(CHOOSE_ACE, true)); states.push_back(HeuristicState(TRY_FOR_DOPPELKOPF, true)); states.push_back(HeuristicState(CHOOSE_FOR_COLOR_TRICK, true)); states.push_back(HeuristicState(SERVE_COLOR_TRICK, true)); states.push_back(HeuristicState(SERVE_TRUMP_TRICK, true)); states.push_back(HeuristicState(JAB_FOX, true)); states.push_back(HeuristicState(CHOOSE_PFUND, true)); states.push_back(HeuristicState(CHOOSE_PFUND_BEFORE_PARTNER, true)); states.push_back(HeuristicState(JAB_FOR_ACE, true)); states.push_back(HeuristicState(PLAY_FOR_TEAM, true)); states.push_back(HeuristicState(RETRY_COLOR, true)); states.push_back(HeuristicState(PLAY_COLOR_FOR_PARTNER, true)); states.push_back(HeuristicState(TRY_COLOR_FOR_PARTNER, true)); states.push_back(HeuristicState(PLAY_COLOR_FOR_PARTNER_ACE, true)); states.push_back(HeuristicState(PARTNER_BACKHAND_DRAW_TRUMP, true)); states.push_back(HeuristicState(CREATE_FEHL, true)); states.push_back(HeuristicState(BEST_WINNING, true)); states.push_back(HeuristicState(LOW_HIGH, true)); states.push_back(HeuristicState(DRAW_TRUMP, true)); states.push_back(HeuristicState(GET_TRICK_FOR_ANNOUNCEMENT, true)); #if 0 // is automatically wrapped this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::DEFAULT, HeuristicsMap::CONTRA)] = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::DEFAULT, HeuristicsMap::RE)]; #endif } // normal { // poverty { // soloplayer vector& states = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::POVERTY, HeuristicsMap::SPECIAL)]; states.push_back(HeuristicState(CHOOSE_ACE, true)); states.push_back(HeuristicState(PLAY_COLOR_FOR_PARTNER, true)); states.push_back(HeuristicState(TRY_COLOR_FOR_PARTNER, true)); states.push_back(HeuristicState(PLAY_COLOR_FOR_PARTNER_ACE, true)); states.push_back(HeuristicState(CHOOSE_PFUND_POVERTY, true)); states.push_back(HeuristicState(POVERTY_SPECIAL_PLAY_PFUND, true)); states.push_back(HeuristicState(POVERTY_SPECIAL_GIVE_NO_POINTS, true)); } // soloplayer { // re vector& states = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::POVERTY, HeuristicsMap::RE)]; states.push_back(HeuristicState(CHOOSE_ACE, true)); states.push_back(HeuristicState(CREATE_FEHL, true)); states.push_back(HeuristicState(SERVE_COLOR_TRICK, true)); states.push_back(HeuristicState(SERVE_TRUMP_TRICK, true)); states.push_back(HeuristicState(CHOOSE_FOR_COLOR_TRICK, true)); states.push_back(HeuristicState(POVERTY_RE_TRUMP_COLOR_TRICK_HIGH, true)); states.push_back(HeuristicState(GET_TRICK_FOR_ANNOUNCEMENT, true)); states.push_back(HeuristicState(DRAW_TRUMP, true)); states.push_back(HeuristicState(POVERTY_RE_PLAY_TRUMP, true)); states.push_back(HeuristicState(POVERTY_BEST_WINNING_CARD, true)); } // re { // contra vector& states = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::POVERTY, HeuristicsMap::CONTRA)]; states.push_back(HeuristicState(CHOOSE_ACE, true)); states.push_back(HeuristicState(POVERTY_CONTRA_PLAY_COLOR, true)); states.push_back(HeuristicState(POVERTY_CONTRA_TRUMP_COLOR_TRICK_HIGH, true)); states.push_back(HeuristicState(CHOOSE_PFUND, true)); states.push_back(HeuristicState(SERVE_TRUMP_TRICK, true)); states.push_back(HeuristicState(SERVE_COLOR_TRICK, true)); states.push_back(HeuristicState(POVERTY_LEAVE_TO_PARTNER, true)); states.push_back(HeuristicState(POVERTY_OVERJAB_RE, true)); states.push_back(HeuristicState(PARTNER_BACKHAND_DRAW_TRUMP, true)); } // contra } // poverty { // solo { // color { // soloplayer vector& states = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::SOLI_COLOR, HeuristicsMap::RE)]; states.push_back(HeuristicState(COLOR_CHOOSE_ACE, true)); states.push_back(HeuristicState(COLOR_JAB_FOR_ACE, true)); states.push_back(HeuristicState(SERVE_COLOR_TRICK, true)); states.push_back(HeuristicState(SERVE_TRUMP_TRICK, true)); states.push_back(HeuristicState(COLOR_BEST_WINNING, true)); states.push_back(HeuristicState(COLOR_LOW_HIGH, true)); states.push_back(HeuristicState(DRAW_TRUMP, true)); states.push_back(HeuristicState(GET_TRICK_FOR_ANNOUNCEMENT, true)); } // soloplayer { // contra vector& states = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::SOLI_COLOR, HeuristicsMap::CONTRA)] = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::DEFAULT, HeuristicsMap::RE)]; for (vector::iterator s = states.begin(); s != states.end(); ++s) { switch (s->heuristic) { case CHOOSE_ACE: s->heuristic = COLOR_CHOOSE_ACE; break; case BEST_WINNING: s->heuristic = COLOR_BEST_WINNING; break; case JAB_FOR_ACE: s->heuristic = COLOR_JAB_FOR_ACE; break; case LOW_HIGH: s->heuristic = COLOR_LOW_HIGH; break; default: break; } // switch (s->heuristic) } // for (s \in states) // ToDo: add PARTNER_BACKHAND_DRAW_TRUMP } // contra } // color { // single picture { // soloplayer vector& states = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::SOLI_SINGLE_PICTURE, HeuristicsMap::RE)]; states.push_back(HeuristicState(COLOR_CHOOSE_ACE, true)); states.push_back(HeuristicState(DRAW_TRUMP, true)); states.push_back(HeuristicState(PICTURE_SECONDBESTTRUMP, true)); states.push_back(HeuristicState(COLOR_JAB_FOR_ACE, true)); states.push_back(HeuristicState(SERVE_COLOR_TRICK, true)); states.push_back(HeuristicState(SERVE_TRUMP_TRICK, true)); states.push_back(HeuristicState(COLOR_BEST_WINNING, true)); states.push_back(HeuristicState(COLOR_LOW_HIGH, true)); states.push_back(HeuristicState(GET_TRICK_FOR_ANNOUNCEMENT, true)); } // soloplayer { // contra this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::SOLI_SINGLE_PICTURE, HeuristicsMap::CONTRA)] = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::DEFAULT, HeuristicsMap::RE)]; } // contra } // single picture { // double picture { // soloplayer vector& states = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::SOLI_DOUBLE_PICTURE, HeuristicsMap::RE)]; states.push_back(HeuristicState(COLOR_CHOOSE_ACE, true)); states.push_back(HeuristicState(DRAW_TRUMP, true)); states.push_back(HeuristicState(PICTURE_SECONDBESTTRUMP, true)); states.push_back(HeuristicState(COLOR_JAB_FOR_ACE, true)); states.push_back(HeuristicState(SERVE_COLOR_TRICK, true)); states.push_back(HeuristicState(SERVE_TRUMP_TRICK, true)); states.push_back(HeuristicState(COLOR_BEST_WINNING, true)); states.push_back(HeuristicState(COLOR_LOW_HIGH, true)); states.push_back(HeuristicState(GET_TRICK_FOR_ANNOUNCEMENT, true)); } // soloplayer { // contra this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::SOLI_DOUBLE_PICTURE, HeuristicsMap::CONTRA)] = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::DEFAULT, HeuristicsMap::RE)]; } // contra } // double picture { // koehler { // soloplayer vector& states = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::SOLO_KOEHLER, HeuristicsMap::RE)]; states.push_back(HeuristicState(COLOR_CHOOSE_ACE, true)); states.push_back(HeuristicState(DRAW_TRUMP, true)); states.push_back(HeuristicState(PICTURE_SECONDBESTTRUMP, true)); states.push_back(HeuristicState(COLOR_JAB_FOR_ACE, true)); states.push_back(HeuristicState(SERVE_COLOR_TRICK, true)); states.push_back(HeuristicState(SERVE_TRUMP_TRICK, true)); states.push_back(HeuristicState(COLOR_BEST_WINNING, true)); states.push_back(HeuristicState(COLOR_LOW_HIGH, true)); states.push_back(HeuristicState(GET_TRICK_FOR_ANNOUNCEMENT, true)); } // soloplayer { // contra this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::SOLO_KOEHLER, HeuristicsMap::CONTRA)] = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::DEFAULT, HeuristicsMap::RE)]; } // contra } // koehler { // meatless { // soloplayer vector& states = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::SOLO_MEATLESS, HeuristicsMap::RE)]; states.push_back(HeuristicState(MEATLESS_PLAYHIGHESTCOLOR, true)); states.push_back(HeuristicState(CHOOSE_ACE, true)); states.push_back(HeuristicState(SERVE_COLOR_TRICK, true)); states.push_back(HeuristicState(JAB_FOX, true)); states.push_back(HeuristicState(CHOOSE_PFUND, true)); states.push_back(HeuristicState(JAB_FOR_ACE, true)); states.push_back(HeuristicState(PLAY_FOR_TEAM, true)); states.push_back(HeuristicState(CREATE_FEHL, true)); states.push_back(HeuristicState(BEST_WINNING, true)); states.push_back(HeuristicState(LOW_HIGH, true)); states.push_back(HeuristicState(DRAW_TRUMP, true)); } // soloplayer { // contra this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::SOLO_MEATLESS, HeuristicsMap::CONTRA)] = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::SOLO_MEATLESS, HeuristicsMap::RE)]; } // contra } // meatless } // solo { // marriage { // undetermined marriage this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::MARRIAGE_UNDETERMINED, HeuristicsMap::RE)] = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::DEFAULT, HeuristicsMap::RE)]; vector& states = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::MARRIAGE_UNDETERMINED, HeuristicsMap::RE)]; states.insert(states.begin(), HeuristicState(PLAY_TO_MARRY, true)); this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::MARRIAGE_UNDETERMINED, HeuristicsMap::CONTRA)] = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::DEFAULT, HeuristicsMap::RE)]; } // undetermined marriage { // silent marriage vector& states = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::MARRIAGE_SILENT, HeuristicsMap::RE)]; states.push_back(HeuristicState(COLOR_CHOOSE_ACE, true)); states.push_back(HeuristicState(COLOR_JAB_FOR_ACE, true)); states.push_back(HeuristicState(COLOR_BEST_WINNING, true)); states.push_back(HeuristicState(COLOR_LOW_HIGH, true)); states.push_back(HeuristicState(DRAW_TRUMP, true)); states.push_back(HeuristicState(GET_TRICK_FOR_ANNOUNCEMENT, true)); this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::MARRIAGE_SILENT, HeuristicsMap::CONTRA)] = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::SOLI_COLOR, HeuristicsMap::CONTRA)]; } // silent marriage } // marriage this->fill_up_heuristic_states(); return ; } // void Aiconfig::init_heuristic_states() /** ** fills up the heuristic states so that all real heuristics are included ** ** @param - ** ** @return - ** ** @author Diether Knof ** ** @version 0.7.3 **/ void Aiconfig::fill_up_heuristic_states() { for (map >::iterator m = this->heuristic_states_.begin(); m != this->heuristic_states_.end(); ++m) { vector& states = m->second; std::set heuristics; for (int h = HEURISTIC_FIRST; h <= HEURISTIC_LAST; ++h) if (Aiconfig::is_real(static_cast(h))) heuristics.insert(static_cast(h)); for (vector::const_iterator s = states.begin(); s != states.end(); ++s) heuristics.erase(s->heuristic); for (std::set::const_iterator h = heuristics.begin(); h != heuristics.end(); ++h) states.push_back(HeuristicState(*h, false)); } // for (m \in this->heuristic_states_) return ; } // void Aiconfig::fill_up_heuristic_states() /** ** -> result ** ** @param key the group key ** @param heuristic the heuristic type ** ** @return the value of the heuristic in the given context ** ** @author Diether Knof ** ** @version 0.7.3 **/ bool Aiconfig::value(HeuristicsMap::Key const& key, Heuristic const heuristic) const { vector const& states = this->heuristic_states(key); for (vector::const_iterator s = states.begin(); s != states.end(); ++s) if (s->heuristic == heuristic) return s->active; return false; } // bool Aiconfig::value(HeuristicsMap::Key key, Heuristic heuristic) const /** ** -> result ** ** @param gametype_group the game type group ** @param playertype_group the player type group ** @param heuristic the heuristic type ** ** @return the value of the heuristic 'type in the given context ** ** @author Diether Knof ** ** @version 0.7.3 **/ bool Aiconfig::value(HeuristicsMap::GametypeGroup const gametype_group, HeuristicsMap::PlayerTypeGroup const playertype_group, Heuristic const heuristic) const { return this->value(HeuristicsMap::Key(gametype_group, playertype_group), heuristic); } // bool Aiconfig::value(HeuristicsMap::GametypeGroup gametype_group, HeuristicsMap::PlayerTypeGroup playertype_group, Heuristic heuristic) const /** ** -> result ** ** @param type the bool type ** ** @return the value of the aiconfig 'type' ** ** @author Diether Knof ** ** @version 0.6.6 **/ bool Aiconfig::value(TypeBool const type) const { return this->bool_p[type - BOOL_FIRST]; } // bool Aiconfig::value(TypeBool) const; /** ** -> result ** ** @param type the unsigned type ** ** @return the value of the aiconfig 'type' ** ** @author Diether Knof ** ** @version 0.6.6 **/ unsigned Aiconfig::value(TypeUnsigned const type) const { return this->unsigned_p[type - UNSIGNED_FIRST]; } // unsigned Aiconfig::value(TypeUnsigned) const; /** ** -> result ** ** @param type the card type ** ** @return the value of the aiconfig 'type' ** ** @author Diether Knof ** ** @version 0.6.6 **/ Card Aiconfig::value(TypeCard const type) const { return this->card_p[type - CARD_FIRST]; } // Card Aiconfig::value(TypeCard const type) const /** ** -> result ** ** @param type config type ** ** @return minimal value for the type ** ** @author Diether Knof ** ** @version 0.7.2 **/ unsigned Aiconfig::min(TypeUnsigned const& type) const { switch(type) { case REMEMBERTRICKS: case LASTFEHLCREATION: case LAST_TRICKS_WITHOUT_HEURISTICS: case FIRST_TRICK_FOR_TRUMP_POINTS_OPTIMIZATION: return 0; case LIMIT_THROW_FEHL: case LIMITQUEEN: case LIMITDOLLE: return 0; case ANNOUNCELIMIT: case ANNOUNCELIMITDEC: case ANNOUNCECONFIG: case ANNOUNCELIMITREPLY: case ANNOUNCECONFIGREPLY: return 0; case TAKEPOVERTY: return 0; case SINGLESOLO: case DOUBLESOLO: case TRIPLESOLO: case COLORSOLO: case MEATLESS: return 0; } // switch(type) return UINT_MAX; } // unsigned Aiconfig::min(TypeUnsigned type) const /** ** -> result ** ** @param type config type ** ** @return maximum value for the type ** ** @author Diether Knof ** ** @version 0.7.2 **/ unsigned Aiconfig::max(TypeUnsigned const& type) const { switch(type) { case REMEMBERTRICKS: case LASTFEHLCREATION: case LAST_TRICKS_WITHOUT_HEURISTICS: case FIRST_TRICK_FOR_TRUMP_POINTS_OPTIMIZATION: // when changing 'with nines' -> 'without nines' -> 'with nines' // it should keep '12' //return ::party.rule()(Rule::NUMBER_OF_TRICKS_IN_GAME); return ::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME); case LIMIT_THROW_FEHL: case LIMITQUEEN: case LIMITDOLLE: return 33; case ANNOUNCELIMIT: case ANNOUNCELIMITDEC: case ANNOUNCECONFIG: case ANNOUNCELIMITREPLY: case ANNOUNCECONFIGREPLY: return 1000; case TAKEPOVERTY: return 1000; case SINGLESOLO: case DOUBLESOLO: case TRIPLESOLO: case COLORSOLO: case MEATLESS: return 1000; } // switch(type) return UINT_MAX; } // unsigned Aiconfig::max(TypeUnsigned type) const /** ** -> result ** ** @param type config type ** ** @return the valid cards ** ** @author Diether Knof ** ** @version 0.7.2 **/ list const& Aiconfig::valid_cards(TypeCard const type) const { switch(type) { case LIMITTHROWING: case LIMITHIGH: case TRUMPLIMIT_NORMAL: case LOWEST_TRUMPLIMIT_NORMAL: case TRUMPLIMIT_SOLOCOLOR: case LOWEST_TRUMPLIMIT_SOLOCOLOR: { static list valid_cards; if (valid_cards.empty()) { valid_cards.push_back(Card(Card::CLUB, Card::QUEEN)); valid_cards.push_back(Card(Card::SPADE, Card::QUEEN)); valid_cards.push_back(Card(Card::HEART, Card::QUEEN)); valid_cards.push_back(Card(Card::DIAMOND, Card::QUEEN)); valid_cards.push_back(Card(Card::CLUB, Card::JACK)); valid_cards.push_back(Card(Card::SPADE, Card::JACK)); valid_cards.push_back(Card(Card::HEART, Card::JACK)); valid_cards.push_back(Card(Card::DIAMOND, Card::JACK)); } // if (valid.cards.empty()) return valid_cards; } case TRUMPLIMIT_SOLOJACK: case LOWEST_TRUMPLIMIT_SOLOJACK: { static list valid_cards; if (valid_cards.empty()) { valid_cards.push_back(Card(Card::CLUB, Card::JACK)); valid_cards.push_back(Card(Card::SPADE, Card::JACK)); valid_cards.push_back(Card(Card::HEART, Card::JACK)); valid_cards.push_back(Card(Card::DIAMOND, Card::JACK)); } // if (valid.cards.empty()) return valid_cards; } case TRUMPLIMIT_SOLOQUEEN: case LOWEST_TRUMPLIMIT_SOLOQUEEN: { static list valid_cards; if (valid_cards.empty()) { valid_cards.push_back(Card(Card::CLUB, Card::QUEEN)); valid_cards.push_back(Card(Card::SPADE, Card::QUEEN)); valid_cards.push_back(Card(Card::HEART, Card::QUEEN)); valid_cards.push_back(Card(Card::DIAMOND, Card::QUEEN)); } // if (valid.cards.empty()) return valid_cards; } case TRUMPLIMIT_SOLOKING: case LOWEST_TRUMPLIMIT_SOLOKING: { static list valid_cards; if (valid_cards.empty()) { valid_cards.push_back(Card(Card::CLUB, Card::KING)); valid_cards.push_back(Card(Card::SPADE, Card::KING)); valid_cards.push_back(Card(Card::HEART, Card::KING)); valid_cards.push_back(Card(Card::DIAMOND, Card::KING)); } // if (valid.cards.empty()) return valid_cards; } case TRUMPLIMIT_SOLOJACKKING: case LOWEST_TRUMPLIMIT_SOLOJACKKING: { static list valid_cards; if (valid_cards.empty()) { valid_cards.push_back(Card(Card::CLUB, Card::KING)); valid_cards.push_back(Card(Card::SPADE, Card::KING)); valid_cards.push_back(Card(Card::HEART, Card::KING)); valid_cards.push_back(Card(Card::DIAMOND, Card::KING)); valid_cards.push_back(Card(Card::CLUB, Card::JACK)); valid_cards.push_back(Card(Card::SPADE, Card::JACK)); valid_cards.push_back(Card(Card::HEART, Card::JACK)); valid_cards.push_back(Card(Card::DIAMOND, Card::JACK)); } // if (valid.cards.empty()) return valid_cards; } case TRUMPLIMIT_SOLOJACKQUEEN: case LOWEST_TRUMPLIMIT_SOLOJACKQUEEN: { static list valid_cards; if (valid_cards.empty()) { valid_cards.push_back(Card(Card::CLUB, Card::QUEEN)); valid_cards.push_back(Card(Card::SPADE, Card::QUEEN)); valid_cards.push_back(Card(Card::HEART, Card::QUEEN)); valid_cards.push_back(Card(Card::DIAMOND, Card::QUEEN)); valid_cards.push_back(Card(Card::CLUB, Card::JACK)); valid_cards.push_back(Card(Card::SPADE, Card::JACK)); valid_cards.push_back(Card(Card::HEART, Card::JACK)); valid_cards.push_back(Card(Card::DIAMOND, Card::JACK)); } // if (valid.cards.empty()) return valid_cards; } case TRUMPLIMIT_SOLOQUEENKING: case LOWEST_TRUMPLIMIT_SOLOQUEENKING: { static list valid_cards; if (valid_cards.empty()) { valid_cards.push_back(Card(Card::CLUB, Card::KING)); valid_cards.push_back(Card(Card::SPADE, Card::KING)); valid_cards.push_back(Card(Card::HEART, Card::KING)); valid_cards.push_back(Card(Card::DIAMOND, Card::KING)); valid_cards.push_back(Card(Card::CLUB, Card::QUEEN)); valid_cards.push_back(Card(Card::SPADE, Card::QUEEN)); valid_cards.push_back(Card(Card::HEART, Card::QUEEN)); valid_cards.push_back(Card(Card::DIAMOND, Card::QUEEN)); } // if (valid.cards.empty()) return valid_cards; } case TRUMPLIMIT_SOLOKOEHLER: case LOWEST_TRUMPLIMIT_SOLOKOEHLER: { static list valid_cards; if (valid_cards.empty()) { valid_cards.push_back(Card(Card::CLUB, Card::KING)); valid_cards.push_back(Card(Card::SPADE, Card::KING)); valid_cards.push_back(Card(Card::HEART, Card::KING)); valid_cards.push_back(Card(Card::DIAMOND, Card::KING)); valid_cards.push_back(Card(Card::CLUB, Card::QUEEN)); valid_cards.push_back(Card(Card::SPADE, Card::QUEEN)); valid_cards.push_back(Card(Card::HEART, Card::QUEEN)); valid_cards.push_back(Card(Card::DIAMOND, Card::QUEEN)); valid_cards.push_back(Card(Card::CLUB, Card::JACK)); valid_cards.push_back(Card(Card::SPADE, Card::JACK)); valid_cards.push_back(Card(Card::HEART, Card::JACK)); valid_cards.push_back(Card(Card::DIAMOND, Card::JACK)); } // if (valid.cards.empty()) return valid_cards; } case TRUMPLIMIT_MEATLESS: case LOWEST_TRUMPLIMIT_MEATLESS: { static list valid_cards; if (valid_cards.empty()) { valid_cards.push_back(Card(Card::DIAMOND, Card::ACE)); valid_cards.push_back(Card(Card::DIAMOND, Card::TEN)); valid_cards.push_back(Card(Card::DIAMOND, Card::KING)); valid_cards.push_back(Card(Card::DIAMOND, Card::QUEEN)); valid_cards.push_back(Card(Card::DIAMOND, Card::JACK)); valid_cards.push_back(Card(Card::DIAMOND, Card::NINE)); } // if (valid.cards.empty()) return valid_cards; } } // switch(type) { static list valid_cards; return valid_cards; } } // list const& Aiconfig::valid_cards(TypeCard const type) const /** ** sets 'type' to 'value' ** ** @param type Aiconfigtype ** @param value new value ** ** @return 'true', if the type is valid, otherwise 'false' ** ** @author Diether Knof ** ** @version 0.6.6 **/ bool Aiconfig::set(string const& type, string const& value) { unsigned i; for (i = Aiconfig::BOOL_FIRST; i <= Aiconfig::BOOL_LAST; i++) { if (type == name(Aiconfig::TypeBool(i))) { this->set(Aiconfig::TypeBool(i), value); return true; } // if (type == name(Aiconfig::TypeBool(i))) } // (i \in BOOL) for (i = Aiconfig::UNSIGNED_FIRST; i <= Aiconfig::UNSIGNED_LAST; i++) { if (type == name(Aiconfig::TypeUnsigned(i))) { this->set(Aiconfig::TypeUnsigned(i), value); return true; } // if (type == name(Aiconfig::TypeUnsigned(i))) } // (i \in UNSIGNED) for (i = Aiconfig::CARD_FIRST; i <= Aiconfig::CARD_LAST; i++) { if (type == name(Aiconfig::TypeCard(i))) { this->set(Aiconfig::TypeCard(i), value); return true; } // if (type == name(Aiconfig::TypeCard(i))) } // (i \in CARD) return false; } // bool Aiconfig::set(string const& type, string const& value) /** ** activates/deactivates the heuristic in the given context ** ** @param gametype_group the game type group ** @param playertype_group the player type group ** @param heuristic the heuristic type ** @param value new value ** ** @return - ** ** @author Diether Knof ** ** @version 0.7.3 **/ void Aiconfig::set(HeuristicsMap::GametypeGroup const gametype_group, HeuristicsMap::PlayerTypeGroup const playertype_group, Heuristic const heuristic, string const& value) { if ( (value != "true") && (value != "false") && (value != "yes") && (value != "no") && (value != "0") && (value != "1")) { cerr << "Aiconfig::set(GametypeGroup, PlayerTypeGroup, Heuristic, value)\n" << " illegal value '" << value << "' for '" << heuristic << "', " << "must be a boolean ('true' or 'false' or 'yes' or 'no' or '1' or '0')." << '\n' << " Taking 'false'." << endl; } this->set(gametype_group, playertype_group, heuristic, ( ( (value == "false") || (value == "no") || (value == "0")) ? false : true) ); return ; } // void Aiconfig::set(HeuristicsMap::GametypeGroup gametype_group, HeuristicsMap::PlayerTypeGroup playertype_group, Heuristic heuristic, string value) /** ** sets 'type' to 'value' ** ** @param type Aiconfigtype ** @param value new value ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.6 **/ void Aiconfig::set(TypeBool const type, string const& value) { if ( (value != "true") && (value != "false") && (value != "yes") && (value != "no") && (value != "0") && (value != "1")) { cerr << "Aiconfig::set(TypeBool, value)\n" << " illegal value '" << value << "' for '" << type << "', " << "must be a boolean ('true' or 'false' or 'yes' or 'no' or '1' or '0')." << '\n' << " Taking 'false'." << endl; } this->set(type, ( ( (value == "false") || (value == "no") || (value == "0") ) ? false : true) ); return ; } // void Aiconfig::set(const TypeBool type, string const& value) /** ** sets 'type' to 'value' ** ** @param type Aiconfigtype ** @param value new value ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.6 **/ void Aiconfig::set(TypeUnsigned const type, string const& value) { char* end_ptr; unsigned number = strtoul(value.c_str(), &end_ptr, 0); if (*end_ptr != '\0') { cerr << "Aiconfig::set(TypeUnsigned, value)\n" << "illegal value '" << value << "' for '" << type << "', " << "must be a digit.\n" << " Taking " << number << "." << endl; } this->set(type, number); return ; } // void Aiconfig::set(const TypeUnsigned type, string const& value) /** ** sets 'type' to 'value' ** ** @param type Aiconfigtype ** @param value new value ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.6 **/ void Aiconfig::set(TypeCard const type, string const& value) { this->set(type, Card(value)); return ; } // void Aiconfig::set(const TypeCard type, string const& value) /** ** activates/deactivates the heuristic in the given context ** ** @param key the context key ** @param heuristic the heuristic type ** @param value new value ** ** @return - ** ** @author Diether Knof ** ** @version 0.7.3 **/ void Aiconfig::set(HeuristicsMap::Key const& key, Heuristic const heuristic, bool const value) { this->set(key.gametype_group, key.playertype_group, heuristic, value); return ; } // void Aiconfig::set(HeuristicsMap::GametypeGroup key, Heuristic heuristic, bool value) /** ** activates/deactivates the heuristic in the given context ** ** @param gametype_group the game type group ** @param playertype_group the player type group ** @param heuristic the heuristic type ** @param value new value ** ** @return - ** ** @author Diether Knof ** ** @version 0.7.3 **/ void Aiconfig::set(HeuristicsMap::GametypeGroup const gametype_group, HeuristicsMap::PlayerTypeGroup const playertype_group, Heuristic const heuristic, bool const value) { vector& states = this->heuristic_states(gametype_group, playertype_group); for (vector::iterator s = states.begin(); s != states.end(); ++s) if (s->heuristic == heuristic) { s->active = value; return; } states.push_back(HeuristicState(heuristic, value)); return ; } // void Aiconfig::set(HeuristicsMap::GametypeGroup gametype_group, HeuristicsMap::PlayerTypeGroup playertype_group, Heuristic heuristic, bool value) /** ** sets the heuristics map to the default one ** ** @param key the context key ** ** @return - ** ** @author Diether Knof ** ** @version 0.7.3 **/ void Aiconfig::set_to_default(HeuristicsMap::Key const& key) { this->heuristic_states(key) = this->heuristic_states(HeuristicsMap::Key::DEFAULT); return ; } // void Aiconfig::set_to_default(HeuristicsMap::Key key) /** ** moves the heuristic to the given position ** all heuristics below are moved one position further ** ** @param key the key of the heuristic group ** @param heuristic the heuristic type ** @param pos new position ** ** @return - ** ** @author Diether Knof ** ** @version 0.7.3 **/ void Aiconfig::move(HeuristicsMap::Key const& key, Heuristic const heuristic, unsigned const pos) { vector& states = this->heuristic_states(key); if (states[pos].heuristic == heuristic) return ; if (pos > states.size()) return ; vector::iterator s; for (s = states.begin(); s != states.end(); ++s) if (s->heuristic == heuristic) break; if (s == states.end()) { states.insert(states.begin() + pos, HeuristicState(heuristic, false)); } else { // if !(s == states.end()) HeuristicState const state = *s; states.erase(s); states.insert(states.begin() + pos, state); } // if !(s == states.end()) return ; } // void Aiconfig::move(HeuristicsMap::Key key, Heuristic heuristic, unsigned pos) /** ** sets the aiconfig 'type' to the value 'value' ** ** @param type heuristic type ** @param value new value ** ** @result - ** ** @author Diether Knof ** ** @version 0.6.6 **/ void Aiconfig::set(TypeBool const type, bool const value) { this->bool_p[type - BOOL_FIRST] = value; return ; } // void Aiconfig::set(TypeBool, bool); /** ** sets the aiconfig 'type' to the value 'value' ** ** @param type heuristic type ** @param value new value ** ** @result - ** ** @author Diether Knof ** ** @version 0.6.6 **/ void Aiconfig::set(TypeUnsigned const type, unsigned const value) { this->unsigned_p[type - UNSIGNED_FIRST] = value; return ; } // void Aiconfig::set(TypeUnsigned, unsigned); /** ** sets the aiconfig 'type' to the value 'value' ** ** @param type heuristic type ** @param value new value ** ** @result - ** ** @author Diether Knof ** ** @version 0.6.6 **/ void Aiconfig::set(TypeCard const type, Card const value) { this->card_p[type - CARD_FIRST] = value; return ; } // void Aiconfig::set(TypeCard, card); /** ** ** @param ostr output stream ** ** @result - ** ** @author Borg Enders ** @author Diether Knof ** ** @version 0.7.4 **/ void Aiconfig::write(ostream& ostr) const { if (Aiconfig::write_standard_type) { if (this->difficulty() != CUSTOM) { ostr << "difficulty = " << ::name(this->difficulty()) << '\n'; return ; } // if (this->difficulty() != CUSTOM) } // if (Aiconfig::write_standard_type) ios_base::fmtflags const flags = ostr.flags(); ostr << boolalpha; #ifdef ALTERNATIVE // Do not use, since it will lead to problems when replaying bug reports. { // Only write the differences to a standard type. // Count the differences to the standard types. // Write only the differences if they are less than MAX_DIFFERENCES_TO_WRITE. unsigned const MAX_DIFFERENCES_TO_WRITE = 0; // the difficulty with the minimal differences Difficulty difficulty_min = CUSTOM; // the minimal differences unsigned differences_min = UINT_MAX; // the string with the differences string differences_min_string; for (int difficulty = DIFFICULTY_FIRST; difficulty <= DIFFICULTY_LAST; difficulty++) { if (difficulty == CUSTOM) continue; Aiconfig const& preset_aiconfig = Aiconfig::preset(static_cast(difficulty)); // the number of differences unsigned differences = 0; // output stream for the differences ostringstream differences_ostr; { // check the values for (unsigned t = BOOL_FIRST; t <= BOOL_LAST; ++t) { if (this->value(static_cast(t)) != preset_aiconfig.value(static_cast(t))) { differences += 1; differences_ostr << " " << static_cast(t) << " = " << (this->value(static_cast(t)) ? "true" : "false") << '\n' << "# " << static_cast(t) << " = " << (preset_aiconfig.value(static_cast(t)) ? "true" : "false") << '\n'; } // if (value differs) } // for (t \in TypeBool) for (unsigned t = UNSIGNED_FIRST; t <= UNSIGNED_LAST; ++t) { if (this->value(static_cast(t)) != preset_aiconfig.value(static_cast(t))) { differences += 1; differences_ostr << " " << static_cast(t) << " = " << this->value(static_cast(t)) << '\n' << "# " << static_cast(t) << " = " << preset_aiconfig.value(static_cast(t)) << '\n'; } // if (value differs) } // for (t \in TypeUnsigned) for (unsigned t = CARD_FIRST; t <= CARD_LAST; ++t) { if (this->value(static_cast(t)) != preset_aiconfig.value(static_cast(t))) { differences += 1; differences_ostr << " " << static_cast(t) << " = " << this->value(static_cast(t)) << '\n' << "# " << static_cast(t) << " = " << preset_aiconfig.value(static_cast(t)) << '\n'; } // if (value differs) } // for (t \in TypeCard) } // check the values if ( (differences >= MAX_DIFFERENCES_TO_WRITE) || (differences >= differences_min)) continue; { // check the ai types for (unsigned t = 0; t < ::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME); t++) { if (this->aitype(t) != preset_aiconfig.aitype(t)) { differences += 1; differences_ostr << " " << "type = " << setw(2) << t << ": " << this->aitype(t) << '\n' << "# " << "type = " << setw(2) << t << ": " << preset_aiconfig.aitype(t) << '\n'; } // if (value differs) } // for (t \in number of tricks) for (unsigned t = 0; t < ::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME); t++) { if (this->rating(t) != preset_aiconfig.rating(t)) { differences += 1; differences_ostr << " " << "rating = " << setw(2) << t << ": " << this->rating(t) << '\n' << "# " << "rating = " << setw(2) << t << ": " << preset_aiconfig.rating(t) << '\n'; } // if (value differs) } // for (t \in number of tricks) for (unsigned t = 0; t < ::party.rule()(Rule::MAX_NUMBER_OF_TRICKS_IN_GAME); t++) { if (this->future_limit(t) != preset_aiconfig.future_limit(t)) { differences += 1; differences_ostr << " " << "future limit = " << setw(2) << t << ": " << this->future_limit(t) << '\n' << "# " << "future limit = " << setw(2) << t << ": " << preset_aiconfig.future_limit(t) << '\n'; } // if (value differs) } // for (t \in number of tricks) } // check the ai types if ( (differences >= MAX_DIFFERENCES_TO_WRITE) || (differences >= differences_min)) continue; { // check the heuristics list const& keys = Aiconfig::keys(); bool first_difference = true; for (list::const_iterator key = keys.begin(); key != keys.end(); ++key) { if (this->heuristic_states(*key) != preset_aiconfig.heuristic_states(*key)) { differences += 5; { // write the differences if (first_difference) { differences_ostr << "heuristics" << '\n' << "{\n"; first_difference = false; } // if (first_difference) differences_ostr << " " << key->gametype_group << " - " << key->playertype_group << '\n' << " {\n"; for (vector::const_iterator h = this->heuristic_states(*key).begin(); h != this->heuristic_states(*key).end(); ++h) differences_ostr << " " << h->heuristic << " = " << (h->active ? "true" : "false") << '\n'; differences_ostr << " }\n"; } // write the differences } // if (heuristic states differ) } // for (key \in keys) if (!first_difference) { // there was a difference differences_ostr << "}\n"; } // if (!first_difference) } // check the heuristics if (differences < differences_min) { // has found a 'nearer' difficulty difficulty_min = static_cast(difficulty); differences_min = differences; differences_min_string = differences_ostr.str(); } // if (differences < differences_min) } // for (difficulty) if (differences_min <= MAX_DIFFERENCES_TO_WRITE) { // write only the differences // write the nearest difficulty and differences ostr << "difficulty = " << ::name(difficulty_min) << '\n'; ostr << "# differences = " << differences_min << '\n'; ostr << '\n' << differences_min_string; return ; } // if (difficulty_min <= MAX_DIFFERENCES_TO_WRITE) } // only write the differences to a standard type #endif // #ifndef RELEASE for (unsigned i = 0; i < this->aitype_p.size(); ++i) ostr << "type = " << setw(2) << i << ": " << this->aitype(i) << '\n'; for (unsigned i = 0; i < this->aitype_p.size(); ++i) ostr << "future limit = " << setw(2) << i << ": " << this->future_limit(i) << '\n'; for (unsigned i = 0; i < this->aitype_p.size(); ++i) ostr << "rating = " << setw(2) << i << ": " << this->rating(i) << '\n'; ostr << '\n'; ostr << '\n'; ostr << "# bool\n"; for (int t = BOOL_FIRST; t <= BOOL_LAST; ++t) ostr << static_cast(t) << " = " << (this->value(static_cast(t)) ? "true" : "false") << '\n'; ostr << '\n'; ostr << "# unsigned\n"; for (int t = UNSIGNED_FIRST; t <= UNSIGNED_LAST; ++t) ostr << static_cast(t) << " = " << this->value(static_cast(t)) << '\n'; ostr << '\n'; ostr << "# card\n"; for (int t = CARD_FIRST; t <= CARD_LAST; ++t) ostr << static_cast(t) << " = " << this->value(static_cast(t)) << '\n'; ostr << '\n'; ostr << "#heuristics" << '\n'; ostr << "heuristics" << '\n' << "{\n"; for (map >::const_iterator s = this->heuristic_states_.begin(); s != this->heuristic_states_.end(); ++s) { ostr << " " << s->first.gametype_group << " - " << s->first.playertype_group << '\n' << " {\n"; for (vector::const_iterator h = s->second.begin(); h != s->second.end(); ++h) ostr << " " << h->heuristic << " = " << (h->active ? "true" : "false") << '\n'; ostr << " }\n"; } // for (s \in this->heuristic_states_) ostr << "}\n"; ostr.flags(flags); return ; } // void Aiconfig::write(ostream& ostr) const /** ** loads the infos from the file ** ** @param filename file to load the aiconfig from ** ** @return whether the loading was successful ** ** @author Diether Knof ** ** @version 0.6.6 **/ bool Aiconfig::load(string const& filename) { { ifstream istr(filename.c_str()); if (istr.good()) { this->reset_to_hardcoded(); return this->read(istr); } } { ifstream istr((::setting(Setting::PRIVATE_DATA_DIRECTORY) + "/" + ::setting(Setting::AI_DIRECTORY) + "/" + filename).c_str()); if (istr.good()) { this->reset_to_hardcoded(); return this->read(istr); } } { ifstream istr((::setting(Setting::PUBLIC_DATA_DIRECTORY) + "/" + ::setting(Setting::AI_DIRECTORY) + "/" + filename).c_str()); if (istr.good()) { this->reset_to_hardcoded(); return this->read(istr); } } return false; } // bool Aiconfig::load(string const& filename) /** ** reads the infos from the stream ** ** @param istr stream with the infos ** ** @return whether the reading was successful ** ** @author Diether Knof ** ** @version 0.5.4 **/ bool Aiconfig::read(istream& istr) { unsigned depth = 0; // read the configuration while (istr.good()) { Config config; istr >> config; if (istr.fail()) break; // finished with the config file if ((config.name == "") && (config.value == "")) break; if (config.separator) { // a setting if (config.name == "difficulty") { // a preset difficulty int difficulty; for (difficulty = DIFFICULTY_FIRST; difficulty <= DIFFICULTY_LAST; difficulty++) { if (config.value == ::name(static_cast(difficulty))) { this->set_to_difficulty(static_cast(difficulty)); break; } } if (difficulty > AITYPE::AITYPE_LAST) cerr << "Aiconfig::read()\n" << " unknown difficulty '" << config.value << "'" << endl; } else if (config.name == "type") { try { stringstream istr(config.value); // tricknumber unsigned trickno; istr >> trickno; if (!istr.good()) { throw config.value; } // separator if (istr.peek() != ':') throw config.value; istr.get(); while (std::isspace(istr.peek()) && istr.good()) istr.get(); if (!istr.good()) throw config.value; // aitype string aitype; std::getline(istr, aitype); { int t; for (t = AITYPE::AITYPE_FIRST; t <= AITYPE::AITYPE_LAST; t++) if (aitype == ::name(AiType(t))) { this->set_aitype(trickno, AiType(t)); break; } if (t > AITYPE::AITYPE_LAST) { throw config.value; } } } // try catch (string value) { cerr << "aiconfig: " << "unknown aitype '" << value << "'." << endl; } } else if (config.name == "future limit") { try { stringstream istr(config.value); // tricknumber unsigned trickno; istr >> trickno; if (!istr.good()) { throw config.value; } // separator if (istr.peek() != ':') { throw config.value; } istr.get(); while (std::isspace(istr.peek()) && istr.good()) istr.get(); if (!istr.good()) { throw config.value; } // future limit unsigned future_limit; istr >> future_limit; if (istr.fail()) { throw config.value; } this->set_future_limit(trickno, future_limit); } // try catch (string value) { cerr << "aiconfig: " << "illegal future limit '" << value << "'." << endl; } } else if (config.name == "rating") { try { stringstream istr(config.value); // tricknumber unsigned trickno; istr >> trickno; if (!istr.good()) { throw config.value; } // separator if (istr.peek() != ':') { throw config.value; } istr.get(); while (std::isspace(istr.peek()) && istr.good()) istr.get(); if (!istr.good()) { throw config.value; } // rating string rating; std::getline(istr, rating); { int t; for (t = Rating::TYPE_FIRST; t <= Rating::TYPE_LAST; t++) if (rating == ::name(Rating::Type(t))) { this->set_rating(trickno, Rating::Type(t)); break; } if (t > Rating::TYPE_LAST) { throw config.value; } } } // try catch (string value) { cerr << "rating type: " << "unknown rating type '" << value << "'." << endl; } } else { if (!this->set(config.name, config.value)) { cerr << "aiconfig: " << "unknown config '" << config.name << "'." << endl; } } // if (config.name == "type") } else { // if (config.separator) // a setting // if the value is in parentencies, remove both if(config.name == "!end") { // ignore the rest of the file break; } else if(config.name == "!stdout") { // output of the data to 'stdout' cout << config.value << endl; } else if(config.name == "!stderr") { // output of the data to 'stderr' cerr << config.value << endl; } else if(config.name == "{") { depth += 1; } else if(config.name == "}") { if (depth == 0) { cerr << "Aiconfig: found a '}' without a '{' before.\n" << "Finish reading the the file." << endl; break; } // if (depth == 0) depth -= 1; if (depth == 0) break; } else if(config.name == "heuristics") { this->read_heuristics(istr); } else if(config.name == "") { cerr << "Aiconfig: " << "Ignoring line \'" << config.value << "\'.\n"; } else { cerr << "Aiconfig: " << "type '" << config.name << "' unknown.\n" << "Ignoring it.\n"; } // if (config.name == .) } // config.separator } // while (istr.good()) return istr.good(); } // bool Aiconfig::read(istream& istr) /** ** reads the heuristics ** ** @param istr input stream ** ** @return whether the reading was successful ** ** @author Diether Knof ** ** @version 0.7.3 **/ bool Aiconfig::read_heuristics(istream& istr) { unsigned depth = 0; string line; while (istr.good()) { std::getline(istr, line); if (istr.fail()) break; while ( !line.empty() && isspace(*line.begin())) line.erase(line.begin()); if (*(line.end() - 1) == '\r') line.erase(line.end() - 1); if (line.empty()) { // empty line } else if (line[0] == '#') { // comment } else if (line == "{") { // block open depth += 1; } else if (line == "}") { // block close if (depth == 0) { cerr << "Aiconfig: found a '}' without a '{' before.\n" << "Finish reading the the file." << endl; break; } // if (depth == 0) depth -= 1; if (depth == 0) break; } else { // gametype group - playertype group string::size_type const pos = line.find('-'); if (pos == string::npos) { cerr << "unknown line '" << line << "'\n" << "ignoring it" << endl; continue; } // if (pos == string::npos) string gametype_group_string(line, 0, pos); while ( !gametype_group_string.empty() && isspace(*gametype_group_string.rbegin())) gametype_group_string.erase(gametype_group_string.size() - 1); string playertype_group_string(line, pos + 1, string::npos); while ( !playertype_group_string.empty() && isspace(*playertype_group_string.begin())) playertype_group_string.erase(playertype_group_string.begin()); HeuristicsMap::GametypeGroup const gametype_group = HeuristicsMap::GametypeGroup_from_name(gametype_group_string); HeuristicsMap::PlayerTypeGroup const playertype_group = HeuristicsMap::PlayerTypeGroup_from_name(playertype_group_string); unsigned depth2 = 0; vector& states = this->heuristic_states_[HeuristicsMap::Key(gametype_group, playertype_group)]; states.clear(); while (istr.good()) { Config config; istr >> config; if (istr.fail()) break; if (config.separator) { Heuristic const heuristic = Heuristic_from_name(config.name); if (is_real(heuristic)) { bool const active = ( (config.value == "true") || (config.value == "yes") || (config.value == "1")); states.push_back(HeuristicState(heuristic, active)); } // if (is_real(heuristic)) } else { // if (config.separator) if(config.name == "{") { depth2 += 1; } else if(config.name == "}") { if (depth2 == 0) { cerr << "Aiconfig: found a '}' without a '{' before.\n" << "Finish reading the the file." << endl; break; } // if (depth2 == 0) depth2 -= 1; if (depth2 == 0) break; } else if(config.name == "") { cerr << "Aiconfig: " << "Ignoring line \'" << config.value << "\'.\n"; } else { cerr << "Aiconfig: " << "type '" << config.name << "' unknown.\n" << "Ignoring it.\n"; } // if (config.name == .) } // config.separator } // while (istr.good()) } // if (line == ...) } // while (istr.good()) return istr.good(); } // bool Aiconfig::read_heuristics(istream& istr) /** ** save the infos in the file ** ** @param filename file to save the aiconfig ** ** @return whether the saving was successful ** ** @author Diether Knof ** ** @version 0.5.4 **/ bool Aiconfig::save(string const& filename) const { ofstream ostr(filename.c_str()); if (ostr.fail()) return false; ostr << "# FreeDoko ai configuration (" << ::version << ")\n" << '\n'; bool const write_standard_type_bak = Aiconfig::write_standard_type; Aiconfig::write_standard_type = false; ostr << *this; Aiconfig::write_standard_type = write_standard_type_bak; return ostr.good(); } // bool Aiconfig::save(string const& filename) const /** ** comparison of two aiconfigs ** ** @param aiconfig_a first aiconfig ** @param aiconfig_b second aiconfig ** ** @return whether the two aiconfigs are equal ** ** @author Diether Knof ** ** @version 0.7.2 **/ bool operator==(Aiconfig const& aiconfig_a, Aiconfig const& aiconfig_b) { return aiconfig_a.equal(aiconfig_b); } // bool operator==(Aiconfig aiconfig_a, Aiconfig aiconfig_b) /** ** comparison of two aiconfigs ** ** @param aiconfig_a first aiconfig ** @param aiconfig_b second aiconfig ** ** @return whether the two aiconfigs are different ** ** @author Diether Knof ** ** @version 0.7.2 **/ bool operator!=(Aiconfig const& aiconfig_a, Aiconfig const& aiconfig_b) { return !(aiconfig_a == aiconfig_b); } // bool operator!=(Aiconfig aiconfig_a, Aiconfig aiconfig_b) /** ** comparison of two heuristic states ** ** @param heuristic_state_a first heuristic state ** @param heuristic_state_b second heuristic state ** ** @return whether the two heuristic states are equal ** ** @author Diether Knof ** ** @version 0.7.2 **/ bool operator==(Aiconfig::HeuristicState const& heuristic_state_a, Aiconfig::HeuristicState const& heuristic_state_b) { return ( (heuristic_state_a.heuristic == heuristic_state_b.heuristic) && (heuristic_state_a.active == heuristic_state_b.active) ); } // bool operator==(Aiconfig::HeuristicState heuristic_state_a, Aiconfig::HeuristicState heuristic_state_b) /** ** -> result ** ** @param heuristic heuristic type ** ** @return the name of 'type' ** ** @author Diether Knof ** ** @version 0.6.8 **/ string name(Aiconfig::Heuristic const heuristic) { switch(heuristic) { case Aiconfig::NO_HEURISTIC: return "no heuristic"; case Aiconfig::MANUAL: return "manual"; case Aiconfig::BUG_REPORT: return "bug report"; case Aiconfig::NETWORK: return "network"; case Aiconfig::ONLY_VALID_CARD: return "only valid card"; case Aiconfig::PLAY_TO_MARRY: return "play to marry"; case Aiconfig::CHOOSE_ACE: return "choose ace"; case Aiconfig::CHOOSE_FOR_COLOR_TRICK: return "choose for color trick"; case Aiconfig::RETRY_COLOR: return "retry color"; case Aiconfig::PLAY_COLOR_FOR_PARTNER: return "play color for partner"; case Aiconfig::TRY_COLOR_FOR_PARTNER: return "try color for partner"; case Aiconfig::PLAY_COLOR_FOR_PARTNER_ACE: return "play color for partner ace"; case Aiconfig::SERVE_COLOR_TRICK: return "serve color trick"; case Aiconfig::SERVE_TRUMP_TRICK: return "serve trump trick"; case Aiconfig::CHOOSE_PFUND: return "choose pfund"; case Aiconfig::CHOOSE_PFUND_POVERTY: return "choose pfund poverty"; case Aiconfig::CHOOSE_PFUND_BEFORE_PARTNER: return "choose pfund before partner"; case Aiconfig::JAB_FOR_ACE: return "jab for ace"; case Aiconfig::CREATE_FEHL: return "create fehl"; case Aiconfig::BEST_WINNING: return "best winning card"; case Aiconfig::LOW_HIGH: return "play low high"; case Aiconfig::PLAY_FOR_TEAM: return "play for team"; case Aiconfig::JAB_FOX: return "jab fox"; case Aiconfig::TRY_FOR_DOPPELKOPF: return "try for doppelkopf"; case Aiconfig::DRAW_TRUMP: return "draw trump"; case Aiconfig::PARTNER_BACKHAND_DRAW_TRUMP: return "partner backhand draw trump"; case Aiconfig::GET_TRICK_FOR_ANNOUNCEMENT: return "get trick for announcement"; case Aiconfig::GRAB_TRICK: return "grab trick"; case Aiconfig::POVERTY_SPECIAL_PLAY_PFUND: return "poverty: special: play pfund"; case Aiconfig::POVERTY_SPECIAL_GIVE_NO_POINTS: return "poverty: special: give no points"; case Aiconfig::POVERTY_RE_TRUMP_COLOR_TRICK_HIGH: return "poverty: re: trump color trick high"; case Aiconfig::POVERTY_RE_PLAY_TRUMP: return "poverty: re: play trump"; case Aiconfig::POVERTY_CONTRA_PLAY_COLOR: return "poverty: contra: play color"; case Aiconfig::POVERTY_CONTRA_TRUMP_COLOR_TRICK_HIGH: return "poverty: contra: trump color trick high"; case Aiconfig::POVERTY_LEAVE_TO_PARTNER: return "poverty: contra: leave to partner"; case Aiconfig::POVERTY_OVERJAB_RE: return "poverty: contra: overjab re"; case Aiconfig::POVERTY_BEST_WINNING_CARD: return "poverty: best winning card"; case Aiconfig::MEATLESS_PLAYHIGHESTCOLOR: return "meatless: play highest color"; case Aiconfig::PICTURE_SECONDBESTTRUMP: return "picture: second best trump"; case Aiconfig::COLOR_CHOOSE_ACE: return "color: choose ace"; case Aiconfig::COLOR_BEST_WINNING: return "color: best winning"; case Aiconfig::COLOR_JAB_FOR_ACE: return "color: jab for ace"; case Aiconfig::COLOR_LOW_HIGH: return "color: play low high"; case Aiconfig::CHOOSE_BEST_CARD: return "choose best card"; } // switch(heuristic) return ""; } // string name(Aiconfig::Heuristic heuristic) /** ** -> result ** ** @param name name of the heuristic ** ** @return the heuristic according to the name ** ** @author Diether Knof ** ** @version 0.7.3 **/ Aiconfig::Heuristic Aiconfig::Heuristic_from_name(string const& name) { for (int h = HEURISTIC_FIRST; h <= HEURISTIC_LAST; ++h) if (name == ::name(static_cast(h))) return static_cast(h); return NO_HEURISTIC; } // static Aiconfig::Heuristic Aiconfig::Heuristic_from_name(string name) /** ** -> result ** ** @param difficulty difficulty ** ** @return the name of 'difficulty' ** ** @author Diether Knof ** ** @version 0.7.2 **/ string name(Aiconfig::Difficulty const difficulty) { switch(difficulty) { case Aiconfig::CUSTOM: return "custom"; case Aiconfig::NOVICE: return "novice"; case Aiconfig::STANDARD_DEFENSIVE: return "standard defensive"; case Aiconfig::STANDARD_OFFENSIVE: return "standard offensive"; case Aiconfig::PROFI: return "profi"; case Aiconfig::PROFI_UNFAIR: return "profi unfair"; } // switch(difficulty) return ""; } // string name(Aiconfig::Difficulty difficulty) /** ** -> result ** ** @param type bool type ** ** @return the name of 'type' ** ** @author Diether Knof ** ** @version 0.6.6 **/ string name(Aiconfig::TypeBool const type) { switch(type) { case Aiconfig::TRUSTING: return "trusting"; case Aiconfig::FAIRPLAYHANDS: return "fairplay hands"; case Aiconfig::FAIRPLAYTEAMS: return "fairplay teams"; case Aiconfig::FEHLCREATIONONFIRSTCARD: return "first card fehl creation"; } // switch(type) return ""; } // string name(Aiconfig::TypeBool type) /** ** -> result ** ** @param type unsigned type ** ** @return the name of 'type' ** ** @author Diether Knof ** ** @version 0.6.6 **/ string name(Aiconfig::TypeUnsigned const type) { switch(type) { case Aiconfig::REMEMBERTRICKS: return "remember tricks"; case Aiconfig::LIMIT_THROW_FEHL: return "limit throw fehl"; case Aiconfig::LIMITQUEEN: return "limit queen"; case Aiconfig::LIMITDOLLE: return "limit dolle"; case Aiconfig::LASTFEHLCREATION: return "last fehlcreation"; case Aiconfig::LAST_TRICKS_WITHOUT_HEURISTICS: return "last tricks without heuristics"; case Aiconfig::FIRST_TRICK_FOR_TRUMP_POINTS_OPTIMIZATION: return "first trick for trump points optimization"; case Aiconfig::ANNOUNCELIMIT: return "announce limit"; case Aiconfig::ANNOUNCELIMITDEC: return "announce limit decrement"; case Aiconfig::ANNOUNCECONFIG: return "announce config"; case Aiconfig::ANNOUNCELIMITREPLY: return "announce limit reply"; case Aiconfig::ANNOUNCECONFIGREPLY: return "announce config reply"; case Aiconfig::TAKEPOVERTY: return "take poverty"; case Aiconfig::SINGLESOLO: return "handvalue single solo"; case Aiconfig::DOUBLESOLO: return "handvalue double solo"; case Aiconfig::TRIPLESOLO: return "handvalue trible solo"; case Aiconfig::COLORSOLO: return "handvalue color solo"; case Aiconfig::MEATLESS: return "handvalue meatless"; } // switch(type) return ""; } // string name(Aiconfig::TypeUnsigned type) /** ** -> result ** ** @param type card type ** ** @return the name of 'type' ** ** @author Diether Knof ** ** @version 0.6.6 **/ string name(Aiconfig::TypeCard const type) { switch(type) { case Aiconfig::LIMITTHROWING: return "limit throwing"; case Aiconfig::LIMITHIGH: return "limit high"; case Aiconfig::TRUMPLIMIT_SOLOCOLOR: return "trump limit color"; case Aiconfig::TRUMPLIMIT_SOLOJACK: return "trump limit jack"; case Aiconfig::TRUMPLIMIT_SOLOQUEEN: return "trump limit queen"; case Aiconfig::TRUMPLIMIT_SOLOKING: return "trump limit king"; case Aiconfig::TRUMPLIMIT_SOLOJACKKING: return "trump limit jack king"; case Aiconfig::TRUMPLIMIT_SOLOJACKQUEEN: return "trump limit jack queen"; case Aiconfig::TRUMPLIMIT_SOLOQUEENKING: return "trump limit queen king"; case Aiconfig::TRUMPLIMIT_SOLOKOEHLER: return "trump limit koehler"; case Aiconfig::TRUMPLIMIT_MEATLESS: return "trump limit meatless"; case Aiconfig::TRUMPLIMIT_NORMAL: return "trump limit normal"; case Aiconfig::LOWEST_TRUMPLIMIT_SOLOCOLOR: return "lowest trump limit color"; case Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACK: return "lowest trump limit jack"; case Aiconfig::LOWEST_TRUMPLIMIT_SOLOQUEEN: return "lowest trump limit queen"; case Aiconfig::LOWEST_TRUMPLIMIT_SOLOKING: return "lowest trump limit king"; case Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACKKING: return "lowest trump limit jack king"; case Aiconfig::LOWEST_TRUMPLIMIT_SOLOJACKQUEEN: return "lowest trump limit jack queen"; case Aiconfig::LOWEST_TRUMPLIMIT_SOLOQUEENKING: return "lowest trump limit queen king"; case Aiconfig::LOWEST_TRUMPLIMIT_SOLOKOEHLER: return "lowest trump limit koehler"; case Aiconfig::LOWEST_TRUMPLIMIT_MEATLESS: return "lowest trump limit meatless"; case Aiconfig::LOWEST_TRUMPLIMIT_NORMAL: return "lowest trump limit normal"; } // switch(type) return ""; } // string name(Aiconfig::TypeCard type) /** ** writes the aiconfig into the output stream ** ** @param ostr stream to write in ** @param aiconfig aiconfig to write ** ** @return output stream ** ** @author Diether Knof ** ** @version 0.6.6 **/ ostream& operator<<(ostream& ostr, Aiconfig const& aiconfig) { aiconfig.write(ostr); return ostr; } // ostream& operator<<(ostream& ostr, const Aiconfig& aiconfig) /** ** -> result ** ** @param aitype ai type ** ** @return the name of 'aitype' ** ** @author Diether Knof ** ** @version 0.6.6 **/ string name(AiType const& aitype) { using namespace AITYPE; switch(aitype) { case NO_CHOOSEBESTCARD: return "no choosebestcard"; case RANDOM: return "random"; case VIRTUAL_GAMES: return "virtual games"; case GAMETREE: return "gametree"; case GAMETREE_WITH_HEURISTICS: return "gametree with heuristics"; case GAMETREE_FOR_TEAM: return "gametree for team"; case MONTE_CARLO: return "monte carlo"; } // switch(aitype) return ""; } // string name(AiType const& aitype)