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 
29 #include "constants.h"
30 #include "trick.h"
31 
32 #include "hand.h"
33 #include "../game/game.h"
34 #include "../player/player.h"
35 #include "../party/party.h"
36 #include "../party/rule.h"
37 #include "../ui/ui.h"
38 #include "../utils/string.h"
39 
40 Trick const Trick::empty = Trick();
41 
42 #define GETLINE(istr, line) \
43   std::getline(istr, line);  \
44   if (*(line.end() - 1) == '\r') \
45   line.erase(line.end() - 1)
46 
47 /** constructor
48  **
49  ** @param    startplayer   the player, who has to play the first card
50  **/
Trick(Player const & startplayer)51 Trick::Trick(Player const& startplayer) :
52   game_(&startplayer.game()),
53   no_(startplayer.game().tricks().current_no()),
54   startplayer_(startplayer.no())
55 { }
56 
57 /** constructor
58  **
59  ** @param    startplayer    the number of the startplayer
60  ** @param    cards          the cards in the trick (in order of playing)
61  ** @param    winnerplayer   the number of the winnerplayer
62  **                            default: UINT_MAX
63  **/
Trick(unsigned const startplayer,vector<Card> const & cards,unsigned const winnerplayer)64 Trick::Trick(unsigned const startplayer,
65              vector<Card> const& cards,
66              unsigned const winnerplayer) :
67   cards_(cards),
68   startplayer_(startplayer),
69   winnerplayer_(winnerplayer)
70 { }
71 
72 /** constructor
73  **
74  ** @param    istr   the stream to read the trick from
75  **/
Trick(istream & istr)76 Trick::Trick(istream& istr)
77 {
78   string line;
79   GETLINE(istr, line);
80   if (String::word_first(line) != "startplayer:")
81     return ;
82 
83   String::word_first_remove(line);
84   this->startplayer_ = static_cast<unsigned>(stoi(line));
85 
86   while (istr.good()) {
87     GETLINE(istr, line);
88     if (line.empty())
89       break;
90     if (String::word_first(line) == "winner:")
91       break;
92 
93     // the line is like: 1: club ace
94     String::word_first_remove(line);
95     String::remove_blanks(line);
96     this->cards_.push_back(HandCard(Card(line)));
97   } // while (istr.good())
98   if (line.empty()
99       || !istr.good())
100     return ;
101 
102   if (String::word_first(line) == "winner:") {
103     String::word_first_remove(line);
104     this->winnerplayer_ = static_cast<unsigned>(stoi(line));
105   } // if (String::word_first(line) == "winner:")
106 }
107 
108 /** default constructor
109  **/
110 Trick::Trick() = default;
111 
112 /** copy constructor
113  **/
114 Trick::Trick(Trick const& trick) = default;
115 
116 /** copy operator
117  **/
118 Trick&
119 Trick::operator=(Trick const& trick) = default;
120 
121 /** @return   iterator to the first card
122  **/
123 Trick::const_iterator
begin() const124 Trick::begin() const
125 { return this->cards_.begin(); }
126 
127 /** @return   iterator to the end of the cards
128  **/
129 Trick::const_iterator
end() const130 Trick::end() const
131 { return this->cards_.end(); }
132 
133 /** set the game
134  **
135  ** @param    game   new game of the trick
136  **/
137 void
set_game(Game const & game)138 Trick::set_game(Game const& game)
139 {
140   this->game_ = &game;
141   for (auto& c : this->cards_)
142     c.set_hand(game.player(c.player().no()).hand());
143 }
144 
145 /** @return   the game
146  **/
147 Game const&
game() const148 Trick::game() const
149 {
150   DEBUG_ASSERTION(this->game_,
151                   "Trick::game()\n"
152                   "  game is not set");
153   return *this->game_;
154 }
155 
156 /** @return   the cards
157  **/
158 HandCards const&
cards() const159 Trick::cards() const
160 { return this->cards_; }
161 
162 
163 /** @return   the number of the trick
164  **/
165 unsigned
no() const166 Trick::no() const
167 { return this->no_; }
168 
169 /** @return   whether the trick is in a trickpile
170  **/
171 bool
intrickpile() const172 Trick::intrickpile() const
173 { return this->intrickpile_; }
174 
175 /** self check
176  ** when an error is found, an ASSERTION is created
177  **
178  ** @return   wether the self-check was successful (no error)
179  **/
180 bool
self_check() const181 Trick::self_check() const
182 {
183   DEBUG_ASSERTION(this->game_,
184                   "Trick::self_check()\n"
185                   "  no game");
186 
187   DEBUG_ASSERTION((this->no_ <= this->game_->tricks().current_no()),
188                   "Trick::self_check()\n"
189                   "  number not valid: " << this->no_);
190 
191   DEBUG_ASSERTION((this == &this->game_->tricks().trick(this->no_)),
192                   "Trick::self_check()\n"
193                   "  Not the trick the number says to be");
194 
195   DEBUG_ASSERTION(this->startplayerno() != UINT_MAX,
196                   "Trick::self_check()\n"
197                   "  no startplayer");
198 
199   DEBUG_ASSERTION((!this->intrickpile_
200                    || (this->winnerplayerno() != UINT_MAX)),
201                   "Trick::self_check()\n"
202                   "  in trickpile but no winnerplayer");
203 
204   return true;
205 }
206 
207 /** output of the trick
208  **
209  ** @param    ostr   output stream
210  ** @param    trick   Trick to be put in the output stream
211  **
212  ** @return   output stream
213  **/
214 ostream&
operator <<(ostream & ostr,Trick const & trick)215 operator<<(ostream& ostr, Trick const& trick)
216 {
217   ostr << "startplayer: " << trick.startplayerno() << "\n";
218   for(unsigned i = 0; i < trick.actcardno(); i++) {
219     ostr
220       << (trick.game_
221           ? trick.playerno_of_card(i)
222           : (trick.startplayerno() + i))
223       << ": "
224       << trick.card(i) << "\n";
225   }
226 
227   if (trick.isfull())
228     ostr << "winner: " << trick.winnerplayerno() << "\n";
229 
230   return ostr;
231 }
232 
233 /** adds the card 'c' to the trick
234  **
235  ** @param    card   card, which should be added to this trick
236  **
237  ** @return   trick with c as last card
238  **/
239 void
add(HandCard const card)240 Trick::add(HandCard const card)
241 {
242   DEBUG_ASSERTION(!card.is_empty(),
243                   "Trick::operator+=(HandCard):\n"
244                   "  shall add empty card to the trick");
245 
246   DEBUG_ASSERTION(   !this->game_
247                   || !this->isfull(),
248                   "Trick::operator+=(HandCard):\n"
249                   "  trick is already full");
250 
251   DEBUG_ASSERTION((   !this->game_
252                    || (&card.player() == &this->actplayer())),
253                   "Trick::operator+=(HandCard):\n"
254                   "  Card is from the wrong player "
255                   << card.player().no()
256                   << " (should be " << this->actplayer().no() << ")\n"
257                   "  Pointer: " << &card.player() << " != "
258                   << &this->actplayer());
259 
260   if (this->game_) {
261     // update the winnerplayer
262     if (this->isstartcard()) {
263       this->winnerplayer_ = this->startplayer_;
264     } else {
265       if (this->winnercard().less(card)) {
266         this->winnerplayer_ = this->actplayer().no();
267       }
268     } // if !(this->isstartcard())
269   } // if (this->game_)
270 
271   // add the card to the trick
272   this->cards_.push_back(card);
273 }
274 
275 /** -> result
276  **
277  ** @param    c   number of card
278  **
279  ** @return   the trick till the given card
280  **/
281 Trick
till_card(unsigned const c) const282 Trick::till_card(unsigned const c) const
283 {
284   DEBUG_ASSERTION((c <= this->actcardno()),
285                   "Trick::till_card(" << c << ")\n"
286                   "  the trick contains only " << this->actcardno() << " cards");
287 
288   Trick t(this->startplayer());
289   for (unsigned i = 0; i <= c; ++i)
290     t.add(this->card(i));
291 
292   return t;
293 }
294 
295 /** -> result
296  **
297  ** @param    player   player
298  **
299  ** @return   the trick till the given player
300  **/
301 Trick
till_player(Player const & player) const302 Trick::till_player(Player const& player) const
303 {
304   DEBUG_ASSERTION(this->has_played(player),
305                   "Trick::till_player(" << player.no() << ")\n"
306                   "  the player has not played so far");
307 
308   Trick t(this->startplayer());
309   auto const n = this->cardno_of_player(player);
310   for (unsigned i = 0; i <= n; ++i)
311     t.add(this->card(i));
312 
313   return t;
314 }
315 
316 /** -> result
317  **
318  ** @param    player   player
319  **
320  ** @return   the trick till before the given player
321  **/
322 Trick
before_player(Player const & player) const323 Trick::before_player(Player const& player) const
324 {
325   DEBUG_ASSERTION(this->has_played(player),
326                   "Trick::before_player(" << player.no() << ")\n"
327                   "  the player has not played so far");
328 
329   Trick t(this->startplayer());
330   auto const n = this->cardno_of_player(player);
331   for (unsigned i = 0; i < n; ++i)
332     t.add(this->card(i));
333 
334   return t;
335 }
336 
337 /** @return   the trick without the last played card
338  **/
339 Trick
before_last_played_card() const340 Trick::before_last_played_card() const
341 {
342   DEBUG_ASSERTION(!this->isempty(),
343                   "Trick::before_before_last_played_card()\n"
344                   "  the trick is empty");
345 
346   Trick t(this->startplayer());
347   for (unsigned i = 0; i + 1 < this->actcardno(); ++i)
348     t.add(this->card(i));
349 
350   return t;
351 }
352 
353 /** -> result
354  **
355  ** @param    c   number of card for the result
356  **
357  ** @return   card c of actual trick
358  **/
359 HandCard
card(unsigned const c) const360 Trick::card(unsigned const c) const
361 {
362   DEBUG_ASSERTION((c < this->actcardno()),
363                   "Trick::card(c):\n"
364                   "  'c' is to great (" << c << ">=" << this->actcardno()
365                   << ")");
366 
367   return this->cards_[c];
368 }
369 
370 /** -> result
371  **
372  ** @param    player   player whose card is returned
373  **
374  ** @return   card of 'player' of actual trick
375  **/
376 HandCard
card_of_player(Player const & player) const377 Trick::card_of_player(Player const& player) const
378 {
379   return ((player.no() >= this->startplayerno())
380           ? this->card(player.no()
381                        - this->startplayerno())
382           : this->card(player.no()
383                        + this->game().playerno()
384                        - this->startplayerno())
385          );
386 }
387 
388 /** -> result
389  **
390  ** @param    c   number of card for the result
391  **
392  ** @return   the player, who has played the 'c'th card
393  **/
394 Player const&
player_of_card(unsigned const c) const395 Trick::player_of_card(unsigned const c) const
396 {
397   return this->game().player(this->playerno_of_card(c));
398 }
399 
400 /** -> result
401  **
402  ** @param    c   number of card for the result
403  **
404  ** @return   the nubmer of the player, who has played the 'c'th card
405  **/
406 unsigned
playerno_of_card(unsigned const c) const407 Trick::playerno_of_card(unsigned const c) const
408 {
409   return ((this->startplayerno() + c
410            < this->game().playerno())
411           ? (c + this->startplayerno())
412           : (c + this->startplayerno()
413              - this->game().playerno())
414          );
415 }
416 
417 /** -> result
418  **
419  ** @param    player   player, whose cardno is returnes
420  **
421  ** @return   the number of the card, the player has played
422  **/
423 unsigned
cardno_of_player(Player const & player) const424 Trick::cardno_of_player(Player const& player) const
425 {
426   return ((this->startplayerno()
427            <= player.no())
428           ? (player.no() - this->startplayerno())
429           : (player.no()
430              + this->game().playerno()
431              - this->startplayerno())
432          );
433 }
434 
435 /** -> result
436  **
437  ** @param    player   player to check
438  **
439  ** @return   whether the player has already played a card
440  **/
441 bool
has_played(Player const & player) const442 Trick::has_played(Player const& player) const
443 {
444   return (this->cardno_of_player(player) < this->actcardno());
445 }
446 
447 /** -> result
448  **
449  ** @param    card   card to check
450  **
451  ** @return   whether the card is in the trick
452  **/
453 bool
contains(Card const card) const454 Trick::contains(Card const card) const
455 {
456   return (find(this->cards_, card) != this->cards_.end());
457 }
458 
459 /** @return   whether the trick contains a trump
460  **/
461 bool
contains_trump() const462 Trick::contains_trump() const
463 {
464   return (find_if(this->cards_,
465                   [](auto const& card)
466                   { return card.istrump();
467                   })
468           != this->cards_.end());
469 }
470 
471 /** @return   whether the trick contains a fox
472  **/
473 bool
contains_fox() const474 Trick::contains_fox() const
475 {
476   return (find_if(this->cards_,
477                   [](auto const& card)
478                   { return card.isfox();
479                   })
480           != this->cards_.end());
481 }
482 
483 /** -> result
484  **
485  ** @param    game    corresponding game
486  **
487  ** @return   whether the trick contains a possible extrapoint
488  **/
489 bool
contains_possible_extrapoint(Game const & game) const490 Trick::contains_possible_extrapoint(Game const& game) const
491 {
492   if (game.is_solo())
493     return false;
494 
495   auto const& rule = game.rule();
496   auto const is_last_trick = game.tricks().is_last_trick();
497 
498   if (   rule(Rule::Type::extrapoint_catch_fox)
499       && this->contains(Card::fox)
500       && !this->game().swines().swines_announced())
501     return true;
502   if (   rule(Rule::Type::extrapoint_fox_last_trick)
503       && is_last_trick
504       && this->winnercard().isfox())
505     return true;
506   if (   rule(Rule::Type::extrapoint_catch_fox_last_trick)
507       && is_last_trick
508       && this->contains(Card::fox) )
509     return true;
510   if (   rule(Rule::Type::extrapoint_charlie)
511       && is_last_trick
512       && (this->winnercard() == Card::charlie) )
513     return true;
514   if (   rule(Rule::Type::extrapoint_catch_charlie)
515       && is_last_trick
516       && this->contains(Card::charlie) )
517     return true;
518   if (   rule(Rule::Type::extrapoint_dulle_jabs_dulle)
519       && (this->winnercard() == Card::dulle) )
520     return true;
521   if (rule(Rule::Type::extrapoint_heart_trick)) {
522     unsigned c = 0;
523     for (c = 0; c < this->actcardno(); c++)
524       if (this->card(c).tcolor() != Card::heart)
525         break;
526     if (c == this->actcardno())
527       return true;
528   }
529 
530   return false;
531 }
532 
533 /** @return   the number of the startplayer
534  **/
535 unsigned
startplayerno() const536 Trick::startplayerno() const
537 {
538   return this->startplayer_;
539 }
540 
541 /** @return   the startplayer
542  **/
543 Player const&
startplayer() const544 Trick::startplayer() const
545 {
546   DEBUG_ASSERTION(this->startplayerno() != UINT_MAX,
547                   "Trick::startplayer():\n"
548                   "  startplayerno() == NULL != UINT_MAX");
549 
550   return this->game().player(this->startplayerno());
551 }
552 
553 /** @return   the last player
554  **/
555 Player const&
lastplayer() const556 Trick::lastplayer() const
557 {
558   DEBUG_ASSERTION(this->startplayerno() != UINT_MAX,
559                   "Trick::lastplayer():\n"
560                   "  startplayerno() == N != UINT_MAX");
561 
562   return this->game().player((this->startplayerno()
563                               + this->game().playerno() - 1)
564                              % this->game().playerno());
565 }
566 
567 /** @return   the last player
568  **/
569 Player const&
secondlastplayer() const570 Trick::secondlastplayer() const
571 {
572   DEBUG_ASSERTION(this->startplayerno() != UINT_MAX,
573                   "Trick::secondlastplayer():\n"
574                   "  startplayerno() == N != UINT_MAX");
575 
576   return this->game().player((this->startplayerno()
577                               + this->game().playerno() - 2)
578                              % this->game().playerno());
579 }
580 
581 /** @return the remaining players
582  **/
583 vector<std::reference_wrapper<Player const>>
remaining_players() const584 Trick::remaining_players() const
585 {
586   auto const playerno = this->game().playerno();
587   vector<std::reference_wrapper<Player const>> players;
588   for (auto i = this->actcardno(); i < playerno; ++i) {
589     players.emplace_back(std::ref(this->player_of_card(i)));
590   }
591   return players;
592 }
593 
594 /** set the startplayer
595  **
596  ** @param    startplayer   new startplayer
597  **
598  ** @return   the startplayer
599  **/
600 void
set_startplayer(Player const & startplayer)601 Trick::set_startplayer(Player const& startplayer)
602 {
603   DEBUG_ASSERTION(this->startplayerno() == UINT_MAX,
604                   "Trick::startplayer_set(startplayer):\n"
605                   "  startplayer already set");
606 
607   this->startplayer_ = startplayer.no();
608 }
609 
610 /** set the startplayer
611  **
612  ** @param    startplayerno   number of new startplayer
613  **
614  ** @return   the startplayer
615  **/
616 void
set_startplayer(unsigned const startplayerno)617 Trick::set_startplayer(unsigned const startplayerno)
618 {
619   DEBUG_ASSERTION(this->startplayerno() == UINT_MAX,
620                   "Trick::startplayer_set(startplayer):\n"
621                   "  startplayer already set");
622 
623   this->startplayer_ = startplayerno;
624 }
625 
626 /** @return   the startcard
627  **/
628 HandCard
startcard() const629 Trick::startcard() const
630 {
631   DEBUG_ASSERTION(!this->isstartcard(),
632                   "Trick::startcard():\n"
633                   "  trick is empty");
634 
635   return this->cards_[0];
636 }
637 
638 /** @return   whether the trick is empty
639  **/
640 bool
isstartcard() const641 Trick::isstartcard() const
642 {
643   return this->cards_.empty();
644 }
645 
646 /** @return   whether the trick is empty
647  **/
648 bool
isempty() const649 Trick::isempty() const
650 {
651   return this->cards_.empty();
652 }
653 
654 /** @return   whether the trick is full
655  **/
656 bool
isfull() const657 Trick::isfull() const
658 {
659   if (!this->game_)
660     return true;
661   return (this->remainingcardno() == 0);
662 }
663 
664 /** @return   whether the trick lacks only one card
665  **/
666 bool
islastcard() const667 Trick::islastcard() const
668 {
669   return (this->remainingcardno() == 1);
670 }
671 
672 /** moves the trick in the trickpile
673  **
674  ** @bug   const cast
675  **/
676 void
move_in_trickpile()677 Trick::move_in_trickpile()
678 {
679   // Bug: const cast
680   const_cast<Player&>(this->winnerplayer()).move_in_trickpile(*this);
681 
682   this->intrickpile_ = true;
683 
684   if (!this->game().isvirtual())
685     ::ui->trick_move_in_pile();
686 }
687 
688 /** @return   the number of the acting card
689  **   (that is, how many cards there are in the tricks)
690  **/
691 unsigned
actcardno() const692 Trick::actcardno() const
693 {
694   return this->cards_.size();
695 }
696 
697 /** @return   the number of remaining cards to play in the trick
698  **/
699 unsigned
remainingcardno() const700 Trick::remainingcardno() const
701 {
702   return (this->game().playerno() - this->actcardno());
703 }
704 
705 /** @return   the acting player
706  **/
707 Player const&
actplayer() const708 Trick::actplayer() const
709 {
710   return this->game().player(this->actplayerno());
711 }
712 
713 /** @return   the acting player number
714  **/
715 unsigned
actplayerno() const716 Trick::actplayerno() const
717 {
718   return ((this->startplayerno() + this->actcardno())
719           % this->game().playerno());
720 }
721 
722 /** @return   the points in the trick
723  **/
724 unsigned
points() const725 Trick::points() const
726 {
727   unsigned points = 0;
728   for (auto const& c : this->cards_)
729     points += (c.is_unknown() ? 0 : c.points());
730   return points;
731 }
732 
733 /** -> result
734  **
735  ** @param    card   card which is checked
736  **
737  ** @return   whether it is valid to play 'card' with its hand
738  **/
739 bool
isvalid(HandCard const & card) const740 Trick::isvalid(HandCard const& card) const
741 {
742   return card.isvalid(*this);
743 }
744 
745 /** -> result
746  **
747  ** @param    card   card which is checked
748  ** @param    hand   hand of the card
749  **
750  ** @return   whether it is valid to play 'card' with the hand 'hand'
751  **/
752 bool
isvalid(Card const card,Hand const & hand) const753 Trick::isvalid(Card const card, Hand const& hand) const
754 {
755   return this->isvalid(HandCard(hand, card));
756 }
757 
758 /** @return   the number of the winnerplayer
759  **/
760 unsigned
winnerplayerno() const761 Trick::winnerplayerno() const
762 {
763   return this->winnerplayer_;
764 }
765 
766 /** @return   the player which wins this trick
767  **/
768 Player const&
winnerplayer() const769 Trick::winnerplayer() const
770 {
771   // for Game::numberoftricks_of_player()
772   if (this->winnerplayer_ == UINT_MAX)
773     return this->startplayer();
774 
775   DEBUG_ASSERTION(this->winnerplayer_ != UINT_MAX,
776                   "Trick::winnerplayer():\n"
777                   "  winnerplayerno() == UINT_MAX");
778 
779   return this->game().player(this->winnerplayer_);
780 }
781 
782 /** @return   the team which wins the trick
783  **/
784 Team
winnerteam() const785 Trick::winnerteam() const
786 {
787   return this->winnerplayer().team();
788 }
789 
790 /** @return   card that `makes` the trick
791  **/
792 HandCard
winnercard() const793 Trick::winnercard() const
794 {
795   if (this->isempty())
796     return {};
797 
798   return this->card_of_player(this->winnerplayer());
799 }
800 
801 /** @return   cardno that `makes` the trick
802  **/
803 unsigned
winnercardno() const804 Trick::winnercardno() const
805 {
806   return this->cardno_of_player(this->winnerplayer());
807 }
808 
809 /** @return   card which wins the trick without taking the last card played into account
810  **/
811 HandCard
winnercard_before() const812 Trick::winnercard_before() const
813 {
814   if (this->actcardno() <= 1)
815     return {};
816 
817   auto winnercard = this->card(0);
818   for (unsigned c = 1; c < this->actcardno() - 1; ++c)
819     if (winnercard.less(this->card(c)))
820       winnercard = this->card(c);
821 
822   return winnercard;
823 }
824 
825 /** -> result
826  **
827  ** @param    cardno   card to analyse
828  **
829  ** @return   whether the card jabs the cards before
830  **/
831 bool
jabs_cards_before(unsigned const cardno) const832 Trick::jabs_cards_before(unsigned const cardno) const
833 {
834   DEBUG_ASSERTION(cardno < this->actcardno(),
835                   "Trick::jabs_cards_before(cardno = " << cardno << ")\n"
836                   "  Card is not played, yet.\n"
837                   "  Trick:\n" << *this);
838 
839   auto const& card = this->card(cardno);
840   for (unsigned c = 0; c < cardno; ++c)
841     if (!this->card(c).less(card))
842       return false;
843 
844   return true;
845 }
846 
847 /** -> result
848  **
849  ** @param    player   player to analyse
850  **
851  ** @return   whether the player jabs the cards before
852  **/
853 bool
jabs_cards_before(Player const & player) const854 Trick::jabs_cards_before(Player const& player) const
855 {
856   DEBUG_ASSERTION(this->has_played(player),
857                   "Trick::jabs_cards_before(player = " << player.no() << ")\n"
858                   "  Player has not played, yet.\n"
859                   "  Trick:\n" << *this);
860 
861   return -this->jabs_cards_before(this->cardno_of_player(player));
862 }
863 
864 /** @return   whether this is the last trick in the game
865  **/
866 bool
islast() const867 Trick::islast() const
868 {
869   return (this->no() == this->game().tricks().max_size() - 1);
870 }
871 
872 /** -> result
873  **
874  ** @param    card   card to test
875  **
876  ** @return   whether the trick will be jabbed by this card
877  **/
878 bool
isjabbed(Card const card) const879 Trick::isjabbed(Card const card) const
880 {
881   if (this->isempty())
882     return true;
883   else
884     return this->winnercard().less(card);
885 }
886 
887 /** -> result
888  ** take possible special cards into account (p.e. swines, that are not announced)
889  **
890  ** @param    card   card to test
891  **
892  ** @return   whether the trick will be jabbed by this card
893  **/
894 bool
isjabbed(HandCard const card) const895 Trick::isjabbed(HandCard const card) const
896 {
897   if (this->isempty())
898     return true;
899   else {
900     if (card.possible_hyperswine())
901       return true;
902     else if (card.possible_swine())
903       return !this->winnercard().ishyperswine();
904     else
905       return this->winnercard().less(card);
906   }
907 }
908 
909 /** -> result
910  ** take possible special cards into account (p.e. swines, that are not announced)
911  **
912  ** @param    card   card to test
913  ** @param    hand   corresponding hand
914  **
915  ** @return   whether the trick will be jabbed by this card
916  **/
917 bool
isjabbed(Card const card,Hand const & hand) const918 Trick::isjabbed(Card const card, Hand const& hand) const
919 {
920   return this->isjabbed(HandCard(hand, card));
921 }
922 
923 /** -> result
924  **
925  ** @param    lhs   number of the first card
926  ** @param    rhs   number of the second card
927  **
928  ** @return   whether the first card is less than the second card in this trick
929  **/
930 bool
less(unsigned const lhs,unsigned rhs) const931 Trick::less(unsigned const lhs, unsigned rhs) const
932 {
933   DEBUG_ASSERTION(   (lhs < this->actcardno())
934                   && (rhs < this->actcardno()),
935                   "Trick::less(" << lhs << ", " << rhs << ")\n"
936                   "  one cardno is less than the actcardno " << this->actcardno()
937                  );
938   if (lhs == rhs)
939     return false;
940   else if (lhs < rhs)
941     return this->card(lhs).less(this->card(rhs));
942   else
943     return !this->card(rhs).less(this->card(lhs));
944 }
945 
946 /** comparison of two tricks
947  **
948  ** @param    lhs   first trick to compare
949  ** @param    rhs   second trick to compare
950  **
951  ** @return   whether the tricks are equal
952  **/
953 bool
operator ==(Trick const & lhs,Trick const & rhs)954 operator==(Trick const& lhs, Trick const& rhs)
955 {
956   if ((lhs.startplayerno() != rhs.startplayerno())
957       || (lhs.actcardno() != rhs.actcardno()))
958     return false;
959 
960   for (unsigned c = 0; c < lhs.actcardno(); c++)
961     if (lhs.card(c) != rhs.card(c))
962       return false;
963 
964   return (lhs.winnerplayerno() == rhs.winnerplayerno());
965 }
966 
967 /** comparison of two tricks
968  **
969  ** @param    lhs   first trick to compare
970  ** @param    rhs   second trick to compare
971  **
972  ** @return   whether the tricks are different
973  **/
974 bool
operator !=(Trick const & lhs,Trick const & rhs)975 operator!=(Trick const& lhs, Trick const& rhs)
976 {
977   return !(lhs == rhs);
978 }
979 
980 /** counts all points witch are turned on in rules and determines
981  ** team which has won this point.
982  ** takes all information from the game the trick belongs to.
983  **
984  ** @return   a vector with names of specialpoints and type of them
985  **   for solo games return value is an empty vector
986  **/
987 Specialpoints
specialpoints() const988 Trick::specialpoints() const
989 {
990   vector<Team> teams;
991 
992   for (auto const& p : this->game().players())
993     teams.push_back(this->game().teaminfo().get(p));
994 
995   return this->specialpoints(teams);
996 }
997 
998 /** counts all points witch are turned on in rules and determines
999  ** team which has won this point
1000  **
1001  ** @param    teams   the teams of the players
1002  **
1003  ** @return   a vector with names of specialpoints and type of them
1004  **   for solo games return value is an empty vector
1005  **/
1006 Specialpoints
specialpoints(vector<Team> const & teams) const1007 Trick::specialpoints(vector<Team> const& teams) const
1008 {
1009   Specialpoints sp;
1010 
1011   Team const local_winnerteam
1012     = ( (  (teams[this->winnerplayerno()] != Team::unknown)
1013          ? teams[this->winnerplayerno()]
1014          : Team::noteam) );
1015 
1016   auto const& rule = this->game().rule();
1017 
1018   // if this game is a solo there are no specialpoints
1019   if (   is_solo(this->game().type())
1020       && !(   (this->game().type() == GameType::marriage_solo)
1021            && (this->no() < this->game().marriage().determination_trickno()) ) )
1022     return sp;
1023 
1024   bool dulle_caught = false;
1025 
1026   // doppelkopf
1027   if (this->points() >= rule(Rule::Type::points_for_doppelkopf)) {
1028     Specialpoint s(Specialpoint::Type::doppelkopf, local_winnerteam);
1029     s.player_get_no = this->winnerplayerno();
1030     sp.push_back(s);
1031   } // if (this->points() >= rule(Rule::Type::points_for_doppelkopf))
1032 
1033 
1034   bool fl_caught_charlie=false;
1035   for (unsigned i = 0; i < this->actcardno(); i++) {
1036     // the card belongs to the winner team
1037     if (   ::is_real(local_winnerteam)
1038         && (local_winnerteam == teams[this->playerno_of_card(i)]) )
1039       continue;
1040 
1041     // fox caught
1042     if (   this->card(i).isfox()
1043         && rule(Rule::Type::extrapoint_catch_fox)
1044         && (this->winnerplayerno() != this->playerno_of_card(i))) {
1045       Specialpoint s(Specialpoint::Type::caught_fox, local_winnerteam);
1046       s.player_get_no = this->winnerplayerno();
1047       s.player_of_no = this->playerno_of_card(i);
1048 
1049       sp.push_back(s);
1050 
1051       if (this->islast()
1052           && rule(Rule::Type::extrapoint_catch_fox_last_trick)) {
1053         Specialpoint s(Specialpoint::Type::caught_fox_last_trick, local_winnerteam);
1054         s.player_get_no = this->winnerplayerno();
1055         s.player_of_no = this->playerno_of_card(i);
1056 
1057         sp.push_back(s);
1058       }
1059     }
1060 
1061     // Charlie caught
1062     if (this->islast()
1063         && (card(i) == Card::charlie)
1064         && !fl_caught_charlie
1065         && rule(Rule::Type::extrapoint_catch_charlie)
1066         && (!rule(Rule::Type::extrapoint_catch_charlie_only_with_diamond_queen)
1067             || (this->winnercard() == Card::diamond_queen) )
1068         && (local_winnerteam != teams[this->playerno_of_card(i)])) {
1069 
1070       fl_caught_charlie=true;
1071 
1072       Specialpoint s(Specialpoint::Type::caught_charlie, local_winnerteam);
1073       s.player_get_no = this->winnerplayerno();
1074       s.player_of_no = this->playerno_of_card(i);
1075       sp.push_back(s);
1076       // check for double charlies caught
1077       if (rule(Rule::Type::extrapoint_catch_double_charlie))
1078         for (unsigned n = i + 1; n < actcardno(); ++n) {
1079           if (   (card(n) == Card::charlie)
1080               && (teams[this->playerno_of_card(n)] != s.team) ) {
1081             Specialpoint s(Specialpoint::Type::caught_charlie,
1082                            local_winnerteam);
1083             s.player_get_no = this->winnerplayerno();
1084             s.player_of_no = this->playerno_of_card(n);
1085             sp.push_back(s);
1086           }
1087         }
1088     } // if (charlie caught)
1089 
1090     // dulle caught
1091     dulle_caught |= this->card(i).isdulle();
1092 
1093   } // for (i < this->actcardno())
1094 
1095   if (rule(Rule::Type::extrapoint_dulle_jabs_dulle)
1096       && dulle_caught
1097       && (winnercard() == Card::dulle)) {
1098     for (unsigned c = 0; c < this->actcardno(); c++) {
1099       if (   (c != this->winnercardno())
1100           && (this->card(c) == Card::dulle)
1101           && (local_winnerteam != teams[this->playerno_of_card(c)]) ) {
1102         Specialpoint s(Specialpoint::Type::dulle_caught_dulle,
1103                        local_winnerteam);
1104         s.player_get_no = this->winnerplayerno();
1105         s.player_of_no = this->playerno_of_card(c);
1106 
1107         sp.push_back(s);
1108       } // if (dulle caught of opposite team)
1109     } // for (c)
1110   } // if (dulle caught)
1111 
1112   if (rule(Rule::Type::extrapoint_heart_trick)
1113       && (is_normal(this->game().type()))
1114       && (this->winnercard().tcolor() == Card::heart)) {
1115     unsigned c;
1116     for (c = 0; c < this->actcardno(); ++c)
1117       if (this->card(c).tcolor() != Card::heart)
1118         break;
1119     if (c == this->actcardno()) {
1120       Specialpoint s(Specialpoint::Type::heart_trick,
1121                      local_winnerteam);
1122       s.player_get_no = this->winnerplayerno();
1123 
1124       sp.push_back(s);
1125     }
1126   } // if (heart trick)
1127 
1128   // check for foxes who are winning the last trick
1129   if (   this->islast()
1130       && (winnercard().isfox())
1131       && rule(Rule::Type::extrapoint_fox_last_trick)) {
1132 
1133     Specialpoint s(Specialpoint::Type::fox_last_trick,
1134                    local_winnerteam);
1135     s.player_get_no = this->winnerplayerno();
1136     //s.player_of_no = this->winnerplayerno();
1137     sp.push_back(s);
1138 
1139     // check for double fox winning
1140     if (rule(Rule::Type::extrapoint_double_fox_last_trick))
1141       for (unsigned n=winnercardno()+1; n<actcardno(); n++)
1142       {
1143         if(card(n).isfox() &&
1144            teams[this->playerno_of_card(n)]==s.team) {
1145           Specialpoint s(Specialpoint::Type::fox_last_trick,
1146                          local_winnerteam);
1147           s.player_get_no = this->winnerplayerno();
1148           //s.player_of_no = this->playerno_of_card(n);
1149           sp.push_back(s);
1150         }
1151       }
1152   }
1153 
1154   // check for charlies in lasttrick
1155   if (this->islast()) {
1156     if ((winnercard()==Card::charlie)
1157         && rule(Rule::Type::extrapoint_charlie))
1158     {
1159       Specialpoint s(Specialpoint::Type::charlie,
1160                      local_winnerteam);
1161 
1162       s.player_get_no = this->winnerplayerno();
1163       //s.player_of_no = this->winnerplayerno();
1164       sp.push_back(s);
1165 
1166       // check for double charlies
1167       if (rule(Rule::Type::extrapoint_double_charlie))
1168         for (unsigned n=winnercardno()+1; n<actcardno(); n++)
1169         {
1170           if(card(n)==Card::charlie &&
1171              teams[this->playerno_of_card(n)]==s.team)
1172           {
1173             Specialpoint s(Specialpoint::Type::charlie,
1174                            local_winnerteam);
1175             s.player_get_no = this->winnerplayerno();
1176             //s.player_of_no = this->playerno_of_card(n);
1177 
1178             sp.push_back(s);
1179           }
1180         }
1181     } // if (charlie)
1182   }
1183 
1184   return sp;
1185 }
1186 
1187 /** @return   a vector with the cards that made a specialpoint
1188  **/
1189 HandCards
specialpoints_cards() const1190 Trick::specialpoints_cards() const
1191 {
1192   auto const spv = this->specialpoints();
1193 
1194   HandCards cards;
1195 
1196   for (auto sp : this->specialpoints()) {
1197     switch (sp.type) {
1198     case Specialpoint::Type::nospecialpoint:
1199       break;
1200     case Specialpoint::Type::caught_fox:
1201     case Specialpoint::Type::caught_fox_last_trick:
1202       for (auto const& c : this->cards_) {
1203         if (c.istrumpace()) {
1204           cards.push_back(c);
1205           break;
1206         }
1207       }
1208       break;
1209     case Specialpoint::Type::fox_last_trick:
1210       cards.push_back(this->winnercard());
1211       break;
1212     case Specialpoint::Type::charlie:
1213       cards.push_back(this->winnercard());
1214       break;
1215     case Specialpoint::Type::caught_charlie:
1216       for (auto const& c : this->cards_) {
1217         if (c == Card::charlie) {
1218           cards.push_back(c);
1219           break;
1220         }
1221       }
1222       break;
1223     case Specialpoint::Type::dulle_caught_dulle:
1224       for (auto c = this->cards_.rbegin();
1225            c != this->cards_.rend();
1226            ++c)
1227         if (*c == Card::dulle) {
1228           cards.push_back(*c);
1229           break;
1230         }
1231       break;
1232     case Specialpoint::Type::heart_trick:
1233       cards.push_back(this->winnercard());
1234       break;
1235     case Specialpoint::Type::doppelkopf:
1236       // check for confusing winnercard
1237       if (   !this->winnercard().istrumpace()
1238           && (this->winnercard() != Card::dulle)) {
1239         cards.push_back(this->winnercard());
1240         break;
1241       }
1242       { // search better card
1243         HandCards::const_iterator c;
1244         for (c = this->cards_.begin();
1245              c != this->cards_.end();
1246              ++c) {
1247           if (   !c->istrumpace()
1248               && (*c != Card::dulle)) {
1249             cards.push_back(*c);
1250             break;
1251           }
1252         } // for (c \in this->cards_)
1253         if (c != this->cards_.end())
1254           break;
1255       } // search better card
1256 
1257       // found no better card -- taking winnercard
1258       cards.push_back(this->winnercard());
1259       break;
1260     case Specialpoint::Type::won:
1261     case Specialpoint::Type::no90:
1262     case Specialpoint::Type::no60:
1263     case Specialpoint::Type::no30:
1264     case Specialpoint::Type::no0:
1265     case Specialpoint::Type::no120_said:
1266     case Specialpoint::Type::no90_said:
1267     case Specialpoint::Type::no60_said:
1268     case Specialpoint::Type::no30_said:
1269     case Specialpoint::Type::no0_said:
1270     case Specialpoint::Type::no90_said_120_got:
1271     case Specialpoint::Type::no60_said_90_got:
1272     case Specialpoint::Type::no30_said_60_got:
1273     case Specialpoint::Type::no0_said_30_got:
1274     case Specialpoint::Type::no120_reply:
1275     case Specialpoint::Type::no90_reply:
1276     case Specialpoint::Type::no60_reply:
1277     case Specialpoint::Type::no30_reply:
1278     case Specialpoint::Type::no0_reply:
1279     case Specialpoint::Type::contra_won:
1280     case Specialpoint::Type::solo:
1281     case Specialpoint::Type::bock:
1282       break;
1283     } // switch (sp.type)
1284   } // for (sp : spv)
1285 
1286   return cards;
1287 }
1288 
1289 /** @return   c   cardnumber of actual trick
1290  **
1291  ** @return   whether this is a specialpoints card
1292  **/
1293 bool
is_specialpoints_card(unsigned const c) const1294 Trick::is_specialpoints_card(unsigned const c) const
1295 {
1296   DEBUG_ASSERTION((c < this->actcardno()),
1297                   "Trick::is_specialpoints_card(c):\n"
1298                   "  'c' is to great (" << c << ">=" << this->actcardno()
1299                   << ")");
1300 
1301   auto const playerno = this->playerno_of_card(c);
1302   for (auto const& sp_card : this->specialpoints_cards()) {
1303     if (sp_card.player().no() == playerno)
1304       return true;
1305   } // for (sp_card : sp_cards)
1306 
1307   return false;
1308 }
1309