/********************************************************************** * * 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 "heuristics.h" #include "HeuristicInterface.h" #include "cards_information.h" #include "cards_information.of_player.h" #include "team_information.h" #include "../../game/game.h" #include "../../party/party.h" #include "../../party/rule.h" #include "../../card/trick.h" //#define ANNOUNCE_DEBUG /* Documentation * * Each heuristic should contain the following documentation for automatic * generation of the description. * Note that the text shall not be split into multiple lines. * The name must be the first entry and the action the last. * For a real example look at 'Heuristics::serve_color_trick()'. * * @heuristic::name the name of the heuristic (as in '::name(Heuristic)') * @heuristic::idea the main idea for the heuristic * @heuristic::comment a simple comment * @heuristic::condition a condition for the heuristic * @heuristic::condition a second condition for the heuristic * @heuristic::action which card is taken */ // missing // @heuristic::name choose pfund poverty // @heuristic::idea ??? // @heuristic::name meatless: play highest color // @heuristic::idea ??? // @heuristic::name picture: second best trump // @heuristic::idea ??? // @heuristic::name color: choose ace // @heuristic::idea ??? // @heuristic::name color: best winning // @heuristic::idea ??? // @heuristic::name color: jab for ace // @heuristic::idea ??? // @heuristic::name color: play low high // @heuristic::idea ??? // special heuristics // @heuristic::name no heuristic // @heuristic::idea internal use: no heuristic was used, yet // @heuristic::name manual // @heuristic::idea The card is played manual (from the human). // // @heuristic::name bug report // @heuristic::idea Play the card from the bug report. // @heuristic::comment This heuristic is used so that in a bug report replay // @heuristic::comment the card suggestion is the card from the bug report. // @heuristic::name network // @heuristic::idea The card is played by the network player. // @heuristic::name only valid card // @heuristic::idea If there is only one valid card, play it. /* Ideen normales Spiel * Partner sitzt hinten: Farbe anspielen, die er nicht hat und von der noch mindestens 1 draußen ist * Startspieler aber kein Farb-As: Re: Karo König, Karo Neun, Karo Bube (damit Partner mit Kreuz-Dame rausrückt) Kontra: Lange Farbe anspielen (>= 4) * Partner sitzt hinter einem, beide Gegner vorne (Trumpfstich): - Pfunden (wenn Fuchs / Karo Zehn da) - rübergehen, damit Partner Sorgen los wird * Wenn Partner direkt nach mir sitzt und noch nicht dran war und kein As gespielt hat: Spiele Farbe an, damit er mit potentiellen As übernehmen kann Armut (z.B. seed 27350 (3) ) * Erster Kontra Spieler nach Re: Wenn Partner noch übertrumpfen kann (trump limit?): Punkte/drunter bleiben. (damit er hinten sitzt) wenn Partner nicht übertrumpfen kann (-> cards information): selber übertrumpfen oder kleinen rein. * Armutler nach Partner: Gegner haben Stich: wenig Punkte geben */ // ToDo: own trumplimit value for poverty unsigned number_of_no_trumps_per_color(); Card lowest_card(Hand const& hand, Card::Value const cv, HeuristicInterface const& hi); Card lowest_jack(Hand const& hand, HeuristicInterface const& hi); Card lowest_queen(Hand const& hand, HeuristicInterface const& hi); Card highest_queen(Hand const& hand, HeuristicInterface const& hi); Card highest_card(Hand const& hand, Card::Value const cv, HeuristicInterface const& hi); bool better_points_optimize(HandCard const& old_card, HandCard const& test_card, HeuristicInterface const& hi); Card lowest_color_card(Trick const& t, Hand h); /// check if opposite team can still win this trick. bool oppositeTeamCanWinTrick( Trick const &t, HeuristicInterface const& hi ) { bool trickLost = (t.winnerplayer().team() != hi.team()); // take a look if all players coming in this trick of other team can still win the trick for( unsigned i = t.actcardno(); i < hi.game().playerno(); i++ ) if( maybe_to_team(hi.teamofplayer(t.player_of_card( i ))) != hi.team() ) { trickLost = (trickLost || hi.handofplayer( t.player_of_card( i ) ).higher_card_exists( t.winnercard() )); } return trickLost; } /********************************************************************** * ** int number_of_no_trumps_per_color() * ** Parameters: number of cards per miscolor * ** Result: * ** Version: Beta * ** Description: * * **********************************************************************/ unsigned number_of_no_trumps_per_color() { DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION, "number_of_no_trumps_per_color()"); unsigned i; unsigned notrump_per_color=0; // calculate number of no trump cards per color // only one color can be trump // if spade is trump caculate with club otherwise with spade if( Card( Card::SPADE, Card::ACE ).istrump( ::party.game() ) ) { for ( i = 0; i < 2 * ::party.rule()(Rule::NUMBER_OF_CARD_VALUES); i += 2 ) if( !Card( Card::InttoColor(Card::CLUB), Card::InttoValue(i) ).istrump( ::party.game() ) ) notrump_per_color+=2; } else { for ( i = 0; i < 2 * ::party.rule()(Rule::NUMBER_OF_CARD_VALUES); i += 2 ) if( !Card( Card::InttoColor( Card::SPADE ), Card::InttoValue(i) ).istrump( ::party.game() ) ) notrump_per_color+=2; } DEBUG_RETURNING( notrump_per_color, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "number_of_no_trumps_per_color()" ); } // unsigned number_of_no_trumps_per_color() /** ** returns a card to play for the bride in an open marriage ** ** @param trick the current trick ** @param hi heuristic interface ** ** @return card to play (or Card()) ** ** @author Borg Enders ** ** @version 0.7.0 **/ Card Heuristics::play_to_marry( Trick const& trick, HeuristicInterface const& hi ) { // @heuristic::name play to marry // @heuristic::idea play card to marry if( !( hi.game().type() == GAMETYPE::MARRIAGE && hi.game().soloplayer().no() == hi.no() ) ) return Card(); Card::Color color = Card::NOCARDCOLOR; switch( hi.game().marriage_selector() ) { case MARRIAGE_SELECTOR::SILENT: case MARRIAGE_SELECTOR::TEAM_SET: return Card(); case MARRIAGE_SELECTOR::FIRST_FOREIGN: if( trick.isempty() ) { vector cards; for (vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c) { Card::Color const& color = *c; if ( Card(color, Card::ACE).istrump(hi.game()) && !HandCard( hi.hand(), Card(color, Card::ACE)).possible_swine() ) cards.push_back(Card(color, Card::ACE)); } for (vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c) { Card::Color const& color = *c; if ( !HandCard( hi.hand(), Card(color, Card::TEN)).isdolle() ) { cards.push_back(Card(color, Card::TEN)); } } for (vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c) { Card::Color const& color = *c; cards.push_back(Card(color, Card::KING)); } for (vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c) { Card::Color const& color = *c; if (! HandCard( hi.hand(), Card(color, Card::NINE)).possible_hyperswine() ) cards.push_back(Card(color, Card::NINE)); } for( vector::const_iterator card = cards.begin(); card != cards.end(); ++card ) { if( ( hi.hand().numberof( *card ) > 0 ) ) return *card; } return Card(); } return Heuristics::choose_pfund_card( trick, hi ); case MARRIAGE_SELECTOR::FIRST_TRUMP: if( !trick.isempty() && trick.startcard().istrump() ) return Heuristics::choose_pfund_card( trick, hi ); if( trick.isempty() ) { // take a 'good' card if( hi.hand().numberoftrumpaces() > 0 && !hi.hand().has_swines() ) return Card(hi.game().trumpcolor(), Card::ACE); if( hi.hand().numberof( Card( hi.game().trumpcolor(), Card::TEN ) ) > 0 ) return Card(hi.game().trumpcolor(), Card::TEN); return Heuristics::lowest_best_trump_card(trick, hi.hand(), hi); } // if (trick.startplayer().no() == hi.no()) break; case MARRIAGE_SELECTOR::FIRST_CLUB: color = Card::CLUB; case MARRIAGE_SELECTOR::FIRST_SPADE: if( color == Card::NOCARDCOLOR ) color = Card::SPADE; case MARRIAGE_SELECTOR::FIRST_HEART: if( color == Card::NOCARDCOLOR ) color = Card::HEART; if( !trick.isempty() && trick.startcard().tcolor() == color ) return Heuristics::choose_pfund_card( trick, hi ); if( trick.isempty() ) { vector cards; if (!hi.game().rule()(Rule::DOLLEN)) cards.push_back(Card(color, Card::TEN)); cards.push_back(Card(color, Card::KING)); cards.push_back(Card(color, Card::NINE)); // cards.push_back(Card(color, Card::ACE)); // With Ace I will probably win the trick bad decision for( vector::const_iterator c = cards.begin(); c != cards.end(); ++c ) if( hi.hand().numberof( *c ) > 0 ) return *c; } break; case MARRIAGE_SELECTOR::FIRST_COLOR: if( trick.isempty() ) { vector cards; for (vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c) { Card::Color const& color = *c; if ( !HandCard( hi.hand(), Card(color, Card::TEN)).isdolle() ) cards.push_back(Card(color, Card::TEN)); } for (vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c) { Card::Color const& color = *c; cards.push_back(Card(color, Card::KING)); } for (vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c) { Card::Color const& color = *c; cards.push_back(Card(color, Card::NINE)); } for( vector::const_iterator card = cards.begin(); card != cards.end(); ++card ) { if( ( hi.hand().numberof( *card ) > 0 ) && !card->istrump( hi.game() ) ) return *card; } return Card(); } if( trick.startplayer().no() != hi.no() && !trick.startcard().istrump() ) return Heuristics::choose_pfund_card( trick, hi ); if( trick.startplayer().no() == hi.no() ) return lowest_color_card(trick, hi.hand()); break; } // switch(marriage_selector) return Card(); } // static Card Heuristics::play_to_marry(Trick trick, HeuristicInterface hi) /** ** for a first card in a trick play a color ace ** if there are still enough cards of this color in the game ** and the color has not been jabbed ** choose the ace with the most cards in that color still in the game ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play (color ace or none) ** ** @author Diether Knof ** @author Borg Enders ** ** @version 0.7.4 **/ Card Heuristics::choose_ace(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name choose ace // @heuristic::idea for the first card in a trick choose the best color Ace to play // I'am not the start Player if( !trick.isstartcard() ) return Card(); // the number of remaining cards for the color map number_of_remaining_cards; // the card to play Card ace_to_play; // the maximal number of remaining cards found so far unsigned best_modified_remaining_cards = 0; for (vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c) { Card::Color const& color = *c; Card const ace(color, Card::ACE); // test that the color is no trumpcolor if ( (color != hi.game().trumpcolor()) // test that the player has an ace of the color && hi.hand().contains(ace)) { // the number of remaining cards for the other players unsigned const remaining_cards = (hi.game().numberof(color) - (hi.cards_information().played(*c) + hi.hand().numberof(*c))); // modified remaining cards // Modified by the number of aces of the color. // This is used to prefer single aces to double aces. unsigned const modified_remaining_cards = (remaining_cards + ( (hi.hand().numberof(ace) + hi.cards_information().played(ace) < hi.game().rule()(Rule::NUMBER_OF_SAME_CARDS)) ? (hi.game().numberof(color) - 1) // *Value* : 0) ); // there are enough cards for all players if ( (remaining_cards >= hi.game().playerno() - 1) // if the color has already been jabbed, it has to be from the own team && ( !hi.colorjabbed(color) || ( hi.jabbedbyownteam(color)) && !hi.jabbedbyotherteam(color)) // no ace found so far && ( !ace_to_play // there must not be less remaining cards then the best || ( (modified_remaining_cards >= best_modified_remaining_cards) // if both colors have the same cards out, // take the one the player has fewer aces && ( (modified_remaining_cards == best_modified_remaining_cards) ? (hi.hand().numberof(ace) < hi.hand().numberof(ace_to_play)) : true) ) ) ) { best_modified_remaining_cards = modified_remaining_cards; ace_to_play = ace; } // if (take card) } // if (the color is no trumpcolor and the player has an ace of the color) } // for (i < ha.cardsnumber()) return ace_to_play; } // Card Heuristics::choose_ace(Trick trick, HeuristicInterface hi) /********************************************************************** * ** Card lowest_card(Hand h,Card::Value cv) * ** Parameters: * ** Result: finds lowest card with value cv * ** Version: Beta * ** Description: * **********************************************************************/ Card lowest_card( Hand const& h, Card::Value const cv, HeuristicInterface const& hi ) { DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_card()"); Card c=Card(); unsigned i; for( i = 0; i < h.cardsnumber(); i++ ) { // find any card if( h.card(i).value() ==cv ) { c = h.card(i); break; } } if( c == Card() ) { DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_jack()" ); } for( i = 0; i < h.cardsnumber(); i++ ) { // find lowest card if( h.card(i).value() == cv && h.card(i).less(c) ) c = h.card(i); } DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_card()" ); } /********************************************************************** * ** Card lowest_card(Hand h,Card::Value cv) * ** Parameters: * ** Result: finds lowest card with value cv * ** Version: Beta * ** Description: * **********************************************************************/ Card highest_card( Hand const& h, Card::Value const cv, HeuristicInterface const& hi ) { DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_card()"); Card c = Card(); unsigned i; for( i = 0; i < h.cardsnumber(); i++ ) { // find any card if( h.card(i).value() == cv ) { c = h.card(i); break; } } if( c == Card() ) { DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_jack()" ); } for( i = 0; i < h.cardsnumber(); i++ ) { // find highest card if( h.card(i).value() == cv && !h.card(i).less(c) ) c=h.card(i); } DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_card()" ); } /********************************************************************** * ** Card lowest_jack(Hand h) * ** Parameters: * ** Result: finds lowest jack on Hand h * ** Version: Beta * ** Description: * **********************************************************************/ Card lowest_jack( Hand const& h, HeuristicInterface const& hi ) { DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::lowest_jack()"); DEBUG_RETURNING( lowest_card( h, Card::JACK, hi ), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_jack()"); } /********************************************************************** * ** Card lowest_queen(Hand h) * ** Parameters: * ** Result: finds lowest queen on Hand h * ** Version: Beta * ** Description: * **********************************************************************/ Card highest_queen( Hand const& h, HeuristicInterface const& hi ) { DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_queen()"); DEBUG_RETURNING( highest_card( h, Card::QUEEN, hi ), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_queen()"); } /********************************************************************** * ** Card lowest_queen(Hand h) * ** Parameters: * ** Result: finds lowest queen on Hand h * ** Version: Beta * ** Description: * **********************************************************************/ Card lowest_queen( Hand const& h, HeuristicInterface const& hi ) { DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_queen()"); DEBUG_RETURNING( lowest_card( h, Card::QUEEN, hi ), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_queen()"); } /** ** checks if there are any trumps in trick t ** ** @author Borg Enders ** **/ bool trumpInTrick( Trick t ) { bool trumpintrick = false; for( unsigned i = 0 ; i < t.actcardno(); i++ ) { trumpintrick = trumpintrick || t.card( i ).istrump(); } return trumpintrick; } /** ** checks if all remaining player in the trick are of my team **/ bool checkAllMyTeam( Trick const& t, HeuristicInterface const& hi ) { bool allmyteam = true; // take a look if all players coming in this trick are of mine team for( unsigned i = t.actcardno(); i < hi.game().playerno(); i++ ) allmyteam = ( allmyteam && ( hi.team() == hi.teamofplayer( t.player_of_card( i ) ) )); return allmyteam; } /********************************************************************** * ** Card Heuristics::best_winning_card(Trick const& t, HeursticInterface const& hi) * ** Parameters: actual trick, HeuristicInterface who plays next card ** point modifikator to add to points of t * ** Result: finds best card on Hand of hi, which wins this trick, ** non trump ace or lowest trump ** greater than jack, only in lastcard lower trumps are allowed ** the card will be chosen taking the value of the trick in account * ** Version: Beta * ** Description: * **********************************************************************/ Card Heuristics::best_winning_card_single_picture(Trick const& t, Card::Value v, HeuristicInterface const& hi, unsigned pointmodi) { // @heuristic::name ? best winning card single picture ? // @heuristic::idea Only valid for soli with only one picture as trump: Tries to find the best card to win a trick depending on different values like Aiconfig::LIMITQUEEN DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()"); if ( t.isstartcard() ) DEBUG_RETURNING( Card(), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()"); Card c = Card(); HandCards const ha = hi.hand().validcards( t ); unsigned i; bool allmyteam = checkAllMyTeam( t, hi ); // find any card that wins this trick greater or equal to lowest_trump_card_limit for( i = 0; i < ha.cardsnumber(); i++ ) { if( t.isvalid( ha.card(i), hi.hand() ) && t.is_jabbed(ha.card(i)) && ( hi.lowest_trump_card_limit().less( ha.card( i ) ) || allmyteam ) ) { c = ha.card(i); break; } } // if can't win this trick and I'am not the last player: that's it if( c == Card() && !t.islastcard() ) { DEBUG_RETURNING(c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()"); } bool trumpintrick = trumpInTrick( t ); // or this is a color trick of a first color run with my card the first trump allmyteam = ( allmyteam || ( t.actcardno() > 1 && hi.color_runs(t.startcard().color()) == 0 && !t.startcard().istrump() && !trumpintrick ) ); // find a better card for( i = 0; i < ha.cardsnumber(); i++ ) { if( t.isvalid( ha.card( i ), hi.hand() ) && t.is_jabbed(ha.card(i)) ) { // non trump ace is always the best choice if color is not already jabbed if( ha.card(i).value() == Card::ACE && !ha.card(i).istrump() && ( !hi.colorjabbed( ha.card(i).color() ) || hi.jabbedbyownteam( ha.card(i).color() ) || allmyteam ) ) { c=ha.card(i); break; } if ( ha.card(i).istrump() ) { // find lowest trump if( ( hi.lowest_trump_card_limit().less( ha.card(i) ) || t.islastcard() || allmyteam ) && ha.card(i).less( c ) ) { c = ha.card(i); continue; } }// if card istrump } // if winneris } // if last card or first_color_run of trick let's check for a better card // Ace, ten, king, nine if( t.islastcard() || allmyteam ||( !t.isstartcard() && !t.startcard().istrump() && hi.color_runs(t.startcard().color()) < 1 && ( t.startcard().color()!= Card::HEART || !HandCard( hi.hand(), Card::HEART, Card::TEN ).isdolle() ) ) ) { for( i = 0; i < ha.cardsnumber(); i++ ) { if( t.isvalid( ha.card( i ), hi.hand() ) && t.is_jabbed(ha.card(i)) ) { // ace is always the best card if( !ha.card(i).isswine() && ha.card(i).value()==Card::ACE && ( allmyteam || !ha.card( i ).istrump() || t.islastcard() ) ) { c = ha.card(i); break; } if( ha.card(i).value() == Card::TEN && !ha.card(i).isdolle() && ( t.islastcard() || allmyteam || ( hi.color_runs( t.startcard().color() ) == 0 && !t.startcard().istrump() ) ) ) { c = ha.card(i); if ( t.islastcard() || allmyteam ) break; continue; } if( ha.card( i ).value() != v && ha.card( i ).value() < Card::TEN ) { c = ha.card(i); continue; } } } // for (i < ha.cardsnumber()) } DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()" ); } // Card Heuristics::best_winning_card_single_picture(Trick t, Card::Value v, HeuristicInterface hi, unsigned pointmodi) /********************************************************************** * ** Card Heuristics::best_winning_card(Trick const& t, HeursticInterface const& hi) * ** Parameters: actual trick, HeuristicInterface who plays next card ** point modifikator to add to points of t * ** Result: finds best card on Hand of hi, which wins this trick, ** non trump ace or lowest trump ** greater than jack, only in lastcard lower trumps are allowed ** the card will be chosen taking the value of the trick in account * ** Version: Beta * ** Description: * **********************************************************************/ Card Heuristics::best_winning_card_double_picture( Trick const& t, Card::Value v1, Card::Value v2, HeuristicInterface const& hi, unsigned pointmodi ) { // @heuristic::name ? best winning card double picture ? // @heuristic::idea Only valid for soli with only tow picutes as trump: Tries to find the best card to win a trick depending on different values like Aiconfig::LIMITQUEEN DEBUG_CALLING( INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()" ); if ( t.isstartcard() ) DEBUG_RETURNING( Card(), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()" ); Trick tr; Card c = Card(); HandCards const ha = hi.hand().validcards(t); unsigned i; bool allmyteam = checkAllMyTeam( t, hi );; // find any card that wins this trick greater or equal to lowest_trump_card_limit for( i = 0; i < ha.cardsnumber(); i++ ) { tr = t; tr += ha.card(i); if( tr.winnerplayer().no() == hi.no() && t.isvalid( ha.card(i),hi.hand() ) && ( hi.lowest_trump_card_limit().less( ha.card(i) ) || allmyteam ) ) { c = ha.card(i); break; } } // if can't win this trick and I'am not the last player: that's it if( c == Card() && !t.islastcard() ) { DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()" ); } bool trumpintrick = trumpInTrick( t ); // or this is a color trick of a first color run with my card the first trump allmyteam = allmyteam ||( t.actcardno() > 1 && hi.color_runs(t.startcard().color()) == 0 && !t.startcard().istrump() && !trumpintrick ); // find a better card for ( i = 0; i < ha.cardsnumber(); i++ ) { tr = t; tr += ha.card( i ); if( tr.winnerplayer().no() == hi.no() && t.isvalid( ha.card(i),hi.hand() ) ) { // non trump ace is always the best choice if color is not already jabbed if( ha.card(i).value() == Card::ACE && !ha.card(i).istrump() && ( !hi.colorjabbed( ha.card(i).color() ) || hi.jabbedbyownteam(ha.card(i).color()) || allmyteam ) ) { c = ha.card( i ); break; } if( ha.card(i).istrump() ) { // find lowest trump if( ( hi.lowest_trump_card_limit().less( ha.card(i) ) || t.islastcard() || allmyteam ) && ha.card(i).less(c) ) { c = ha.card(i); continue; } }// if card istrump } // if winneris } // if last card or first_color_run of trick let's check for a better card // Ace, ten, king, nine if( t.islastcard() || allmyteam ||( !t.isstartcard() && !t.startcard().istrump() && hi.color_runs(t.startcard().color())<1 && ( t.startcard().color()!= Card::HEART || !HandCard( hi.hand(), Card::HEART, Card::TEN ).isdolle() ) ) ) { for( i = 0; i < ha.cardsnumber(); i++ ) { tr = t; tr += ha.card(i); if( tr.winnerplayer().no()==hi.no() && t.isvalid(ha.card(i),hi.hand()) ) { // ace is always the best card if( !ha.card(i).isswine() && ha.card(i).value()==Card::ACE && ( allmyteam || !ha.card(i).istrump() || t.islastcard() ) ) { c = ha.card(i); break; } if( ha.card(i).value() == Card::TEN && !ha.card(i).isdolle() && ( t.islastcard() || allmyteam || ( hi.color_runs(t.startcard().color()) == 0 && !t.startcard().istrump() ) ) ) { c = ha.card(i); if ( t.islastcard() || allmyteam ) break; continue; } if( ha.card(i).value() != v1 && ha.card(i).value() != v2 && ha.card(i).value() < Card::TEN ) { c = ha.card(i); continue; } } } } DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()"); } /********************************************************************** * ** Card Heuristics::best_winning_card(Trick const& t, HeursticInterface const& hi) * ** Parameters: actual trick, HeuristicInterface who plays next card ** point modifikator to add to points of t * ** Result: finds best card on Hand of hi, which wins this trick, ** non trump ace or lowest trump ** greater than jack, only in lastcard lower trumps are allowed ** the card will be chosen taking the value of the trick in account * ** Version: Beta * ** Description: * **********************************************************************/ Card Heuristics::best_winning_card_triple_picture( Trick const& t, HeuristicInterface const& hi, unsigned pointmodi ) { // @heuristic::name ? best winning card triple picture ? // @heuristic::idea Only valid for soli with only three pictures as trump: Tries to find the best card to win a trick depending on different values like Aiconfig::LIMITQUEEN DEBUG_CALLING( INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()" ); if ( t.isstartcard() ) DEBUG_RETURNING( Card(), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()" ); Trick tr; Card c = Card(); HandCards const ha = hi.hand().validcards( t ); unsigned i; bool allmyteam = checkAllMyTeam( t, hi );; // find any card that wins this trick greater or equal to lowest_trump_card_limit for( i = 0; i < ha.cardsnumber(); i++ ) { tr = t; tr += ha.card( i ); if( tr.winnerplayer().no() == hi.no() && t.isvalid( ha.card(i), hi.hand() ) && ( hi.lowest_trump_card_limit().less( ha.card(i) ) || allmyteam ) ) { c = ha.card(i); break; } } // if can't win this trick and I'am not the last player: that's it if( c==Card() && !t.islastcard() ) { DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()" ); } bool trumpintrick = trumpInTrick( t ); // or this is a color trick of a first color run with my card the first trump allmyteam = allmyteam || ( t.actcardno() > 1 && hi.color_runs(t.startcard().color()) == 0 && !t.startcard().istrump() && !trumpintrick ); // find a better card for( i = 0; i < ha.cardsnumber(); i++ ) { tr = t; tr += ha.card(i); if( tr.winnerplayer().no() == hi.no() && t.isvalid( ha.card( i ), hi.hand() ) ) { // non trump ace is always the best choice if color is not already jabbed if( ha.card(i).value() == Card::ACE && !ha.card(i).istrump() && ( !hi.colorjabbed( ha.card( i ).color() ) || hi.jabbedbyownteam( ha.card( i ).color() ) || allmyteam ) ) { c = ha.card( i ); break; } if( ha.card(i).istrump() ) { // find lowest trump if( ( hi.lowest_trump_card_limit().less( ha.card(i) ) || t.islastcard() || allmyteam ) && ha.card(i).less(c) ) { c = ha.card( i ); continue; } }// if card istrump } // if winneris } // if last card or first_color_run of trick let's check for a better card // Ace, ten, king, nine if( t.islastcard() || allmyteam ||( !t.isstartcard() && !t.startcard().istrump() && hi.color_runs( t.startcard().color() ) < 1 && ( t.startcard().color()!= Card::HEART || !HandCard( hi.hand(), Card::HEART, Card::TEN ).isdolle() ) ) ) { for( i = 0; i < ha.cardsnumber(); i++ ) { tr = t; tr += ha.card( i ); if( tr.winnerplayer().no() == hi.no() && t.isvalid( ha.card( i ), hi.hand() ) ) { // ace is always the best card if( !ha.card(i).isswine() && ha.card(i).value() == Card::ACE && ( allmyteam || !ha.card(i).istrump() || t.islastcard() ) ) { c = ha.card(i); break; } if( ha.card(i).value() == Card::TEN && !ha.card(i).isdolle() && ( t.islastcard() || allmyteam || ( hi.color_runs( t.startcard().color()) == 0 && !t.startcard().istrump() ) ) ) { c = ha.card( i ); if ( t.islastcard() || allmyteam ) break; continue; } if( ha.card(i).value() == Card::NINE ) { c = ha.card(i); continue; } } } } DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()" ); } /********************************************************************** * ** Card Heuristics::best_winning_card(Trick const& t, HeursticInterface const& hi) * ** Parameters: actual trick, HeuristicInterface who plays next card ** point modifikator to add to points of t * ** Result: finds best card on Hand of hi, which wins this trick, ** non trump ace or lowest trump ** greater than jack, only in lastcard lower trumps are allowed ** the card will be chosen taking the value of the trick in account * ** Version: Beta * ** Description: * **********************************************************************/ Card Heuristics::best_winning_card(Trick const& t, HeuristicInterface const& hi, unsigned pointmodi ) { // @heuristic::name best winning card // @heuristic::idea Tries to find the best card to win a trick depending on different values like Aiconfig::LIMITQUEEN switch (hi.game().type()) { case GAMETYPE::SOLO_JACK: return best_winning_card_single_picture( t, Card::JACK, hi, pointmodi ); case GAMETYPE::SOLO_QUEEN: return best_winning_card_single_picture( t, Card::QUEEN, hi, pointmodi); case GAMETYPE::SOLO_KING: return best_winning_card_single_picture( t, Card::KING, hi, pointmodi); case GAMETYPE::SOLO_QUEEN_JACK: return best_winning_card_double_picture( t, Card::JACK, Card::QUEEN, hi, pointmodi); case GAMETYPE::SOLO_KING_JACK: return best_winning_card_double_picture( t, Card::JACK, Card::KING, hi, pointmodi); case GAMETYPE::SOLO_KING_QUEEN: return best_winning_card_double_picture( t, Card::KING, Card::QUEEN, hi, pointmodi); case GAMETYPE::SOLO_KOEHLER: return best_winning_card_triple_picture( t, hi, pointmodi); default: break; } // switch (hi.game().type()) if( t.isstartcard() ) DEBUG_RETURNING( Card(), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()" ); HandCard c( hi.hand() ); HandCards const ha = hi.hand().validcards( t ); unsigned i; Game const& game = t.game(); bool allmyteam = checkAllMyTeam( t, hi ); unsigned tpoints = t.points() + pointmodi; bool trickLost = false; // take a look if all players coming in this trick of other team can still win the trick for( unsigned i = t.actcardno(); i < hi.game().playerno(); i++ ) if( maybe_to_team(hi.teamofplayer(t.player_of_card( i ))) != hi.team() ) { trickLost = (trickLost || hi.handofplayer( t.player_of_card( i ) ).higher_card_exists( t.winnercard() )); } if( !trickLost || allmyteam ) { // take lowest trump which takes this trick for( i = 0; i < ha.cardsnumber(); i++ ) { HandCard const& card = ha.card(i); if (!t.is_jabbed(card)) continue; if( !card.isdolle() && !card.possible_swine() && !card.possible_hyperswine() && ( c == Card() || c.value() <= card.value() ) ) c = card; } } if( c != Card() && !t.islastcard() ) { DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()" ); } // find any card that wins this trick greater or equal to lowest_trump_card_limit for( i = 0; i < ha.cardsnumber(); i++ ) { HandCard const& card = ha.card(i); if (!t.is_jabbed(card)) continue; if (!( hi.lowest_trump_card_limit().less(card) || allmyteam) ) continue; if( (card.value() == Card::QUEEN ) && (tpoints >= hi.value(Aiconfig::LIMITQUEEN)) ) { c = card; if (!t.islastcard()) { break; } } if( card.value() == Card::QUEEN ) continue; if( ( card.isdolle() || card.possible_swine() || card.possible_hyperswine() ) && tpoints >= hi.value( Aiconfig::LIMITDOLLE ) ) { c = card; if (!t.islastcard()) { break; } } if( card.isdolle() || card.possible_swine() || card.possible_hyperswine() ) continue; c = card; break; } // for(i) // if can't win this trick and I'am not the last player: that's it if( (c == Card()) && !t.islastcard() ) { DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()" ); } bool trumpintrick = trumpInTrick( t ); // or this is a color trick of a first color run with my card the first trump allmyteam = allmyteam ||( t.actcardno() > 1 && hi.color_runs(t.startcard().color()) == 0 && !t.startcard().istrump() && !trumpintrick && ( t.startcard().color()!= Card::HEART || !HandCard(hi.hand(), Card::HEART, Card::TEN ).isdolle() ) ); // find a better card for( i = 0; i < ha.cardsnumber(); i++ ) { HandCard const& card = ha.card(i); if (!t.is_jabbed(card)) continue; // non trump ace is always the best choice if color is not already jabbed if( card.value() == Card::ACE && !card.istrump() && ( !hi.colorjabbed( card.color() ) || hi.jabbedbyownteam( card.color() ) || allmyteam ) ) { c = card; break; } if( card.istrump() ) { // find lowest trump if( t.islastcard() && card.less(Card(Card::DIAMOND, Card::JACK)) && card.less( c ) ) { c = card; continue; } if (!card.less(Card(Card::DIAMOND, Card::JACK))) { if( !t.isstartcard() && card.less(Card(Card::DIAMOND, Card::QUEEN)) && !t.startcard().istrump() && card.less( c ) && ( !hi.colorjabbed( t.startcard().color() ) || tpoints <= hi.value( Aiconfig::LIMITQUEEN ) || ha.numberof( Card::QUEEN ) < 2 || t.islastcard() ) ) { c = card; continue; } if( (card.value() == Card::QUEEN) && (tpoints >= hi.value( Aiconfig::LIMITQUEEN ) ) && ( ( c.less(Card(Card::DIAMOND, Card::QUEEN)) && !t.islastcard() && ( hi.color_runs( t.startcard().color() ) != 0 || ( hi.color_runs( t.startcard().color() ) == 0 && hi.game().type() == GAMETYPE::POVERTY ) || t.startcard().istrump() || tpoints > hi.value( Aiconfig::LIMITDOLLE ) ) ) || ( card.less( c ) && ( c != Card( Card::CLUB, Card::QUEEN ) || hi.game().player( hi.no() ).announcement() != ANNOUNCEMENT::NOANNOUNCEMENT ) ) || ( card == Card( Card::CLUB, Card::QUEEN ) && hi.game().player( hi.no() ).announcement() == ANNOUNCEMENT::NOANNOUNCEMENT ) ) ) { c = card; continue; } if( ( card.isdolle() || card.possible_swine() || card.possible_hyperswine() ) && ( card.less(c) || ( tpoints >= hi.value( Aiconfig::LIMITDOLLE ) && c.less(Card(Card::DIAMOND, Card::QUEEN)) && !hi.color_runs( t.startcard().color() ) < 1 && !t.islastcard() ) ) ) { c = card; continue; } }//if card>jack }// if card istrump } // if winneris if( c == Card() ) { DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()" ); } Trick tempTrick = t; tempTrick += c; //if opposite team can win trick no further optimization if ( oppositeTeamCanWinTrick( tempTrick, hi ) && !t.islastcard() ) { // make it as hard as possible with selected trump type if( c.value() ==Card::JACK || c.value() == Card::QUEEN ) c = highest_card( hi.hand(), c.value(), hi ); DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()" ); } // if last card or first_color_run of trick let's check for a better card // Ace, ten, king, nine if( t.islastcard() || allmyteam ||( !t.isstartcard() && !t.startcard().istrump() && hi.color_runs( t.startcard().color() ) < 1 && ( t.startcard().color() != Card::HEART || !HandCard( hi.hand(), Card::HEART, Card::TEN ).isdolle() ) ) ) { for( i = 0; i < ha.cardsnumber(); i++ ) { HandCard const& card = ha.card(i); if (!t.is_jabbed(card)) continue; // Maybe it's time to get the heart ten back home if( card.isdolle() &&( ( hi.hand().numberoftrumps() < 5 && hi.hand().numberof( Card::DOLLE ) == 1 && hi.game().rule()(Rule::EXTRAPOINT_DOLLE_JABS_DOLLE) && !hi.cards_information().played(Card::DOLLE) ) || ( hi.hand().numberoftrumps() < 6 && hi.game().swines_owner() != NULL && hi.teamofplayer( *hi.game().swines_owner() ) != hi.team() ) || ( hi.hand().numberoftrumps() < 6 && hi.game().hyperswines_owner() != NULL && hi.teamofplayer( *hi.game().hyperswines_owner() ) != hi.team() ) ) ) { c = card; break; } // ace is always the best card if( !card.possible_swine() && card.value() == Card::ACE && ( allmyteam || !card.istrump() || t.islastcard() ) ) { c = card; break; } if( card.value() == Card::TEN && !card.isdolle() && c.value() != Card::ACE && ( t.islastcard() || allmyteam || ( hi.color_runs( t.startcard().color() ) == 0 && hi.game().type() != GAMETYPE::POVERTY && !t.startcard().istrump() ) ) ) { c = card; continue; } if( card.value() == Card::KING && game.type() != GAMETYPE::SOLO_KOEHLER && !card.possible_hyperswine() ) { if( c.value()!=Card::TEN || c.isdolle() ) { c = card; } continue; } if( card.value() == Card::NINE && !card.possible_hyperswine() ) { if( ( c.value() != Card::TEN && c.value() != Card::KING && c.value() != Card::ACE && better_points_optimize( c, card, hi ) ) || c.isdolle() || c.possible_hyperswine() ) { c = card; } continue; } if( c.istrump() && card.istrump() && card.less(c) ) { if( ( c.value() != Card::TEN && c.value() != Card::KING && c.value() != Card::ACE && better_points_optimize( c, card, hi ) && ( c != Card( Card::CLUB, Card::QUEEN ) || hi.game().player( hi.no() ).announcement() != ANNOUNCEMENT::NOANNOUNCEMENT ) ) || c.isdolle() || c.possible_hyperswine() ) { c = card; } continue; } } // for (i) } // if (last card or first color run) DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::best_winning_card()" ); } // Card Heuristics::best_winning_card(Trick t, HeuristicInformation hi, unsigned pointmodi) /********************************************************************** * ** Card lowest_color_card(Trick const& t, Hand h) * ** Parameters: actual trick, and hand of player * ** Result: finds lowest color card on Hand h * ** Version: Beta * ** Description: * **********************************************************************/ Card lowest_color_card( Trick const& t, Hand h ) { return h.lowest_card(t.startcard().tcolor()); #ifdef OUTDATED // 0.7.4 2006-09-19 DEBUG_CALLING( INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_color_card()" ); Card c = Card(); HandCards const ha = h.validcards( t ); unsigned i; // find any card that's allowed for this trick for( i =0; i < ha.cardsnumber(); i++ ) { if( !ha.card( i ).istrump() ) { c = ha.card( i ); break; } } if( c == Card() ) { DEBUG_RETURNING(c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_color_card()" ); } // find a better card for( i += 1; i < ha.cardsnumber(); i++ ) { if( !ha.card(i).istrump() && (c.value() <= ha.card( i ).value()) ) c = ha.card( i ); } DEBUG_RETURNING(c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_color_card()" ); #endif } /********************************************************************** * ** Card lowest_color_card_meatless(Trick const& t, Hand h) * ** Parameters: actual trick, and hand of player * ** Result: finds lowest color card on Hand h, wihich is the best ** in a meatless solo * ** Version: Beta * ** Description: * **********************************************************************/ Card lowest_color_card_meatless( Trick const& t, Hand h ) { DEBUG_CALLING( INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_color_card()" ); Card c = Card(); HandCards const ha = h.validcards( t ); unsigned i; // find any card that's allowed for this trick for( i = 0; i < ha.cardsnumber(); i++ ) { if( !ha.card( i ).istrump() ) { c = ha.card( i ); break; } } if( c == Card() ) { DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_color_card()" ); } // find a better card for( i = 0; i < ha.cardsnumber(); i++ ) { if( !ha.card( i ).istrump() && c.value() <= ha.card(i).value() && ( ha.numberof( ha.card(i).color() ) > ha.numberof( c.color() ) || ( ha.numberof( ha.card(i).color(), Card::TEN ) == 0 && ha.numberof( ha.card(i).color(), Card::ACE ) == 0 ) ) ) c = ha.card(i); } DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_color_card()"); } /********************************************************************** * ** Card lowest_trump_card(Trick const& t, Hand h) * ** Parameters: actual trick, and hand of player * ** Result: finds lowest trump card on Hand h * ** Version: Beta * ** Description: * **********************************************************************/ Card lowest_trump_card( Trick const& t, Hand h ) { DEBUG_CALLING( INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_trump_card()" ); Card c = Card(); HandCards const ha = h.validcards( t ); unsigned i; // find any card that's allowed for this trick for( i = 0; i < ha.cardsnumber(); i++ ) { if( ha.card( i ).istrump() ) { c = ha.card( i ); break; } } if( c == Card() ) { DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_trump_card()" ); } // find a better card for( i = 0; i < ha.cardsnumber(); i++ ) { if( ha.card(i).less( c ) && ha.card(i).istrump() ) c = ha.card( i ); } DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_trump_card()" ); } /********************************************************************** * ** Card lowest_best_trump_card(Trick const& t, Hand h) * ** Parameters: actual trick, and hand of player * ** Result: finds lowest trump card on Hand h, but gives only fuchs or ten back ** if there are better cards to keep * ** Version: Beta * ** Description: * **********************************************************************/ Card Heuristics::lowest_best_trump_card( Trick const& t, Hand const& h, HeuristicInterface const& hi ) { // @heuristic::name ? lowest best trump ? // @heuristic::idea find smallest best trump card (avoiding for example a fox in most situations) DEBUG_CALLING( INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_best_trump_card()" ); HandCard c( h ); HandCards const ha = hi.hand().validcards( t ); unsigned i; // find any card that's allowed for this trick for( i = 0; i < ha.cardsnumber(); i++ ) { if ( ha.card( i ).istrump() ) { c = ha.card( i ); break; } } if( c == Card() ) { DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_best_trump_card()" ); } // find a better card for( i = 0; i < ha.cardsnumber(); i++ ) { if( ha.card( i ).less( c ) && ha.card( i ).istrump() && !ha.card( i ).isfox() && ( ha.card(i).value() != Card::TEN || c.isfox() ) ) c = ha.card( i ); } if( !c.less( hi.trump_card_limit() ) ) // maybe a diamond ten isn't all that bad { for( i = 0; i < ha.cardsnumber(); i++ ) { if( ha.card( i ).less( c ) && ha.card( i ).istrump() && !ha.card( i ).isfox() ) c = ha.card( i ); } } if( !c.less( hi.trump_card_limit() ) ) // maybe a diamond Ace isn't all that bad { for( i = 0; i < ha.cardsnumber(); i++ ) { if( ha.card( i ).less( c ) && ha.card(i).istrump() ) c = ha.card( i ); } } DEBUG_RETURNING(c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::lowest_best_trump_card()"); } /********************************************************************** * ** Card Heuristics::choose_pfund_card(Trick t, HeursticInterface const& hi) * ** Parameters: actual played trick, HeuristicInterface who plays next card * ** Result: result see description, otherwise ** result is a card with Card::NOCARDVALUE and Card::NOCARDCOLOR * ** Version: Beta * ** Description: ** best pfund on hand ** a trump Ass, color ten or Ace, trump ten, a king, ** a notrump queen or jack, nine * **********************************************************************/ Card Heuristics::choose_pfund_card( Trick const& trick, HeuristicInterface const& hi ) { // @heuristic::name ? choose pfund card ? // @heuristic::idea find a pfund card Trick t = trick; DEBUG_ASSERTION( !t.isempty(), "Heuristics::choose_pfund_card():\n" " Called with empty trick"); unsigned i; bool allmyteam = ( checkAllMyTeam( t, hi ) && hi.jabbedbyownteam( t.startcard().color() ) ); // marriage determination for the bride if ( (hi.game().type() == GAMETYPE::MARRIAGE) && is_selector(t.startcard().tcolor(), hi.game().marriage_selector()) && (hi.no() == hi.game().soloplayer().no()) ) allmyteam = true; Card c = Card(); HandCards const ha = hi.hand().validcards( t ); bool solo_check = ( GAMETYPE::is_solo( hi.game().type() ) && hi.color_runs(t.startcard().color()) == 0 && !t.startcard().istrump() && t.winnerplayer() == hi.game().soloplayer() && t.winnercard().less( hi.trump_card_limit() ) && !t.islastcard() ) ; // then find first trump ace for( i = 0; i < ha.cardsnumber(); i++ ) { if( ha.card(i).value() == Card::ACE && ha.card(i).istrump() && ( t.islastcard() || ha.numberoftrumps() < 3 || ( hi.color_runs(t.startcard().color()) == 0 && !t.startcard().istrump() ) || ( ! hi.cards_information().higher_card_exists( t.winnercard()) //!t.winnercard().less( Card( Card::CLUB, Card::QUEEN ) ) && hi.teamofplayer( t.winnerplayer() )== hi.team() ) || ( hi.game().type() == GAMETYPE::MARRIAGE && hi.game().soloplayer().no() == hi.no() && hi.game().marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET && hi.game().marriage_selector() == MARRIAGE_SELECTOR::FIRST_FOREIGN ) ) && !ha.card(i).possible_swine() ) { t += ha.card( i ); if( ( (hi.teamofplayer( t.winnerplayer() )== hi.team()) && !( hi.game().rule()(Rule::GENSCHER) && (hi.game().type() == GAMETYPE::NORMAL) && !hi.cards_information().played(Card(Card::DIAMOND, Card::KING)) && (ha.numberoftrumps() >= 6) // *Value* ) ) || ( hi.game().type() == GAMETYPE::MARRIAGE && hi.game().soloplayer().no() == hi.no() && hi.game().marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET // ToDo: other marriage selectors && (hi.game().marriage_selector() == MARRIAGE_SELECTOR::FIRST_FOREIGN ) ) ) { DEBUG_RETURNING( ha.card(i), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_pfund_card()" ); } } } // for (i < ha.cardsnumber) Card best_ace; // choose an ace of a color if the player has two aces for( vector::const_iterator color = hi.game().rule().card_colors().begin(); color != hi.game().rule().card_colors().end(); ++color ) { Card const local_ace( *color, Card::ACE ); if( ( hi.hand().numberof( local_ace ) == hi.game().rule()(Rule::NUMBER_OF_SAME_CARDS) || ( hi.hand().numberof(local_ace) == 1 && ( ( (hi.cards_information().played(*color) >= 4) && (hi.game().type() != GAMETYPE::SOLO_MEATLESS)) || (hi.hand().numberof(*color) == 1) ) ) ) && !local_ace.istrump( hi.game() ) && t.isvalid(local_ace, hi.hand()) && ( hi.teamofplayer(t.winnerplayer()) == hi.team() || solo_check || allmyteam ) ) { if( !best_ace || (hi.cards_information().remaining_others(*color) > hi.cards_information().remaining_others(best_ace.color())) ) best_ace = local_ace; } } // for (color \in card_colors) if( best_ace ) { DEBUG_RETURNING( best_ace, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_pfund_card()"); } // or a ten of color for( i = 0; i < ha.cardsnumber(); i++ ) if( ha.card(i).value() == Card::TEN && !ha.card(i).istrump() && t.isvalid( ha.card( i ),hi.hand() ) && ( hi.teamofplayer(t.winnerplayer()) == hi.team() || solo_check || allmyteam ) ) { DEBUG_RETURNING( ha.card(i), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_pfund_card()"); } bool to_fat_solo = GAMETYPE::is_solo( hi.game().type() ) && t.points() > hi.value( Aiconfig::LIMITQUEEN ) && t.player_of_card( 3 ) == hi.game().soloplayer(); // or a Ace of color for( i = 0; i < ha.cardsnumber(); i++ ) { int cardsInGame = hi.cards_information().remaining_others(ha.card(i).color()); if( (ha.card(i) == Card(t.startcard().color(), Card::ACE)) && (hi.color_runs(ha.card(i).color()) == 0) && (hi.hand().numberof(t.startcard().color()) >= 3) && !ha.card(i).istrump() /// @todo see 'choose pfund', check that enough cards still remain && (cardsInGame >= 2 ) && ( hi.teamofplayer(t.winnerplayer()) == hi.team() || solo_check || allmyteam ) ) return ha.card(i); if( ha.card(i).value()==Card::ACE && ( hi.color_runs(ha.card(i).color()) > 0 || ( t.winnercard().istrump() && allmyteam ) ) && cardsInGame >= 2 && !ha.card(i).istrump() && t.isvalid( ha.card(i),hi.hand() ) && !to_fat_solo && ( ( hi.game().type()!=GAMETYPE::SOLO_JACK // with not much trumps && hi.game().type()!=GAMETYPE::SOLO_QUEEN // it is good to && hi.game().type()!=GAMETYPE::SOLO_KING // keep a second ace ) || hi.color_runs(t.startcard().color()) > 0 ) ) { DEBUG_RETURNING( ha.card(i), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_pfund_card()" ); } } // or a ten of trump for( i = 0; i < ha.cardsnumber(); i++ ) if( ha.card(i).value() == Card::TEN && ha.card(i).istrump() && !ha.card(i).isdolle() ) { DEBUG_RETURNING( ha.card(i),INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_pfund_card()" ); } // or a King of color for ( i = 0; i < ha.cardsnumber(); i++ ) if( ha.card(i).value() == Card::KING && !ha.card(i).istrump() ) { DEBUG_RETURNING( ha.card(i), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_pfund_card()"); } // or a king of trump for( i = 0; i < ha.cardsnumber(); i++ ) if( ha.card(i).value() == Card::KING && !ha.card(i).ishyperswine() && ha.card(i).istrump() && hi.game().type() != GAMETYPE::SOLO_KING && hi.game().type() != GAMETYPE::SOLO_KING_QUEEN && hi.game().type() != GAMETYPE::SOLO_KING_JACK && hi.game().type() != GAMETYPE::SOLO_KOEHLER ) { DEBUG_RETURNING( ha.card(i), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_pfund_card()" ); } // or Queen if no trump for ( i = 0; i < ha.cardsnumber(); i++ ) if( ha.card(i).value()==Card::QUEEN && !ha.card(i).istrump() && hi.game().type() != GAMETYPE::SOLO_QUEEN && hi.game().type() != GAMETYPE::SOLO_KING_QUEEN && hi.game().type() != GAMETYPE::SOLO_QUEEN_JACK && hi.game().type() != GAMETYPE::SOLO_KOEHLER ) { DEBUG_RETURNING( ha.card(i), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_pfund_card()" ); } // or Jack if no trump for( i = 0; i < ha.cardsnumber(); i++ ) if( ha.card(i).value() == Card::JACK && !ha.card(i).istrump() && hi.game().type() != GAMETYPE::SOLO_JACK && hi.game().type() != GAMETYPE::SOLO_QUEEN_JACK && hi.game().type() != GAMETYPE::SOLO_KING_JACK && hi.game().type() != GAMETYPE::SOLO_KOEHLER ) { DEBUG_RETURNING( ha.card(i), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_pfund_card()"); } // or a nine of color for( i = 0; i < ha.cardsnumber(); i++ ) if( ha.card(i).value() == Card::NINE && !ha.card(i).istrump() ) { DEBUG_RETURNING( ha.card(i), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_pfund_card()" ); } // or a nine of trump for ( i = 0; i < ha.cardsnumber(); i++ ) if( ha.card(i).value() == Card::NINE && ha.card(i).istrump() && !ha.card(i).ishyperswine() ) { DEBUG_RETURNING( ha.card(i), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_pfund_card()" ); } DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_pfund_card()" ); } /** ** checks if a solo player sits behind the player **/ bool soloPlayerBehind( Trick const& t, HeuristicInterface const& hi ) { bool soloPlayer = false; if( GAMETYPE::is_solo( hi.game().type() ) ) for( Player const* player = &( t.game().player_following( t.actplayer() ) ); player != &t.startplayer(); player = &(t.game().player_following(*player)) ) if( *player == hi.game().soloplayer () ) soloPlayer = true; return soloPlayer; } /********************************************************************** * ** Card Heuristics::choose_for_color_trick(Trick const& t, HeursticInterface const& hi) * ** Parameters: actual palyed trick, HeuristicInterface who plays next card * ** Result: result see description, if no good card found ** result is a card with Card::NOCARDVALUE and Card::NOCARDCOLOR * ** Version: Beta * ** Description: ** play a good card for the last card in one Trick with color, which ** hi doesn't have anymore, ** if this trick is won by own team ** play a pfund ** if there are only color cards in this trick ** choose best_winning_card or if there is no ** lowest_color_card ** if there is already a trump try jab this trump with lowest possible ** trump, if there are more then a limit of points already in this trick * **********************************************************************/ Card Heuristics::choose_for_color_trick( Trick const& t, HeuristicInterface const& hi ) { // @heuristic::name choose for color trick // @heuristic::idea choose a card for a color trick either a pfund for the own team or a small card for the opponents DEBUG_CALLING( INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)" ); HandCard c( hi.hand() ); if( t.isempty() ) return c; HandCards ha; bool allmyteam = ( checkAllMyTeam( t, hi ) && hi.jabbedbyownteam( t.startcard().color() ) && !t.islastcard()); bool soloPlayer = soloPlayerBehind( t, hi ); allmyteam = ( allmyteam && ( hi.teamofplayer(t.winnerplayer())==hi.team() || ( t.winnercard().less( hi.trump_card_limit() ) && t.winnercard().istrump() ) ) ); // lets see if this is the last card for this trick // or the first run of this color // and first card is no trump if ( !soloPlayer && ( t.islastcard() || allmyteam || ( !t.isstartcard() && hi.color_runs(t.startcard().color()) == 0 ) ) && !t.startcard().istrump() ) { ha = hi.hand().validcards( t ); // first check if this trick goes to my team bool pred = ( t.points() >= hi.value(Aiconfig::LIMITDOLLE) ? hi.teamofplayer(t.winnerplayer()) == hi.team() : maybe_to_team(hi.teamofplayer(t.winnerplayer())) == hi.team() ); if( hi.game().type()==GAMETYPE::MARRIAGE ) { if ( is_selector(t.startcard().tcolor(), hi.game().marriage_selector()) ) { if (hi.no() == hi.game().soloplayer().no()) pred = true; else pred = false; } else { // if !(trick determines marriage) pred = hi.teamofplayer(t.winnerplayer()) == maybe_to_team( hi.team() ); } // if !(trick determines marriage) } // if (hi.game().type() == GAMETYPE::MARRIAGE) pred = ( pred && ( t.islastcard() || ( ( t.winnercard().value() == Card::ACE && hi.color_runs(t.startcard().color()) == 0 ) ||( t.winnercard().istrump() && !t.winnercard().less( hi.trump_card_limit() ) ) ) )); pred = pred || allmyteam; if( hi.game().type() == GAMETYPE::POVERTY ) { pred &= (hi.no() == hi.game().poverty_partner().no()) && ( ( !hi.game().rule()(Rule::DOLLEN) || t.startcard().color() != Card::HEART) || allmyteam); } if ( pred || ( GAMETYPE::is_solo( hi.game().type() ) && t.winnerplayer() != hi.game().soloplayer() && hi.color_runs(t.startcard().color()) == 0 && t.winnercard().less( hi.trump_card_limit() ) && !t.islastcard() ) ) { DEBUG_RETURNING( choose_pfund_card( t, hi ), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)"); } // if own Team gets this trick // if there are only color cards in this trick bool trumpintrick = trumpInTrick( t ); if( !trumpintrick ) { c = best_winning_card( t, hi ); if( !ha.existstcolor(t.startcard().color() ) ) { if( c!=Card() ) { if( t.points() > hi.value( Aiconfig::LIMITDOLLE ) ) DEBUG_RETURNING(c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)" ); if( t.points() > hi.value( Aiconfig::LIMITQUEEN ) && ( !Card( Card::CLUB, Card::QUEEN ).less( c ) || t.islastcard() ) ) DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)"); if( !Card( Card::CLUB, Card::JACK ).less( c ) || t.islastcard() ) DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)"); } DEBUG_RETURNING( Card(), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)" ); } else if( c != Card() ) { DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)" ); } else { GameType gt = hi.game().type(); if( gt != GAMETYPE::SOLO_MEATLESS ) { if( hi.color_runs(t.startcard().color()) == 0 && t.winnercard().value() != Card::ACE && ha.numberof( t.startcard().color(), Card::ACE ) > 0 ) DEBUG_RETURNING( Card( t.startcard().color(), Card::ACE ), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)" ); if( hi.color_runs(t.startcard().color()) > 0) DEBUG_RETURNING( lowest_color_card( t, hi.hand() ), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)"); else DEBUG_RETURNING( lowest_best_trump_card(t, hi.hand(), hi ), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)" ); } else { DEBUG_RETURNING( lowest_color_card_meatless( t, hi.hand() ), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)" ); } } DEBUG_RETURNING(Card(), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)" ); }// there was no other trumps in trick else // there is a trump in this trick { // if there is already a trump try jab this trump with lowest possible trump, // and my partner doesn't already win this trick // if there are more then 10 points already in this trick if( maybe_to_team( hi.teamofplayer( t.winnerplayer() ) ) != hi.team() ) { c = best_winning_card( t, hi ); if( c != Card() ) { if( t.points() > hi.value( Aiconfig::LIMITDOLLE ) ) DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)" ); if( t.points() > hi.value( Aiconfig::LIMITQUEEN ) && !Card( Card::CLUB, Card::QUEEN ).less( c ) ) DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)"); if (t.points() < hi.value(Aiconfig::LIMIT_THROW_FEHL)) { Card const card = lowest_color_card(t, hi.hand()); if ( (card.value() == Card::NINE) || (card.value() == Card::KING)) if (better_points_optimize(c, HandCard(hi.hand(), card), hi)) return card; } // if (t.points() < 5) if( !Card( Card::CLUB, Card::JACK ).less( c ) ) { DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)"); } } // if (c != Card()) } DEBUG_RETURNING(Card(), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)" ); } } // check if trick is valid for this heuristic DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::choose_for_color_trick() (long)"); } // Card Heuristics::choose_for_color_trick( Trick t, HeuristicInterface hi ) /** ** Play a color again when not jabbed or the own team has jabbed it ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Borg Enders, Diether Knof ** ** @version 0.7.2 **/ Card Heuristics::retry_color(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name retry color // @heuristic::idea serve a color again, which was not jabbed or jabbed by the own team if (!trick.isstartcard()) return Card(); for (vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c) { if ( (hi.color_runs(*c) == 0) || (hi.hand().numberof(*c) == 0)) continue; if ( hi.colorjabbed(*c) && !hi.jabbedbyownteam(*c)) continue; // check that the trick could get through if (hi.cards_information().played(*c) + (hi.game().playerno() - 1) + hi.hand().numberof(*c) > hi.game().numberof(*c)) continue; if ( (hi.hand().numberof(Card(*c, Card::TEN)) > 0) && hi.jabbedbyownteam(*c) && (hi.teamofplayer(trick.lastplayer()) == hi.team()) ) return Card(*c, Card::TEN); if (hi.hand().numberof(Card(*c, Card::NINE)) > 0) return Card(*c, Card::NINE); if (hi.hand().numberof(Card(*c, Card::KING)) > 0) return Card(*c, Card::KING); } // for (c \in valid card colors) return Card(); } // Card Heuristics::retry_color(Trick trick, HeuristicInterface hi) /** ** Play a color the partner does not have ** prerequisites: ** 1. it must be the first card in the trick ** 2. the partner does not have the color ** 3. the players behind the partner can have the color ** Then take the card with the greatest value in the shortest color ** ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Diether Knof ** ** @version 0.7.4 **/ Card Heuristics::play_color_for_partner(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name play color for partner // @heuristic::idea play a color the partner does not have // @heuristic::condition startplayer in the trick if (!trick.isstartcard()) return Card(); // best card so far to play Card best_card; // maximal remaining cards of the selected color unsigned max_remaining_cards_no = 0; for (vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c) { Card::Color const& color = *c; // test that the color is no trumpcolor if (color == hi.game().trumpcolor()) continue; unsigned const remaining_cards_no = hi.cards_information().remaining_others(*c); // @heuristic::condition there are at least as many remaining cards as the best so far if (remaining_cards_no < max_remaining_cards_no) continue; // @heuristic::condition the partner is the last player // @heuristic::condition or there are enough remaining cards for all opponents // (players - me - partner) if ( (::maybe_to_team(hi.teamofplayer(trick.lastplayer())) != hi.team()) && (remaining_cards_no < hi.game().playerno() - 1 - 1) ) continue; // @heuristic::condition the partner does not have the color // @heuristic::condition behind the partner all players have the color unsigned p; for (p = hi.game().playerno() - 1; p > trick.actcardno(); --p) { Player const& player = trick.player_of_card(p); bool const same_team = (::maybe_to_team(hi.teamofplayer(player)) == hi.team()); if ( same_team == (hi.handofplayer(player).existstcolor(color)) ) { p = trick.actcardno(); break; } // if (partner has color or opponent has not the color) if (same_team) { break; } } // for (p \in cardno) if (p == trick.actcardno()) continue; // search the card with the highest value HandCard const& card = hi.hand().highest_card(color); if ( !best_card || (remaining_cards_no > max_remaining_cards_no) || (card.value() > best_card.value()) ) { best_card = card; max_remaining_cards_no = remaining_cards_no; } // if (found better card) } // for (c \in possible colors) // @heuristic::action play the card with the highest value in the smallest color return best_card; } // Card Heuristics::play_color_for_partner(Trick trick, HeuristicInterface hi) /** ** Play a color the partner hopefully does not have ** prerequisites: ** 1. it must be the first card in the trick ** 2. the partner is the last player ** 3. there is only one remaining card of the color ** 4. another player could have the card ** Then take the card with the lowest value in the shortest color ** ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Diether Knof ** ** @version 0.7.4 ** ** @todo take card value into account **/ Card Heuristics::try_color_for_partner(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name try color for partner // @heuristic::idea try a color the partner hopefully does not have // @heuristic::condition startplayer in the trick if (!trick.isstartcard()) return Card(); // @heuristic::condition last player of the trick is partner if (!(::maybe_to_team(hi.teamofplayer(trick.lastplayer())) == hi.team())) return Card(); // best card so far to play Card best_card; // maximal number of other players who can have the card // there must be at least one unsigned max_other_players = 1; for (vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c) { Card::Color const& color = *c; // test that the color is no trumpcolor if (color == hi.game().trumpcolor()) continue; // the player has the color if (hi.hand().numberof(color) == 0) continue; // @heuristic::condition the last player can have the last remaining card of the color if (!( (hi.handofplayer(trick.lastplayer()).existstcolor(color)) && (hi.cards_information().remaining_others(color) == 1)) ) continue; // number of other players who can have the last card unsigned other_players = 0; for (unsigned p = hi.game().playerno() - 2; p > trick.actcardno(); --p) { Player const& player = trick.player_of_card(p); // ToDo: check that the card value for 'p' is greater than // the card value for the partner if (hi.handofplayer(player).existstcolor(color)) other_players += 1; } // for (p \in trick.actcardno()) // search the card with the lowest value HandCard const& card = hi.hand().lowest_card(color); if ( (other_players > max_other_players) || ( (other_players == max_other_players) && ( !best_card || (card.value() < best_card.value())) ) ) { best_card = card; max_other_players = other_players; } // if (found better card) } // for (c \in possible colors) // @heuristic::action play the card with the lowest value return best_card; } // Card Heuristics::try_color_for_partner(Trick trick, HeuristicInterface hi) /** ** Start a new color hoping the partner has an ace ** prerequisites: ** 1. it must be the first card in the trick ** 2. first run of the color ** 3. the partner is behind the player ** 4. the partner can have the ace ** Then take the card with the greatest value in the shortest color ** ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Diether Knof ** ** @version 0.7.4 **/ Card Heuristics::play_color_for_partner_ace(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name play color for partner ace // @heuristic::idea play a color hoping the partner has the ace // @heuristic::condition startplayer in the trick if (!trick.isstartcard()) return Card(); // the nmber of the next partner in line unsigned partnerno = UINT_MAX; for (unsigned c = 1; c < hi.game().playerno(); ++c) { if (::maybe_to_team(hi.teamofplayer(trick.player_of_card(c))) == hi.team()) { partnerno = trick.player_of_card(c).no(); break; } } // for (c < hi.game().playerno()) // a partner is found if (partnerno == UINT_MAX) return Card(); // best card so far to play Card best_card; // maximal remaining cards of the selected color // @heuristic::condition or there are enough remaining cards for all players // (players - me) unsigned max_remaining_cards_no = hi.game().playerno() - 1; for (vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c) { Card::Color const& color = *c; // test that the color is no trumpcolor // @heuristic::condition first run of the color if ( (color == hi.game().trumpcolor()) || (hi.cards_information().played(color) > hi.cards_information().of_player(hi.no()).played(color)) ) continue; Card const ace(color, Card::ACE); // the player has the color if (hi.hand().numberof(color) == 0) continue; // @heuristic::condition the partner is next in line unsigned const remaining_cards_no = hi.cards_information().remaining_others(*c); // there are at least as many remaining cards as the best so far if (remaining_cards_no < max_remaining_cards_no) continue; { // the position of the partner in the trick unsigned const partneractcardno = trick.cardno_of_player(trick.game().player(partnerno)); unsigned c; // @heuristic::condition all players between me and the partner do not have an ace of the color but do have the color for (c = 1; c < partneractcardno; ++c) { Hand const& hand = hi.handofplayer(trick.player_of_card(c)); if ( !hand.existstcolor(color) || hand.contains(ace)) break; } // for (c < partneractcardno) if (c < partneractcardno) continue; // @heuristic::condition the partner can have an ace of the color if (!hi.handofplayer(partnerno).contains(ace)) continue; } // search the card with the highest value HandCard const& card = hi.hand().highest_card(color); if ( (remaining_cards_no > max_remaining_cards_no) || (card.value() > best_card.value()) ) { best_card = card; max_remaining_cards_no = remaining_cards_no; } // if (found better card) } // for (c \in possible colors) // @heuristic::action play the card with the highest value in the smallest color return best_card; } // Card Heuristics::play_color_for_partner_ace(Trick trick, HeuristicInterface hi) /** ** When a player cannot get a color trick take the card with the smallest value ** prerequisites: ** 1. it must not be the first card in the trick ** 2. the trick must be a color trick; ** 3. one must have to serve the color ** 4. the winnercard must be an ace or a trump or one does not have the ace; ** 5. the winnerplayer must not be of the own team; ** The main case is that one is the last to play and has only got to ** take ones lowest card. ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Diether Knof ** ** @version 0.6.6 **/ Card Heuristics::serve_color_trick(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name serve color trick // @heuristic::idea When a player cannot get a color trick take the card with the smallest value. The main case is that one is the last to play and has only got to take ones lowest card. // @heuristic::condition it must not be the first card in the trick if (trick.isstartcard()) return Card(); Card::Color const color = trick.startcard().color(); // @heuristic::condition the trick must be a color trick if (trick.startcard().istrump()) return Card(); // @heuristic::condition one has to serve the color if (hi.hand().numberof(color) == 0) return Card(); HandCards const color_cards = hi.hand().validcards( trick ); // @heuristic::condition the winnercard must be an ace or a trump or one does not have the ace in the non-trump case and no partner is behind if (!( (trick.winnercard().value() == Card::ACE) || trick.winnercard().istrump() || ( !trick.winnercard().istrump() && (color_cards.numberof(Card(color, Card::ACE)) == 0) && !( is_solo(hi.game().type()) && !soloPlayerBehind(trick, hi)) ) ) ) { return Card(); } // if (trick.winnercard.value() != Card::ACE) && (...) // @heuristic::condition the winnerplayer must not be of the own team if (hi.guessedteamofplayer( trick.winnerplayer() ) == hi.team()) return Card(); // @heuristic::condition it must not be an undetermined marriage if ( (hi.game().type() == GAMETYPE::MARRIAGE) && (hi.game().marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET) && !( is_selector(color, hi.game().marriage_selector()) && (hi.no() != hi.game().soloplayer().no())) ) return Card(); return hi.hand().lowest_card(color); } // Card Heuristics::serve_color_trick(Trick trick, HeuristicInterface hi) /** ** If a player cannot get a trump trick take the card with the smallest value ** prerequisites: ** 1. it must not be the first card in the trick ** 2. the trick must be a trump trick; ** 3. one cannot get the trick ** 4. if the value of the cards are not the same: ** a) the winnerplayer must not be of the own team; ** b) the remaining players must not be of the own team ** 5. There is a smallest card both in value and in jab order ** or diamond king against spade jack or higher ** The main case is p.e. in a jack solo to play the smallest jack when the ** club jack is played ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Diether Knof ** @author Borg Enders ** ** @version 0.6.8 **/ Card Heuristics::serve_trump_trick(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name serve trump trick // @heuristic::idea When a player cannot get a trump trick take the card with the smallest value. The main case is that one is the last to play and has only got to take ones lowest card. // it must not be the first card in the trick if( trick.isstartcard() ) DEBUG_RETURNING( Card(), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::serve_trump_trick(trick, hi) = false"); // the trick must be a trump trick if( !trick.startcard().istrump() ) DEBUG_RETURNING( Card(), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::serve_trump(trick, hi) = false"); HandCards const valid_cards = hi.hand().validcards( trick ); HandCard lowest_card; if( !hi.hand().hastrump() ) { // No trump so we want the lowest color card of any color. // @todo prefer short colors // we have not trump, so get any card for initialization. lowest_card = hi.hand().card( 0 ); for( unsigned i = 1; i < hi.hand().cardsnumber(); i++ ) if( hi.hand().card( i ).value() < lowest_card.value() ) lowest_card = hi.hand().card( i ); return lowest_card; } // if !(hastrump) lowest_card = hi.hand().lowest_trump(); Player const& player = hi.game().player( hi.no() ); bool const swines = ( ( ( hi.game().swines_owner() && hi.game().swines_owner() == &player ) || hi.game().swines_announcement_valid( player ) ) && hi.hand().hastrump() ); bool const hyperswines = ( ( ( hi.game().hyperswines_owner() && hi.game().hyperswines_owner() == &player ) || hi.game().hyperswines_announcement_valid( player ) ) && hi.hand().hastrump() ); // one cannot get the trick if( trick.winnercard().less(hi.hand().highest_trump()) || swines || hyperswines ) return Card(); Card const trump_ace( hi.game().trumpcolor(), Card::ACE ); Card const trump_hyperswine( hi.game().trumpcolor(), ( hi.game().rule()(Rule::WITH_NINES) ? Card::NINE : Card::KING ) ); // the points of the lowest card unsigned const points = lowest_card.points(); // the lowest points of a card unsigned lowest_points = points; if ( trick.startcard().istrump() ) { // if it is a color trick we allready have card with lowest points for( HandCards::const_iterator c = valid_cards.begin(); c != valid_cards.end(); ++c ) { if( c->points() < lowest_points ) lowest_points = c->points(); } // for (c \in trump_cards) } // end of is trump // the winnerplayer must not be of the own team Player const& winnerplayer = trick.winnerplayer(); if( hi.teamofplayer( winnerplayer ) == hi.team() ) return Card(); if (points != lowest_points) { // whether the highest possible card was played bool highest_card_played = false; switch( hi.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: // ToDo: test which possible highest cards were already played if( hi.game().rule()( Rule::HYPERSWINES ) && ( hi.game().hyperswines_owner() || !hi.game().rule()(Rule::HYPERSWINES_ANNOUNCEMENT_BEGIN) ) ) { if( trick.winnercard() == trump_hyperswine ) highest_card_played = true; } else if( hi.game().rule()(Rule::SWINES) && ( hi.game().swines_owner() || !hi.game().rule()(Rule::SWINES_ANNOUNCEMENT_BEGIN) ) ) { if( trick.winnercard() == trump_ace ) highest_card_played = true; } else if( hi.game().rule()(Rule::DOLLEN) ) { if( !hi.game().rule()(Rule::DOLLEN_SECOND_OVER_FIRST) && trick.winnercard() == Card::DOLLE ) highest_card_played = true; } else if( trick.winnercard() == Card::CLUB_QUEEN ) { highest_card_played = true; } break; case GAMETYPE::THROWN_NINES: case GAMETYPE::THROWN_KINGS: case GAMETYPE::THROWN_NINES_AND_KINGS: case GAMETYPE::FOX_HIGHEST_TRUMP: // no game break; case GAMETYPE::SOLO_JACK: // ToDo: when both club jack have already been played if( trick.winnercard() == Card(Card::CLUB, Card::JACK) ) highest_card_played = true; break; case GAMETYPE::SOLO_QUEEN: case GAMETYPE::SOLO_QUEEN_JACK: if( trick.winnercard() == Card(Card::CLUB, Card::QUEEN) ) highest_card_played = true; break; case GAMETYPE::SOLO_KING: case GAMETYPE::SOLO_KING_JACK: case GAMETYPE::SOLO_KING_QUEEN: case GAMETYPE::SOLO_KOEHLER: if( trick.winnercard() == Card(Card::CLUB, Card::KING) ) highest_card_played = true; break; case GAMETYPE::SOLO_MEATLESS: // no trump break; } // switch (hi.game().type()) // the remaining players must not be of the own team if( !highest_card_played ) { for( Player const* player = &( trick.game().player_following( trick.actplayer() ) ); player != &trick.startplayer(); player = &( trick.game().player_following( *player ) ) ) if( hi.teamofplayer(*player) == hi.team() ) return Card(); } // if (!highest_card_played) } // if (points != lowest_points) HandCard card; switch (hi.game().type()) { case GAMETYPE::NORMAL: // ToDo Genscher 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: if( hi.game().rule()(Rule::EXTRAPOINT_CHARLIE) // ToDo: check solo games && hi.hand().numberof(Card::CHARLIE) > 0 ) break; // special case: diamond king // play it if the alternatives are diamond ten, diamond ace or >= spade jack // only needed if trump on hand if (hi.hand().hastrump()) { if (lowest_card == Card(hi.game().trumpcolor(), Card::KING)) { card = lowest_card; for( HandCards::const_iterator c = valid_cards.begin() + 1; c != valid_cards.end(); ++c ) { if ( (c->value() == Card::NINE) || ( (c->value() == Card::JACK) && (c->color() <= Card::HEART) ) ) { card = Card(); break; } } // for (c \in trump_cards) } // if (lowest_trump == trump king } // has trump if( lowest_card.points() == lowest_points ) card = lowest_card; break; case GAMETYPE::THROWN_NINES: case GAMETYPE::THROWN_KINGS: case GAMETYPE::THROWN_NINES_AND_KINGS: case GAMETYPE::FOX_HIGHEST_TRUMP: // no game break; case GAMETYPE::SOLO_JACK: case GAMETYPE::SOLO_QUEEN: case GAMETYPE::SOLO_KING: case GAMETYPE::SOLO_QUEEN_JACK: case GAMETYPE::SOLO_KING_JACK: case GAMETYPE::SOLO_KING_QUEEN: case GAMETYPE::SOLO_KOEHLER: // simple card = lowest_card; break; case GAMETYPE::SOLO_MEATLESS: // no trump break; } // switch (hi.game().type()) return card; } // Card Heuristics::serve_trump_trick(Trick const& trick, HeuristicInterface const& hi) /********************************************************************** * ** Card Heuristics::choose_pfund(Trick const& t, HeursticInterface const& hi) * ** Parameters: actual played trick, HeuristicInterface who plays next card * ** Result: result see description, otherwise ** result is a card with Card::NOCARDVALUE and Card::NOCARDCOLOR * ** Version: Beta * ** Description: ** for the last card in a trick, which wins your own team ** or where your teammate has already a played a high enough trump ** play a pfund * **********************************************************************/ Card Heuristics::choose_pfund( Trick const& t, HeuristicInterface const& hi ) { // @heuristic::name choose pfund // @heuristic::idea choose for trump trick won by the own team a pfund // I'm the start Player if( t.isstartcard() ) return Card(); // undetermined marriage => no pfund if ( (hi.game().type() == GAMETYPE::MARRIAGE) && (hi.game().marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET) && ( ( !is_selector(t.startcard().color(), hi.game().marriage_selector()) && (hi.no() == hi.game().soloplayer().no())) || (hi.no() != hi.game().soloplayer().no()) ) ) return Card(); // special case: first color run Card::Color color = t.startcard().tcolor(); if ( (color != Card::TRUMP) && (hi.color_runs(color) == 0) && (hi.teamofplayer(t.winnerplayer()) == hi.team()) && (t.winnercard().istrump() || (t.winnercard().value() == Card(color, Card::ACE))) && (hi.cards_information().remaining_others_cards_no() /// @todo number of players who have not jabbed, yet / 3 >= 1) ) return choose_pfund_card( t, hi ); // some oppenent behind me can jab the trick if( !t.islastcard() && !checkAllMyTeam( t, hi ) && oppositeTeamCanWinTrick( t, hi )) return Card(); if( t.islastcard() && (hi.teamofplayer(t.winnerplayer()) != hi.team()) ) return Card(); bool soloPlayer = soloPlayerBehind( t, hi ); // if winner is own team if( ( hi.teamofplayer(t.winnerplayer()) == hi.team() && !oppositeTeamCanWinTrick( t, hi ) ) || ( maybe_to_team(hi.teamofplayer(t.winnerplayer())) == hi.team() && ( !hi.cards_information().higher_card_exists( t.winnercard() ) ||( !soloPlayer && ( t.islastcard() || !t.winnercard().less( hi.trump_card_limit() ) ) ) ) ) || ( GAMETYPE::is_solo( hi.game().type() ) && t.winnerplayer() == hi.game().soloplayer() && t.winnercard().less( hi.trump_card_limit() ) && !t.islastcard() && choose_pfund_card(t,hi).points() > 0 && t.startcard().istrump() ) || ( checkAllMyTeam( t, hi ) && ( hi.teamofplayer(t.winnerplayer()) == hi.team() || ( t.winnercard().less( hi.trump_card_limit() ) && !t.islastcard() ) ) ) ) { return choose_pfund_card( t, hi ); } return Card(); } // Card Heuristics::choose_pfund( Trick t, HeuristicInterface hi ) /** ** if the partner has the highest card in the game, play a pfund (>= 10 points) ** ** @param trick current trick ** @param hi heuristics interface ** ** @return card to play ** ** @author Diether Knof ** ** @version 2006-09-18 **/ Card Heuristics::choose_pfund_before_partner(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name choose pfund before partner // @heuristic::idea if the partner has the highest card in the game play a pfund // @heuristic::condition the partner has the highest trump still in the game // whether the partner has the highest card bool partner_has_highest_card = false; // the partner Player const* partner = hi.team_information().guessed_partner(); if (!partner) return Card(); // the highest trump the other players can have Card const highest_trump = hi.cards_information().highest_remaining_trump_of_others(); // no partner behind if (trick.cardno_of_player(trick.game().player(partner->no())) < trick.actcardno() ) return Card(); // normal case // ToDo: use estimated hands if ( partner // the partner has the highest card && hi.cards_information().of_player(*partner).must_have(highest_trump) // no other player has also the highest card && (hi.cards_information().of_player(*partner).must_have(highest_trump) + hi.cards_information().played(highest_trump) + hi.hand().numberof(highest_trump) == hi.game().rule()(Rule::NUMBER_OF_SAME_CARDS) ) ) partner_has_highest_card = true; // special case: partner re but I do not know who he is if ( (hi.game().type() == GAMETYPE::NORMAL) // re team && (hi.team() == TEAM::RE) // ToDo: replace with 'previous players are contra' && trick.isstartcard() // the club queen is the highest card && (highest_trump == Card::CLUB_QUEEN) // my partner still has the club queen && (hi.cards_information().played(Card::CLUB_QUEEN) == hi.cards_information().of_player(hi.no()).played(Card::CLUB_QUEEN)) ) partner_has_highest_card = true; if (!partner_has_highest_card) return Card(); // @heuristic::action play a pfund of at least 10 points if (trick.isstartcard()) { // play a fox if ( (hi.hand().numberoftrumpaces() > 0) && !hi.hand().has_swines()) return Card(hi.game().trumpcolor(), Card::ACE); // play a diamond ten Card const card(hi.game().trumpcolor(), Card::ACE); if (hi.hand().numberof(card) > 0) return card; // ToDo: play a color card of a color the partner does not have return Card(); } else { // if !(trick.isstartcard()) Card const card = Heuristics::choose_pfund_card(trick, hi); if (card.value() >= Card::TEN) return card; else return Card(); } // if !(trick.isstartcard()) } // Card Heuristics::choose_pfund_before_partner(Trick trick, HeuristicInterface hi) /** ** return lowest allowed Jack or Queen if they are trump ** and there is a ace to play, which is not already jabbed, ** else return empty card ** ** @param t current trick ** @param hi heuristic interface ** ** @result -> description ** ** @author Borg Enders ** ** @version 0.6.9 **/ Card Heuristics::jab_for_ace( Trick const& t, HeuristicInterface const& hi ) { // @heuristic::name jab for ace // @heuristic::idea jab a trick to serve next trick a ace // must not be the first player if (t.isstartcard()) return Card(); // the ace to jab for Card const ace = Heuristics::choose_ace( Trick(), hi ); if (!ace) return Card(); // for a solo don't jab for ace, if there are players of my team behind me // and myself doesn't have that many trumps if ( GAMETYPE::is_solo( hi.game().type() ) && (t.winnerplayer() == hi.game().soloplayer()) && t.winnercard().less( hi.trump_card_limit() ) && !t.islastcard() && (hi.hand().numberoftrumps() < 4) ) return Card(); if( (hi.hand().numberof( ace ) < hi.game().rule()(Rule::NUMBER_OF_SAME_CARDS)) && (hi.color_runs(ace.color()) == 0) && ( (TEAM::maybe_to_team(hi.teamofplayer(t.winnerplayer())) != hi.team()) || ( (TEAM::maybe_to_team(hi.teamofplayer(t.winnerplayer())) == hi.team()) && t.winnercard().less( hi.trump_card_limit() ) ) || (hi.game().trick_current_no() == 0) ) ) { Card c = best_winning_card( t, hi, hi.value( Aiconfig::LIMITDOLLE ) - ( 4 - t.actcardno() ) ); if( c != Card() ) { Trick tempTrick = t; tempTrick += HandCard( hi.hand(), c ); if( ( HandCard( hi.hand(), c ).isdolle() || HandCard( hi.hand(), c ).possible_swine() ) && oppositeTeamCanWinTrick( tempTrick, hi ) ) return Card(); } return c; } return Card(); } // Card Heuristics::jab_for_ace( Trick t, HeuristicInterface hi ) /********************************************************************** * ** Card Heuristics::play_low_high(Trick const& t,HeursticInterface const& hi) * ** Parameters: actual played trick, HeuristicInterface who plays next card * ** Result: plays high and low trumps changing * ** Version: Beta * ** Description: * **********************************************************************/ Card Heuristics::play_low_high(Trick const& t,HeuristicInterface const& hi) { // @heuristic::name play low high // @heuristic::idea play changing low and high trumps to force opponent to jab or either draw his trumps DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::play_low_high"); if( GAMETYPE::is_solo( hi.game().type() ) && hi.game().soloplayer ().no() != hi.no() ) return Card(); if( t.isstartcard() && hi.hand().numberoftrumps() > hi.game().tricks_remaining_no() / 2 ) { if( hi.next_low() ) { if( hi.hand().numberof( Card::QUEEN ) < 2 * hi.hand().numberof( Card::JACK ) ) { Card c = lowest_jack( hi.hand(), hi ); if( c != Card() && !t.isvalid(c,hi.hand())) // ToDo: Hier wird doch die erste Karte im Trumpf betrachtet, daher dürfte die Bedingung nie greifen (siehe auch unten) c = Card(); DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::play_low_high()" " = jack"); } } else { // if !(hi.next_low()) Card c = lowest_queen( hi.hand(), hi ); if( c!=Card() && !t.isvalid( c, hi.hand() ) ) c = Card(); DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::play_low_high()" " = queen"); } // if !(hi.next_low()) } // if (t.isstartcard()) DEBUG_RETURNING( Card(), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::play_low_high()" " = card()"); } /********************************************************************** * ** Card Heuristics::SecondBestTrump(HeuristicInterface const& hi) * ** Parameters: actual played trick, HeuristicInterface who plays next card * ** Result: plays the scond highest trump * ** Version: Beta * ** Description: ** usefull for color soli * **********************************************************************/ Card Heuristics::SecondBestTrump(HeuristicInterface const& hi) { // @heuristic::name ? second best trump ? // @heuristic::idea play the seconmd highest trump (especially useful for solo player in picture soli) DEBUG_CALLING( INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::SecondBestTrump" ); Hand h = hi.hand(); Card c = Card(); Card bestcard; if( hi.cards_information().remaining_trumps_others() == 0 ) return c; // first find highest trump on hand unsigned i; unsigned best = 0; bestcard = h.card( best ); for( i = 1; i < h.cardsnumber();i++ ) { if( h.card(i).istrump() && bestcard.less( h.card( i ) ) ) { bestcard = h.card( i ); best = i; } } // find second best card for (i = 0; i < h.cardsnumber(); i++) { if( h.card(i).istrump() && ( h.card(i).less(bestcard) || h.card(i) == bestcard ) && c.less( h.card(i) ) && i != best ) { c = h.card( i ); } } DEBUG_ASSERT( c ); DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::SecondBestTrump" ); } // Card Heuristics::SecondBestTrump(HeuristicInterface const& hi) /********************************************************************** * ** Card Heuristics::play_for_team(Trick const& t,HeursticInterface const& hi) * ** Parameters: actual played trick, HeuristicInterface who plays next card * ** Result: puts a nice card to a trick of a team mate * ** Version: Beta * ** Description: ** result a King, ten (no dolle), or a Ace (no swine) ** or a nine in this order * **********************************************************************/ Card Heuristics::play_for_team( Trick const& t, HeuristicInterface const& hi ) { // @heuristic::name play for team // @heuristic::idea put a good card in a trick of the team mate DEBUG_CALLING(INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::play_for_team"); // I'am the start Player if( t.isstartcard() ) DEBUG_RETURNING( Card(), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::play_for_team()"); bool soloPlayer = soloPlayerBehind( t, hi ); Card c = Card(); if( maybe_to_team(hi.teamofplayer(t.winnerplayer())) == hi.team() && !soloPlayer && !t.winnercard().less(hi.value(Aiconfig::LIMITTHROWING)) ) { unsigned i; for( i = 0; i < hi.hand().cardsnumber(); i++ ) { Trick tr = t; if( tr.isvalid( hi.hand().card(i), hi.hand() ) ) { tr += hi.hand().card( i ); if( tr.winnerplayer().no() != hi.no() && hi.hand().card(i).value()==Card::KING && !hi.hand().card(i).ishyperswine() && hi.game().type() != GAMETYPE::SOLO_KING && hi.game().type() != GAMETYPE::SOLO_KING_QUEEN && hi.game().type() != GAMETYPE::SOLO_KING_JACK ) c = hi.hand().card( i ); } } if( c != Card() ) DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::play_for_team" ); for( i = 0; i < hi.hand().cardsnumber(); i++ ) { Trick tr = t; if( tr.isvalid( hi.hand().card( i ), hi.hand() ) ) { tr += hi.hand().card( i ); if( tr.winnerplayer().no() != hi.no() && hi.hand().card(i).value() == Card::TEN && !tr.winnercard().less(hi.value(Aiconfig::LIMITHIGH)) && !hi.hand().card(i).isdolle() ) c=hi.hand().card(i); } } if( c != Card() ) DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::play_for_team" ); for( i = 0; i < hi.hand().cardsnumber(); i++ ) { Trick tr = t; if( tr.isvalid( hi.hand().card(i),hi.hand() ) ) { tr += hi.hand().card( i ); // last player after me is player with poverty bool lastPoverty = (soloPlayer && tr.actcardno() == 3 && hi.game().soloplayer() == tr.player_of_card(3) ); if( tr.winnerplayer().no() != hi.no() && hi.hand().card(i).value() == Card::ACE && ( !tr.winnercard().less( hi.value( Aiconfig::LIMITHIGH ) ) || t.islastcard() || lastPoverty ) && !hi.hand().card( i ).isswine() && ( !hi.hand().card( i ).isfox() || t.islastcard() || lastPoverty ) ) c = hi.hand().card( i ); } } if( c != Card() ) DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::play_for_team" ); // ToDo: Wieso ist eine Neun ein Spiel 'für' das eigene Team? Da gibt doch ein Bube mehr Punkte for( i = 0; i < hi.hand().cardsnumber(); i++ ) { Trick tr = t; if( tr.isvalid( hi.hand().card(i), hi.hand() ) ) { tr += hi.hand().card( i ); if( tr.winnerplayer().no() != hi.no() && hi.hand().card(i).value() == Card::NINE && !hi.hand().card(i).ishyperswine() ) c = hi.hand().card( i ); } } } DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::play_for_team" ); } /********************************************************************** * ** Card Heuristics::jab_fox(Trick const& t,HeursticInterface const& hi) * ** Parameters: actual played trick, HeuristicInterface who plays next card * ** Result: jabs a fox if in this in the trick * ** Version: Beta * ** Description: * **********************************************************************/ Card Heuristics::jab_fox( Trick const& t, HeuristicInterface const& hi ) { // @heuristic::name jab fox // @heuristic::idea jab a fox if played in this trick DEBUG_CALLING(INFO_HEURISTICS&&INFO_OTHER_FUNCTION,"Heuristics::jab_fox"); Card c=Card(); bool fox_exists = false; // first lets check if there is a fox for( unsigned i = 0; i < t.actcardno(); i++ ) { if( t.card( i ).isfox() ) { fox_exists = true; break; } } if( fox_exists ) { // if lastcard just take the best winning card if( t.islastcard() && hi.teamofplayer(t.winnerplayer()) != hi.team() ) { DEBUG_RETURNING( best_winning_card(t, hi, 10 ), ///@todo 10 replace with AiConfig INFO_HEURISTICS&&INFO_OTHER_FUNCTION,"Heuristics::jab_fox"); } // lastcard and this is our trick nothing to do. if( ( t.islastcard() || !oppositeTeamCanWinTrick( t, hi ) ) && hi.teamofplayer(t.winnerplayer())==hi.team() ) { return Card(); } { // if I can jab the fox surely, take the card // take the best cards of all players behind me that are not in my team Trick const& trick = t; HandCard highest_card_behind( hi.hand() ); for( Player const* player = &(trick.game().player_following(trick.actplayer())); player != &trick.startplayer(); player = &(trick.game().player_following(*player))) { if( hi.teamofplayer(*player) != hi.team() ) { HandCard const highest_card = player->hand().highest_card(); if( !highest_card_behind || highest_card_behind.less( highest_card ) ) highest_card_behind = highest_card; } // if (hi.teamofplayer(*player) != hi.team()) } // for (player) if( highest_card_behind ) { // the partner has the best possible card if( hi.teamofplayer(trick.winnerplayer()) == hi.team() && !trick.winnercard().less( highest_card_behind ) /// @todo next_higher_card_of_other_team ) DEBUG_RETURNING( Card(), INFO_HEURISTICS&&INFO_VALUE, "Heuristics::jab_fox = false"); // look whether I have the best card Card lowest_better_card; HandCards const valid_cards = hi.hand().validcards( t ); for( HandCards::const_iterator c = valid_cards.begin(); c != valid_cards.end(); ++c ) { Trick tempTrick = trick; tempTrick += *c; if( c->less( highest_card_behind ) && trick.is_jabbed( *c ) && !tempTrick.is_jabbed( highest_card_behind ) && ( !lowest_better_card || lowest_better_card.less(*c) ) ) lowest_better_card = *c; } // for (c) if( lowest_better_card ) { DEBUG_RETURNING( lowest_better_card, INFO_HEURISTICS&&INFO_VALUE, "Heuristics::jab_fox = false"); // Card of partner is fine DEBUG_RETURNING( Card(), INFO_HEURISTICS&&INFO_VALUE, "Heuristics::jab_fox = false"); } } // if (highest_card_behind) } // if I can jab the fox surely, take the card // for all other we take our highest queen HandCard ca( hi.hand(), highest_queen( hi.hand(), hi) ); if( !ca ) { DEBUG_RETURNING( ca, INFO_HEURISTICS&&INFO_VALUE, "Heuristics::jab_fox"); } Trick tr = t; tr += ca; if( t.isvalid( ca, hi.hand() ) && tr.winnerplayer().no()==hi.no() ) { DEBUG_RETURNING( ca, INFO_HEURISTICS&&INFO_OTHER_FUNCTION, "Heuristics::jab_fox"); } } DEBUG_RETURNING( c, INFO_HEURISTICS&&INFO_OTHER_FUNCTION,"Heuristics::jab_fox"); } // Card Heuristics::jab_fox( Trick t, HeuristicInterface hi ) /** ** -> result ** ** @param trick trick ** @param hi heuristic interface ** ** @result card with ten points, if the heuristic matches ** ** @author Borg Enders ** @author Diether Knof ** ** @version 0.6.9 **/ Card Heuristics::try_for_doppelkopf( Trick const& trick, HeuristicInterface const& hi ) { // @heuristic::name try for doppelkopf // @heuristic::idea try to get a doppelkopf for the own team // at max one player behind me if( trick.actcardno() < hi.game().playerno() - 2 ) return Card(); // each player has to give ten points if( trick.points() < 10 * trick.actcardno() ) return Card(); //last player opposite team ? if ( !trick.islastcard() && hi.teamofplayer( trick.lastplayer() ) != hi.team() ) return Card(); Player const& player = hi.game().player( hi.no() ); if ( !trick.islastcard() && player.announcement() == ANNOUNCEMENT::NOANNOUNCEMENT && !hi.game().announcement_valid( ANNOUNCEMENT::NO120, player ) ) return Card(); // search a ten or an ace vector try_cards; try_cards.push_back( Card( hi.game().trumpcolor(), Card::TEN ) ); try_cards.push_back( Card( hi.game().trumpcolor(), Card::ACE ) ); try_cards.push_back( Card::DOLLE ); for( vector::const_iterator c = try_cards.begin(); c != try_cards.end(); ++c ) if( hi.hand().numberof(*c) > 0 && trick.isvalid( *c, hi.hand() ) && trick.winnercard().less( *c ) ) return *c; return Card(); } // Card Heuristics::try_for_doppelkopf(Trick const& trick,HeuristicInterface const& hi) /** ** -> result ** ** @param trick current trick ** @param hi heuristic interface ** ** @return low fehl card with many cards of the color remaining ** ** @author Borg Enders ** @author Diether Knof ** ** @version 0.7.4 **/ Card choose_best_fehl(Trick const& trick, HeuristicInterface const& hi ) { // the best card Card best_card = Card(); // the best number of remaining cards // There should be at lest so as many cards remaining // as there are other players unsigned best_remaining = (hi.game().playerno() - 1); // all valid cards HandCards const cards = hi.hand().validcards(trick); for (HandCards::const_iterator card = cards.begin(); card != cards.end(); ++card) { unsigned const remaining = hi.cards_information().remaining_others(card->color()); if( !card->istrump() && (remaining > best_remaining) && (hi.hand().numberof(card->color()) <= 1) && ( card->value() == Card::KING || card->value() == Card::NINE ) ) { best_card = *card; best_remaining = remaining; } // if (found better card) } // for (card \in cards) return best_card; } // Card choose_best_fehl( Trick trick, HeuristicInterface hi ) /********************************************************************** * ** Card Heuristics::create_fehl(Trick const& t,HeursticInterface const& hi) * ** Parameters: actual played trick, HeuristicInterface who plays next card * ** Result: result play single color nine or king to get fehl ** in second run of a color ** result is a card with Card::NOCARDVALUE and Card::NOCARDCOLOR * ** Version: Alpha * ** Description: * **********************************************************************/ Card Heuristics::create_fehl( Trick const& t, HeuristicInterface const& hi ) { // @heuristic::name create fehl // @heuristic::idea create a missing color (only allowed for first card depending on Aiconfig::FEHLCREATIONONFIRSTCARD) if ((hi.game().type() == GAMETYPE::MARRIAGE) && (hi.game().marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET)) return Card(); // if this trick is still worth fehl creation if( !(hi.game().trick_current_no() < hi.value(Aiconfig::LASTFEHLCREATION) ) ) return Card(); // if this is the firstcard if( hi.value( Aiconfig::FEHLCREATIONONFIRSTCARD ) ) if (t.actcardno() == 0 ) return choose_best_fehl( t, hi ); // this is not the first colorrun and there are not more then 10 points if( (t.actcardno() > 0) && (hi.color_runs( t.startcard().color() ) > 0) && (t.points() < hi.value(Aiconfig::LIMIT_THROW_FEHL)) ) { // the trick is jabbed high enough if( t.winnercard().istrump() && !t.winnercard().less( hi.lowest_trump_card_limit() ) ) return choose_best_fehl( t,hi ); // the winnercard is already a no trump ace if( !t.winnercard().istrump() && (t.winnercard().value() >= Card::ACE) ) return choose_best_fehl( t,hi ); } return Card(); } // Card Heuristics::create_fehl( Trick t, HeuristicInterface hi ) /********************************************************************** * ** int calchandvalue(HeursticInterface const& hi) * ** Parameters: HeuristicInterface who checks for an announcement * ** Result: value of cards for announcement * ** Version: Beta * ** Description: * **********************************************************************/ int Heuristics::CalcHandValue( HeuristicInterface const& hi, const Game& g ) { // @heuristic::name ? calc hand value ? // @heuristic::idea calculates the value of a hand for decision making of announcements, soli decisions,... DEBUG_CALLING( INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::CalcHandValue" ); int value = 0; unsigned i; unsigned v_queen = 0; unsigned v_jack = 0; unsigned v_highest = 0; unsigned v_king = 0; unsigned v_ace = 0; unsigned v_fehl = 0; if( g.type() == GAMETYPE::NORMAL ) { v_queen = 2; v_jack = 1; v_highest = 3; v_king = 0; v_ace = 1; v_fehl = 2; } if( g.type() == GAMETYPE::POVERTY ) { v_queen = 2; v_jack = 1; v_highest = 3; v_king = 0; v_ace = 0; v_fehl = 2; value = -3; } if( g.type() == GAMETYPE::MARRIAGE ) { v_queen = 2; v_jack = 1; v_highest = 3; v_king = 0; v_ace = 1; v_fehl = 2; } if( g.type() == GAMETYPE::SOLO_JACK ) { v_queen = 0; v_jack = 3; v_highest = 0; v_king = 0; v_ace = 2; v_fehl = 1; if (hi.team() == TEAM::RE) { value = -5; } else { value = -2; } } if (g.type()==GAMETYPE::SOLO_QUEEN) { v_queen = 3; v_jack = 0; v_highest = 0; v_king = 0; v_ace = 2; v_fehl = 1; if (hi.team() == TEAM::RE) { value = -5; } else { value = -2; } } if( g.type() == GAMETYPE::SOLO_KING ) { v_queen = 0; v_jack = 0; v_highest = 0; v_king = 3; v_ace = 2; v_fehl = 1; if (hi.team() == TEAM::RE) { value = -5; } else { value = -2; } } if( g.type() == GAMETYPE::SOLO_QUEEN_JACK ) { v_queen = 3; v_jack = 2; v_highest = 0; v_king = 0; v_ace = 1; v_fehl = 1; if (hi.team() == TEAM::RE) { value = -6; } else { value = -3; } } if( g.type() == GAMETYPE::SOLO_KING_JACK ) { v_queen = 0; v_jack = 2; v_highest = 0; v_king = 3; v_ace = 1; v_fehl = 1; if (hi.team() == TEAM::RE) { value = -6; } else { value = -3; } } if( g.type() == GAMETYPE::SOLO_KING_QUEEN ) { v_queen = 2; v_jack = 0; v_highest = 0; v_king = 3; v_ace = 1; v_fehl = 1; if (hi.team() == TEAM::RE) { value = -6; } else { value = -3; } } if( g.type() == GAMETYPE::SOLO_KOEHLER ) { v_queen = 2; v_jack = 1; v_highest = 0; v_king = 3; v_ace = 0; v_fehl = 0; if (hi.team() == TEAM::RE) { value = -5; } else { value = -2; } } if( g.type()==GAMETYPE::SOLO_CLUB || g.type()==GAMETYPE::SOLO_HEART || g.type()==GAMETYPE::SOLO_SPADE || g.type()==GAMETYPE::SOLO_DIAMOND ) { v_queen = 2; v_jack = 1; v_highest = 3; v_king = 0; v_ace = 1; v_fehl = 2; if (hi.team() == TEAM::RE) { value = -7; } else { value = 0; } } if( g.type() == GAMETYPE::SOLO_MEATLESS ) { v_queen = 0; v_jack = 0; v_highest = 0; v_king = 0; v_ace = 4; v_fehl = 1; // missing aces value = -2; } for( i = 0; i < hi.hand().cardsnumber(); i++ ) { if( hi.hand().card(i).isdolle() || hi.hand().card(i).isswine() || hi.hand().card(i).possible_swine() || hi.hand().card(i).ishyperswine() || hi.hand().card(i).possible_hyperswine() ) value += v_highest; else if( hi.hand().card(i).value()==Card::QUEEN || hi.hand().card(i).possible_genscher() ) value += v_queen; else if( hi.hand().card(i).value()==Card::JACK ) value += v_jack; else if( hi.hand().card(i).value()==Card::KING ) value += v_king; else if( hi.hand().card(i).value()==Card::ACE && !hi.hand().card(i).istrump() && !hi.jabbedbyotherteam(hi.hand().card(i).color())) value += v_ace; } for (vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c) { Card::Color const color = *c; if ( !Card( color, Card::ACE ).istrump( hi.game() ) && !hi.hand().existstcolor( color ) && !hi.jabbedbyotherteam(color) ) if( ::in_running_game() ) { if( hi.game().trick_current().actcardno()>0 && hi.color_runs( color ) == 0 && (hi.game().trick_current().startcard().tcolor() != color) ) value += v_fehl; } else { value += v_fehl; } } if( g.type() == GAMETYPE::SOLO_MEATLESS ) { for (vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c) { if( hi.hand().existstcolor( *c ) ) value -= v_fehl * ( 2 - hi.hand().numberof( *c, Card::ACE ) ); } if( hi.no() == hi.game().soloplayer().no() ) { unsigned longColor = 0; for (vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c) { if( hi.hand().numberof(*c,Card::ACE) == 2 && hi.hand().numberof(*c ) > longColor ) longColor = hi.hand().numberof(*c ); } value += longColor; } } else { Player const& player = hi.game().player( hi.no() ); for( vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c ) { Card::Color color = *c; if( color == hi.game().trumpcolor() ) continue; // including this trick the player does not have the color if ( !hi.hand().existstcolor( color ) && !( ::in_running_game() && ( hi.game().trick_current().actcardno() > hi.game().trick_current().cardno_of_player( player ) ) && ( hi.game().trick_current().card_of_player( player ).tcolor() == color ) ) ) continue; if ( ( hi.hand().numberof( color, Card::ACE ) == 0 ) && !hi.jabbedbyownteam(color) ) value -= v_fehl; if( ( hi.hand().numberof( color ) + hi.color_runs( color ) + ( ::in_running_game() && hi.game().trick_current().actcardno() > 0 && ( hi.game().trick_current().startcard().color() == color ) ? 1 : 0 ) > ( hi.game().different_cards_no( color ) - 1 - ( hi.game().rule()(Rule::WITH_NINES) ? 0 : 1 ) ) ) && !hi.jabbedbyownteam(color) ) value -= v_fehl; if ( ( hi.hand().numberof( color ) + hi.color_runs( color ) + ( ( ::in_running_game() && hi.game().trick_current().actcardno()>0 && ( hi.game().trick_current().startcard().color() == color) ) ? 1 : 0) >= 3) && ( hi.hand().numberof( Card( color, Card::ACE ) ) < 2 ) && !hi.jabbedbyownteam(color) ) value -= v_ace; } // (for color) } // if (...) if( g.type() == GAMETYPE::SOLO_KOEHLER ) { for( vector::const_iterator c = hi.game().rule().card_colors().begin(); c != hi.game().rule().card_colors().end(); ++c ) { if( hi.hand().existstcolor(*c) && !hi.jabbedbyownteam(*c) ) value-=5; } } // if( g.type() == GAMETYPE::SOLO_KOEHLER ) if( ( hi.game().swines_owner() != NULL && hi.game().swines_owner()->no() != hi.no() ) || hi.game().swines_announcement_valid( hi.game().player( hi.no() ) ) ) { Player const& swines_player = ( hi.game().swines_owner() ? *hi.game().swines_owner() : hi.game().player( hi.no() ) ); if( hi.teamofplayer(swines_player) == hi.team() || hi.game().swines_announcement_valid( swines_player ) ) { if(swines_player.no() != hi.no() ) { value += v_highest; } else { value += 1; } } else { value -= 2* v_highest; } } if( ( hi.game().hyperswines_owner() != NULL && hi.game().hyperswines_owner()->no() != hi.no() ) || hi.game().hyperswines_announcement_valid( hi.game().player( hi.no() ) ) ) { Player const& hyperswines_player = ( hi.game().hyperswines_owner() ? *hi.game().hyperswines_owner() : hi.game().player( hi.no() ) ); if( hi.teamofplayer(hyperswines_player) == hi.team() || hi.game().hyperswines_announcement_valid( hyperswines_player ) ) { if(hyperswines_player.no() != hi.no() ) { value += v_highest; } else { value += 1; } } else { value -= 2* v_highest; } } if (hi.hand().numberoftrumps() >= ( (hi.cards_information().remaining_trumps_others() / 3) + round( (::in_running_game() ? hi.game().tricks_remaining_no() : hi.game().trickno() )/ 3) ) ) value += 2; DEBUG_RETURNING( value, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::CalcHandValue"); } /** ** If the poverty partner is the last player play many points ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Borg Enders, Diether Knof ** ** @version 0.7.2 ** ** @todo if the opposite team has played a high card (p.e. dolle) ** do _not_ pfund although the own teammate is last player. ** @todo if an opposite player is behind, check, that the winnercard ** of the teammate is high enough ** (-> play_pfund?) **/ Card Heuristics::poverty_special_play_pfund(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name poverty: special: play pfund // @heuristic::idea If the trick goes or will go to the own team, play a pfund. This heuristic should only be used by the poverty player. if (trick.isstartcard()) return Card(); // @heuristic::condition the last player must be of the own team (oneself or the partner) if (hi.teamofplayer(trick.lastplayer()) != hi.team() ) return Card(); // the teammate vector::const_iterator teammate; for (teammate = hi.game().players_begin(); teammate != hi.game().players_end(); ++teammate) if ( ((*teammate)->no() != hi.no()) && (hi.teamofplayer(**teammate) == TEAM::RE) ) break; // @heuristic::condition the own team has already the trick or the partner is behind if ( (TEAM::maybe_to_team(hi.teamofplayer(trick.winnerplayer())) != hi.team()) && (trick.cardno_of_player(**teammate) < trick.actcardno()) ) return Card(); // @heuristic::action play a pfund // ToDo: Borg: use 'play_pfund' Card c = Card(); HandCards const ha = hi.hand().validcards( trick ); // find any card that's allowed for this trick for( unsigned i = 0; i < ha.cardsnumber(); i++ ) if( !ha.card(i).istrump() ) { c = ha.card(i); break; } if( c == Card() ) return Card(); // find a better card for( unsigned i = 0; i < ha.cardsnumber(); i++ ) { if( !ha.card(i).istrump() && (ha.card(i).value() != Card::ACE) && (ha.card(i).value() > c.value()) && ( (ha.numberof( ha.card(i).color() ) > ha.numberof(c.color())) || (ha.numberof( ha.card(i).color(), Card::ACE ) == 0) ) ) c = ha.card(i); } // for (i) return c; } // Card Heuristics::poverty_special_play_pfund(Trick trick, HeuristicInterface hi) /** ** 1) poverty player ** 2) contra players get trick ** give as few points as possible ** ** reason: do not give points to the opposite team ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Diether Knof ** ** @version 0.7.3 ** ** @todo choose a 'good' color (to keep as much freedom as possible) ** @todo 'anfüttern' of a high re-card with a king ** @todo not in the first color run, if the re has or can get the trick **/ Card Heuristics::poverty_special_give_no_points(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name poverty: special: give no points // @heuristic::idea If the contra team gets the trick, give as few points as possible. // @heuristic::condition the player must be the poverty player if (hi.game().type() != GAMETYPE::POVERTY) return Card(); if (hi.no() != hi.game().soloplayer().no()) return Card(); // the accepter of the poverty Player const& re_player = hi.game().poverty_partner(); // check whether the contra team gets the trick: // @heuristic::condition the partner has played already // @heuristic::condition contra already has the trick or the re player can be overjabbed if (trick.cardno_of_player(re_player) > trick.actcardno()) return Card(); if ( trick.islastcard() && (trick.winnerplayerno() == re_player.no()) ) return Card(); if ( trick.startcard().istrump() && hi.hand().hastrump()) return Card(); /// @todo Use 'cards information' for checking that the contra team can jab. if ( (trick.winnerplayerno() == re_player.no()) && (!trick.winnercard().less(hi.value(Aiconfig::TRUMPLIMIT_NORMAL)) || ( !trick.startcard().istrump() && (hi.color_runs(trick.startcard().tcolor()) == 0) ) ) ) { return Card(); } // @heuristic::action play the lowest card // search the lowest card // ToDo: check for a 'good' color // ToDo: create and use 'best_loosing_card' HandCards const cards = hi.hand().cards_single(); HandCard card; // the card to play for (HandCards::const_iterator c = cards.begin(); c != cards.end(); ++c) { if (!trick.isvalid(*c)) continue ; if (!card) { card = *c; continue; } if (c->value() < card.value()) card = *c; } // for (c \in cards) return card; } // Card Heuristics::poverty_special_give_no_points(Trick trick, HeuristicInterface hi) /** ** 1) re player in a poverty ** 2) color trick, cannot serve it ** play high trump (small queen or so) ** ** reason: jab for the points ** ** note: Should be called after 'serve color trick' ** because this is overreacted for the first color run. ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Diether Knof ** ** @version 0.7.3 ** ** @todo for more points take a higher card **/ Card Heuristics::poverty_re_trump_color_trick_high(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name poverty: re: trump color trick high // @heuristic::idea Jab the trick with a small queen in order to get the points // @heuristic::condition re player (not poverty player) in a poverty if (hi.game().type() != GAMETYPE::POVERTY) return Card(); if ( (hi.team() != TEAM::RE) || (hi.no() == hi.game().soloplayer().no()) ) return Card(); // @heuristic::condition only my team behind me, I don't need to jab high if( checkAllMyTeam( trick, hi ) ) return Card(); // @heuristic::condition neither first nor last card in the trick if (trick.isstartcard()) return Card(); if (trick.islastcard()) return Card(); // @heuristic::condition color trick which must not be served if ( trick.startcard().istrump() || hi.hand().existstcolor(trick.startcard().tcolor())) return Card(); // @heuristic::action play high trump (small queen) // ToDo: Borg: use 'choose_best_card' // search in the order one of the following cards to play list cards_to_play; cards_to_play.push_back(Card(Card::HEART, Card::QUEEN)); cards_to_play.push_back(Card(Card::DIAMOND, Card::QUEEN)); cards_to_play.push_back(Card(Card::CLUB, Card::JACK)); cards_to_play.push_back(Card(Card::SPADE, Card::JACK)); cards_to_play.push_back(Card(Card::SPADE, Card::QUEEN)); cards_to_play.push_back(Card(Card::HEART, Card::JACK)); cards_to_play.push_back(Card(Card::DIAMOND, Card::JACK)); for (list::const_iterator c = cards_to_play.begin(); c != cards_to_play.end(); ++c) if ( (hi.hand().numberof(*c) > 0) && trick.winnercard().less(*c)) return *c; return Card(); } // Card Heuristics::poverty_re_trump_color_trick_high(Trick trick, HeuristicInterface hi) /** ** 1) re player in a poverty ** 2) first player ** play a trump (diamond jack, ..., club queen) ** ** reason: draw trump from the contra players ** ** note: this heuristic shall be called after 'draw trump' ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Diether Knof ** ** @version 0.7.3 **/ Card Heuristics::poverty_re_play_trump(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name poverty: re: play trump // @heuristic::idea As first player draw trump fro the contra players. // @heuristic::condition re player (not poverty player) in a poverty if (hi.game().type() != GAMETYPE::POVERTY) return Card(); if ( (hi.team() != TEAM::RE) || (hi.no() == hi.game().soloplayer().no()) ) return Card(); // @heuristic::condition first player if (!trick.isstartcard()) return Card(); // @heuristic::condition partner has no trump if (!hi.cards_information().of_player(hi.game().soloplayer()).does_not_have(Card::TRUMP)) return Card(); // @heuristic::action play a small jack list cards_to_play; cards_to_play.push_back(Card(Card::CLUB, Card::JACK)); cards_to_play.push_back(Card(Card::SPADE, Card::JACK)); cards_to_play.push_back(Card(Card::HEART, Card::JACK)); cards_to_play.push_back(Card(Card::DIAMOND, Card::JACK)); cards_to_play.push_back(Card(Card::DIAMOND, Card::QUEEN)); cards_to_play.push_back(Card(Card::HEART, Card::QUEEN)); cards_to_play.push_back(Card(Card::SPADE, Card::QUEEN)); cards_to_play.push_back(Card(Card::CLUB, Card::QUEEN)); for (list::const_iterator c = cards_to_play.begin(); c != cards_to_play.end(); ++c) if (hi.hand().numberof(*c) > 0) return *c; return Card(); } // Card Heuristics::poverty_re_play_trump(Trick trick, HeuristicInterface hi) /** ** 1) contra player in a poverty ** 2) first player ** play a color ** ** reason: do not draw trump ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Diether Knof ** ** @version 0.7.3 **/ Card Heuristics::poverty_contra_play_color(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name poverty: contra: play color // @heuristic::idea Start with a color. // @heuristic::condition contra player in a poverty if (hi.game().type() != GAMETYPE::POVERTY) return Card(); if (hi.team() != TEAM::CONTRA) return Card(); // @heuristic::condition first player if (!trick.isstartcard()) return Card(); // the player with the poverty Player const& poverty_player = hi.game().soloplayer(); // the accepter of the poverty Player const& re_player = hi.game().poverty_partner(); // the partner // Bug: this formula does only work with four players Player const& partner = hi.game().player( (0 + 1 + 2 + 3) - poverty_player.no() - re_player.no() - hi.no()); // @heuristic::action Play a color the partner does not have; if the partner is behind the re player, take a high card, else take a low one. Else take the longest color. { // search a color to play vector const& colors = hi.game().rule().card_colors(); vector::const_iterator c; // first search for a color the partner does not have for (c = colors.begin(); c != colors.end(); ++c) if ( hi.cards_information().of_player(partner).does_not_have(*c) && hi.hand().existstcolor(*c)) break; if (c != colors.end()) { // There is a color the partner does not have. HandCards const cards = hi.hand().cards_single(); HandCard card; // the card to play for (HandCards::const_iterator c = cards.begin(); c != cards.end(); ++c) { if (c->istrump()) continue; if (!hi.cards_information().of_player(partner).does_not_have(c->tcolor())) continue; if (!card) { card = *c; continue; } // If the partner is behind the re player, take the highest card // else take the lowest if ( (c->value() > card.value()) == (trick.cardno_of_player(partner) > trick.cardno_of_player(re_player)) ) card = *c; } // for (c \in cards) return card; } else { // if !(c != colors.end()) // There is no color the partner does not have. // Play the color I have the most number of. Card::TColor color = Card::NOCARDCOLOR; unsigned max_num = 0; for (vector::const_iterator c = colors.begin(); c != colors.end(); ++c) if (hi.hand().numberof(*c) > max_num) color = *c, max_num = hi.hand().numberof(*c); // play the smallest card of the color HandCards const cards = hi.hand().cards_single(); HandCard card; // the card to play for (HandCards::const_iterator c = cards.begin(); c != cards.end(); ++c) { if (c->tcolor() != color) continue; if (c->value() < card.value()) card = *c; } // for (c \in cards) return card; } // if !(c != colors.end()) } // search a color to play return Card(); } // Card Heuristics::poverty_contra_play_color(Trick trick, HeuristicInterface hi) /** ** 1) contra player in a poverty ** 2) color trick, cannot serve it ** 3) re player is behind ** 4) a) partner before: ** - partner has played low ** - there are some points in the trick ** b) partner behind: ** - partner can have the color ** play high trump (small queen or so) ** ** reason: The re player does in most cases not have the color ** so make the trick expensive for him. ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Diether Knof ** ** @version 0.7.3 ** ** @todo use 'best_winning_card()' **/ Card Heuristics::poverty_contra_trump_color_trick_high(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name poverty: contra: trump color trick high // @heuristic::idea Play a high trump (small queen) in color tricks, so that the trick is expensive for the re player. // @heuristic::condition contra player in a poverty if (hi.game().type() != GAMETYPE::POVERTY) return Card(); if (hi.team() != TEAM::CONTRA) return Card(); // @heuristic::condition a color trck the player must not serve if (trick.isstartcard()) return Card(); if ( trick.startcard().istrump() || hi.hand().existstcolor(trick.startcard().tcolor())) return Card(); // the player with the poverty Player const& poverty_player = hi.game().soloplayer(); // the accepter of the poverty Player const& re_player = hi.game().poverty_partner(); // the partner // Bug: this formula does only work with four players Player const& partner = hi.game().player( (0 + 1 + 2 + 3) - poverty_player.no() - re_player.no() - hi.no()); // @heuristic::condition the re player is behind if (trick.cardno_of_player(re_player) < trick.actcardno()) return Card(); if (trick.cardno_of_player(partner) < trick.actcardno()) { // @heuristic::condition a) the partner has played low (trump limit) if (!( !trick.card_of_player(partner).istrump() || trick.card_of_player(partner).less(hi.value(Aiconfig::TRUMPLIMIT_NORMAL))) ) return Card(); // @heuristic::condition a) there are some points (>= 8) in the trick if (trick.points() < 8) // *Value* return Card(); } else { // if !(partner before) // @heuristic::condition b) the partner is behind // @heuristic::condition b) the partner can have the color if (hi.cards_information().of_player(partner).does_not_have(trick.startcard().tcolor())) return Card(); } // if !(partner before) // the partner was before and has played low // @heuristic::action play high trump (small queen) // ToDo: Borg: use 'best_winning_card' // search in the order one of the following cards to play list cards_to_play; cards_to_play.push_back(Card(Card::HEART, Card::QUEEN)); cards_to_play.push_back(Card(Card::DIAMOND, Card::QUEEN)); cards_to_play.push_back(Card(Card::CLUB, Card::JACK)); cards_to_play.push_back(Card(Card::SPADE, Card::JACK)); cards_to_play.push_back(Card(Card::SPADE, Card::QUEEN)); cards_to_play.push_back(Card(Card::HEART, Card::JACK)); cards_to_play.push_back(Card(Card::DIAMOND, Card::JACK)); for (list::const_iterator c = cards_to_play.begin(); c != cards_to_play.end(); ++c) if (hi.hand().numberof(*c) > 0) return *c; return Card(); } // Card Heuristics::poverty_contra_trump_color_trick_high(Trick trick, HeuristicInterface hi) /** ** 1) contra player in a poverty ** 2) re has played trump ** 3) partner is behind and can jab the trick ** play a small trump so that the partner can get the trick ** ** reason: make myself be behind the re player ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Diether Knof ** ** @version 0.7.3 **/ Card Heuristics::poverty_leave_to_partner(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name poverty: contra: leave to partner // @heuristic::idea Make myself be behind the re player. // @heuristic::condition contra player in a poverty if (hi.game().type() != GAMETYPE::POVERTY) return Card(); if ( (hi.team() != TEAM::CONTRA) && (hi.no() != hi.game().soloplayer().no()) ) return Card(); // the player with the poverty Player const& poverty_player = hi.game().soloplayer(); // the accepter of the poverty Player const& re_player = hi.game().poverty_partner(); // the partner // Bug: this formula does only work with four players Player const& partner = hi.game().player( (0 + 1 + 2 + 3) - poverty_player.no() - re_player.no() - hi.no()); // @heuristic::condition the re player has played a trump // more precise: it has been started with trump and re has already played // (contains the case that the poverty player has started with trump) if (trick.isstartcard()) return Card(); if (!trick.startcard().istrump()) return Card(); if (trick.cardno_of_player(re_player) > trick.actcardno()) return Card(); // @heuristic::condition the partner is behind and can jab the trick if (trick.cardno_of_player(partner) < trick.actcardno()) return Card(); // ToDo: use cards information if (!trick.winnercard().less(hi.value(Aiconfig::TRUMPLIMIT_NORMAL))) return Card(); // @heuristic::action play a low trump // ToDo: Borg: use 'play_pfund'? list cards_to_play; // special case: // poverty player behind has still trump and // re player has played a small trump if (!( (hi.game().type() == GAMETYPE::POVERTY) && (trick.startplayer().team() == TEAM::RE) // ToDo: better card value && trick.startcard().less(hi.value(Aiconfig::LIMITHIGH)) && (trick.cardno_of_player(hi.game().soloplayer()) > trick.actcardno()) && !hi.cards_information().of_player(hi.game().soloplayer()).does_not_have(Card::TRUMP)) ) { if (!hi.hand().has_swines()) cards_to_play.push_back(Card(Card::DIAMOND, Card::ACE)); cards_to_play.push_back(Card(Card::DIAMOND, Card::TEN)); } // if (special case poverty) cards_to_play.push_back(Card(Card::DIAMOND, Card::KING)); cards_to_play.push_back(Card(Card::DIAMOND, Card::NINE)); // ToDo: Hand function 'next greater card' cards_to_play.push_back(Card(Card::DIAMOND, Card::JACK)); cards_to_play.push_back(Card(Card::HEART, Card::JACK)); cards_to_play.push_back(Card(Card::SPADE, Card::JACK)); cards_to_play.push_back(Card(Card::CLUB, Card::JACK)); cards_to_play.push_back(Card(Card::DIAMOND, Card::QUEEN)); cards_to_play.push_back(Card(Card::HEART, Card::QUEEN)); cards_to_play.push_back(Card(Card::SPADE, Card::QUEEN)); cards_to_play.push_back(Card(Card::CLUB, Card::QUEEN)); for (list::const_iterator c = cards_to_play.begin(); c != cards_to_play.end(); ++c) if (hi.hand().numberof(*c) > 0) return *c; return Card(); } // Card Heuristics::poverty_leave_to_partner(Trick trick, HeuristicInterface hi) /** ** 1) contra player in a poverty ** 2) re player has won with a trump ** 3) can play a better card than the re player ** play next higher card ** ** reason: If you can, overjab the re player in order to get points. ** ** note: Should be called after 'leave to partner' ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Diether Knof ** ** @version 0.7.3 **/ Card Heuristics::poverty_overjab_re(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name poverty: contra: overjab re // @heuristic::idea Overjab the re player in order to get the points. // @heuristic::condition contra player in a poverty if (hi.game().type() != GAMETYPE::POVERTY) return Card(); if (hi.team() != TEAM::CONTRA) return Card(); // @heuristic::condition the re player has won so far with a trump if (trick.winnerplayer().no() != hi.game().poverty_partner().no()) return Card(); if (!trick.winnercard().istrump()) return Card(); // @heuristic::condition the player can play a better card than the re player if (!( trick.startcard().istrump() || !hi.hand().existstcolor(trick.startcard().tcolor()) ) ) return Card(); // @heuristic::action Take the best winning card. return Heuristics::best_winning_card(trick, hi); } // Card Heuristics::poverty_overjab_re(Trick trick, HeuristicInterface hi) /** ** best winning card for the last card * ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Diether Knof ** ** @version 0.7.3 **/ Card Heuristics::poverty_best_winning_card(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name poverty: best winning card // @heuristic::idea As last player in a trick take the lowest card to win the trick. // @heuristic::condition only for the not poverty player in a poverty if (hi.game().type() != GAMETYPE::POVERTY) return Card(); if ( (hi.team() != TEAM::RE) || (hi.no() == hi.game().soloplayer().no()) ) return Card(); // @heuristic::condition last player in the trick if (!trick.islastcard() ) return Card(); // @heuristic::action Play the best winning card. return Heuristics::best_winning_card(trick, hi); } // Card Heuristics::poverty_best_winning_card(Trick trick, HeuristicInterface hi) /********************************************************************** * ** bool Heuristics::make_announcement(HeursticInterface const& hi) * ** Parameters: HeuristicInterface who checks for an announcement * ** Result: true if hi should say re or contra ** false otherwise * ** Version: Beta * ** Description: * **********************************************************************/ bool Heuristics::make_announcement( HeuristicInterface const& hi, const Game& g ) { // @heuristic::name ? make announcement ? // @heuristic::idea announcement decision bases on Heuristics::CalcHandValue DEBUG_CALLING( INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::make_announcement" ); int value=0; value= CalcHandValue( hi, g ); #ifdef ANNOUNCE_DEBUG if( !g.isvirtual() ) COUT << "RE/CO: " << hi.no() << "\t" << value << "\t" << (int)hi.value(Aiconfig::ANNOUNCELIMIT) << " + " << (int)hi.value(Aiconfig::ANNOUNCECONFIG) << std::endl; #endif DEBUG_RETURNING( value >= (int)hi.value(Aiconfig::ANNOUNCELIMIT) + (int)hi.value(Aiconfig::ANNOUNCECONFIG), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::make_announcement" ); } ///calculates all point of own team in Game g int calcPointsOfOwnTeam( HeuristicInterface const& hi, Game const& g ) { int points_p = 0; for( unsigned int i = 0; i < g.playerno(); i++ ) { if( hi.teamofplayer( g.player(i) ) == hi.team() ) { points_p += g.points_of_player( g.player(i) ); } } Trick tr = g.trick_current(); if( tr.isfull() ) if( TEAM::maybe_to_team(hi.teamofplayer(tr.winnerplayer())) == hi.team() ) { points_p += tr.points(); } return points_p; } ///calculates all point of all players not of own team in Game g int calcPointsOfOppositeTeam( HeuristicInterface const& hi, Game const& g) { int points_p = 0; for( unsigned int i = 0; i < g.playerno(); i++ ) { if( hi.teamofplayer( g.player(i) ) != hi.team() ) { points_p += g.points_of_player( g.player(i) ); } } Trick tr = g.trick_current(); if( tr.isfull() ) if( TEAM::maybe_to_team(hi.teamofplayer(tr.winnerplayer())) != hi.team() ) { points_p += tr.points(); } return points_p; } /********************************************************************** * ** bool Heuristics::say_no90(HeuristicInterface const& hi ,Game g) * ** Parameters: HeuristicInterface who checks for an announcement * ** Result: true if hi should say No90 ** false otherwise * ** Version: Beta * ** Description: * **********************************************************************/ bool Heuristics::say_no90( HeuristicInterface const& hi ,const Game& g ) { // @heuristic::name ? say no 90 ? // @heuristic::idea decision to make the annoncement no 90 depending on Heuristics::CalcHandValue DEBUG_CALLING( INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no90" ); int value = 0; if( g.announcement_of_team( opposite( hi.team() ) ).announcement > ANNOUNCEMENT::NO120 ) return false; value = CalcHandValue( hi, g ) - std::max( 0, (int)g.tricks_remaining_no() - 8) * static_cast(hi.value(Aiconfig::ANNOUNCELIMITDEC)); if( !g.hastrick(::opposite(hi.team())) ) value += 2 * static_cast(hi.value(Aiconfig::ANNOUNCELIMITDEC)); int own_p = calcPointsOfOwnTeam( hi, g ); int opp_p = calcPointsOfOppositeTeam( hi, g ); if( own_p > 150 ) DEBUG_RETURNING( true, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no90"); opp_p+= 5 * g.tricks_remaining_no(); own_p+= 6 * g.tricks_remaining_no(); own_p += (int)(1.9 * hi.hand().numberoftrumps() * hi.hand().numberofswines()); own_p += (int)(1.4 * hi.hand().numberoftrumps() * hi.hand().numberofhyperswines()); if( GAMETYPE::is_solo( hi.game().type() ) ) { own_p += 20 * hi.hand().numberoftrumps(); opp_p += 20 * hi.cards_information().remaining_trumps_others(); } #ifdef ANNOUNCE_DEBUG if( !g.isvirtual() ) COUT << "NO90: " << hi.no() << "\t" << value << " + " << 2 * (int)hi.value(Aiconfig::ANNOUNCELIMITDEC ) << "\t" << (int)hi.value(Aiconfig::ANNOUNCELIMIT) << " + " << 2 * (int)hi.value(Aiconfig::ANNOUNCECONFIG) << std::endl; #endif DEBUG_RETURNING( ( ( value + 2 * (int)hi.value(Aiconfig::ANNOUNCELIMITDEC ) > (int)hi.value(Aiconfig::ANNOUNCELIMIT) + 2*(int)hi.value(Aiconfig::ANNOUNCECONFIG) ) && own_p > 2 * opp_p && opp_p < 90 && ( opp_p > 0 || g.last_chance_to_announce(ANNOUNCEMENT::NO90, g.player(hi.no())) ) ), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no90"); } /********************************************************************** * ** bool Heuristics::say_no60(HeuristicInterface const& hi ,Game g) * ** Parameters: HeuristicInterface who checks for an announcement * ** Result: true if hi should No60 ** false otherwise * ** Version: Beta * ** Description: * **********************************************************************/ bool Heuristics::say_no60( HeuristicInterface const& hi, const Game& g ) { // @heuristic::name ? say no 60 ? // @heuristic::idea decision to make the annoncement no 60 depending on Heuristics::CalcHandValue DEBUG_CALLING( INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no60" ); int value = 0; if( g.announcement_of_team( opposite( hi.team() ) ).announcement > ANNOUNCEMENT::NO120 ) return false; value = CalcHandValue( hi, g ) - std::max( 0, (int)g.tricks_remaining_no() - 5) * static_cast(hi.value(Aiconfig::ANNOUNCELIMITDEC)); int own_p = calcPointsOfOwnTeam( hi, g ); int opp_p = calcPointsOfOppositeTeam( hi, g ); if( own_p > 180 ) DEBUG_RETURNING( true, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no60"); opp_p+= 5 * g.tricks_remaining_no(); own_p+= 5 * g.tricks_remaining_no(); own_p += 3 * hi.hand().numberoftrumps() * hi.hand().numberofswines(); own_p += 3 * hi.hand().numberoftrumps() * hi.hand().numberofhyperswines(); DEBUG_RETURNING( ( ( value + 4 * (int)hi.value(Aiconfig::ANNOUNCELIMITDEC) > (int)hi.value(Aiconfig::ANNOUNCELIMIT) + 2 * (int)hi.value(Aiconfig::ANNOUNCECONFIG) ) && own_p > 3 * opp_p && opp_p < 60 && ( opp_p > 0 || g.last_chance_to_announce(ANNOUNCEMENT::NO60, g.player(hi.no())) ) ), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no60"); } /********************************************************************** * ** bool Heuristics::say_no30(HeuristicInterface const& hi ,Game g) * ** Parameters: HeuristicInterface who checks for an announcement * ** Result: true if hi should say no30 ** false otherwise * ** Version: Beta * ** Description: * **********************************************************************/ bool Heuristics::say_no30( HeuristicInterface const& hi, const Game& g ) { // @heuristic::name ? say no 30 ? // @heuristic::idea decision to make the annoncement no 30 depending on Heuristics::CalcHandValue DEBUG_CALLING( INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no30" ); int value = 0; if( g.announcement_of_team( opposite( hi.team() ) ).announcement > ANNOUNCEMENT::NO120 ) return false; value = CalcHandValue( hi, g ) - std::max( 0, (int)g.tricks_remaining_no() - 3) * static_cast(hi.value(Aiconfig::ANNOUNCELIMITDEC)); int own_p = calcPointsOfOwnTeam( hi, g ); int opp_p = calcPointsOfOppositeTeam( hi, g ); if( own_p > 210 ) DEBUG_RETURNING( true, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no30"); opp_p+= 4 * g.tricks_remaining_no(); own_p+= 5 * g.tricks_remaining_no(); DEBUG_RETURNING( ( ( value + 6 * (int)hi.value(Aiconfig::ANNOUNCELIMITDEC) > (int)hi.value(Aiconfig::ANNOUNCELIMIT) + (int)hi.value(Aiconfig::ANNOUNCECONFIG) ) && own_p > 7 * opp_p && opp_p < 30 && ( opp_p > 0 || g.last_chance_to_announce(ANNOUNCEMENT::NO30, g.player(hi.no())) ) ), INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::say_no60"); } /** ** test whether a 'no 0' could be announced ** checks, that the other team does not have a trick ** and that the hand value is big enoug. ** ** @param hi heuristic interface ** @param game current gaem ** ** @return whether to announce 'no 0' ** ** @author Borg Enders ** @author Diether Knof ** ** @version 0.7.3 **/ bool Heuristics::say_no0( HeuristicInterface const& hi, Game const& game ) { // @heuristic::name ? say no 0 ? // @heuristic::idea decision to make the annoncement no 0 depending on Heuristics::CalcHandValue if( game.announcement_of_team( opposite( hi.team() ) ).announcement != ANNOUNCEMENT::NOANNOUNCEMENT ) return false; // make sure, that the other team does not have a trick if (game.hastrick(::opposite(hi.team()))) return false; for (unsigned p = 0; p < game.playerno(); ++p) if ( (hi.teamofplayer(game.player(p)) != hi.team()) && game.hastrick(game.player(p))) return false; // as long as the current trick is not closed, it has to be taken into account if ( game.trick_current().isfull() && (hi.teamofplayer(game.trick_current().winnerplayer()) != hi.team()) ) return false; // wait for the last possible moment if (!game.last_chance_to_announce(ANNOUNCEMENT::NO0, game.player(hi.no()))) return false; // ToDo: check that no opposite player has the highest trump card // Test: force a player by 'ANNOUNCELIMITDEC' high int const value = CalcHandValue( hi, game ) - std::max( 0, (int)game.tricks_remaining_no() ) * static_cast(hi.value(Aiconfig::ANNOUNCELIMITDEC)); return (value + 4 * static_cast(hi.value(Aiconfig::ANNOUNCELIMITDEC)) > static_cast(hi.value(Aiconfig::ANNOUNCELIMIT) + 3 * hi.value(Aiconfig::ANNOUNCECONFIG)) ); } // bool Heuristics::say_no0( HeuristicInterface hi, Game game ) /********************************************************************** * ** Card play_highest_color(Trick const& t,AI& hi,Card::COLOR c) * ** Parameters: * ** Result: finds highest card of color c ** If Card() then you should calculate a new best color * ** Version: Beta * ** Description: * **********************************************************************/ Card Heuristics::play_highest_color( Trick const& t, HeuristicInterface const& hi, Card::Color co ) { // @heuristic::name meatless: play highest color // @heuristic::idea Heuristic for solo::MEATLESS to play the longest color or follow previous color DEBUG_CALLING( INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::play_highest_color" ); Hand h = hi.hand(); HandCard c( h ); unsigned i; for( i = 0; i < h.cardsnumber(); i++ ) { // find any card if( h.card( i ).color() == co ) { c = h.card( i ); break; } } if( c == Card() ) { DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::play_highest_color"); } for( i = 0; i < h.cardsnumber(); i++ ) { // find highest card if( h.card(i).color() == co && c.less( h.card(i) ) ) c = h.card(i); } if( hi.no() == hi.game().soloplayer().no() || hi.hand().numberof( Card::ACE ) != 0 ) for ( unsigned value = 0 ; value < hi.game().rule()(Rule::NUMBER_OF_CARD_VALUES); value++ ) { Card const c2 = Card( c.color(), Card::InttoValue( value ) ); if( !hi.cards_information().played(c2) && c.less( c2 ) ) { c = Card(); break; } } DEBUG_RETURNING( c, INFO_HEURISTICS && INFO_OTHER_FUNCTION,"Heuristics::play_highest_color"); } /********************************************************************** * ** Card drawTrumps(Trick const& t,AI& hi ) * ** Parameters: * ** Result: play trumps to draw the last trumps * ** Version: 0.6.1 * ** Description: * **********************************************************************/ /** ** play trumps to draw the last trumps ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play ** ** @author Borg Enders ** @author Diether Knof ** ** @version 0.7.4 **/ Card Heuristics::draw_trump( Trick const& trick, HeuristicInterface const& hi ) { // @heuristic::name draw trump // @heuristic::idea play trumps to force other players to play also trumps // @heuristic::condition first player if( !trick.isstartcard() ) return Card(); // @heuristic::condition more trumps then remaining trumps if (! ( (hi.hand().numberoftrumps() > hi.cards_information().remaining_trumps_others()) && hi.cards_information().remaining_trumps_others() ) ) return Card(); return hi.hand().highest_trump(); } // Card Heuristics::draw_trump(Trick trick, HeuristicInterface hi) /** ** As first player and the partner in backhand, take a small trump. ** prerequisites: ** 1. first player in the trick ** 2. last player is partner ** take a small trump ** If the partner has the highest card still in the game, take a trump ** with a high value (fox or ten) ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Diether Knof ** ** @version 0.7.4 ** ** @todo check that the partner has no problems with his trumps **/ Card Heuristics::partner_backhand_draw_trump(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name partner backhand draw trump // @heuristic::idea as first player and the partner in backhand, draw trump // @heuristic::condition first player in the trick if (!trick.isstartcard() ) return Card(); // @heuristic::condition last player is partner if (!(::maybe_to_team(hi.teamofplayer(trick.lastplayer())) == hi.team())) return Card(); // the partner Player const& partner = trick.lastplayer(); bool partner_has_highest_trump = false; { // check whether the partner has the highest trump in the game HandCard const highest_trump = HandCard(hi.hand(), hi.cards_information().highest_remaining_trump_of_others()); if (hi.handofplayer(partner).contains(highest_trump)) { // check that no other player does have the card, also if ( highest_trump.isdolle() && hi.game().second_dolle_over_first() && hi.cards_information().of_player(partner).must_have(Card::DOLLE)) { partner_has_highest_trump = true; } else { partner_has_highest_trump = true; for (unsigned p = 0; p < hi.game().playerno(); ++p) { Player const& player = hi.game().player(p); if ( (::maybe_to_team(hi.teamofplayer(player)) != hi.team()) && (hi.handofplayer(player).contains(highest_trump))) { partner_has_highest_trump = false; break; } } // for (p < hi.game().playerno()) } // if !(second dolle over first) } // if (partner has highest trump) } // check whether the partner has the highest trump in the game list cards_to_play; if (partner_has_highest_trump) { cards_to_play.push_back(Card(Card::DIAMOND, Card::ACE)); cards_to_play.push_back(Card(Card::DIAMOND, Card::TEN)); } else if (hi.hand().numberoftrumps() >= 3) { // *Value* cards_to_play.push_back(Card(Card::DIAMOND, Card::KING)); cards_to_play.push_back(Card(Card::DIAMOND, Card::JACK)); cards_to_play.push_back(Card(Card::HEART, Card::JACK)); cards_to_play.push_back(Card(Card::SPADE, Card::JACK)); cards_to_play.push_back(Card(Card::DIAMOND, Card::NINE)); } // @heuristic::condition at least three trump on the hand if the partner does not have the highest card // ToDo: improve for (list::const_iterator c = cards_to_play.begin(); c != cards_to_play.end(); ++c) if ( hi.hand().contains(*c) && !hi.game().is_special(HandCard(hi.hand(), *c))) return *c; return Card(); } // static Card Heuristics::partner_backhand_draw_trump(Trick trick, HeuristicInterface hi) /** ** as last player grab the trick ** prerequisites: ** 1. the player must be the last player or the players behind cannot get the trick ** 2. the player can get the trick ** take the best card to win the trick ** ** @param trick current trick ** @param hi heuristic interface ** ** @return card to play, 'Card()' if the heuristic does not match ** ** @author Diether Knof ** ** @version 0.7.4 **/ Card Heuristics::grab_trick(Trick const& trick, HeuristicInterface const& hi) { // @heuristic::name grab trick // @heuristic::idea as last player jab the trick if possible // @heuristic::condition last player in the trick if (!trick.islastcard() && oppositeTeamCanWinTrick(trick, hi)) return Card(); // @heuristic::condition the trick does not go to the own team if (hi.guessedteamofplayer(trick.winnerplayer()) == hi.team()) return Card(); // @heuristic::action Play the best winning card. return Heuristics::best_winning_card(trick, hi, Card::ACE * hi.game().playerno()); } // Card Heuristics::grab_trick(Trick trick, HeuristicInterface hi) /********************************************************************** * ** Card getTrickForKeepingAnnouncement(Trick const& t, HeuristicInterface const& hi ) * ** Parameters: * ** Result: * ** Version: 0.7.0 * ** Description: * **********************************************************************/ Card Heuristics::getTrickForKeepingAnnouncement( Trick const& t, HeuristicInterface const& hi ) { // @heuristic::name get trick for announcement // @heuristic::idea If this trick would open the possibility for the other team to win there announcement try to win this trick for the own team // ToDo: Gegenansagen Card c = Card(); if( hi.game().announcement_of_team( hi.team() ).announcement != ANNOUNCEMENT::NOANNOUNCEMENT ) { unsigned oppositeToGet = 120; for( int a = (int)ANNOUNCEMENT::NO90; a <= hi.game().announcement_of_team( hi.team() ).announcement; a++ ) oppositeToGet -= 30; if( hi.game().points_of_team( opposite( hi.team() ) ) + t.points() + 10 >= oppositeToGet && TEAM::maybe_to_team(hi.teamofplayer(t.winnerplayer())) == opposite( hi.team() ) ) c = best_winning_card( t, hi, 30 ); } #ifdef POSTPHONED if( hi.game().announcement_of_team( opposite( hi.team() ) ).announcement != ANNOUNCEMENT::NOANNOUNCEMENT ) { unsigned ownToGet = 120; for( int a = (int)ANNOUNCEMENT::NO90; a <= hi.game().announcement_of_team( opposite( hi.team() ) ).announcement; a++ ) ownToGet -= 30; if( hi.game().points_of_team( hi.team() ) + t.points() + 10 >= ownToGet && TEAM::maybe_to_team(hi.teamofplayer(t.winnerplayer())) == opposite( hi.team() ) ) c = best_winning_card( t, hi, 30 ); } #endif return c; } /********************************************************************** * ** Announcement make_reply(HeuristicInterface const& hi ,const Game& g) * ** Parameters: * ** Result: Announcment::Reply if wanted * ** Version: 0.6.3 * ** Description: * **********************************************************************/ Announcement Heuristics::make_reply( HeuristicInterface const& hi, const Game& g ) { // @heuristic::name ? make reply ? // @heuristic::idea announcement reply decision bases on Heuristics::CalcHandValue DEBUG_CALLING( INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::make_reply" ); if( g.announcement_of_team( opposite( hi.team() ) ).announcement != ANNOUNCEMENT::NOANNOUNCEMENT ) { int value = 0; value = CalcHandValue( hi, g ); for( int a = (int)ANNOUNCEMENT::NO90; a <= g.announcement_of_team( opposite( hi.team() ) ).announcement; a++ ) value += (int)hi.value(Aiconfig::ANNOUNCECONFIGREPLY); for( unsigned i = 0; i < hi.hand().cardsnumber(); i++ ) { if( hi.hand().card(i).isdolle() || hi.hand().card(i).isswine() || hi.hand().card(i).possible_swine() || hi.hand().card(i).ishyperswine() || hi.hand().card(i).possible_hyperswine() ) value += (int)hi.value(Aiconfig::ANNOUNCECONFIGREPLY); } #ifdef ANNOUNCE_DEBUG if( !g.isvirtual() ) COUT << "REPLY: " << hi.no() << "\t" << value << "\t" << (int)hi.value(Aiconfig::ANNOUNCELIMITREPLY) << std::endl; #endif if( value >= (int)hi.value(Aiconfig::ANNOUNCELIMITREPLY) ) DEBUG_RETURNING( ANNOUNCEMENT::REPLY, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::make_reply" ); } DEBUG_RETURNING( ANNOUNCEMENT::NOANNOUNCEMENT, INFO_HEURISTICS && INFO_OTHER_FUNCTION, "Heuristics::make_reply" ); } /** ** -> result ** ** @param old_card best card till now ** @param test_card card to test ** @param hi hi (with the configuration) ** ** @return whether the card 'test_card' is to preferred to 'old_card' ** that is has more points ** ** @author Borg Enders ** ** @version 0.6.9 **/ bool better_points_optimize(HandCard const& old_card, HandCard const& test_card, HeuristicInterface const& hi ) { return ( ( hi.game().trick_current_no() >= hi.value(Aiconfig::FIRST_TRICK_FOR_TRUMP_POINTS_OPTIMIZATION) ) && ( old_card.value() <= test_card.value() ) ); } // bool better_points_optimize(HandCard old_card, HandCard test_card, Ai hi)