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 "card.h"
30
31 #include "hand_card.h"
32 #include "../game/game.h"
33 #include "../party/rule.h"
34
35 Card const Card::empty{};
36 Card const Card::unknown(Card::unknowncardcolor, Card::unknowncardvalue);
37 Card const Card::fox(Card::diamond, Card::ace);
38 Card const Card::dulle(Card::heart, Card::ten);
39 Card const Card::charlie(Card::club, Card::jack);
40 Card const Card::club_ace(Card::club, Card::ace);
41 Card const Card::spade_ace(Card::spade, Card::ace);
42 Card const Card::heart_ace(Card::heart, Card::ace);
43 Card const Card::diamond_ace(Card::diamond, Card::ace);
44 Card const Card::club_ten(Card::club, Card::ten);
45 Card const Card::spade_ten(Card::spade, Card::ten);
46 Card const Card::heart_ten(Card::heart, Card::ten);
47 Card const Card::diamond_ten(Card::diamond, Card::ten);
48 Card const Card::club_king(Card::club, Card::king);
49 Card const Card::spade_king(Card::spade, Card::king);
50 Card const Card::heart_king(Card::heart, Card::king);
51 Card const Card::diamond_king(Card::diamond, Card::king);
52 Card const Card::club_queen(Card::club, Card::queen);
53 Card const Card::spade_queen(Card::spade, Card::queen);
54 Card const Card::heart_queen(Card::heart, Card::queen);
55 Card const Card::diamond_queen(Card::diamond, Card::queen);
56 Card const Card::club_jack(Card::club, Card::jack);
57 Card const Card::spade_jack(Card::spade, Card::jack);
58 Card const Card::heart_jack(Card::heart, Card::jack);
59 Card const Card::diamond_jack(Card::diamond, Card::jack);
60 Card const Card::club_nine(Card::club, Card::nine);
61 Card const Card::spade_nine(Card::spade, Card::nine);
62 Card const Card::heart_nine(Card::heart, Card::nine);
63 Card const Card::diamond_nine(Card::diamond, Card::nine);
64
65 /** -> result
66 **
67 ** @param color_name name of the color
68 **
69 ** @return color 'name'
70 **/
71 Card::Color
color(string const & color_name)72 Card::color(string const& color_name)
73 {
74 if (color_name == to_string(Card::club))
75 return Card::club;
76 else if (color_name == to_string(Card::spade))
77 return Card::spade;
78 else if (color_name == to_string(Card::heart))
79 return Card::heart;
80 else if (color_name == to_string(Card::diamond))
81 return Card::diamond;
82 else
83 DEBUG_ASSERTION(false,
84 "Card::color(color_name):\n"
85 " color '" << color_name << "' unknown");
86
87 return Card::nocardcolor;
88 } // static Card::Color Card::color(string color_name)
89
90 /** -> result
91 **
92 ** @param value_name name of the value
93 **
94 ** @return value 'name'
95 **/
96 Card::Value
value(string const & value_name)97 Card::value(string const& value_name)
98 {
99 if (value_name == to_string(Card::nine))
100 return Card::nine;
101 else if (value_name == to_string(Card::jack))
102 return Card::jack;
103 else if (value_name == to_string(Card::queen))
104 return Card::queen;
105 else if (value_name == to_string(Card::king))
106 return Card::king;
107 else if (value_name == to_string(Card::ten))
108 return Card::ten;
109 else if (value_name == to_string(Card::ace))
110 return Card::ace;
111 else
112 DEBUG_ASSERTION(false,
113 "Card::value(value_name):\n"
114 " value '" << value_name << "' unknown");
115
116 return nocardvalue;
117 } // static Card::Value Card::value(string value_name)
118
119 /** constructor
120 ** reads 'color' and 'value' from 'name'
121 **
122 ** @param name the card name
123 **/
Card(string const & name)124 Card::Card(string const& name)
125 {
126 istringstream istr(name);
127 this->read(istr);
128 } // Card::Card(string name)
129
130 /** read the card from the stream
131 **
132 ** @param istr stream to read the card from
133 **
134 ** @return stream
135 **/
136 istream&
read(istream & istr)137 Card::read(istream& istr)
138 {
139 Color color;
140 Value value;
141 istr >> color >> value;
142 *this = Card(color, value);
143 return istr;
144 } // istrean& Card::read(istream& istr)
145
146 /** -> result
147 ** This value is used to use 'vector<.>' instead of 'map<Card, .>'
148 ** because of performance reasons (~15% better when using in 'CardCounter')
149 **
150 ** @return integer value of the card
151 **/
152 int
to_int() const153 Card::to_int() const noexcept
154 {
155 if (this->color() == nocardcolor)
156 return 0;
157 switch (this->value()) {
158 case Card::nocardvalue:
159 case Card::unknowncardvalue:
160 return 0;
161 case Card::nine:
162 return (this->color() * 6 + 1);
163 case Card::jack:
164 return (this->color() * 6 + 2);
165 case Card::queen:
166 return (this->color() * 6 + 3);
167 case Card::king:
168 return (this->color() * 6 + 4);
169 case Card::ten:
170 return (this->color() * 6 + 5);
171 case Card::ace:
172 return (this->color() * 6 + 6);
173 }; // switch (this->value())
174
175 return 0;
176 } // int Card::to_int() const
177
178 /** -> result
179 **
180 ** @param game the game
181 **
182 ** @return the tcolor of the card
183 **/
184 Card::TColor
tcolor(Game const & game) const185 Card::tcolor(Game const& game) const
186 {
187 if (this->istrump(game))
188 return Card::trump;
189 else
190 return this->color();
191 } // Card::TColor Card::tcolor(Game game) const
192
193 /** -> result
194 **
195 ** @param game the game
196 **
197 ** @return true if card is trump in the game
198 **/
199 bool
istrump(Game const & game) const200 Card::istrump(Game const& game) const
201 {
202 return this->istrump(game.type(), game.rule()(Rule::Type::dullen));
203 } // bool Card::istrump(Game game) const
204
205 /** -> result
206 **
207 ** @param gametype the gametype
208 ** @param dullen whether dullen are allowed
209 **
210 ** @return true if card is trump in the game
211 **/
212 bool
istrump(GameType const gametype,bool const dullen) const213 Card::istrump(GameType const gametype, bool const dullen) const
214 {
215 if (this->isdulle(gametype, dullen))
216 return true;
217
218 switch (gametype) {
219 case GameType::thrown_nines:
220 return (this->value() == nine);
221 case GameType::thrown_kings:
222 return (this->value() == king);
223 case GameType::thrown_nines_and_kings:
224 return ( (this->value() == nine)
225 || (this->value() == king) );
226 case GameType::thrown_richness:
227 return true;
228 case GameType::normal:
229 case GameType::poverty:
230 case GameType::fox_highest_trump:
231 case GameType::redistribute:
232 case GameType::genscher:
233 case GameType::marriage:
234 case GameType::marriage_solo:
235 case GameType::marriage_silent:
236 case GameType::solo_diamond:
237 return ( (this->color() == diamond)
238 || (this->value() == jack)
239 || (this->value() == queen) );
240 case GameType::solo_jack:
241 return (this->value() == jack);
242 case GameType::solo_queen:
243 return (this->value() == queen);
244 case GameType::solo_king:
245 return (this->value() == king);
246 case GameType::solo_queen_jack:
247 return ( (this->value() == jack)
248 || (this->value() == queen) );
249 break;
250 case GameType::solo_king_jack:
251 return ( (this->value() == jack)
252 || (this->value() == king) );
253 case GameType::solo_king_queen:
254 return ( (this->value() == queen)
255 || (this->value() == king) );
256 case GameType::solo_koehler:
257 return ( (this->value() == jack)
258 || (this->value() == queen)
259 || (this->value() == king) );
260 case GameType::solo_club:
261 return ( (this->color() == club)
262 || (this->value() == jack)
263 || (this->value() == queen) );
264 case GameType::solo_heart:
265 return ( (this->color() == heart)
266 || (this->value() == jack)
267 || (this->value() == queen) );
268 case GameType::solo_spade:
269 return ( (this->color() == spade)
270 || (this->value() == jack)
271 || (this->value() == queen) );
272 case GameType::solo_meatless:
273 return false;
274 } // switch(gametype)
275
276 return false;
277 } // bool Card::istrump(GameType gametype, bool dullen) const
278
279 /** -> result
280 **
281 ** @param game the game
282 **
283 ** @return true if card is a dulle
284 **/
285 bool
isdulle(Game const & game) const286 Card::isdulle(Game const& game) const
287 {
288 return this->isdulle(game.type(), game.rule()(Rule::Type::dullen));
289 } // bool Card::isdulle(Game game) const
290
291 /** -> result
292 **
293 ** @param gametype the gametype
294 ** @param dullen whether dullen are allowed
295 **
296 ** @return true if card is a dulle
297 **/
298 bool
isdulle(GameType const gametype,bool const dullen) const299 Card::isdulle(GameType const gametype, bool const dullen) const
300 {
301 if (!dullen)
302 return false;
303
304 if (*this != Card::dulle)
305 return false;
306
307 switch (gametype) {
308 case GameType::normal:
309 case GameType::poverty:
310 case GameType::genscher:
311 case GameType::marriage:
312 case GameType::marriage_solo:
313 case GameType::marriage_silent:
314 case GameType::solo_club:
315 case GameType::solo_heart:
316 case GameType::solo_spade:
317 case GameType::solo_diamond:
318 return true;
319 case GameType::solo_meatless:
320 case GameType::solo_jack:
321 case GameType::solo_queen:
322 case GameType::solo_king:
323 case GameType::solo_queen_jack:
324 case GameType::solo_king_jack:
325 case GameType::solo_king_queen:
326 case GameType::solo_koehler:
327 case GameType::thrown_nines:
328 case GameType::thrown_kings:
329 case GameType::thrown_nines_and_kings:
330 case GameType::thrown_richness:
331 case GameType::fox_highest_trump:
332 case GameType::redistribute:
333 return false;
334 } // switch (gametype)
335
336 return false;
337 } // bool Card::isdulle(GameType gametype, bool dullen) const
338
339 /** -> result
340 **
341 ** @note if both cards are equal, the first (this) is not less than
342 ** the second (card)
343 ** (but the dullen -- see rules)
344 **
345 ** @param card the card to compare with
346 **
347 ** @return true, if the card is less than 'b', else false
348 **
349 ** @todo is this function still called?
350 **/
351 bool
less(HandCard const & card) const352 Card::less(HandCard const& card) const
353 {
354 if (card.is_empty())
355 return false;
356
357 if (card.possible_hyperswine())
358 return (*this != card);
359 if ( card.game().swines().hyperswines_announced()
360 && (*this == card.game().cards().hyperswine()))
361 return false;
362 if (card.possible_swine())
363 return (*this != card);
364
365 return card.game().cards().less(*this, card);
366 } // bool HandCard::less(Card card) const
367
368 /** -> result
369 **
370 ** @param tcolor tcolor
371 ** @param marriage_selector marriage selector
372 **
373 ** @result whether the marriage is determined by a 'tcolor'-trick
374 **/
375 bool
is_selector(Card::TColor const tcolor,MarriageSelector const marriage_selector)376 is_selector(Card::TColor const tcolor,
377 MarriageSelector const marriage_selector)
378 {
379 switch (marriage_selector) {
380 case MarriageSelector::team_set:
381 case MarriageSelector::silent:
382 return false;
383 case MarriageSelector::first_foreign:
384 return true;
385 case MarriageSelector::first_trump:
386 return (tcolor == Card::trump);
387 case MarriageSelector::first_color:
388 return (tcolor != Card::trump);
389 case MarriageSelector::first_club:
390 return (tcolor == Card::club);
391 case MarriageSelector::first_spade:
392 return (tcolor == Card::spade);
393 case MarriageSelector::first_heart:
394 return (tcolor == Card::heart);
395 } // switch (marriage_selector)
396
397 return false;
398 } // bool is_selector(Card::TColor tcolor, MarriageSelector marriage_selector)
399
400 /** @return the corresponding single picture solo
401 **/
402 GameType
solo(Card::Value const picture)403 solo(Card::Value const picture) noexcept
404 {
405 switch (picture) {
406 case Card::jack:
407 return GameType::solo_jack;
408 case Card::queen:
409 return GameType::solo_queen;
410 case Card::king:
411 return GameType::solo_king;
412 default:
413 DEBUG_ASSERTION(false,
414 "solo(picture = " << picture << ")\n"
415 " no picture");
416 return GameType::normal;
417 }
418 }
419
420 /** @return the corresponding color solo
421 **/
422 GameType
solo(Card::Value const picture1,Card::Value const picture2)423 solo(Card::Value const picture1, Card::Value const picture2) noexcept
424 {
425 if (picture1 == Card::jack && picture2 == Card::queen)
426 return GameType::solo_queen_jack;
427 if (picture2 == Card::jack && picture1 == Card::queen)
428 return GameType::solo_queen_jack;
429 if (picture1 == Card::jack && picture2 == Card::king)
430 return GameType::solo_king_jack;
431 if (picture2 == Card::jack && picture1 == Card::king)
432 return GameType::solo_king_jack;
433 if (picture1 == Card::queen && picture2 == Card::king)
434 return GameType::solo_king_queen;
435 if (picture2 == Card::queen && picture1 == Card::king)
436 return GameType::solo_king_queen;
437 DEBUG_ASSERTION(false,
438 "solo(picture1 = " << picture1 << ", picture2 = " << picture2 << ")\n"
439 " picture1 and picture2 no pictures or equal");
440 return GameType::normal;
441 }
442
443 /** @return the corresponding color solo
444 **/
445 GameType
solo(Card::Color const color)446 solo(Card::Color const color) noexcept
447 {
448 switch (color) {
449 case Card::club:
450 return GameType::solo_club;
451 case Card::spade:
452 return GameType::solo_spade;
453 case Card::heart:
454 return GameType::solo_heart;
455 case Card::diamond:
456 return GameType::solo_diamond;
457 default:
458 DEBUG_ASSERTION(false,
459 "solo(color = " << color << ")\n"
460 " no color");
461 return GameType::normal;
462 }
463 }
464
465 /** -> result
466 **
467 ** @param value card value
468 **
469 ** @return name of the value
470 **/
471 string
to_string(Card::Value const value)472 to_string(Card::Value const value) noexcept
473 {
474 switch(value) {
475 case Card::nine:
476 return "nine";
477 (void)_("Card::Value::nine");
478 case Card::jack:
479 return "jack";
480 (void)_("Card::Value::jack");
481 case Card::queen:
482 return "queen";
483 (void)_("Card::Value::queen");
484 case Card::king:
485 return "king";
486 (void)_("Card::Value::king");
487 case Card::ten:
488 return "ten";
489 (void)_("Card::Value::ten");
490 case Card::ace:
491 return "ace";
492 (void)_("Card::Value::ace");
493 case Card::nocardvalue:
494 return "no card value";
495 (void)_("Card::Value::no card value");
496 case Card::unknowncardvalue:
497 return "unknown card value";
498 (void)_("Card::Value::unknown card value");
499 } // switch(value)
500
501 return {};
502 } // string to_string(Card::Value value)
503
504 /** -> result
505 **
506 ** @param tcolor card tcolor
507 **
508 ** @return name of the tcolor
509 **/
510 string
to_string(Card::TColor const tcolor)511 to_string(Card::TColor const tcolor) noexcept
512 {
513 switch(tcolor) {
514 case Card::club:
515 return "club";
516 (void)_("Card::Color::club");
517 case Card::spade:
518 return "spade";
519 (void)_("Card::Color::spade");
520 case Card::heart:
521 return "heart";
522 (void)_("Card::Color::heart");
523 case Card::diamond:
524 return "diamond";
525 (void)_("Card::Color::diamond");
526 case Card::trump:
527 return "trump";
528 (void)_("Card::Color::trump");
529 case Card::nocardcolor:
530 return "no card color";
531 (void)_("Card::Color::no card color");
532 case Card::unknowncardcolor:
533 return "unknown card color";
534 (void)_("Card::Color::unknown card color");
535 } // switch(tcolor)
536
537 return {};
538 } // string to_string(Card::TColor tcolor)
539
540 /** @result the name of the card
541 **/
542 string
to_string(Card const & card)543 to_string(Card const& card) noexcept
544 {
545 if (card.is_empty())
546 return "empty";
547 else if (card.is_unknown())
548 return "unknown";
549 else
550 return (to_string(card.color()) + " " + to_string(card.value()));
551 } // string to_string(Card card)
552
553 /** translation
554 **
555 ** @param value card value
556 **
557 ** @return translation
558 **/
559 string
gettext(Card::Value const value)560 gettext(Card::Value const value)
561 {
562 return gettext("Card::Value::" + to_string(value));
563 }
564
565 /** translation
566 **
567 ** @param color card color
568 **
569 ** @return translation
570 **/
571 string
gettext(Card::Color const color)572 gettext(Card::Color const color)
573 {
574 return gettext("Card::Color::" + to_string(color));
575 }
576
577 /** translation
578 **
579 ** @param value card value
580 **
581 ** @return translation
582 **/
583 string
gettext(Card const & card)584 gettext(Card const& card)
585 {
586 // gettext: %t = color, %t = value
587 return _("Card::%t %t",
588 _(card.color()), _(card.value()));
589 }
590
591 /** -> result
592 **
593 ** @param lhs left hand side
594 ** @param rhs right hand side
595 **
596 ** @return whether 'lhs' is greater than 'rhs'
597 ** (in the order: 'club', 'spade', 'heart', 'diamond'
598 **/
599 bool
operator >(Card::Color const lhs,Card::Color const rhs)600 operator>(Card::Color const lhs, Card::Color const rhs)
601 {
602 switch (lhs) {
603 case Card::club:
604 return ( (rhs == Card::spade)
605 || (rhs == Card::heart)
606 || (rhs == Card::diamond) );
607 case Card::spade:
608 return ( (rhs == Card::heart)
609 || (rhs == Card::diamond) );
610 case Card::heart:
611 return (rhs == Card::diamond);
612 case Card::diamond:
613 return false;
614 default:
615 DEBUG_ASSERTION(false,
616 "operator>(lhs, rhs): illegal value");
617
618 break;
619 } // switch (lhs)
620
621 return false;
622 } // bool operator>(Card::Color lhs, Card::Color rhs)
623
624 /** writes the card value in the output stream
625 **
626 ** @param ostr output stream
627 ** @param value card value
628 **
629 ** @return output stream
630 **/
631 ostream&
operator <<(ostream & ostr,Card::Value const value)632 operator<<(ostream& ostr, Card::Value const value)
633 {
634 return (ostr << to_string(value));
635 } // ostream& operator<<(ostream& ostr, Card::Value value);
636
637 /** read the card value out of the stream
638 **
639 ** @param istr input stream
640 ** @param value card value
641 **
642 ** @return output stream
643 **/
644 istream&
operator >>(istream & istr,Card::Value & value)645 operator>>(istream& istr, Card::Value& value)
646 {
647 string value_name;
648 istr >> value_name;
649
650 value = Card::value(value_name);
651
652 return istr;
653 } // istream& operator>>(istream& istr, Card::Value& value);
654
655 /** writes the card color in the output stream
656 **
657 ** @param ostr output stream
658 ** @param tcolor card color
659 **
660 ** @return output stream
661 **/
662 ostream&
operator <<(ostream & ostr,Card::TColor const tcolor)663 operator<<(ostream& ostr, Card::TColor const tcolor)
664 {
665 return (ostr << to_string(tcolor));
666 } // ostream& operator<<(ostream& ostr, Card::TColor tcolor);
667
668 /** read the card color out of the stream
669 **
670 ** @param istr input stream
671 ** @param color card color
672 **
673 ** @return output stream
674 **/
675 istream&
operator >>(istream & istr,Card::Color & color)676 operator>>(istream& istr, Card::Color& color)
677 {
678 string color_name;
679 istr >> color_name;
680 color = Card::color(color_name);
681
682 return istr;
683 } // istream& operator>>(istream& istr, Card::Color& color);
684
685 /** writes the card in the output stream
686 **
687 ** @param ostr output stream
688 ** @param card card
689 **
690 ** @return output stream
691 **/
692 ostream&
operator <<(ostream & ostr,Card const & card)693 operator<<(ostream& ostr, Card const& card)
694 {
695 return (ostr << to_string(card));
696 } // ostream& operator<<(ostream& ostr, Card const& card);
697
698 /** read the card out of the stream
699 **
700 ** @param istr input stream
701 ** @param card card
702 **
703 ** @return output stream
704 **/
705 istream&
operator >>(istream & istr,Card & card)706 operator>>(istream& istr, Card& card)
707 {
708 return card.read(istr);
709 } // istream& operator>>(istream& istr, Card& card);
710
711