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 #include "game.h"
30 #include "gameplay.h"
31 #include "gameplay_actions/announcement.h"
32 #include "../party/rule.h"
33 #include "../ui/ui.h"
34 
35 /** constructor
36  **
37  ** @param    game   corresponding game
38  **/
Announcements(Game & game)39 Announcements::Announcements(Game& game) :
40   game_(&game)
41 { }
42 
43 /** constructor
44  **
45  ** @param    announcements   announcements to copy
46  ** @param    game   corresponding game
47  **/
Announcements(Announcements const & announcements,Game & game)48 Announcements::Announcements(Announcements const& announcements,
49                              Game& game) :
50   game_(&game),
51   announcements_(announcements.announcements_)
52 { }
53 
54 /** -> result
55  **
56  ** @param    team   the team
57  **
58  ** @return   the announcement of the team 'team'
59  **/
60 AnnouncementWithTrickno
last(Team const team) const61 Announcements::last(Team const team) const
62 {
63   auto const& game = *this->game_;
64   DEBUG_ASSERTION(   (team == Team::re)
65                   || (team == Team::contra)
66                   || game.marriage().is_undetermined(),
67                   "Announcements::last(team)\n"
68                   "  invalid team = " << team);
69 
70   // In an undetermined marriage the contra team cannot have announced.
71   // This case is treated here, because in this case there does not
72   // exists a player of the team 'contra' so the assertion later on would fail.
73   if (   game.marriage().is_undetermined()
74       && (team != Team::re) )
75     return {};
76 
77   // the player of the team, that has made the highest announcement
78   Player const* player = nullptr;
79   auto const& rule = game.rule();
80 
81   // take the highest announcement
82   for (auto const& p : game.players()) {
83     if (   rule(Rule::Type::knocking)
84         && !is_real(game.teaminfo().get(p)))
85       continue;
86 
87     if (p.team() == team)
88       if (!player
89           || (this->last(p).announcement
90               > this->last(*player).announcement))
91         player = &p;
92   } // for (p : this->players())
93 
94   if (   rule(Rule::Type::knocking)
95       && !player)
96     return {};
97 
98   if (!player) {
99     DEBUG_ASSERTION(game.isvirtual(),
100                     "Announcements::last(team):\n"
101                     "  no player of team '" << team << "' found!");
102     return {};
103   }
104 
105   return this->last(*player);
106 } // AnnouncementWithTrickno Announcements::last(Team team) const
107 
108 /** -> result
109  **
110  ** @param    player   the player
111  **
112  ** @return   the highest announcement of player 'player'
113  **/
114 AnnouncementWithTrickno
last(Player const & player) const115 Announcements::last(Player const& player) const
116 {
117   auto const& announcements = this->announcements_[player.no()];
118   if (announcements.empty())
119     return {};
120   return announcements.back();
121 }
122 
123 /** -> result
124  **
125  ** @param    player   the player
126  **
127  ** @return   all announcements of player 'player'
128  **/
129 vector<AnnouncementWithTrickno> const&
all(Player const & player) const130 Announcements::all(Player const& player) const
131 {
132   return this->announcements_[player.no()];
133 }
134 
135 /** initializion for a new game
136  **/
137 void
init()138 Announcements::init()
139 {
140   auto const& game = *this->game_;
141   auto const& rule = game.rule();
142   auto const number_of_players = rule(Rule::Type::number_of_players_in_game);
143   this->announcements_
144     = vector<vector<AnnouncementWithTrickno>>(number_of_players);
145 }
146 
147 /** remove all announcements but re and contra
148  **/
149 void
remove_all_but_re_contra()150 Announcements::remove_all_but_re_contra()
151 {
152   auto const& game = *this->game_;
153   for (unsigned p = 0; p < game.players().size(); p++) {
154     auto const& player = game.players().player(p);
155     auto& announcements = this->announcements_[p];
156     if (announcements.size() <= 1)
157       continue;
158     if (is_reply(announcements.front().announcement)) {
159       announcements.erase(announcements.begin() + 1,
160                           announcements.end());
161       continue;
162     }
163     // the player has made an announcement
164     announcements.erase(announcements.begin() + 2,
165                         announcements.end());
166     announcements[1].announcement = Announcement::no120;
167     if (!game.isvirtual()) {
168       ::ui->announcement_made(Announcement::no120, player);
169       this->signal_announcement_made_(Announcement::no120, player);
170     }
171   } // for (p < this->playerno())
172 }
173 
174 /** request announcements from the players
175  **/
176 void
request_from_players()177 Announcements::request_from_players()
178 {
179   auto& game = *this->game_;
180   bool ask_again = true;
181 
182   while (ask_again) {
183     ask_again = false;
184 
185     // ask for announcements
186     for (auto& p : game.players()) {
187       if (this->valid_announcement(p) != Announcement::noannouncement) {
188         auto const announcement = p.announcement_request();
189         if (this->is_valid(announcement, p)) {
190           this->make_announcement(announcement, p);
191           if (this->last(p) == announcement)
192             ask_again = true;
193         } // if (this->announcement_valid(announcement, p))
194       } // if (this->valid_announcement(p))
195     } // for (p < this->playerno())
196   } // while (again)
197 } // void Announcements::request_from_players()
198 
199 /** evaluate the trick for announcements
200  **/
201 void
evaluate_trick(Trick const & trick)202 Announcements::evaluate_trick(Trick const& trick)
203 {
204   auto& game = *this->game_;
205   auto const& rule = game.rule();
206   auto const& winnerplayer = trick.winnerplayer();
207 
208   // test whether the player has to make an announcement
209   if (   (game.type() == GameType::normal)
210       && (game.tricks().current_no() == 1)
211       && (rule(Rule::Type::announcement_first_trick_thirty_points))
212       && (trick.points() >= 30)
213       && (this->last(winnerplayer.team())
214           != Announcement::no0)
215       && (    !rule(Rule::Type::announcement_first_trick_thirty_points_only_first)
216           || (   (this->last(Team::re) == Announcement::noannouncement)
217               && (this->last(Team::contra) == Announcement::noannouncement) )
218          )
219       && (   !rule(Rule::Type::announcement_first_trick_thirty_points_only_re_contra)
220           || (this->last(winnerplayer.team())
221               == Announcement::noannouncement) )
222       && (   !is_marriage(game.type())
223           || rule(Rule::Type::announcement_first_trick_thirty_points_in_marriage))
224      ) {
225     this->make_announcement(next(this->last(winnerplayer.team())), winnerplayer);
226   } // if (player must make an announcement)
227 }
228 
229 /** -> result
230  **
231  ** @param    player   player to check
232  **
233  ** @result    valid announcement for 'player'
234  **            noannouncement, if 'player' cannot announce anymore
235  **/
236 Announcement
valid_announcement(Player const & player) const237 Announcements::valid_announcement(Player const& player) const
238 {
239   if (!is_real(player.team()))
240     return Announcement::noannouncement;
241 
242   auto const opposite_announcement = this->last(opposite(player.team()));
243   if (   is_real(opposite_announcement)
244       && this->is_valid(to_reply(opposite_announcement), player))
245     return to_reply(opposite_announcement);
246 
247   if (this->is_valid(player.next_announcement(), player))
248     return player.next_announcement();
249 
250   return Announcement::noannouncement;
251 }
252 
253 
254 /** 'player' announces 'announcement'
255  **
256  ** @param    announcement   announcement made
257  ** @param    player   player who announces
258  **
259  ** @result   -
260  **/
261 void
make_announcement(Announcement announcement,Player const & player)262 Announcements::make_announcement(Announcement announcement,
263                                  Player const& player)
264 {
265   if (!is_valid(announcement, player))
266     return ;
267 #ifdef TODO
268   // when necessary, a 're' is changed to a 'reply'
269 #endif
270 
271   auto& game = *this->game_;
272   if (announcement == Announcement::reply) {
273     auto const opposite_announcement = this->last(opposite(player.team()));
274     announcement = to_reply(opposite_announcement);
275   }
276 
277   // set the announcement
278   this->announcements_[player.no()].push_back(AnnouncementWithTrickno(announcement, game.tricks().current_no()));
279   // update the team info
280   if (!game.rule()(Rule::Type::knocking))
281     game.teaminfo().set(player, player.team());
282 
283   // tell all players, that the announcement is made
284   for (auto& p : game.players())
285     p.announcement_made(announcement, player);
286 
287   game.gameplay_->gameplay_action(GameplayActions::Announcement(player.no(),
288                                                                 announcement));
289   if (!game.isvirtual()) {
290     ::ui->announcement_made(announcement, player);
291     this->signal_announcement_made_(announcement, player);
292     ::ui->gameplay_action(GameplayActions::Announcement(player.no(),
293                                                         announcement));
294     game.signal_gameplay_action_(GameplayActions::Announcement(player.no(),
295                                                                announcement));
296   }
297 } // void Announcements::make_announcement(Announcement announcement, Player player)
298 
299 /** -> result
300  **
301  ** @param    announcement   the announcement
302  ** @param    player   the player, who asks to make the announcement
303  **
304  ** @return   the announcement, if it is valid (but 'reply' for 're', if it is only allowed as reply)
305  **/
306 bool
is_valid(Announcement announcement,Player const & player) const307 Announcements::is_valid(Announcement announcement,
308                         Player const& player) const
309 {
310   auto const& game = *this->game_;
311   auto const& tricks = game.tricks();
312   auto const& rule = game.rule();
313   // test, whether status is in a game
314   if ( !::in_running_game())
315     return false;
316   if (tricks.empty())
317     return false;
318 
319   // no announcement after the 'Rule::Type::announcement_last' trick
320   if (tricks.remaining_no()
321       < (rule(Rule::Type::announcement_last)
322          + (tricks.current().isfull() ? 1 : 0))) {
323     return false;
324   }
325 
326   // as long as the marriage is not determined, no announcement is valid
327   if (   (game.marriage().selector() != MarriageSelector::team_set)
328       && (game.marriage().selector() != MarriageSelector::silent))
329     return false;
330 
331   Announcement const& last_announcement
332     = ( (   rule(Rule::Type::knocking)
333          && is_with_unknown_teams(game.type()))
334        ? this->last(player).announcement
335        : this->last(player.team()).announcement);
336 
337   if (is_reply(last_announcement)) {
338     return false;
339   }
340 
341   // change the announcement
342   if (announcement == Announcement::reply) {
343     if (!this->last(opposite(player.team())).announcement)
344       return false;
345 
346     if (   (rule(Rule::Type::announcement_strict_limit))
347         && is_real(this->last(opposite(player.team())).announcement) ) {
348       announcement = to_reply(this->last(opposite(player.team())
349                                         ).announcement);
350     } else {
351       announcement = Announcement::no120;
352       //return false;
353     }
354   } // if (announcement == Announcement::reply)
355 
356   // the announcement must be a better one
357   if (last_announcement >= announcement) {
358     return false;
359   }
360 
361   unsigned const marriage_deferral
362     = (  (   (game.type() == GameType::marriage)
363           || (game.type() == GameType::marriage_solo))
364        ? (game.marriage().determination_trickno()
365           - 1)
366        : 0);
367   // whether a normal announcement is valid
368   bool valid = (((rule(Rule::Type::announcement_till_full_trick)
369                   ? tricks.real_remaining_no()
370                   : player.hand().cardsnumber())
371                  + marriage_deferral)
372                 >= rule.remaining_cards(announcement));
373 
374   // change a 're' to a 'reply', if no futher announcement can be made
375   if (!valid && !is_reply(announcement)) {
376     if (   (announcement == Announcement::no120)
377         && !rule(Rule::Type::announcement_strict_limit))
378       announcement = Announcement::reply;
379     else
380       return false;
381   }
382 
383   if (is_reply(announcement)) {
384     if (!rule(Rule::Type::announcement_reply)) {
385       return false;
386     }
387 
388     if (last_announcement != Announcement::noannouncement) {
389       return false;
390     }
391 
392     Announcement const opposite_announcement
393       = this->last(opposite(player.team()));
394 
395     if (   (announcement != Announcement::reply)
396         && (from_reply(announcement) != opposite_announcement) ) {
397       return false;
398     }
399 
400     // till one trick after the last possible moment
401     // - I can make my announcement
402     // Remark: 'this->tricks().current_no()' can be different from
403     //         'this->trick_.size()'
404     if (((rule(Rule::Type::announcement_till_full_trick)
405           ? tricks.real_remaining_no()
406           : player.hand().cardsnumber())
407          + marriage_deferral)
408         + 1
409         >= rule.remaining_cards(opposite_announcement)) {
410       return true;
411     }
412 
413     return false;
414   } // if (announcement == Announcement::reply)
415 
416   // verify that all announcements before are valid
417   if (   !rule(Rule::Type::announcement_limit_only_for_current)
418       && (announcement > Announcement::no120)
419       && (last_announcement
420           != previous(announcement) ) ) {
421     return this->is_valid(previous(announcement), player);
422   }
423 
424   return valid;
425 } // bool Announcements::is_valid(Announcement announcement, Player player)
426 
427 /** -> result
428  **
429  ** @param    announcement   the announcement
430  ** @param    player   the player, who asks to make the announcement
431  **
432  ** @return   whether this is the last possibility to announce 'announcement'
433  **/
434 bool
last_chance_to_announce(Announcement const announcement,Player const & player) const435 Announcements::last_chance_to_announce(Announcement const announcement,
436                                        Player const& player) const
437 {
438   auto const& game = *this->game_;
439   auto const& tricks = game.tricks();
440   auto const& rule = game.rule();
441   if (!this->is_valid(announcement, player))
442     return false;
443 
444   auto const marriage_deferral = (  (game.type() == GameType::marriage)
445                                   ? (game.marriage().determination_trickno()
446                                      - 1)
447                                   : 0);
448 
449   // re as a reply
450   if (   (announcement == Announcement::no120
451           && !rule(Rule::Type::announcement_strict_limit)) ) {
452     Announcement const& opposite_announcement
453       = this->last(::opposite(player.team()));
454     if (opposite_announcement != Announcement::noannouncement)
455       return (((rule(Rule::Type::announcement_till_full_trick)
456                 ? tricks.real_remaining_no()
457                 : player.hand().cardsnumber())
458                + marriage_deferral) + 1
459               == rule.remaining_cards(opposite_announcement));
460   } // if (re as reply)
461 
462 
463   if (rule(Rule::Type::announcement_till_full_trick)) {
464     if (!tricks.current().isfull())
465       return false;
466     return (tricks.real_remaining_no()
467             + marriage_deferral
468             == rule.remaining_cards(announcement));
469   } else {
470     if (game.players().current_player() != player)
471       return false;
472     if (tricks.current().has_played(player))
473       return false;
474     return ( player.hand().cardsnumber()
475             + marriage_deferral
476             == rule.remaining_cards(announcement));
477   }
478 } // bool Announcements::last_chance_to_announce(Announcement announcement, Player player) const
479 
480 /** @return   signal, when an announcement is made
481  **/
482 Signal<void(Announcement, Player const&)>&
signal_announcement_made()483 Announcements::signal_announcement_made()
484 { return this->signal_announcement_made_; }
485 
486