/********************************************************************** * * 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 "trickweighting.h" #include "VirtualGamesInterface.h" #include "ai.h" #include "info.h" #include "../../party/party.h" #include "../../game/game.h" #include "../../game/exception.h" #include "../../card/trick.h" #include "../../misc/setting.h" #include "../../ui/ui.h" #ifdef BENDERS // whether to print some weighting informations #define PLAYERCHECK #endif #ifdef DKNOF #define PLAYERCHECK #endif /** ** ** -> result ** ** @param vgi the virtual games interface ** @param trick the trick to be examined ** @param t the team which should make points ** @param card the card played by the player ** ** @return the weighting of the trick for the team 'team' ** ** @version 0.4.4 ** ** @author Borg Enders ** ** @todo perhaps points for getting the fox home ** @todo perhaps when playing the highest card, subtract in modi ** the distance to the next lower card **/ int TrickWeighting::modi(VirtualGamesInterface const& vgi, Trick const& trick, Team const t, HandCard const& card) { DEBUG_CALLING(INFO_W_VIRTUAL_GAMES && INFO_VALUE, "WVirtualGames::modi()"); DEBUG_ASSERTION(trick.isfull(), "TrickWeighting::modi()\n" " trick is not full"); Game const& game_virt = trick.game(); Ai const& ai = (dynamic_cast(&game_virt.player(vgi.no())) ? static_cast(game_virt.player( vgi.no() )) : static_cast(vgi.game().player(vgi.no())) ); //Team const winnerteam = ai.teamofplayer(trick.winnerplayer()); Team winnerteam = ::maybe_to_team(vgi.teamofplayer(trick.winnerplayer())); if (winnerteam == TEAM::UNKNOWN) winnerteam = ::opposite(t); if ((game_virt.type() == GAMETYPE::MARRIAGE) && (game_virt.marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET)) { // in an undetermined marriage all players shall play for themselves if (t == TEAM::RE) winnerteam = ::maybe_to_team(ai.teaminfo(trick.winnerplayer())); else if (trick.winnerplayer().no() == vgi.no()) winnerteam = ::maybe_to_team(t); else winnerteam = ::opposite(::maybe_to_team(t)); } Team const team = ((game_virt.type() == GAMETYPE::MARRIAGE) ? maybe_to_team(t) : t); int modi = 0; if (winnerteam == team) modi += trick.points(); else modi -= trick.points(); #ifdef PLAYERCHECK // Playernumber for which to produce output unsigned playerCheck = 3; #if 1 // so in virtual games no informatin is shown if (vgi.game().isvirtual()) playerCheck = 10; #endif playerCheck = 10; if ( (game_virt.real_trick_current_no() == 10) && (game_virt.trick(10).card(0) == Card(Card::HEART, Card::QUEEN)) && (game_virt.trick(10).card(1) == Card(Card::SPADE, Card::QUEEN)) && (game_virt.trick(10).card(2) == Card(Card::DIAMOND, Card::ACE)) && (game_virt.trick(10).card(3) == Card(Card::DIAMOND, Card::ACE)) ) playerCheck = 1; #endif #ifdef PLAYERCHECK if (vgi.no() == playerCheck) { //COUT << trick.game().player(0).hand(); COUT << '\n'; COUT << trick << endl; COUT << team << "\t" << trick.winnerplayer().no() << " " << winnerteam << std::endl; for( unsigned i = 0; i < ai.game().playerno(); i++ ) COUT << game_virt.player( i ).team() << "\t"; COUT << std::endl; // 1. block COUT << card << "\t" << modi << "\t"; } #endif if ( (vgi.game().type() == GAMETYPE::SOLO_MEATLESS) && ai.no() != vgi.game().soloplayer().no() && vgi.no() != trick.winnerplayer().no() && ai.hand().numberof(card.color(), vgi.game()) > 0 && ai.hand().numberof(card.color(), vgi.game()) < 3 && ( ai.hand().numberof(Card(card.color(),Card::ACE)) > 0 || ai.hand().numberof(Card(card.color(),Card::TEN)) > 0 || card.value() == Card::ACE || card.value() == Card::TEN ) ) { // prevent non soloplayer from blank playing of cards modi -= 12; } // high cards in meatless if ( vgi.game().type() == GAMETYPE::SOLO_MEATLESS && ( card.value() == Card::ACE || card.value() == Card::TEN ) ) modi -= card.value() - 3; if ( (vgi.game().type() == GAMETYPE::MARRIAGE) && (vgi.game().marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET) && card.value() >= 10 ) modi -= 9; // have played a very high card if ( card.isswine() || card.ishyperswine() || card.isdolle()) // 2005-08-06: swines in the last three tricks // modi -= 29; // previous values: 23,14,21,24, 29, 33, 35,31 modi -= (33 - std::max((int)ai.game().played_cards_no() - 11, 0)); if ( card.isswine() || card.ishyperswine() ) // so that a dolle is prefered to a swine modi -= 9; //previous values: 2, 7, 3 if ( card.istrump() && ( card.value() == Card::QUEEN ) ) modi -= 2; if ( card.istrump() && ( card.value() == Card::QUEEN || card.isswine() || card.ishyperswine() || card.isdolle()) && trick.points() - card.value() < ai.value(Aiconfig::LIMITQUEEN)) modi-= 4; if ( card.istrump() && trick.startcard().istrump() && !card.less(Card(Card::DIAMOND, Card::QUEEN)) && (trick.points() >= ai.value(Aiconfig::LIMITQUEEN)) ) { modi += 2; } if ( card.istrump() && ( card.value() == Card::QUEEN || card.isswine() || card.ishyperswine() || card.isdolle()) && trick.cardno_of_player(card.player()) == 3 ) modi -= 11; if ( card.istrump() && card.value() == Card::JACK && trick.cardno_of_player(card.player()) == 3 ) modi -= 2; if( card.istrump() && vgi.no() != trick.winnerplayer().no() && ( card.value() == Card::QUEEN || card.isswine() || card.ishyperswine() || card.isdolle()) ) { modi -= (36 - std::max((int)ai.game().played_cards_no() - 13, 0)); modi += trick.points()/2; if( trick.cardno_of_player( trick.winnerplayer() ) < trick.cardno_of_player( card.player() ) ) modi -= 7; } if( ( vgi.game().type()==GAMETYPE::SOLO_KING || vgi.game().type()==GAMETYPE::SOLO_KING_JACK || vgi.game().type()==GAMETYPE::SOLO_KING_QUEEN || vgi.game().type()==GAMETYPE::SOLO_KOEHLER ) && card.value() == Card::KING && vgi.no() != trick.winnerplayer().no() ) { modi -= (36 - std::max((int)ai.game().played_cards_no() - 13, 0)); modi += trick.points()/2; if( trick.cardno_of_player( trick.winnerplayer() ) < trick.cardno_of_player( card.player() ) ) modi -= 4; } if( !card.istrump() && vgi.no() != trick.winnerplayer().no() && GAMETYPE::is_solo( vgi.game().type() ) && ( trick.cardno_of_player( trick.winnerplayer() ) > trick.cardno_of_player( vgi.game().soloplayer() ) ) && !trick.card_of_player( vgi.game().soloplayer() ).less( vgi.trump_card_limit() ) ) modi -= card.value(); if( card.istrump() && ( vgi.no() != trick.winnerplayer().no() || trick.winnercardno() != 3) && trick.cardno_of_player(card.player()) == 3 ) { modi -= 2; if( vgi.game().type()!=GAMETYPE::SOLO_KING && vgi.game().type()!=GAMETYPE::SOLO_QUEEN_JACK && vgi.game().type()!=GAMETYPE::SOLO_KING_JACK && vgi.game().type()!=GAMETYPE::SOLO_KING_QUEEN && vgi.game().type()!=GAMETYPE::SOLO_KOEHLER && (card.value() == Card::JACK || card.value() == Card::QUEEN) ) // a king is better, but has two points more modi -= 3; } if( ( vgi.game().type()==GAMETYPE::SOLO_KING || vgi.game().type()==GAMETYPE::SOLO_KING_JACK || vgi.game().type()==GAMETYPE::SOLO_KING_QUEEN || vgi.game().type()==GAMETYPE::SOLO_KOEHLER ) && card.value() == Card::KING ) modi -= 2; if( card.istrump() && ( vgi.game().type()==GAMETYPE::SOLO_KING || vgi.game().type()==GAMETYPE::SOLO_QUEEN || vgi.game().type()==GAMETYPE::SOLO_JACK ) ) modi -= 4; if (!card.istrump()) { // prefer color cards a little bit if( card.value() == Card::NINE && trick.winnerplayer().team() != vgi.team() ) modi += 2; if( card.value() == Card::KING && trick.winnerplayer().team() != vgi.team() ) modi += 3; } // if (!card.istrump()) #ifdef PLAYERCHECK if (vgi.no() == playerCheck) { // 2. block COUT << modi << "\t"; } #endif // have played a high card if ((ai.value(Aiconfig::LIMITHIGH).less(card) || ai.value(Aiconfig::LIMITHIGH) == card) && trick.points() - card.value() < ai.value(Aiconfig::LIMITQUEEN) ) { modi -= 3; if ((2 * ai.hand().numberof_ge(ai.value(Aiconfig::LIMITHIGH)) < ai.hand().numberoftrumps()) && (ai.hand().numberof_ge(ai.value(Aiconfig::LIMITHIGH)) < 3)) modi -= 13; // previous: 18 } if ( card.istrump() && !trick.startcard().istrump() && card.less(ai.value(Aiconfig::LIMITHIGH)) && (trick.points() >= ai.value(Aiconfig::LIMITQUEEN)) ) { modi -= 3; if ( vgi.color_runs( trick.startcard().color() ) > 0 ) modi -= 6; } if( card.isfox() ) // to play a fox it must be worth it { modi -= 16; // previous 7 } if( card.istrump() && game_virt.next_higher_card( card ).value() != card.value() && (trick.cardno_of_player(trick.winnerplayer()) > trick.cardno_of_player(card.player())) ) { // a higher card in value is needed to jab my card // for example a queen to jab my jack modi += 1; } bool allmyteam=true; for( unsigned i = trick.cardno_of_player( ai ); i < ai.game().playerno(); i++ ) allmyteam=allmyteam && ( ai.team() == ::maybe_to_team( vgi.teamofplayer( trick.player_of_card(i) ) ) ); if ( !card.istrump() && vgi.color_runs( card.color() ) == 0 && card.value() == Card::ACE && ai.team() == winnerteam ) { modi += 2; } if ( !card.istrump() && card.value() == Card::ACE ) { modi -= 2 - vgi.color_runs( card.color() ); } else if( card.istrump() && card.less( ai.value(Aiconfig::LIMITHIGH) ) && !trick.startcard().istrump() && (trick.cardno_of_player(trick.winnerplayer()) > trick.cardno_of_player(card.player())) && !( trick.islastcard() || allmyteam ) ) { modi -= card.value() * std::min(vgi.color_runs( trick.startcard().color() ), 2u); } // force enemy with a jack to play a queen if ( vgi.no() != trick.winnerplayer().no() && (trick.cardno_of_player(trick.winnerplayer()) > trick.cardno_of_player(card.player())) && (card.value() == Card::JACK) && (trick.winnercard().value() == Card::QUEEN) && (ai.team() != winnerteam) && card.istrump() && trick.winnercard().istrump() ) modi += 1; // force enemy to play high card if ( vgi.no() != trick.winnerplayer().no() && (trick.cardno_of_player(trick.winnerplayer()) > trick.cardno_of_player(card.player())) && ai.value(Aiconfig::LIMITHIGH).less(trick.winnercard()) && ai.team() != winnerteam ) { bool bIsForceTrump = true; for (unsigned c = 0; c < trick.actcardno(); c++) { if (trick.card(c).isfox() ) modi += 11; if( card.less( trick.card(c) ) //2do compare in trick order && trick.player_of_card(c).no() != trick.winnerplayer().no() ) bIsForceTrump = false; } if ( bIsForceTrump ) modi += 27; } if ( vgi.game().teaminfo( ai ) != ai.team() && card == Card::CLUB_QUEEN && ai.hand().numberoftrumps() <= 3 + (ai.hand().has_swines()?0:ai.hand().numberoftrumpaces()) ) modi += 13; // create the teams-vector vector teams; for (vector::const_iterator player = game_virt.players_begin(); player != game_virt.players_end(); player++) { // determine team of player from ai out of virtual game Team const t = ai.teamofplayer( **player ); if ( t != TEAM::UNKNOWN) { teams.push_back( maybe_to_team( t ) ); } else { teams.push_back( opposite( maybe_to_team(ai.team()) ) ); } } // for (player) #ifdef PLAYERCHECK if (vgi.no() == playerCheck) { // 3. block COUT << modi << "\t"; } #endif if ( !card.istrump() && vgi.no() != trick.winnerplayer().no() && winnerteam != team && trick.startcard().color() != card.color() && !trick.startcard().istrump() ) { modi -= 16; //previous 6 } if(( card.isswine() || card.ishyperswine() || card.isdolle() ) && maybe_to_team(winnerteam) != team) modi -= 26; if ( (vgi.no() != trick.startplayer().no()) || card.istrump()) { if (maybe_to_team(winnerteam) == team) { Specialpointsvector spv=trick.specialpoints(teams); modi += (30 * Sum_of_Specialpoints(spv, winnerteam, trick.startplayer().game())); if ( card.isfox() && winnerteam == team && ai.value(Aiconfig::LIMITHIGH).less(trick.winnercard()) ) modi += 30; // fox home } else { Specialpointsvector spv=trick.specialpoints(teams); modi -= (30 * Sum_of_Specialpoints(spv, winnerteam, trick.startplayer().game())); } } // if ( (vgi.no() != trick.startplayer().no()) || card.istrump()) // bad style to play fox as first card if( card.isfox() && trick.startplayer().no() == vgi.no() ) { modi -= 90; // previous } if ( (vgi.no() == trick.startplayer().no()) && card.istrump()) { modi -= 1; } if ( ( card.isswine() || card.ishyperswine() || card.isdolle() ) && trick.startplayer().no() == vgi.no() ) { // previous: 12 modi -= 17; } /// @todo jabbed by player of other team behind me if( !trick.startcard().istrump() && vgi.jabbedbyotherteam( trick.startcard().color() ) && card.value() >= 10 && !allmyteam ) modi -= 4; #ifdef PLAYERCHECK if (vgi.no() == playerCheck) { // 4. block COUT << modi << "\t"; } #endif if (( (vgi.no() != trick.startplayer().no()) || card.istrump()) ) { for (unsigned c = 0; c < trick.actcardno(); c++) { // test, whether the fox has been brought home if (trick.card(c).isfox() ) { if(( vgi.game().type() != GAMETYPE::POVERTY || //only for not poverty-player vgi.no() == vgi.game().poverty_partner().no() )) { unsigned fact = 25; if( !ai.value(Aiconfig::FAIRPLAYHANDS) || ai.value(Aiconfig::TRUSTING) ) { fact += 10; if( card.isfox() ) fact += 5; } if( !card.isfox() ) fact += 5; bool allmyteam = true; // take a look if all players coming in this trick are of mine team for( unsigned i = trick.cardno_of_player( ai ); i < vgi.game().playerno(); i++ ) allmyteam = allmyteam && ( ai.team() == ai.teaminfo( trick.player_of_card( i ) ) ); if ( card.isfox() && !trick.startcard().istrump() && ai.color_runs( trick.startcard().color() ) > 0 && !allmyteam ) { fact -= 21; } modi += fact * ((team == winnerteam) ? +1 : -1); } else { // fox from above neutralized. if ( card.isfox() ) modi += 30 * ((team != winnerteam) ? +1 : 0); } } } // for (c < trick.actcardno()) } // if ( (vgi.no() != trick.startplayer().no()) || card.istrump()) if ( trick.cardno_of_player(card.player()) == 0 && (vgi.game().type() == GAMETYPE::MARRIAGE) ) { switch (vgi.game().marriage_selector()) { case MARRIAGE_SELECTOR::SILENT: case MARRIAGE_SELECTOR::TEAM_SET: // the marriage is determined break; case MARRIAGE_SELECTOR::FIRST_COLOR: case MARRIAGE_SELECTOR::FIRST_FOREIGN: if ( !card.istrump() ) { modi -= 5; } break; case MARRIAGE_SELECTOR::FIRST_TRUMP: if ( card.istrump() ) { modi -= 5; } break; case MARRIAGE_SELECTOR::FIRST_CLUB: if ( !card.istrump() && card.color() == Card::CLUB ) { modi -= 5; } break; case MARRIAGE_SELECTOR::FIRST_SPADE: if ( !card.istrump() && card.color() == Card::SPADE ) { modi -= 5; } break; case MARRIAGE_SELECTOR::FIRST_HEART: if ( !card.istrump() && card.color() == Card::HEART ) { modi -= 5; } break; } // switch (this->game().marriage_selector()) } // if !(marriage && !card is trickstartcard()) if ( card.possible_swine() || card.possible_hyperswine() ) modi += 9; #ifdef PLAYERCHECK if (vgi.no() == playerCheck) { // 5. block COUT << modi << endl; } #endif DEBUG_RETURNING(modi, INFO_W_VIRTUAL_GAMES && INFO_VALUE, "WVirtualGames::modi()"); DEBUG_ASSERTION(false, "WVirtualGames::modi():\n" " after 'RETURNING'"); return 0; } // int WVirtualGames::modi(Trick const& trick, Team const& team, Card const& card) /** ** ** -> result ** ** @param vgi virtual game interface ** @param c the card played by the player ** @param game_virt actual virtual game ** ** @return weighting modifier for getting own team in backhand ** ** @version 0.6.3 ** ** @author Borg Enders ** ** **/ int TrickWeighting::backhand(VirtualGamesInterface const& vgi, HandCard const& c, Game const& game_virt ) { int result = 0; // add some points, if the own team is in the back, if (game_virt.trick_current_no() < game_virt.trickno() - 1) { if (game_virt.player_previous( game_virt.trick_current().winnerplayer() ).team() == vgi.team() && !c.isfox() && vgi.game().type() != GAMETYPE::SOLO_MEATLESS ) { result = 5; if (game_virt.type() == GAMETYPE::POVERTY ) result -= 3; } else result = -5; return result; } // if (game_virt.trick_current_no() < game_virt.trickno() - 1) return 0; }