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