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 "human.h"
31 #ifdef POSTPHONED
32 #include "humanDb.h"
33 #endif
34 
35 #include "../../party/rule.h"
36 #include "../../misc/preferences.h"
37 #include "../../ui/ui.h"
38 #include "../../os/bug_report_replay.h"
39 #include "../../game/gameplay_actions.h"
40 
41 /** Construktor
42  **/
Human()43 Human::Human() :
44   Ai()
45 {
46   // *** HACK
47   this->set_type(Player::Type::human);
48   this->set_name("");
49 #ifdef POSTPHONED
50   this->db_ = new HumanDb();
51 #endif
52 } // Human::Human()
53 
54 /** construktor
55  **
56  ** @param    istr   stream with the infos
57  **/
Human(istream & istr)58 Human::Human(istream& istr) :
59   Ai(istr)
60 {
61   this->set_type(Player::Type::human);
62 } // Human::Human(istream& istr)
63 
64 /** copy-constructor
65  **
66  ** @param    player   player to copy
67  **/
Human(Player const & player)68 Human::Human(Player const& player) :
69   Ai(player)
70 {
71   this->set_type(Player::Type::human);
72 } // Human::Human(Player player)
73 
74 /** copy-constructor
75  **
76  ** @param    player   player to copy
77  ** @param    aiconfig   configuration to copy
78  **/
Human(Player const & player,Aiconfig const & aiconfig)79 Human::Human(Player const& player, Aiconfig const& aiconfig) :
80   Ai(player, aiconfig)
81 {
82   this->set_type(Player::Type::human);
83 } // Human::Human(Player player, Aiconfig aiconfig)
84 
85 /** copy-constructor
86  **
87  ** @param    ai   ai to copy
88  **/
Human(Ai const & ai)89 Human::Human(Ai const& ai) :
90   Ai(static_cast<Ai const&>(ai))
91 {
92   this->set_type(Player::Type::human);
93 } // Human::Human(Ai ai)
94 
95 /** copy-constructor
96  **
97  ** @param    human   human to copy
98  **/
Human(Human const & human)99 Human::Human(Human const& human) :
100   Ai(static_cast<Ai const&>(human))
101 {
102   this->set_type(Player::Type::human);
103 } // Human::Human(Human human)
104 
105 /** clone the player
106  **
107  ** @return   pointer of a clone
108  **/
109 unique_ptr<Player>
clone() const110 Human::clone() const
111 {
112   return make_unique<Human>(*this);
113 } // virtual unique_ptr<Player> Human::clone() const
114 
115 /** returns the reservation of the player
116  ** (taken from the ui)
117  **
118  ** @param    is_duty   whether the player has to play a duty solo
119  **   (default: false)
120  **
121  ** @return   reservation of the player
122  **/
123 Reservation const&
reservation_get(bool const is_duty)124 Human::reservation_get(bool const is_duty)
125 {
126   DEBUG_ASSERTION(!this->game().isvirtual(),
127 		  "Human::reservation_get():\n"
128 		  "  Game is virtual");
129 
130   { // bug report replay
131     if (   ::bug_report_replay
132 	&& ::bug_report_replay->auto_action()
133 	&& (::bug_report_replay->current_action().type()
134 	    == GameplayActions::Type::reservation)
135 	&& (dynamic_cast<GameplayActions::Reservation const&>(::bug_report_replay->current_action()).player
136 	    == this->no())
137        ) {
138       this->reservation() = dynamic_cast<GameplayActions::Reservation const&>(::bug_report_replay->current_action()).reservation;
139       return this->reservation();
140     } // if (auto execute)
141   } // bug report replay
142 
143   if (::fast_play & FastPlay::player) {
144     this->reservation() = this->Ai::reservation_get(is_duty);
145     return this->reservation();
146   }
147 
148   (void)is_duty;
149 
150   this->reservation() = ::ui->get_reservation(*this);
151 
152   return this->reservation();
153 } // Reservation const& Human::reservation_get(bool const is_duty = false)
154 
155 /** the game is started
156  **/
157 void
game_start()158 Human::game_start()
159 {
160   this->Ai::game_start();
161   if (::preferences(Preferences::Type::announce_swines_automatically)) {
162     if (this->game().rule()(Rule::Type::swines_announcement_begin))
163       if (this->game().swines().swines_announcement_valid(*this))
164 	this->game().swines().swines_announce(*this);
165 
166   } // if (::preferences(Preferences::Type::announce_swines_automatically))
167 } // void Human::game_start()
168 
169 /** @return   no announcement / announcement from the bug report
170  **/
171 Announcement
announcement_request() const172 Human::announcement_request() const
173 {
174   { // bug report replay
175     if (   ::bug_report_replay
176 	&& ::bug_report_replay->auto_action()
177 	&& (::bug_report_replay->current_action().type()
178 	    == GameplayActions::Type::announcement)
179 	&& (dynamic_cast<GameplayActions::Announcement const&>(::bug_report_replay->current_action()).player
180 	    == this->no())
181        ) {
182       return dynamic_cast<GameplayActions::Announcement const&>(::bug_report_replay->current_action()).announcement;
183     } // if (auto execute)
184   } // bug report replay
185 
186   return Announcement::noannouncement;
187 } // Announcement Human::announcement_request() const
188 
189 /** returns the card played by the human
190  **
191  ** @return   the card choosen by a human player
192  **/
193 HandCard
card_get()194 Human::card_get()
195 {
196   DEBUG_ASSERTION(!this->game().isvirtual(),
197 		  "Human::card_get():\n"
198 		  "  Game is virtual");
199 
200   { // bug report replay
201     if (   ::bug_report_replay
202 	&& ::bug_report_replay->auto_action()
203        ) {
204       if ( (::bug_report_replay->current_action().type()
205 	    == GameplayActions::Type::swines)
206 	  && (dynamic_cast<GameplayActions::Swines const&>(::bug_report_replay->current_action()).player
207 	    == this->no()))
208 	this->game().swines().swines_announce(*this);
209 
210       if ( (::bug_report_replay->current_action().type()
211 	    == GameplayActions::Type::hyperswines)
212 	  && (dynamic_cast<GameplayActions::Hyperswines const&>(::bug_report_replay->current_action()).player
213 	    == this->no()))
214 	this->game().swines().hyperswines_announce(*this);
215 
216       if ( (::bug_report_replay->current_action().type()
217 	    == GameplayActions::Type::card_played)
218 	  && (dynamic_cast<GameplayActions::CardPlayed const&>(::bug_report_replay->current_action()).player
219               == this->no())) {
220         this->set_last_heuristic_to_bug_report();
221         return HandCard(this->hand(), dynamic_cast<GameplayActions::CardPlayed const&>(::bug_report_replay->current_action()).card);
222       }
223     } // if (auto execute card play)
224   } // bug report replay
225 
226   if (::fast_play & FastPlay::player) {
227     HandCard const card = this->Ai::card_suggestion();
228     if (!card.is_empty()
229         && card.isvalid(this->game().tricks().current())) {
230       return card;
231     }
232   }
233 
234   this->set_last_heuristic_to_manual();
235   auto const card = ::ui->get_card(*this);
236 
237   if (::game_status != GameStatus::game_play)
238     return HandCard(this->hand(), Card());
239 
240   DEBUG_ASSERTION(!card.is_empty(),
241                   "Human::card_get():\n"
242                   "  result of 'ui->card_get()' is an empty card");
243 
244   if (::preferences(Preferences::Type::announce_swines_automatically)) {
245     auto const& rule = this->game().rule();
246     auto& swines = this->game().swines();
247     if (card.possible_swine()
248         && !rule(Rule::Type::swines_announcement_begin)
249         && swines.swines_announcement_valid(*this)) {
250       if (rule(Rule::Type::swine_only_second)) {
251         if (this->hand().count_trump_aces() == 1)
252           swines.swines_announce(*this);
253       } else {
254         swines.swines_announce(*this);
255       }
256     }
257     if (card.possible_hyperswine()
258         && !rule(Rule::Type::hyperswines_announcement_begin)
259         && swines.hyperswines_announcement_valid(*this))
260       swines.hyperswines_announce(*this);
261   } // if (::preferences(Preferences::Type::announce_swines_automatically))
262 
263   return card;
264 } // HandCard Human::card_get()
265 
266 /** updates the team information
267  **/
268 void
teaminfo_update()269 Human::teaminfo_update()
270 {
271   this->Ai::teaminfo_update();
272   if (::preferences(Preferences::Type::show_ai_information_teams)
273       && !this->game().isvirtual()) {
274     for (auto const& p : this->game().players()) {
275       ::ui->teaminfo_changed(p);
276     }
277   }
278 } // void Human::teaminfo_update()
279 
280 /** returns which cards the player shifts
281  **
282  ** @return   the cards that are to be shifted
283  **/
284 HandCards
poverty_shift()285 Human::poverty_shift()
286 {
287   { // bug report replay
288     if (   ::bug_report_replay
289         && ::bug_report_replay->auto_action()
290         && (::bug_report_replay->current_action().type()
291             == GameplayActions::Type::poverty_shift)
292         && (dynamic_cast<GameplayActions::PovertyShift const&>(::bug_report_replay->current_action()).player
293             == this->no())
294        ) {
295       HandCards const cards(this->hand(),
296                             dynamic_cast<GameplayActions::PovertyShift const&>(::bug_report_replay->current_action()).cards);
297       this->hand().remove(cards);
298       return cards;
299     } // if (auto execute)
300   } // bug report replay
301 
302   if (::fast_play & FastPlay::player)
303     return this->Ai::poverty_shift();
304 
305   return ::ui->get_poverty_cards_to_shift(*this);
306 } // void Human::poverty_shift(Player const& player)
307 
308 /** returns whether 'player' accepts the shifted cards
309  **
310  ** @param    cardno   the number of shifted cards
311  **
312  ** @return   whether to accept the cards
313  **/
314 bool
poverty_take_accept(unsigned const cardno)315 Human::poverty_take_accept(unsigned const cardno)
316 {
317   { // bug report replay
318     if (   ::bug_report_replay
319         && ::bug_report_replay->auto_action()) {
320       if (   (::bug_report_replay->current_action().type()
321               == GameplayActions::Type::poverty_accepted)
322           && (dynamic_cast<GameplayActions::PovertyAccepted const&>(::bug_report_replay->current_action()).player
323               == this->no()) )
324         return true;
325       if (   (::bug_report_replay->current_action().type()
326               == GameplayActions::Type::poverty_denied)
327           && (dynamic_cast<GameplayActions::PovertyDenied const&>(::bug_report_replay->current_action()).player
328               == this->no()) )
329         return false;
330     } // if (auto execute)
331   } // bug report replay
332 
333   if (::fast_play & FastPlay::player)
334     return this->Ai::poverty_take_accept(cardno);
335 
336   return ::ui->get_poverty_take_accept(*this, cardno);
337 } // void Human::poverty_take_accept(unsigned const cardno)
338 
339 /** changes the cards from the poverty-player
340  **
341  ** @param    cards   the cards that are given to the player
342  **
343  ** @return   the cards that are returned to the poverty-player
344  **/
345 HandCards
poverty_cards_change(HandCards const & cards)346 Human::poverty_cards_change(HandCards const& cards)
347 {
348   { // bug report replay
349     if (   ::bug_report_replay
350         && ::bug_report_replay->auto_action()) {
351       if (::bug_report_replay->current_action().type()
352           == GameplayActions::Type::poverty_returned) {
353         this->hand().add(cards);
354         HandCards const cards_returned(this->hand(),
355                                        dynamic_cast<GameplayActions::PovertyReturned const&>(::bug_report_replay->current_action()).cards);
356         this->hand().remove(cards_returned);
357 #ifdef WORDAROUND
358         // the ai has to update the cards
359         this->set_hand(this->hand());
360 #endif
361         return cards_returned;
362       }
363     } // if (auto execute)
364   } // bug report replay
365 
366   if (::fast_play & FastPlay::player)
367     return this->Ai::poverty_cards_change(cards);
368 
369 #ifdef WORKAROUND
370   // the ai has to update the cards
371   HandCards const cards_returned
372     = ::ui->get_poverty_exchanged_cards(*this, cards);
373   this->Ai::set_hand(this->hand());
374 
375   return cards_returned;
376 #else
377   return ::ui->poverty_cards_change(*this, cards);
378 #endif
379 } // HandCards Human::poverty_cards_change(HandCards cards)
380 
381 /** gets the cards from the partner and add them to the hand
382  **
383  ** @param    cards   the cards that are given to the player
384  **/
385 void
poverty_cards_get_back(HandCards const & cards)386 Human::poverty_cards_get_back(HandCards const& cards)
387 {
388   { // bug report replay
389     if (   ::bug_report_replay
390         && ::bug_report_replay->auto_action()) {
391       this->Ai::poverty_cards_get_back(cards);
392       return ;
393     } // if (auto execute)
394   } // bug report replay
395 
396   if (::fast_play & FastPlay::player) {
397     this->Ai::poverty_cards_get_back(cards);
398     return ;
399   }
400 
401   ::ui->poverty_cards_get_back(*this, cards);
402 #ifdef WORKAROUND
403   // the ai has to update the cards
404   this->Ai::set_hand(this->hand());
405 #endif
406 } // void Human::poverty_cards_get_back(HandCards cards)
407 
408 /** 'player' has announce hyperswines
409  **
410  ** @param    player   player that has announced the hyperswines
411  **/
412 void
swines_announced(Player const & player)413 Human::swines_announced(Player const& player)
414 {
415   this->Ai::swines_announced(player);
416 
417   if (::preferences(Preferences::Type::announce_swines_automatically)) {
418     if (this->game().swines().hyperswines_announcement_valid(*this)
419         && this->game().rule()(Rule::Type::hyperswines_announcement_begin))
420       this->game().swines().hyperswines_announce(*this);
421 
422   } // if (::preferences(Preferences::Type::announce_swines_automatically))
423 } // void Human::swines_announced(Player player)
424 
425 /** genscher: -> result
426  **
427  ** @return   pointer to the new teammate,
428  **            NULL if the genscher is not to be announced
429  **/
430 Player const*
genscher_partner()431 Human::genscher_partner()
432 {
433   { // bug report replay
434     if (   ::bug_report_replay
435         && ::bug_report_replay->auto_action()
436         && (::bug_report_replay->current_action().type()
437             == GameplayActions::Type::genscher)
438         && (dynamic_cast<GameplayActions::Genscher const&>(::bug_report_replay->current_action()).player
439             == this->no())
440        ) {
441       unsigned const partner_no
442         = dynamic_cast<GameplayActions::Genscher const&>(::bug_report_replay->current_action()).partner;
443       if (partner_no == UINT_MAX)
444         return {};
445       else
446         return &this->game().player(partner_no);
447     } // if (auto execute)
448   } // bug report replay
449 
450   if (::fast_play & FastPlay::player)
451     return this->Ai::genscher_partner();
452 
453   return ::ui->get_genscher_partner();
454 } // Player const* Human::genscher_partner()
455