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