1 /**********************************************************************
2 *
3 * FreeDoko a Doppelkopf-Game
4 *
5 * Copyright (C) 2001 – 2018 by Diether Knof and Borg Enders
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 * You can find this license in the file 'gpl.txt'.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 *
23 * Contact:
24 * Diether Knof dknof@posteo.de
25 *
26 ********************************************************************/
27
28 #include "constants.h"
29
30 #include "ai.h"
31 #include "team_information.h"
32 #include "cards_information.h"
33 #include "heuristic_ai.h"
34 #include "virtual_games_ai.h"
35 #include "solo_decision.h"
36
37 #include "heuristic.h"
38 #include "heuristics.h"
39 #include "weighting.h"
40 #include "aiDb.h"
41 #include "../../party/party.h"
42 #include "../../party/rule.h"
43 #include "../../card/trick.h"
44 #include "../../game/gameplay_actions.h"
45 #ifndef OUTDATED
46 // for 'nextcard()' errors
47 #include "../../misc/bug_report.h"
48 #include "../../os/bug_report.h"
49 #endif
50 #include "../../os/bug_report_replay.h"
51 #ifndef WORKAROUND
52 // for replaying old bug reports
53 #include "../../utils/version.h"
54 #endif
55 #ifdef CHECK_RUNTIME
56 #include "../../runtime.h"
57 #endif
58
59 //#define DEBUG_PLAYER ((::party->game().tricks().current_no() == 8) ? 2 : 22)
60 #define DEBUG_PLAYER 33
61
62 // whether to debug the game decision
63 #ifndef RELEASE
64 #define DEBUG_RESERVATION_PLAYER 9
65 #endif
66 #ifdef DEBUG_RESERVATION_PLAYER
67 #define DEBUG_RESERVATION(solo, value, max) \
68 if (this->no() == DEBUG_RESERVATION_PLAYER) { \
69 COUT << solo << ": " << value << (value == max ? " * " : "") << '\n'; \
70 } else (void)0
71 #else
72 #define DEBUG_RESERVATION(solo, value, max) (void)0
73 #endif
74
75 /** construktor
76 **
77 ** @param istr stream with the infos
78 **
79 ** @todo using constructor Aiconfig(istr)
80 ** @todo update to the new format
81 **/
Ai(istream & istr)82 Ai::Ai(istream& istr) :
83 Player(Player::Type::ai),
84 trick_(::party->rule()(Rule::Type::number_of_tricks_in_game)),
85 colorjabbed_(::party->rule()(Rule::Type::number_of_card_colors),
86 vector<bool>(::party->rule()(Rule::Type::number_of_players_in_game),
87 false)),
88 vgi_(make_unique<VirtualGamesAi>(*this)),
89 hi_(make_unique<HeuristicAi>(*this))
90 {
91 this->db_ = make_unique<AiDb>();
92
93 while (istr.good()) {
94 string line;
95 getline(istr, line);
96 if (istr.fail() || istr.eof())
97 break;
98
99 if (*line.rbegin() == '\r')
100 line.erase(line.end() - 1);
101
102 if ((line == "")
103 || (line[0] == '#')) {
104 continue;
105 }
106 if ( (line == "Aiconfig")
107 || (line == "aiconfig") ) {
108 // this is the last entry
109 this->Aiconfig::read(istr);
110 break;
111 } else if (line == "Database") {
112 this->db_->read(istr);
113 } else {
114 cerr << "Reading the ai:\n"
115 << "found following unknown line:\n"
116 << line << '\n'
117 << "ignoring it."
118 << endl;
119 #ifndef RELEASE
120 exit(EXIT_FAILURE);
121 #endif
122 }
123 }; // while (istr.good())
124 }
125
126 /** standard constructor
127 **
128 ** @result -
129 **/
Ai()130 Ai::Ai() :
131 Player(Player::Type::ai),
132 trick_(::party->rule()(Rule::Type::number_of_tricks_in_game)),
133 colorjabbed_(::party->rule()(Rule::Type::number_of_card_colors),
134 vector<bool>(::party->rule()(Rule::Type::number_of_players_in_game),
135 false)),
136 vgi_(make_unique<VirtualGamesAi>(*this)),
137 hi_(make_unique<HeuristicAi>(*this))
138 {
139 this->db_ = make_unique<AiDb>();
140 for (auto const game_type : ::game_type_solo_list) {
141 this->solo_decisions_.emplace_back(SoloDecision::create(game_type, *this));
142 }
143 }
144
145 /** constructor
146 **
147 ** @param aiconfig ai configuration
148 **
149 ** @result -
150 **/
Ai(Aiconfig const & aiconfig)151 Ai::Ai(Aiconfig const& aiconfig) :
152 Player(Player::Type::ai),
153 Aiconfig(aiconfig),
154 trick_(::party->rule()(Rule::Type::number_of_tricks_in_game)),
155 colorjabbed_(::party->rule()(Rule::Type::number_of_card_colors),
156 vector<bool>(::party->rule()(Rule::Type::number_of_players_in_game),
157 false)),
158 vgi_(make_unique<VirtualGamesAi>(*this)),
159 hi_(make_unique<HeuristicAi>(*this))
160 {
161 this->db_ = make_unique<AiDb>();
162 for (auto const game_type : ::game_type_solo_list) {
163 this->solo_decisions_.emplace_back(SoloDecision::create(game_type, *this));
164 }
165 }
166
167 /** copy constructor
168 **
169 ** @param player player to copy
170 **/
Ai(Player const & player)171 Ai::Ai(Player const& player) :
172 Player(player),
173 trick_(::party->rule()(Rule::Type::number_of_tricks_in_game)),
174 colorjabbed_(::party->rule()(Rule::Type::number_of_card_colors),
175 vector<bool>(::party->rule()(Rule::Type::number_of_players_in_game),
176 false)
177 ) ,
178 vgi_(make_unique<VirtualGamesAi>(*this)),
179 hi_(make_unique<HeuristicAi>(*this))
180 {
181 this->set_type(Player::Type::ai);
182 this->db_ = make_unique<AiDb>(player.db());
183 for (auto const game_type : ::game_type_solo_list) {
184 this->solo_decisions_.emplace_back(SoloDecision::create(game_type, *this));
185 }
186 }
187
188 /** copy constructor
189 **
190 ** @param player player to copy
191 ** @param aiconfig configuration to copy
192 **/
Ai(Player const & player,Aiconfig const & aiconfig)193 Ai::Ai(Player const& player, Aiconfig const& aiconfig) :
194 Player(player),
195 Aiconfig(aiconfig),
196 trick_(::party->rule()(Rule::Type::number_of_tricks_in_game)),
197 colorjabbed_(::party->rule()(Rule::Type::number_of_card_colors),
198 vector<bool>(::party->rule()(Rule::Type::number_of_players_in_game),
199 false)
200 ) ,
201 vgi_(make_unique<VirtualGamesAi>(*this)),
202 hi_(make_unique<HeuristicAi>(*this))
203 {
204 this->set_type(Player::Type::ai);
205
206 if (::game_status & GameStatus::game)
207 DEBUG_ASSERTION(false,
208 "Ai::Ai(player):\n"
209 " in game");
210
211 this->db_ = make_unique<AiDb>(player.db());
212 for (auto const game_type : ::game_type_solo_list) {
213 this->solo_decisions_.emplace_back(SoloDecision::create(game_type, *this));
214 }
215 }
216
217 /** copy constructor
218 **/
Ai(Ai const & ai)219 Ai::Ai(Ai const& ai) :
220 Player(ai),
221 Aiconfig(ai),
222 team_information_(ai.team_information_
223 ? new TeamInformation(ai.team_information())
224 : nullptr),
225 cards_information_(ai.cards_information_
226 ? new CardsInformation(ai.cards_information())
227 : nullptr),
228 teaminfo_(ai.teaminfo_),
229 trick_(ai.trick_),
230 trickno_(ai.trickno_),
231 colorjabbed_(ai.colorjabbed_),
232 low_(ai.low_),
233 meatlesscolor_(ai.meatlesscolor_),
234 trumpless_( ai.trumpless_ ),
235 last_trick_to_calculate_(ai.last_trick_to_calculate_),
236 last_heuristic_(ai.last_heuristic_),
237 last_heuristic_rationale_(ai.last_heuristic_rationale_),
238 vgi_(make_unique<VirtualGamesAi>(*this)),
239 hi_(make_unique<HeuristicAi>(*this)),
240 silent_marriage_(ai.silent_marriage_)
241 {
242 if (::game_status & GameStatus::game)
243 DEBUG_ASSERTION(!this->trumpless_.empty(),
244 "Ai::Ai(ai):\n"
245 " 'trumpless_.size() == 0");
246
247 this->set_type(Player::Type::ai);
248 if (this->team_information_)
249 this->team_information_->set_player(*this);
250 if (this->cards_information_)
251 this->cards_information_->set_player(*this);
252
253 if (ai.db())
254 this->db_ = make_unique<AiDb>(*ai.db());
255 else
256 this->db_ = make_unique<AiDb>();
257 for (auto const game_type : ::game_type_solo_list) {
258 this->solo_decisions_.emplace_back(SoloDecision::create(game_type, *this));
259 }
260
261 if (::game_status & GameStatus::game) {
262 for (unsigned i = 0; i < this->colorjabbed_.size(); ++i) {
263 DEBUG_ASSERTION((ai.colorjabbed_[i].size() == this->game().playerno()),
264 "Ai::Ai(ai)\n"
265 "ai");
266 DEBUG_ASSERTION((this->colorjabbed_[i].size() == this->game().playerno()),
267 "Ai::Ai(ai)\n"
268 "this");
269 }
270 } // if (::game_status & GameStatus::game)
271 }
272
273 /** destructor
274 **/
275 Ai::~Ai() = default;
276
277 /** clone the player
278 **
279 ** @return pointer of a clone
280 **/
281 unique_ptr<Player>
clone() const282 Ai::clone() const
283 {
284 return make_unique<Ai>(*this);
285 }
286
287 /** cast to 'VirtualGamesInterface'
288 **/
operator VirtualGamesInterface const&() const289 Ai::operator VirtualGamesInterface const&() const
290 { return *this->vgi_; }
291
292 /** cast to 'HeuristicInterface'
293 **/
operator HeuristicInterface const&() const294 Ai::operator HeuristicInterface const&() const
295 { return *this->hi_; }
296
297 /** @return the team information
298 **/
299 TeamInformation const&
team_information() const300 Ai::team_information() const
301 { return *this->team_information_; }
302
303 /** @return the team information
304 **/
305 TeamInformation&
team_information()306 Ai::team_information()
307 { return *this->team_information_; }
308
309 /** @return the cards information
310 **/
311 CardsInformation const&
cards_information() const312 Ai::cards_information() const
313 { return *this->cards_information_; }
314
315 /** @return the cards information
316 **/
317 CardsInformation&
cards_information()318 Ai::cards_information()
319 { return *this->cards_information_; }
320
321 /** @return the database
322 **/
323 AiDb const*
db() const324 Ai::db() const
325 { return dynamic_cast<AiDb const*>(this->db_.get()); }
326
327 /** @return the database
328 **/
329 AiDb*
db()330 Ai::db()
331 { return dynamic_cast<AiDb*>(db_.get()); }
332
333 /** writes the ai into the stream
334 **
335 ** @param ostr stream the ai is to be written in
336 **
337 ** @return the output stream
338 **/
339 ostream&
write(ostream & ostr) const340 Ai::write(ostream& ostr) const
341 {
342 // output of the name, type and database
343 this->Player::write(ostr);
344
345 // output of the configuration
346 ostr << '\n'
347 << "Aiconfig\n"
348 << "{\n";
349 this->Aiconfig::write(ostr);
350 ostr << "}\n";
351
352 return ostr;
353 }
354
355 /** read the config of the player
356 **
357 ** @param config configuration to read
358 ** @param istr input stream
359 **
360 ** @return whether the configuration was valid
361 **/
362 bool
read(Config const & config,istream & istr)363 Ai::read(Config const& config, istream& istr)
364 {
365 if ( !config.separator
366 && ( (config.name == "Aiconfig")
367 || (config.name == "aiconfig") ) ) {
368 return this->Aiconfig::read(istr);
369 }
370
371 return this->Player::read(config, istr);
372 }
373
374 /** compares the '*this' with 'ai'
375 **
376 ** @param ai ai to compare with
377 **
378 ** @return whether 'ai' is equal to '*this'
379 **
380 ** @todo test 'cards_information', 'team_information'
381 **/
382 bool
isequal(Ai const & ai) const383 Ai::isequal(Ai const& ai) const
384 {
385 // ToDo: test team_information
386 // ToDo: test cards_information
387
388 if (this->colorjabbed_.size() != ai.colorjabbed_.size())
389 return false;
390
391 for (unsigned i = 0; i < this->colorjabbed_.size(); i++) {
392 if (this->colorjabbed_[i].size() != ai.colorjabbed_[i].size())
393 return false;
394
395 for (unsigned j = 0; j < this->colorjabbed_[i].size(); j++)
396 if (this->colorjabbed_[i][j] != ai.colorjabbed_[i][j])
397 return false;
398 } // for (i < this->colorjabbed_.size())
399
400 if (this->trumpless_.size() != ai.trumpless_.size())
401 return false;
402
403 for (unsigned i = 0; i < this->trumpless_.size(); i++)
404 if (this->trumpless_[i] != ai.trumpless_[i])
405 return false;
406
407 if (this->trickno_ != ai.trickno_)
408 return false;
409
410 if (this->low_ != ai.low_)
411 return false;
412
413 if (this->meatlesscolor_ != ai.meatlesscolor_)
414 return false;
415
416 if (this->last_trick_to_calculate_ != ai.last_trick_to_calculate_)
417 return false;
418
419 if (this->last_heuristic_ != ai.last_heuristic_)
420 return false;
421
422 if (this->last_heuristic_rationale_ != ai.last_heuristic_rationale_)
423 return false;
424
425 #if 0
426 vector<Trick> trick_; // last played tricks
427 #endif
428
429 return true;
430 }
431
432 /** @return the aitype for the current trick
433 **/
434 AiType
aitype() const435 Ai::aitype() const
436 {
437 #ifdef RELEASE
438 // Workaround
439 if( !( (::game_status >= GameStatus::game_play)
440 && (::game_status < GameStatus::game_finished) ))
441 return this->Aiconfig::aitype(0);
442 #else
443 DEBUG_ASSERTION( (::game_status >= GameStatus::game_play)
444 && (::game_status < GameStatus::game_finished),
445 "Ai::aitype():\n"
446 " game status not in game: " << ::game_status);
447 #endif
448
449 return this->Aiconfig::aitype(this->game().tricks().current().no());
450 }
451
452 /** @return the rating type for the current trick
453 **/
454 Rating::Type
rating() const455 Ai::rating() const
456 {
457 #ifdef RELEASE
458 // Workaround
459 if( !( (::game_status >= GameStatus::game_play)
460 && (::game_status < GameStatus::game_finished) ))
461 return this->Aiconfig::rating(0);
462 #else
463 DEBUG_ASSERTION( (::game_status >= GameStatus::game_play)
464 && (::game_status < GameStatus::game_finished),
465 "Ai::rating():\n"
466 " game status not in game: " << ::game_status);
467 #endif
468
469 return this->Aiconfig::rating(this->game().tricks().current().no());
470 }
471
472 /** sets the cards information
473 **
474 ** @param cards_information new cards information
475 **/
476 void
set_cards_information(CardsInformation const & cards_information)477 Ai::set_cards_information(CardsInformation const& cards_information)
478 {
479 if (this->cards_information_.get() == &cards_information)
480 return ;
481
482 this->cards_information_ = make_unique<CardsInformation>(cards_information);
483 this->cards_information_->set_player(*this);
484 }
485
486 /** @return the future limit for the current trick
487 **/
488 unsigned
future_limit() const489 Ai::future_limit() const
490 {
491 DEBUG_ASSERTION( (::game_status >= GameStatus::game_play)
492 && (::game_status < GameStatus::game_finished),
493 "Ai::future_limit():\n"
494 " game status not in game: " << ::game_status);
495
496 return this->Aiconfig::future_limit(this->game().tricks().current().no());
497 }
498
499 /** sets the game of the ai
500 **
501 ** @param game the new game for the ai
502 **/
503 void
set_game(Game & game)504 Ai::set_game(Game& game)
505 {
506 //bool const old_isvirtual = this->game().isvirtual();
507 this->Player::set_game(game);
508 }
509
510 /** sets the hand of the ai
511 **
512 ** @param hand new hand
513 **
514 ** @return the hand
515 **/
516 Hand const&
set_hand(const Hand & hand)517 Ai::set_hand(const Hand& hand)
518 {
519 this->Player::set_hand(hand);
520 if (::game_status <= GameStatus::game_init)
521 return this->hand();
522 this->cards_information().set_hand(*this, hand);
523 this->team_information().update_teams();
524
525 // how to start in the heuristic 'play low high'
526 this->low_ = (this->hand().count(Card::jack) >= this->hand().count(Card::queen) +2);
527
528 return this->hand();
529 }
530
531 /** the rule has changed
532 **
533 ** @param type rule type to have changed
534 ** @param old_value old value of the rule
535 **/
536 void
rule_changed(int const type,void const * const old_value)537 Ai::rule_changed(int const type, void const* const old_value)
538 {
539 this->Aiconfig::rule_changed(type, old_value);
540 }
541
542 /** the game 'game' is opened
543 **
544 ** @param game opened game
545 **/
546 void
game_open(Game & game)547 Ai::game_open(Game& game)
548 {
549 this->Player::game_open(game);
550 this->team_information().reset();
551 this->cards_information().reset();
552 }
553
554 /** the game is started
555 **/
556 void
game_start()557 Ai::game_start()
558 {
559 if (::game_status == GameStatus::game_redistribute)
560 return ;
561
562 this->Player::game_start();
563
564 { // in a poverty the hand can have changed
565 this->cards_information().reset();
566 this->cards_information().set_hand(*this, this->hand());
567 }
568
569 this->team_information().game_start();
570 this->cards_information().game_start();
571 this->team_information().update_teams();
572 }
573
574 /** the game is closed
575 **
576 ** @param game game that is closed
577 **/
578 void
game_close(Game const & game)579 Ai::game_close(Game const& game)
580 {
581 this->Player::game_close(game);
582
583 this->team_information_ = {};
584 this->cards_information_ = {};
585 }
586
587 /** -> result
588 ** - if 'Aiconfig::hands_known' the real hand of the player is returned
589 ** (independent on 'Rule::Type::show_all_hands')
590 ** - if not 'Aiconfig::hands_known' the hand is calculated,
591 ** see 'CardsInformation'
592 **
593 ** @param player player whose hand is returned
594 **
595 ** @result hand of 'player'
596 **/
597 Hand const&
handofplayer(Player const & player) const598 Ai::handofplayer(Player const& player) const
599 {
600 if ( !this->game().isvirtual()
601 && (player == *this))
602 return this->hand();
603
604 if (this->Aiconfig::value(Aiconfig::Type::hands_known))
605 return player.hand();
606
607 // If it is the last trick and the player has already played a card,
608 // his hand is empty.
609 if ( (::game_status == GameStatus::game_play)
610 && (this->game().tricks().real_remaining_no() == 1)
611 && (this->game().tricks().current().cardno_of_player(player)
612 < this->game().tricks().current().actcardno()))
613 return player.hand();
614
615 #ifndef RELEASE
616 Hand const& hand = this->cards_information().estimated_hand(player);
617 hand.self_check();
618 return hand;
619 #else
620 return this->cards_information().estimated_hand(player);
621 #endif
622 }
623
624 /** the known team of the player
625 **/
626 Team
teamofplayer(Player const & player) const627 Ai::teamofplayer(Player const& player) const
628 {
629 // In the marriage case, as long as the teams are not determined,
630 // the player shall think that every other player is against him.
631 if (this->game().type() == GameType::marriage)
632 return this->teaminfo(player);
633
634 if (this->Aiconfig::value(Aiconfig::Type::teams_known))
635 return player.team();
636
637 return this->teaminfo( player );
638 }
639
640 /** set the teams
641 **
642 ** @param teams teams of the players
643 **/
644 void
set_teams(vector<Team> const & teams)645 Ai::set_teams(vector<Team> const& teams)
646 {
647 this->team_information().set_teams(teams);
648 this->set_team(teams[this->no()]);
649 }
650
651 /** the trick is opened
652 **
653 ** @param trick opened trick
654 **/
655 void
trick_open(Trick const & trick)656 Ai::trick_open(Trick const& trick)
657 {
658 this->cards_information().trick_open(trick);
659 this->team_information().update_teams();
660 }
661
662 /** the trick is full
663 **
664 ** @param trick full trick
665 **/
666 void
trick_full(Trick const & trick)667 Ai::trick_full(Trick const& trick)
668 {
669 DEBUG_ASSERT( trick.isfull() );
670
671 this->team_information().trick_full(trick);
672 this->cards_information().trick_full(trick);
673 this->team_information().update_teams();
674
675 if( trick.startcard().istrump() ) {
676 for ( unsigned i = 0; i < trick.actcardno(); i++) {
677 if (!trick.card(i).istrump()) {
678 DEBUG_ASSERTION((this->trumpless_.size()
679 > trick.player_of_card(i).no()),
680 "Ai::trick_full(trick):\n"
681 " 'this->trumpless_' is too small: "
682 << this->trumpless_.size() << " <= "
683 << trick.player_of_card(i).no());
684 this->trumpless_[ trick.player_of_card(i).no() ] = true;
685 }
686 }
687 }
688 }
689
690 /** @return card played by the ai
691 **/
692 HandCard
card_get()693 Ai::card_get()
694 {
695 auto const& current_trick = this->game().tricks().current();
696 auto const card = this->nextcard(current_trick);
697 HandCard const handcard(this->hand(), card);
698
699 auto& swines = this->game().swines();
700 if ( handcard.possible_swine()
701 && swines.swines_announcement_valid(*this))
702 swines.swines_announce(*this);
703 if ( handcard.possible_hyperswine()
704 && swines.hyperswines_announcement_valid(*this))
705 swines.hyperswines_announce(*this);
706 { // ToDo: check for last chance to announce
707 auto announcement = this->announcement_request();
708 while (!!announcement) {
709 this->game().announcements().make_announcement(announcement, *this);
710 if (this->announcement() != announcement)
711 break;
712 announcement = this->announcement_request();
713 }
714 }
715 this->check_and_make_first_announcement(handcard);
716
717 return handcard;
718 }
719
720 /** @return suggested card
721 **/
722 HandCard
card_suggestion()723 Ai::card_suggestion()
724 {
725 if (::bug_report_replay) {
726 static bool bug_report_flip = false;
727 if (this->last_heuristic_ != Aiconfig::Heuristic::bug_report)
728 bug_report_flip = true;
729 else
730 bug_report_flip ^= true;
731 if (bug_report_flip) {
732 this->set_last_heuristic_to_bug_report();
733 auto const card = ::bug_report_replay->next_card(*this);
734 if ( !card.is_empty()
735 && this->hand().contains(card)) {
736 return HandCard(this->hand(), card);
737 }
738 }
739 }
740 auto const& current_trick = this->game().tricks().current();
741 auto const card = this->nextcard(current_trick);
742 #ifndef RELEASE
743 #ifdef DKNOF
744 cout << "card suggestion: " << card << '\n'
745 << this->last_heuristic() << '\n'
746 << this->last_heuristic_rationale() << '\n';
747 #endif
748 #endif
749 return HandCard(this->hand(), card);
750 }
751
752 /** 'player' has played the card 'card'
753 **
754 ** @param card played card
755 **/
756 void
card_played(HandCard const & card)757 Ai::card_played(HandCard const& card)
758 {
759 this->cards_information().card_played(card);
760 this->team_information().card_played(card);
761 this->team_information().update_teams();
762
763 if( this->no() == DEBUG_PLAYER ) {
764 COUT << "card played " << card << endl;
765 COUT << "virtual = " << this->game().isvirtual() << endl;
766 }
767
768 Player const& player = card.player();
769 Card::Color jabbed = Card::nocardcolor;
770
771
772 Trick t = player.game().tricks().current();
773
774 if (!t.startcard().istrump())
775 {
776 jabbed = t.startcard().color();
777 }
778
779
780 if (jabbed!=Card::nocardcolor && card.istrump())
781 {
782 colorjabbed_[jabbed][player.no()] = true;
783 }
784 if( jabbed != Card::nocardcolor
785 && card.color() != jabbed
786 && (this->cards_information().remaining_trumps_others()
787 >= game().tricks().remaining_no() ) )
788 {
789 colorjabbed_[jabbed][player.no()] = true;
790 }
791
792
793 if (player == *this) {
794 switch (this->last_heuristic_) {
795 case Aiconfig::Heuristic::low_high:
796 case Aiconfig::Heuristic::color_low_high:
797 if (! ( this->low_
798 && (this->game().tricks().current().winnerplayer() == *this)) )
799 this->check_low_high(card);
800 break;
801
802 default:
803 break;
804 }
805 if( this->hand().count(Card::jack) >= this->hand().count(Card::queen) +2 )
806 this->low_ = true;
807 } // if (player == *this)
808
809 this->teaminfo_update();
810 }
811
812 /** check a swines announcement at the game start
813 **/
814 void
check_swines_announcement_at_game_start()815 Ai::check_swines_announcement_at_game_start()
816 {
817 if (this->type() == Player::Type::ai) {
818 // announce swines
819 if (this->game().rule()(Rule::Type::swines_announcement_begin))
820 if (this->game().swines().swines_announcement_valid(*this))
821 this->game().swines().swines_announce(*this);
822
823 // hyperswines are announced by 'Ai::swines_announced(player)'
824 } // if (this->type() == Player::Type::ai)
825 }
826
827 /** 'player' has announce swines
828 ** if possible announce hyperswines
829 **
830 ** @param player player that has announced the swines
831 **/
832 void
swines_announced(Player const & player)833 Ai::swines_announced(Player const& player)
834 {
835 this->cards_information().swines_announced(player);
836 this->team_information().update_teams();
837
838 if (this->type() == Player::Type::ai) {
839 if ( this->game().swines().hyperswines_announcement_valid(*this)
840 && this->game().rule()(Rule::Type::hyperswines_announcement_begin))
841 this->game().swines().hyperswines_announce(*this);
842 } // if (this->type() == Player::Type::ai)
843 }
844
845 /** 'player' has announce hyperswines
846 **
847 ** @param player player that has announced the hyperswines
848 **/
849 void
hyperswines_announced(Player const & player)850 Ai::hyperswines_announced(Player const& player)
851 {
852 this->cards_information().hyperswines_announced(player);
853 this->team_information().update_teams();
854 }
855
856 /** the marriage partner has found a bride
857 ** if the bride is the bridegroom, the bridegroom must play a solo
858 **
859 ** @param bridegroom the player with the marriage
860 ** @param bride the bride
861 **/
862 void
marriage(Player const & bridegroom,Player const & bride)863 Ai::marriage(Player const& bridegroom, Player const& bride)
864 {
865 this->team_information().marriage(bridegroom, bride);
866 this->teaminfo_update();
867 }
868
869 /** a player has a genscher and selected a new partner
870 **
871 ** @param genscher genscher player
872 ** @param partner partner of the gensher player
873 **/
874 void
genscher(Player const & genscher,Player const & partner)875 Ai::genscher(Player const& genscher, Player const& partner)
876 {
877 this->team_information().genscher(genscher, partner);
878 this->cards_information().genscher(genscher, partner);
879 this->team_information().update_teams();
880 }
881
882 /** selects a card to play
883 **
884 ** @param trick current trick
885 **
886 ** @return card to play
887 **/
888 Card
nextcard(Trick const & trick)889 Ai::nextcard(Trick const& trick)
890 {
891 if (!this->game().isvirtual())
892 db()->increase( Aiconfig::Heuristic::no_heuristic );
893
894 #ifdef CHECK_RUNTIME
895 auto const ssp = ( !this->game().isvirtual()
896 ? ::runtime["ai heuristics"].start_stop_proxy()
897 : nullptr);
898 #endif
899
900 // special case: unset marriage and last chance
901 if ( (this->game().type() == GameType::marriage)
902 && (this->game().players().soloplayer() == *this)
903 && (this->game().marriage().selector() != MarriageSelector::silent)
904 && (this->game().marriage().selector() != MarriageSelector::team_set)
905 && (this->game().tricks().current().isempty())
906 && (this->game().tricks().current_no() + 1 == this->game().rule()(Rule::Type::marriage_determination)) ) {
907 Card const card = Heuristics::play_to_get_married(trick, *this);
908 if (card) {
909 this->last_heuristic_ = Aiconfig::Heuristic::play_to_get_married;
910 this->last_heuristic_rationale_.clear();
911 this->db()->increase(Aiconfig::Heuristic::play_to_get_married);
912 return card;
913 }
914 }
915
916 auto
917 heuristics_vector = ( this->silent_marriage_
918 ? (this->heuristic_states(HeuristicsMap::GameTypeGroup::marriage_silent,
919 HeuristicsMap::PlayerTypeGroup::re))
920 : this->heuristic_states(HeuristicsMap::Key(*this)));
921 heuristics_vector.insert(heuristics_vector.begin(),
922 {Heuristic::only_one_valid_card, true});
923 heuristics_vector.insert(heuristics_vector.begin(),
924 {Heuristic::bug_report, true});
925 for (auto const& heuristic_state : heuristics_vector) {
926 if (!heuristic_state.active)
927 continue;
928 auto const heuristic = heuristic_state.heuristic;
929 if (heuristic == Aiconfig::Heuristic::error) {
930 continue;
931 }
932
933 auto heuristic_logic = ::Heuristic::create(heuristic, *this);
934 DEBUG_ASSERTION(heuristic_logic->heuristic() == heuristic,
935 "Heuristic " << heuristic << " is of the wrong type");
936 heuristic_logic->set_player(*this);
937 auto const card = heuristic_logic->get_card(trick);
938 if ( !this->game().isvirtual()
939 && ( ::debug("heuristics")
940 || ::debug(to_string(heuristic)))) {
941 cout << this->no() << ' ' << this->name() << ": " << card << " (" << heuristic << ")\n";
942 cout << heuristic_logic->rationale();
943 }
944
945 if (!card)
946 continue;
947 if ( HEURISTIC_OUTPUT
948 && !this->game().isvirtual()) {
949 cout << setw(2) << this->no() << " "
950 << setw(20) << card << " "
951 << heuristic
952 << endl;
953 }
954
955 if ( (heuristic == Aiconfig::Heuristic::try_for_doppelkopf)
956 && (this->announcement() == Announcement::noannouncement)
957 && !trick.islastcard()
958 && (this->teaminfo(trick.player_of_card(this->game().playerno()))
959 != ::opposite(this->team()))) {
960 // make an announcement so that the player behind can give points
961 this->game().announcements().make_announcement(Announcement::no120, *this);
962 }
963
964 this->last_heuristic_ = heuristic;
965 this->last_heuristic_rationale_ = heuristic_logic->rationale();
966 this->db()->increase(heuristic);
967
968 return card;
969 } // for (heuristic_state : heuristics_vector)
970
971 { // choosebestcard
972
973 auto const heuristic = Aiconfig::Heuristic::choose_best_card;
974 auto const card = Weighting::best_card(this->aitype(), *this);
975
976 if (HEURISTIC_OUTPUT
977 && !this->game().isvirtual())
978 cout << setw(2) << this->no() << " "
979 << setw(16) << card << " "
980 << setw(39) << heuristic << " (" << this->aitype() << ") "
981 << endl;
982
983 this->last_heuristic_ = heuristic;
984 this->last_heuristic_rationale_.clear();
985 // only increment, if the ai could select a heuristic
986 if (static_cast<int>(this->game().tricks().remaining_no()) >
987 this->Aiconfig::value(Aiconfig::Type::last_tricks_without_heuristics ) ) {
988 this->db()->increase(heuristic);
989 }
990
991 if (::game_status != GameStatus::game_play)
992 return Card();
993
994 if (this->aitype() != AiType::no_choosebestcard)
995 DEBUG_ASSERT(!card.is_empty());
996
997 return card;
998 } // choosebestcard
999 }
1000
1001 /** @return the last heuristic
1002 **/
1003 Aiconfig::Heuristic
last_heuristic() const1004 Ai::last_heuristic() const
1005 {
1006 return this->last_heuristic_;
1007 }
1008
1009 /** @return the rationale of the last heuristic
1010 **/
1011 Rationale const&
last_heuristic_rationale() const1012 Ai::last_heuristic_rationale() const
1013 {
1014 return this->last_heuristic_rationale_;
1015 }
1016
1017 /** set the last heuristic to manual
1018 **/
1019 void
set_last_heuristic_to_manual()1020 Ai::set_last_heuristic_to_manual()
1021 {
1022 this->last_heuristic_ = Aiconfig::Heuristic::manual;
1023 this->last_heuristic_rationale_.clear();
1024 }
1025
1026 /** set the last heuristic to bug report
1027 **/
1028 void
set_last_heuristic_to_bug_report()1029 Ai::set_last_heuristic_to_bug_report()
1030 {
1031 this->last_heuristic_ = Aiconfig::Heuristic::bug_report;
1032 this->last_heuristic_rationale_.clear();
1033 }
1034
1035 /** @return whether a player has jabbed the color
1036 **/
1037 bool
colorjabbed(Card::Color const color) const1038 Ai::colorjabbed(Card::Color const color) const
1039 {
1040 if (color == Card::nocardcolor)
1041 return false;
1042
1043 for (unsigned i = 0; i < game().playerno(); ++i) {
1044 if (colorjabbed_[color][i])
1045 return true;
1046 }
1047
1048 return false;
1049 }
1050
1051 /** @return whether the color has been jabbed by the own team
1052 **/
1053 bool
jabbedbyownteam(Card::Color const color) const1054 Ai::jabbedbyownteam(Card::Color const color) const
1055 {
1056 if (color == Card::nocardcolor)
1057 return false;
1058
1059 auto const team = this->team();
1060 auto const& game = this->game();
1061 for (unsigned i = 0; i < game.playerno(); ++i) {
1062 if ( (i != this->no())
1063 && maybe_to_team(this->teaminfo(game.player(i))) == team) {
1064 if (colorjabbed_[color][i])
1065 return true;
1066 }
1067 }
1068
1069 return false;
1070 }
1071
1072 /** @return whether the color was jabbed by the other team
1073 **/
1074 bool
jabbedbyotherteam(Card::Color const color) const1075 Ai::jabbedbyotherteam(Card::Color const color) const
1076 {
1077 if (color == Card::nocardcolor)
1078 return false;
1079
1080 auto const team = this->team();
1081 auto const& game = this->game();
1082 for (unsigned i = 0; i < game.playerno(); ++i) {
1083 if ( (i != this->no())
1084 && (maybe_to_team(teaminfo(game.player(i))) != team)) {
1085 if (colorjabbed_[color][i])
1086 return true;
1087 }
1088 }
1089
1090 return false;
1091 }
1092
1093 /** -> result
1094 **
1095 ** @param color color
1096 **
1097 ** @return how many times the color has run
1098 **/
1099 unsigned
color_runs(Card::Color const color) const1100 Ai::color_runs(Card::Color const color) const
1101 {
1102 return this->cards_information().color_runs(color);
1103 }
1104
1105 /** -> result
1106 **
1107 ** @param trick current trick
1108 **
1109 ** @return how many times the color of the trick has run
1110 **/
1111 unsigned
color_runs(Trick const & trick) const1112 Ai::color_runs(Trick const& trick) const
1113 {
1114 DEBUG_ASSERTION(!trick.isempty(),
1115 "Ai::color_runs(trick)\n"
1116 " trick is empty");
1117 return this->cards_information().color_runs(trick.startcard().tcolor());
1118 }
1119
1120 /** @return whether the next card should be a low trump
1121 **/
1122 bool
next_low() const1123 Ai::next_low() const
1124 {
1125 return this->low_;
1126 }
1127
1128 /** sets low_ to true if c>=diamond queen to false if card < diamond queen
1129 **/
1130 void
check_low_high(HandCard const & card)1131 Ai::check_low_high(HandCard const& card)
1132 {
1133 if ( card.istrump()
1134 && !(card.less(Card::diamond_queen)))
1135 this->low_ = true;
1136 else
1137 this->low_ = false;
1138 }
1139
1140 /** initialize the ai for a new game
1141 **/
1142 void
new_game(Game & game)1143 Ai::new_game(Game& game)
1144 {
1145 this->Player::new_game(game);
1146
1147 this->team_information_ = make_unique<TeamInformation>(*this);
1148 this->cards_information_ = make_unique<CardsInformation>(*this);
1149
1150 this->teaminfo_ = vector<Team>(this->game().playerno(), Team::unknown);
1151
1152 this->meatlesscolor_ = Card::nocardcolor;
1153
1154 this->low_ = true;
1155
1156 this->trick_ = vector<Trick>(this->game().rule()(Rule::Type::number_of_tricks_in_game));
1157
1158 this->trumpless_ = vector<bool>(this->game().playerno(), false );
1159 this->trickno_ = 0;
1160 for ( unsigned x = 0;
1161 x < this->game().rule()(Rule::Type::number_of_card_colors); x++)
1162 {
1163 this->colorjabbed_[x] = vector<bool>(this->game().playerno(), false );
1164 for(unsigned y = 0; y < this->game().playerno(); y++) {
1165 this->colorjabbed_[x][y] = false;
1166 } // for (y < this->game().playerno())
1167 } // for (x < this->game().playerno())
1168
1169 this->silent_marriage_ = false;
1170 }
1171
1172 /** @return tricktype which determines teams for a marraige
1173 **/
1174 MarriageSelector
get_Marriage() const1175 Ai::get_Marriage() const
1176 {
1177 bool const isstartplayer = (this->game().startplayer() == *this);
1178 // ToDo: Test rules
1179 if (this->game().rule()(Rule::Type::marriage_first_foreign))
1180 return MarriageSelector::first_foreign;
1181
1182 if (hand().count_trumps()<6
1183 && hand().count_trump_aces()==1
1184 && ( isstartplayer
1185 || this->game().rule()(Rule::Type::marriage_determination) >= 4)) {
1186 return MarriageSelector::first_trump;
1187 }
1188
1189 if (Card::heart_ten.istrump(this->game())) {
1190 if ( hand().count(Card::heart) > 3
1191 && hand().count(Card::heart_ace) > 0) {
1192 return MarriageSelector::first_heart;
1193 }
1194 } else {
1195 if ( hand().count(Card::heart) > 4
1196 || ( hand().count(Card::heart) < 2
1197 && ( ( hand().count(Card::heart_ten) == 1
1198 && isstartplayer)
1199 )
1200 )
1201 ) {
1202 return MarriageSelector::first_heart;
1203 }
1204 }
1205 if ( hand().count(Card::club) > 4
1206 || ( hand().count(Card::club) < 2
1207 && ( ( hand().count(Card::club_ten) == 1
1208 && isstartplayer)
1209 )
1210 )
1211 ) {
1212 return MarriageSelector::first_club;
1213 }
1214 if ( hand().count(Card::spade) > 4
1215 || ( hand().count(Card::spade) < 2
1216 && ( hand().count(Card::spade_ten) == 1
1217 && isstartplayer)
1218 )
1219 ) {
1220 return MarriageSelector::first_spade;
1221 }
1222 if ( hand().count(Card::heart) == 1
1223 && hand().count(Card::heart_ace) != 1
1224 && isstartplayer) {
1225 return MarriageSelector::first_heart;
1226 }
1227 if ( hand().count(Card::club) == 1
1228 && hand().count(Card::club_ace) != 1
1229 && isstartplayer) {
1230 return MarriageSelector::first_club;
1231 }
1232 if ( hand().count(Card::spade) == 1
1233 && hand().count(Card::spade_ace) != 1
1234 && isstartplayer) {
1235 return MarriageSelector::first_spade;
1236 }
1237
1238
1239
1240 if ( hand().count_trumps() >= 8
1241 && !isstartplayer) {
1242 return MarriageSelector::first_color;
1243 }
1244
1245 return MarriageSelector::first_foreign;
1246 }
1247
1248 /** -> result
1249 **
1250 ** @param isDuty whether the player must play a duty solo
1251 ** (has no effect, yet)
1252 **
1253 ** @result the reservation of the ai
1254 **/
1255 Reservation const&
reservation_get(bool const isDuty)1256 Ai::reservation_get( bool const isDuty )
1257 {
1258 this->team_information().reset();
1259 this->cards_information().reset();
1260 auto& reservation = this->reservation();
1261
1262 { // bug report replay
1263 if ( ::bug_report_replay
1264 && ::bug_report_replay->auto_action()
1265 && (::bug_report_replay->current_action().type()
1266 == GameplayActions::Type::reservation)
1267 && (dynamic_cast<GameplayActions::Reservation const&>(::bug_report_replay->current_action()).player
1268 == this->no())
1269 ) {
1270 return (this->reservation() = dynamic_cast<GameplayActions::Reservation const&>(::bug_report_replay->current_action()).reservation);
1271 } // if (auto execute)
1272 } // bug report replay
1273
1274 reservation = this->reservation_get_default();
1275
1276 auto const& rule = this->game().rule();
1277
1278 // check, whether to announce 'richness'
1279 if (reservation.game_type == GameType::thrown_richness) {
1280 if (Heuristics::make_announcement(*this))
1281 reservation.game_type = GameType::normal;
1282 }
1283
1284 { // decide solo game
1285 SoloDecision::Points max_points = 120;
1286 if ( this->game().is_duty_solo()
1287 && *this == this->game().startplayer()) {
1288 max_points = INT_MIN;
1289 }
1290 GameType best_game_type = GameType::normal;
1291 // first all duty soli
1292 for (auto& decision : this->solo_decisions_) {
1293 auto const game_type = decision->game_type();
1294 if (!rule(game_type))
1295 continue;
1296 if (!this->is_remaining_duty_solo(game_type))
1297 continue;
1298 decision->set_player(*this);
1299 auto const points = decision->estimated_points();
1300 if (points > max_points) {
1301 best_game_type = game_type;
1302 max_points = points;
1303 DEBUG("solo decision rationale") << this->name() << ": " << decision->game_type() << ": " << points << " points\n"
1304 << decision->rationale() << '\n';
1305 }
1306 }
1307 max_points = 120;
1308 if (best_game_type == GameType::normal) {
1309 // lust solo games
1310 for (auto& decision : this->solo_decisions_) {
1311 auto const game_type = decision->game_type();
1312 if (!rule(game_type))
1313 continue;
1314 if (this->is_remaining_duty_solo(game_type))
1315 continue;
1316 decision->set_player(*this);
1317 auto const points = decision->estimated_points();
1318 if (points > max_points) {
1319 best_game_type = game_type;
1320 max_points = points;
1321 DEBUG("solo decision rationale") << this->name() << ": " << decision->game_type() << ": " << points << " points\n"
1322 << decision->rationale() << '\n';
1323 }
1324 }
1325 }
1326 if (best_game_type != GameType::normal) {
1327 reservation.game_type = best_game_type;
1328 if (is_color_solo(best_game_type)) {
1329 reservation.swines = true;
1330 reservation.hyperswines = true;
1331 }
1332 }
1333 }
1334
1335 #ifndef OLD
1336 if (reservation.game_type == GameType::marriage) {
1337 reservation.marriage_selector=get_Marriage();
1338 #ifndef POSTPONED
1339 // ToDo: to be removed
1340 if (!rule(reservation.marriage_selector))
1341 reservation.marriage_selector = this->reservation_get_default().marriage_selector;
1342 #endif
1343 }
1344 #endif
1345
1346 // special case: with swines announced the player does not have a poverty
1347 if ( reservation.game_type == GameType::poverty
1348 && (this->hand().count_poverty_cards()
1349 > rule(Rule::Type::max_number_of_poverty_trumps)) ) {
1350 reservation.swines = false;
1351 }
1352
1353 return reservation;
1354 }
1355
1356 /** -> result
1357 **
1358 ** @param player whose teaminfo is returned
1359 **
1360 ** @return the team of the given player, as far as this player knows it
1361 **/
1362 Team
teaminfo(Player const & player) const1363 Ai::teaminfo(Player const& player) const
1364 {
1365 return this->team_information().team(player);
1366 }
1367
1368 /** updates the information of the teams (uses the current trick)
1369 **
1370 ** @return the known teams
1371 **/
1372 void
teaminfo_update()1373 Ai::teaminfo_update()
1374 {
1375 this->team_information().update_teams();
1376 }
1377
1378 /** @return the partner of the player, nullptr, if not known for sure
1379 **/
1380 Player const*
partner(Player const & player) const1381 Ai::partner(Player const& player) const
1382 {
1383 if (::game_status < GameStatus::game_play)
1384 return nullptr;
1385
1386 if (!this->team_information().all_known())
1387 return nullptr;
1388
1389 Player const* partner = nullptr;
1390
1391 for (unsigned p = 0; p < this->game().playerno(); ++p) {
1392 if ( (p != player.no())
1393 && (this->teaminfo(this->game().player(p))
1394 == this->teaminfo(player))) {
1395 if (partner != nullptr)
1396 return nullptr; // more than one partner
1397 partner = &this->game().player(p);
1398 }
1399 } // for (p)
1400
1401 return partner;
1402 }
1403
1404 /** @return the points the team has made
1405 **/
1406 unsigned
points_of_team() const1407 Ai::points_of_team() const
1408 {
1409 unsigned points = this->game().points_of_player(*this);
1410
1411
1412 if (this->team_information().all_known()) {
1413 for (unsigned p = 0; p < this->game().playerno(); ++p)
1414 if ( (p != this->no())
1415 && (this->team_information().team(p) == this->team()))
1416 points += this->game().points_of_player(p);
1417 } else if (this->team_information().guessed_partner() != nullptr) {
1418 // normal game, partner guessed
1419 points += this->game().points_of_player(*this->team_information().guessed_partner());
1420 } else { // if (no partner known)
1421 // add the lowest points of the players
1422 unsigned lowest_points = 240;
1423 for (unsigned p = 0; p < this->game().playerno(); ++p)
1424 if ( (p != this->no())
1425 && (this->game().points_of_player(p) < lowest_points))
1426 lowest_points = this->game().points_of_player(p);
1427 points += lowest_points;
1428 } // if (no partner known)
1429
1430 return points;
1431 }
1432
1433 /** -> result
1434 ** (uses Heuristics)
1435 **
1436 ** @see Heuristics::make_announcement()
1437 ** @see Heuristics::say_no90
1438 ** @see Heuristics::say_no60
1439 ** @see Heuristics::say_no30
1440 ** @see Heuristics::say_no0
1441 **
1442 ** @return announcement of the player
1443 **/
1444 Announcement
announcement_request() const1445 Ai::announcement_request() const
1446 {
1447 if ( ::bug_report_replay
1448 && ::bug_report_replay->auto_action()) {
1449 if ( (::bug_report_replay->current_action().type()
1450 == GameplayActions::Type::announcement)
1451 && (dynamic_cast<GameplayActions::Announcement const&>(::bug_report_replay->current_action()).player
1452 == this->no())
1453 ) {
1454 return dynamic_cast<GameplayActions::Announcement const&>(::bug_report_replay->current_action()).announcement;
1455 } // if (current action = announcement)
1456 return Announcement::noannouncement;
1457 } // if (bug report auto execute)
1458
1459
1460 Announcement res = Announcement::noannouncement;
1461
1462 for (auto a : real_announcements) {
1463 // make the announcement as late as possible
1464 if (!this->game().announcements().last_chance_to_announce(a, *this))
1465 continue;
1466 switch(a) {
1467 case Announcement::noannouncement:
1468 case Announcement::reply:
1469 case Announcement::no120_reply:
1470 case Announcement::no90_reply:
1471 case Announcement::no60_reply:
1472 case Announcement::no30_reply:
1473 case Announcement::no0_reply:
1474 DEBUG_ASSERTION(false,
1475 "Ai::announcement_request():\n"
1476 " wrong announcement in 'switch': "
1477 << a);
1478 break;
1479 case Announcement::no120:
1480 if (Heuristics::make_announcement(*this))
1481 res = a;
1482 break;
1483 case Announcement::no90:
1484 if (Heuristics::say_no90(*this))
1485 res = a;
1486 break;
1487 case Announcement::no60:
1488 if (Heuristics::say_no60(*this))
1489 res = a;
1490 break;
1491 case Announcement::no30:
1492 if (Heuristics::say_no30(*this))
1493 res = a;
1494 break;
1495 case Announcement::no0:
1496 if (Heuristics::say_no0(*this))
1497 res = a;
1498 break;
1499 } // switch(a)
1500 } // for (a \in announcements)
1501
1502 if ( ( res == Announcement::noannouncement )
1503 && this->game().tricks().current().isfull()
1504 && this->game().announcements().is_valid(Announcement::reply, *this) )
1505 res = Heuristics::make_reply(*this);
1506
1507 return res;
1508 }
1509
1510 /** check whether re/contra shall be announced to announce the team
1511 **
1512 ** @param handcard card that is to be played
1513 **/
1514 void
check_and_make_first_announcement(HandCard const & handcard)1515 Ai::check_and_make_first_announcement(HandCard const& handcard)
1516 {
1517 if ( ::bug_report_replay
1518 && ::bug_report_replay->auto_action()) {
1519 return ;
1520 }
1521
1522 if (is_real(this->game().teaminfo().get(*this)))
1523 return ;
1524
1525 if (!Heuristics::make_announcement(*this))
1526 return ;
1527
1528 auto const& trick = this->game().tricks().current();
1529 // Make an announcement earlier so that the partner can pfund
1530 if (!trick.isjabbed(handcard))
1531 return ;
1532
1533 if (!handcard.istrump()) {
1534 if (handcard.value() != Card::ace)
1535 return ;
1536 // first color run
1537 auto const color = handcard.tcolor();
1538 if (this->cards_information().played(handcard.tcolor())
1539 > trick.cards().count(color))
1540 return ;
1541 } else {
1542 if ( trick.isempty()
1543 || trick.startcard().istrump()) {
1544 if (handcard.less(this->trump_card_limit()))
1545 return ;
1546 } else {
1547 auto const color = trick.startcard().tcolor();
1548 if (this->cards_information().played(handcard.tcolor())
1549 > trick.cards().count(color))
1550 return ;
1551 }
1552 }
1553 this->game().announcements().make_announcement(Announcement::no120, *this);
1554 }
1555
1556 /** the announcement 'announcement' has been made by player 'player'
1557 **
1558 ** @param announcement the announcement
1559 ** @param player the player, who has made the announcement
1560 **/
1561 void
announcement_made(Announcement const announcement,Player const & player)1562 Ai::announcement_made(Announcement const announcement,
1563 Player const& player)
1564 {
1565 this->team_information().announcement_made(announcement, player);
1566 this->cards_information().announcement_made(announcement, player);
1567 this->team_information().update_teams();
1568
1569 this->teaminfo_update();
1570 } // void Ai::announcement_made(Announcement announcement, Player player)
1571
1572 /** @return modificator for the end depth for calculating tricks
1573 ** in WVirtualGames
1574 **/
1575 unsigned
last_trick_to_calculate() const1576 Ai::last_trick_to_calculate() const
1577 {
1578 return this->last_trick_to_calculate_;
1579 }
1580
1581 /** sets the parameter to the last trick to calculate
1582 **
1583 ** @param last_trick_to_calculate new value
1584 **
1585 ** @return modificator for the end depth for calculating tricks
1586 ** in WVirtualGames
1587 **/
1588 void
set_last_trick_to_calculate(unsigned const last_trick_to_calculate)1589 Ai::set_last_trick_to_calculate(unsigned const last_trick_to_calculate)
1590 {
1591 this->last_trick_to_calculate_ = last_trick_to_calculate;
1592 }
1593
1594 /** returns which cards the player shifts
1595 **
1596 ** @return the cards that are to be shifted
1597 **/
1598 HandCards
poverty_shift()1599 Ai::poverty_shift()
1600 {
1601 DEBUG_ASSERTION(this->hand().count_trumps() <= 5,
1602 "Ai::poverty_shift()\n"
1603 " more then 5 trumps:\n" << this->hand());
1604
1605 { // bug report replay
1606 if ( ::bug_report_replay
1607 && ::bug_report_replay->auto_action()
1608 && (::bug_report_replay->current_action().type()
1609 == GameplayActions::Type::poverty_shift)
1610 && (dynamic_cast<GameplayActions::PovertyShift const&>(::bug_report_replay->current_action()).player == this->no())
1611 ) {
1612 HandCards const cards(this->hand(),
1613 dynamic_cast<GameplayActions::PovertyShift const&>(::bug_report_replay->current_action()).cards);
1614 this->hand().remove(cards);
1615 return cards;
1616 } // if (auto execute)
1617 } // bug report replay
1618
1619 Hand& hand = this->hand();
1620
1621 HandCards res;
1622
1623 // number of remaining cards to shift
1624 unsigned rem = hand.count_poverty_cards();
1625
1626 for (auto const card : hand)
1627 if (card.istrump())
1628 res.push_back(card);
1629
1630 hand.remove(res);
1631
1632 DEBUG_ASSERTION((res.size() <= rem),
1633 "Ai::poverty_shift()\n"
1634 " too many trumps: " << res.size() << " > " << rem << '\n'
1635 << " trumps found:\n"
1636 << res);
1637 rem -= res.size();
1638
1639 if ( !this->game().rule()(Rule::Type::poverty_shift_only_trump)
1640 && rem > 0) {
1641 HandCards addon;
1642
1643 auto color = Card::heart;
1644 auto size = hand.count(color);
1645
1646 if (hand.count(Card::spade) < size) {
1647 color = Card::spade;
1648 size = hand.count(color);
1649 }
1650
1651 if (hand.count(Card::club) < size) {
1652 color = Card::club;
1653 size = hand.count(color);
1654 }
1655
1656 Hand::Position p = 0;
1657 while (rem > 0) {
1658 if (p >= hand.cardsnumber())
1659 p = 0;
1660 auto const card = hand.card(p);
1661 if (size > 0) {
1662 if (card.color() == color) {
1663 addon.push_back(card);
1664 hand.remove(p);
1665 size--;
1666 rem--;
1667 }
1668 } else {
1669 addon.push_back(card);
1670 hand.remove(p);
1671 rem--;
1672 }
1673 p += 1;
1674 }
1675
1676 res.insert(res.end(), addon.begin(), addon.end());
1677 }// !this->game().rule()( Rule::Type::poverty_shift_only_trump ) && rem > 0
1678
1679 return res;
1680 }
1681
1682 /** returns whether 'player' accepts the shifted cards
1683 **
1684 ** @param cardno the number of shifted cards
1685 **
1686 ** @return whether to accept the cards
1687 **/
1688 bool
poverty_take_accept(unsigned const cardno)1689 Ai::poverty_take_accept(unsigned const cardno)
1690 {
1691 { // bug report replay
1692 if ( ::bug_report_replay
1693 && ::bug_report_replay->auto_action()) {
1694 if ( (::bug_report_replay->current_action().type()
1695 == GameplayActions::Type::poverty_accepted)
1696 && (dynamic_cast<GameplayActions::PovertyAccepted const&>(::bug_report_replay->current_action()).player == this->no()) )
1697 return true;
1698 if ( (::bug_report_replay->current_action().type()
1699 == GameplayActions::Type::poverty_denied)
1700 && (dynamic_cast<GameplayActions::PovertyDenied const&>(::bug_report_replay->current_action()).player == this->no()) )
1701 return false;
1702 } // if (auto execute)
1703 } // bug report replay
1704
1705 unsigned trumpno_possible = cardno;
1706 if (!this->game().rule()(Rule::Type::poverty_shift_only_trump)) {
1707 if (!this->game().rule()(Rule::Type::throw_with_one_trump))
1708 trumpno_possible = 2;
1709 else
1710 trumpno_possible = 1;
1711 }
1712
1713 int value = Heuristics::CalcHandValue( *this );
1714
1715 if( this->hand().count_trumps() >= 12 - cardno )
1716 value += this->hand().count( Card::queen );
1717
1718 std::multimap<unsigned, Card::Color> color_nums;
1719 for (auto const c : this->game().rule().card_colors()) {
1720 color_nums.insert(std::make_pair(this->hand().count(c), c));
1721 }
1722
1723 for (auto const& c : color_nums) {
1724 if (c.first > trumpno_possible)
1725 break;
1726
1727 value += 2;
1728 trumpno_possible -= c.first;
1729 }
1730 if( this->hand().count_trumps() >= 12 - cardno - 1 )
1731 value += (this->hand().count( Card::queen )
1732 + this->hand().count_trump_aces());
1733
1734
1735 if ( this->game().rule()(Rule::Type::dullen))
1736 value -= 4 - 2 * this->hand().count(Card::heart, Card::ten);
1737
1738 value -= 4 - 2 * this->hand().count_club_queens();
1739 value -= 2 - this->hand().count(Card::spade, Card::queen);
1740
1741
1742 //COUT << no() << "\t" << value << "\t" << static_cast<signed>(this->value(Aiconfig::takepoverty)) << std::endl;
1743
1744 return (value >= 15);
1745 }
1746
1747 /** changes the cards from the poverty-player
1748 **
1749 ** @param cards the cards that are given to the player
1750 **
1751 ** @return the cards that are returned to the poverty-player
1752 **/
1753 HandCards
poverty_cards_change(HandCards const & cards)1754 Ai::poverty_cards_change(HandCards const& cards)
1755 {
1756 { // bug report replay
1757 if ( ::bug_report_replay
1758 && ::bug_report_replay->auto_action()) {
1759 if (::bug_report_replay->current_action().type()
1760 == GameplayActions::Type::poverty_returned) {
1761 HandCards const reshifted_cards(this->hand(),
1762 dynamic_cast<GameplayActions::PovertyReturned const&>(::bug_report_replay->current_action()).cards);
1763 this->hand().add(cards);
1764 this->hand().remove(reshifted_cards);
1765 return reshifted_cards;
1766 }
1767 } // if (auto execute)
1768 } // bug report replay
1769
1770 auto& hand = this->hand();
1771 hand.add(cards);
1772
1773 HandCards res;
1774 unsigned rem = cards.size();
1775
1776 // create Fehl for Heart
1777 if ( hand.count(Card::heart) > 0
1778 && hand.count(Card::heart) <= rem
1779 && this->game().rule()(Rule::Type::dullen)) {
1780 HandCards addon;
1781
1782 for (auto const c : hand) {
1783 if ( c.color() == Card::heart
1784 && !c.istrump()) {
1785 addon.push_back(c);
1786 }
1787 }
1788 hand.remove(addon);
1789 res.insert(res.end(), addon.begin(), addon.end());
1790 rem -= addon.size();
1791 }
1792
1793 // create Fehl for Club
1794 if( hand.count( Card::club ) > 0 && hand.count( Card::club ) <= rem )
1795 {
1796 bool ace_removed = false;
1797 if( hand.count( Card::club_ace ) == 2 )
1798 {
1799 hand.remove (Card::club_ace); // keep second ace.
1800 ace_removed = true;
1801 }
1802
1803 HandCards addon;
1804 for( unsigned int i = 0; i < hand.cardsnumber(); i++ )
1805 if ( ( hand.card( i ).color() == Card::club ) && !hand.card(i).istrump() )
1806 addon.push_back( hand.card( i ) );
1807 hand.remove( addon );
1808 res.insert(res.end(), addon.begin(), addon.end());
1809 rem-= addon.size();
1810
1811 if (ace_removed)
1812 hand.add( Card::club_ace );
1813 }
1814
1815
1816 // create Fehl for Spade
1817 if( hand.count( Card::spade ) > 0 && hand.count( Card::spade ) <= rem )
1818 {
1819 bool ace_removed = false;
1820 if( hand.count( Card::spade_ace ) == 2 )
1821 {
1822 hand.remove (Card::spade_ace); // keep second ace.
1823 ace_removed = true;
1824 }
1825
1826 HandCards addon;
1827 for( unsigned int i = 0; i < hand.cardsnumber(); i++ )
1828 if( ( hand.card( i ).color() == Card::spade ) && !hand.card(i).istrump() )
1829 addon.push_back( hand.card( i ) );
1830 hand.remove( addon );
1831 res.insert(res.end(), addon.begin(), addon.end());
1832 rem-= addon.size();
1833
1834 if (ace_removed)
1835 hand.add( Card::spade_ace );
1836 }
1837
1838 // create Fehl for Heart
1839 if( hand.count( Card::heart ) > 0 && hand.count( Card::heart ) <= rem )
1840 {
1841
1842 bool ace_removed = false;
1843 if( hand.count( Card::heart_ace ) == 2 )
1844 {
1845 hand.remove (Card::heart_ace); // keep second ace.
1846 ace_removed = true;
1847 }
1848 HandCards addon;
1849 for( unsigned int i = 0; i < hand.cardsnumber(); i++ )
1850 if( ( hand.card( i ).color() == Card::heart ) && !hand.card(i).istrump() )
1851 addon.push_back( hand.card( i ) );
1852 hand.remove( addon );
1853 res.insert(res.end(), addon.begin(), addon.end());
1854 rem-= addon.size();
1855
1856 if (ace_removed)
1857 hand.add( Card::heart_ace );
1858 }
1859
1860
1861 while ( rem > 0 ) {
1862 //adding highest color card not ace
1863 if ( hand.count_trumps() < hand.cardsnumber()) {
1864 HandCard c;
1865 for( unsigned int i = 0; i < hand.cardsnumber(); i++ )
1866 if ( !hand.card( i ).istrump() )
1867 c = hand.card( i );
1868
1869 if( !c.is_empty() )
1870 {
1871 for( unsigned int i = 0; i < hand.cardsnumber(); i++ )
1872 if ( !hand.card( i ).istrump() && c.less(hand.card( i )) )
1873 c = hand.card( i );
1874
1875 hand.remove( c );
1876 res.push_back( c );
1877 rem--;
1878 continue;
1879 }
1880 }
1881
1882 { // adding color card
1883 if (hand.count_trumps() < hand.cardsnumber()) {
1884 HandCard c;
1885 for (unsigned int i = 0; i < hand.cardsnumber(); i++) {
1886 if (!hand.card(i).istrump()) {
1887 c = hand.card(i);
1888 }
1889 }
1890
1891 hand.remove(c);
1892 res.push_back(c);
1893 rem--;
1894 continue;
1895 }
1896 } // adding color card
1897
1898 if (rem > 0 ) {
1899 // add low trump cards
1900 static vector<Card> const cards_to_check = {
1901 Card::diamond_nine,
1902 Card::diamond_king,
1903 Card::diamond_jack,
1904 Card::diamond_queen,
1905 Card::diamond_ten,
1906 Card::heart_jack,
1907 Card::spade_jack,
1908 Card::club_jack,
1909 Card::diamond_ace,
1910 Card::heart_queen,
1911 Card::spade_queen,
1912 Card::club_queen,
1913 };
1914
1915 for (auto card = cards_to_check.begin(); rem > 0; ++card) {
1916 while ((hand.count(*card) > 0) && (rem > 0)) {
1917 auto c = HandCard(hand, *card);
1918 if (c.possible_swine() || c.possible_hyperswine() )
1919 break;
1920 hand.remove(c);
1921 res.push_back(c);
1922 rem--;
1923 }
1924 } // for (card)
1925 } // add low trump cards
1926
1927 } // if ( rem > 0 )
1928
1929 this->cards_information().reset();
1930 this->set_hand(hand); // to update the cards information
1931
1932 return res;
1933 }
1934
1935
1936 /** gets the cards from the partner and add them to the hand
1937 **
1938 ** @param cards the cards that are given to the player
1939 **/
1940 void
poverty_cards_get_back(HandCards const & cards)1941 Ai::poverty_cards_get_back(HandCards const& cards)
1942 {
1943 this->hand().add(cards);
1944 this->cards_information().reset();
1945 this->set_hand(this->hand()); // to update the cards information
1946 }
1947
1948
1949 /** @return limit card for some heuristic decisions
1950 **/
1951 Card
trump_card_limit() const1952 Ai::trump_card_limit() const
1953 {
1954 if (this->silent_marriage_)
1955 return this->Aiconfig::value(Aiconfig::Type::trumplimit_solocolor);
1956
1957 switch (this->game().type()) {
1958 case GameType::solo_club:
1959 case GameType::solo_heart:
1960 case GameType::solo_spade:
1961 case GameType::solo_diamond:
1962 return this->Aiconfig::value(Aiconfig::Type::trumplimit_solocolor);
1963 case GameType::solo_jack:
1964 return this->Aiconfig::value(Aiconfig::Type::trumplimit_solojack);
1965 case GameType::solo_queen:
1966 return this->Aiconfig::value(Aiconfig::Type::trumplimit_soloqueen);
1967 case GameType::solo_king:
1968 return this->Aiconfig::value(Aiconfig::Type::trumplimit_soloking);
1969 case GameType::solo_queen_jack:
1970 return this->Aiconfig::value(Aiconfig::Type::trumplimit_solojackqueen);
1971 case GameType::solo_king_jack:
1972 return this->Aiconfig::value(Aiconfig::Type::trumplimit_solojackking);
1973 case GameType::solo_king_queen:
1974 return this->Aiconfig::value(Aiconfig::Type::trumplimit_soloqueenking);
1975 case GameType::solo_koehler:
1976 return this->Aiconfig::value(Aiconfig::Type::trumplimit_solokoehler);
1977 case GameType::solo_meatless:
1978 return this->Aiconfig::value(Aiconfig::Type::trumplimit_meatless);
1979 default:
1980 return this->Aiconfig::value(Aiconfig::Type::trumplimit_normal);
1981 }
1982 }
1983
1984 /** @return limit card for some heuristic decisions
1985 **/
1986 Card
lowest_trump_card_limit() const1987 Ai::lowest_trump_card_limit() const
1988 {
1989 if (this->silent_marriage_)
1990 return this->Aiconfig::value(Aiconfig::Type::lowest_trumplimit_solocolor);
1991
1992 switch (this->game().type()) {
1993 case GameType::solo_club:
1994 case GameType::solo_heart:
1995 case GameType::solo_spade:
1996 case GameType::solo_diamond:
1997 return this->Aiconfig::value(Aiconfig::Type::lowest_trumplimit_solocolor);
1998 case GameType::solo_jack:
1999 return this->Aiconfig::value(Aiconfig::Type::lowest_trumplimit_solojack);
2000 case GameType::solo_queen:
2001 return this->Aiconfig::value(Aiconfig::Type::lowest_trumplimit_soloqueen);
2002 case GameType::solo_king:
2003 return this->Aiconfig::value(Aiconfig::Type::lowest_trumplimit_soloking);
2004 case GameType::solo_queen_jack:
2005 return this->Aiconfig::value(Aiconfig::Type::lowest_trumplimit_solojackqueen);
2006 case GameType::solo_king_jack:
2007 return this->Aiconfig::value(Aiconfig::Type::lowest_trumplimit_solojackking);
2008 case GameType::solo_king_queen:
2009 return this->Aiconfig::value(Aiconfig::Type::lowest_trumplimit_soloqueenking);
2010 case GameType::solo_koehler:
2011 return this->Aiconfig::value(Aiconfig::Type::lowest_trumplimit_solokoehler);
2012 case GameType::solo_meatless:
2013 return this->Aiconfig::value(Aiconfig::Type::lowest_trumplimit_meatless);
2014 default:
2015 return this->Aiconfig::value(Aiconfig::Type::lowest_trumplimit_normal);
2016 }
2017 }
2018
2019 /** returns the selected partner for a genscher
2020 **
2021 ** @return pointer to the partner
2022 ** nullptr if not to use the genscher
2023 **/
2024 Player const*
genscher_partner()2025 Ai::genscher_partner()
2026 {
2027 Player const* res = nullptr;
2028
2029 // first find original teammate
2030 for ( unsigned i = 0; i < this->game().playerno(); i++ ) {
2031 if( this->teamofplayer( this->game().player(i) ) == this->team()
2032 && this->game().player(i) != *this)
2033 {
2034 res = &(this->game().player(i));
2035 break;
2036 }
2037 }
2038 /// @todo use teams after genscher...
2039
2040 // check Specialpoints
2041 std::vector<int> bonusPoints( this->game().playerno(), 0 );
2042 for (auto const& t : this->trick_) {
2043 // DK: if hinzugefuegt
2044 if (!t.isempty())
2045 bonusPoints[t.winnerplayer().no()] += t.specialpoints().size() * 30;
2046 }
2047
2048 // secure victory
2049 unsigned int points = 0;
2050 bool found = false;
2051 if ( this->game().points_of_team( this->team() ) < 120 )
2052 for ( unsigned i = 0; i < this->game().playerno(); i++ ) {
2053 if( this->game().points_of_player( this->game().player(i) )
2054 + this->game().points_of_player( *this )
2055 > 120
2056 && (this->game().player(i) != *this )
2057 && this->game().points_of_player( this->game().player(i) )
2058 + bonusPoints[ i ] > points ) {
2059 res = &(this->game().player(i));
2060 points = this->game().points_of_player( this->game().player(i) )
2061 + bonusPoints[ i ] ;
2062 found = true;
2063 }
2064 }
2065
2066 if (found)
2067 return res;
2068
2069 for ( unsigned i = 0; i < this->game().playerno(); i++ ) {
2070 if ( (this->game().points_of_player(this->game().player(i))
2071 + bonusPoints[i]) > points
2072 && this->game().player(i) != *this) {
2073 points = (this->game().points_of_player(this->game().player(i))
2074 + bonusPoints[i]);
2075 res = &(this->game().player(i));
2076 }
2077 }
2078
2079 Announcement highest_announcement = Announcement::noannouncement;
2080 // calculate highest announcements of this team
2081 for (auto const& p : this->game().players()) {
2082 if (p.team() == this->team()) {
2083 if (p.announcement() > highest_announcement )
2084 highest_announcement = p.announcement();
2085 }
2086 }
2087
2088 if ( highest_announcement >= Announcement::no0
2089 && this->game().tricks().has_trick(opposite(this->team())))
2090 return res;
2091
2092 if ( highest_announcement >= Announcement::no30
2093 && this->game().points_of_team(opposite(this->team())) >= 30)
2094 return res;
2095
2096 if ( highest_announcement >= Announcement::no60
2097 && this->game().points_of_team(opposite(this->team())) >= 60)
2098 return res;
2099
2100 if ( highest_announcement >= Announcement::no90
2101 && this->game().points_of_team(opposite(this->team())) >= 90)
2102 return res;
2103
2104 // don't use genscher
2105 return {};
2106 }
2107