OSDN Git Service

Merge pull request #2716 from Hourier/Move-Dungeon-to-System
[hengbandforosx/hengbandosx.git] / src / market / poker.cpp
1 #include "market/poker.h"
2 #include "io/input-key-acceptor.h"
3 #include "system/angband.h"
4 #include "term/screen-processor.h"
5 #include "term/term-color-types.h"
6 #include "util/int-char-converter.h"
7 #include <iterator>
8 #include <numeric>
9
10 /*!
11  * ポーカーの現在の手札ID
12  */
13 static int cards[5];
14
15 #define ODDS_5A 3000 /*!< ファイブエースの役倍率 */
16 #define ODDS_5C 400 /*!< ファイブカードの役倍率 */
17 #define ODDS_RF 200 /*!< ロイヤルストレートフラッシュの役倍率 */
18 #define ODDS_SF 80 /*!< ストレートフラッシュの役倍率 */
19 #define ODDS_4C 16 /*!< フォアカードの役倍率 */
20 #define ODDS_FH 12 /*!< フルハウスの役倍率 */
21 #define ODDS_FL 8 /*!< フラッシュの役倍率 */
22 #define ODDS_ST 4 /*!< ストレートの役倍率 */
23 #define ODDS_3C 1 /*!< スリーカードの役倍率 */
24 #define ODDS_2P 1 /*!< ツーペアの役倍率 */
25
26 /*! @note
27  * kpoker no (tyuto-hannpa na)pakuri desu...
28  * joker ha shineru node haitte masen.
29  *
30  * TODO: donataka! tsukutte!
31  *  - agatta yaku no kiroku (like DQ).
32  *  - kakkoii card no e.
33  *  - sousa-sei no koujyo.
34  *  - code wo wakariyasuku.
35  *  - double up.
36  *  - Joker... -- done.
37  *
38  * 9/13/2000 --Koka
39  * 9/15/2000 joker wo jissou. soreto, code wo sukosi kakikae. --Habu
40  */
41
42 #define SUIT_OF(card) ((card) / 13) /*!< トランプカードのスートを返す */
43 #define NUM_OF(card) ((card) % 13) /*!< トランプカードの番号を返す */
44 #define IS_JOKER(card) ((card) == 52) /*!< トランプカードがジョーカーかどうかを返す */
45
46 /*!
47  * @brief ポーカーの山札を切る
48  * @param deck デッキの配列
49  */
50 static void reset_deck(int (&deck)[53])
51 {
52     std::iota(std::begin(deck), std::end(deck), 0);
53     rand_shuffle(std::begin(deck), std::end(deck));
54 }
55
56 /*!
57  * @brief ポーカープレイ中にジョーカーを持っているかの判定を返す
58  * @param なし
59  * @return ジョーカーを持っているか
60  */
61 static bool has_joker(void)
62 {
63     for (int i = 0; i < 5; i++) {
64         if (IS_JOKER(cards[i])) {
65             return true;
66         }
67     }
68     return false;
69 }
70
71 /*!
72  * @brief ポーカーの手札に該当の番号の札があるかを返す
73  * @param num 探したいカードの番号
74  * @return 該当の番号が手札にあるか。
75  */
76 static bool find_card_num(int num)
77 {
78     for (int i = 0; i < 5; i++) {
79         if (NUM_OF(cards[i]) == num && !IS_JOKER(cards[i])) {
80             return true;
81         }
82     }
83
84     return false;
85 }
86
87 /*!
88  * @brief ポーカーの手札がフラッシュ役を得ているかを帰す
89  * @param なし
90  * @return 役の判定結果
91  */
92 static bool poker_hand_check_flush(void)
93 {
94     bool joker_is_used = false;
95
96     int suit = IS_JOKER(cards[0]) ? SUIT_OF(cards[1]) : SUIT_OF(cards[0]);
97     for (int i = 0; i < 5; i++) {
98         if (SUIT_OF(cards[i]) == suit) {
99             continue;
100         }
101
102         if (has_joker() && !joker_is_used) {
103             joker_is_used = true;
104         } else {
105             return false;
106         }
107     }
108
109     return true;
110 }
111
112 /*!
113  * @brief ポーカーの手札がストレートを含んだ高位の役を得ているかを帰す
114  * @param なし
115  * @return 役の判定結果 0…ストレート、フラッシュいずれもなし/1…ストレートのみ/2…ストレートフラッシュ/3…ロイヤルストレートフラッシュ
116  */
117 static int poker_hand_check_straight(void)
118 {
119     int lowest = 99;
120     bool joker_is_used = false;
121     bool straight = false;
122
123     for (int i = 0; i < 5; i++) {
124         if (NUM_OF(cards[i]) < lowest && !IS_JOKER(cards[i])) {
125             lowest = NUM_OF(cards[i]);
126         }
127     }
128
129     if (poker_hand_check_flush()) {
130         int i;
131         if (lowest == 0) {
132             for (i = 0; i < 4; i++) {
133                 if (!find_card_num(9 + i)) {
134                     if (has_joker() && !joker_is_used) {
135                         joker_is_used = true;
136                     } else {
137                         break;
138                     }
139                 }
140             }
141
142             if (i == 4) {
143                 return 3;
144             }
145         }
146
147         if (lowest == 9) {
148             for (i = 0; i < 3; i++) {
149                 if (!find_card_num(10 + i)) {
150                     break;
151                 }
152             }
153
154             if (i == 3 && has_joker()) {
155                 return 3;
156             }
157         }
158     }
159
160     joker_is_used = false;
161
162     if (lowest == 0) {
163         int i;
164         for (i = 0; i < 4; i++) {
165             if (!find_card_num(9 + i)) {
166                 if (has_joker() && !joker_is_used) {
167                     joker_is_used = true;
168                 } else {
169                     break;
170                 }
171             }
172         }
173
174         if (i == 4) {
175             straight = true;
176         }
177     }
178
179     joker_is_used = false;
180
181     int i;
182     for (i = 0; i < 5; i++) {
183         if (!find_card_num(lowest + i)) {
184             if (has_joker() && !joker_is_used) {
185                 joker_is_used = true;
186             } else {
187                 break;
188             } /* None */
189         }
190     }
191
192     if (i == 5) {
193         straight = true;
194     }
195
196     if (straight && poker_hand_check_flush()) {
197         return 2;
198     } /* Straight Flush */
199     else if (straight) {
200         return 1;
201     } /* Only Straight */
202     else {
203         return 0;
204     }
205 }
206
207 /*!
208  * @brief ポーカーのペア役の状態を返す。
209  * @param なし
210  * @return 0:nopair 1:1 pair 2:2 pair 3:3 cards 4:full house 6:4cards
211  */
212 static int poker_hand_check_pair(void)
213 {
214     int matching = 0;
215     for (int i = 0; i < 5; i++) {
216         for (int j = i + 1; j < 5; j++) {
217             if (IS_JOKER(cards[i]) || IS_JOKER(cards[j])) {
218                 continue;
219             }
220             if (NUM_OF(cards[i]) == NUM_OF(cards[j])) {
221                 matching++;
222             }
223         }
224     }
225
226     if (has_joker()) {
227         switch (matching) {
228         case 0:
229             matching = 1;
230             break;
231         case 1:
232             matching = 3;
233             break;
234         case 2:
235             matching = 4;
236             break;
237         case 3:
238             matching = 6;
239             break;
240         case 6:
241             matching = 7;
242             break;
243         default:
244             /* don't reach */
245             break;
246         }
247     }
248
249     return matching;
250 }
251
252 /*!
253  * @brief ポーカーの役をチェックし、その結果を画面に表示しつつ結果を返す。
254  * @return 役のID
255  */
256 static int poker_hand_check(void)
257 {
258     prt("                            ", 4, 3);
259
260     switch (poker_hand_check_straight()) {
261     case 3: /* RF! */
262         c_put_str(TERM_YELLOW, _("ロイヤルストレートフラッシュ", "Royal Flush"), 4, 3);
263         return ODDS_RF;
264     case 2: /* SF! */
265         c_put_str(TERM_YELLOW, _("ストレートフラッシュ", "Straight Flush"), 4, 3);
266         return ODDS_SF;
267     case 1:
268         c_put_str(TERM_YELLOW, _("ストレート", "Straight"), 4, 3);
269         return ODDS_ST;
270     default:
271         /* Not straight -- fall through */
272         break;
273     }
274
275     if (poker_hand_check_flush()) {
276         c_put_str(TERM_YELLOW, _("フラッシュ", "Flush"), 4, 3);
277         return ODDS_FL;
278     }
279
280     switch (poker_hand_check_pair()) {
281     case 1:
282         c_put_str(TERM_YELLOW, _("ワンペア", "One pair"), 4, 3);
283         return 0;
284     case 2:
285         c_put_str(TERM_YELLOW, _("ツーペア", "Two pair"), 4, 3);
286         return ODDS_2P;
287     case 3:
288         c_put_str(TERM_YELLOW, _("スリーカード", "Three of a kind"), 4, 3);
289         return ODDS_3C;
290     case 4:
291         c_put_str(TERM_YELLOW, _("フルハウス", "Full house"), 4, 3);
292         return ODDS_FH;
293     case 6:
294         c_put_str(TERM_YELLOW, _("フォーカード", "Four of a kind"), 4, 3);
295         return ODDS_4C;
296     case 7:
297         if (!NUM_OF(cards[0]) && !NUM_OF(cards[1])) {
298             c_put_str(TERM_YELLOW, _("ファイブエース", "Five ace"), 4, 3);
299             return ODDS_5A;
300         } else {
301             c_put_str(TERM_YELLOW, _("ファイブカード", "Five of a kind"), 4, 3);
302             return ODDS_5C;
303         }
304     default:
305         break;
306     }
307
308     return 0;
309 }
310
311 /*!
312  * @brief ポーカーの捨てる/残すインターフェイスの表示を更新する。
313  * @param hoge カーソルの現在位置
314  * @param kaeruka カードの捨てる/残すフラグ配列
315  */
316 static void display_kaeruka(int hoge, int kaeruka[])
317 {
318     char col = TERM_WHITE;
319     for (int i = 0; i < 5; i++) {
320         if (i == hoge) {
321             col = TERM_YELLOW;
322         } else if (kaeruka[i]) {
323             col = TERM_WHITE;
324         } else {
325             col = TERM_L_BLUE;
326         }
327
328         if (kaeruka[i]) {
329             c_put_str(col, _("かえる", "Change"), 14, 5 + i * 16);
330         } else {
331             c_put_str(col, _("のこす", " Stay "), 14, 5 + i * 16);
332         }
333     }
334
335     if (hoge > 4) {
336         col = TERM_YELLOW;
337     } else {
338         col = TERM_WHITE;
339     }
340     c_put_str(col, _("決定", "Sure"), 16, 38);
341
342     if (hoge < 5) {
343         move_cursor(14, 5 + hoge * 16);
344     } else {
345         move_cursor(16, 38);
346     }
347 }
348
349 /*!
350  * @brief ポーカーの手札を表示する
351  * @param なし
352  * @todo _() でまとめる
353  */
354 static void display_cards(void)
355 {
356     char suitcolor[4] = { TERM_YELLOW, TERM_L_RED, TERM_L_BLUE, TERM_L_GREEN };
357 #ifdef JP
358     concptr suit[4] = { "★", "●", "¶", "†" };
359     concptr card_grph[13][7] = { { "A   %s     ",
360                                      "     変     ",
361                                      "     愚     ",
362                                      "     蛮     ",
363                                      "     怒     ",
364                                      "     %s     ",
365                                      "          A" },
366         { "2          ",
367             "     %s     ",
368             "            ",
369             "            ",
370             "            ",
371             "     %s     ",
372             "          2" },
373         { "3          ",
374             "     %s     ",
375             "            ",
376             "     %s     ",
377             "            ",
378             "     %s     ",
379             "          3" },
380         { "4          ",
381             "   %s  %s   ",
382             "            ",
383             "            ",
384             "            ",
385             "   %s  %s   ",
386             "          4" },
387         { "5          ",
388             "   %s  %s   ",
389             "            ",
390             "     %s     ",
391             "            ",
392             "   %s  %s   ",
393             "          5" },
394         { "6          ",
395             "   %s  %s   ",
396             "            ",
397             "   %s  %s   ",
398             "            ",
399             "   %s  %s   ",
400             "          6" },
401         { "7          ",
402             "   %s  %s   ",
403             "     %s     ",
404             "   %s  %s   ",
405             "            ",
406             "   %s  %s   ",
407             "          7" },
408         { "8          ",
409             "   %s  %s   ",
410             "     %s     ",
411             "   %s  %s   ",
412             "     %s     ",
413             "   %s  %s   ",
414             "          8" },
415         { "9 %s  %s   ",
416             "            ",
417             "   %s  %s   ",
418             "     %s     ",
419             "   %s  %s   ",
420             "            ",
421             "   %s  %s 9" },
422         { "10 %s  %s   ",
423             "     %s     ",
424             "   %s  %s   ",
425             "            ",
426             "   %s  %s   ",
427             "     %s     ",
428             "   %s  %s 10" },
429         { "J   Λ     ",
430             "%s   ||     ",
431             "     ||     ",
432             "     ||     ",
433             "     ||     ",
434             "   |=亜=| %s",
435             "     目   J" },
436         { "Q ######   ",
437             "%s#      #  ",
438             "  # ++++ #  ",
439             "  # +==+ #  ",
440             "   # ++ #   ",
441             "    #  #  %s",
442             "     ##   Q" },
443         { "K          ",
444             "%s `⌒´   ",
445             "  γγγλ  ",
446             "  ο ο ι  ",
447             "   υ    ∂ ",
448             "    σ ノ %s",
449             "          K" } };
450     concptr joker_grph[7] = { "            ",
451         "     J     ",
452         "     O     ",
453         "     K     ",
454         "     E     ",
455         "     R     ",
456         "            " };
457
458 #else
459
460     concptr suit[4] = { "[]", "qp", "<>", "db" };
461     concptr card_grph[13][7] = { { "A    %s     ",
462                                      "     He     ",
463                                      "     ng     ",
464                                      "     ba     ",
465                                      "     nd     ",
466                                      "     %s     ",
467                                      "           A" },
468         { "2           ",
469             "     %s     ",
470             "            ",
471             "            ",
472             "            ",
473             "     %s     ",
474             "           2" },
475         { "3           ",
476             "     %s     ",
477             "            ",
478             "     %s     ",
479             "            ",
480             "     %s     ",
481             "           3" },
482         { "4           ",
483             "   %s  %s   ",
484             "            ",
485             "            ",
486             "            ",
487             "   %s  %s   ",
488             "           4" },
489         { "5           ",
490             "   %s  %s   ",
491             "            ",
492             "     %s     ",
493             "            ",
494             "   %s  %s   ",
495             "           5" },
496         { "6           ",
497             "   %s  %s   ",
498             "            ",
499             "   %s  %s   ",
500             "            ",
501             "   %s  %s   ",
502             "           6" },
503         { "7           ",
504             "   %s  %s   ",
505             "     %s     ",
506             "   %s  %s   ",
507             "            ",
508             "   %s  %s   ",
509             "           7" },
510         { "8           ",
511             "   %s  %s   ",
512             "     %s     ",
513             "   %s  %s   ",
514             "     %s     ",
515             "   %s  %s   ",
516             "           8" },
517         { "9  %s  %s   ",
518             "            ",
519             "   %s  %s   ",
520             "     %s     ",
521             "   %s  %s   ",
522             "            ",
523             "   %s  %s  9" },
524         { "10 %s  %s   ",
525             "     %s     ",
526             "   %s  %s   ",
527             "            ",
528             "   %s  %s   ",
529             "     %s     ",
530             "   %s  %s 10" },
531         { "J    /\\     ",
532             "%s   ||     ",
533             "     ||     ",
534             "     ||     ",
535             "     ||     ",
536             "   |=HH=| %s",
537             "     ][    J" },
538         { "Q  ######   ",
539             "%s#      #  ",
540             "  # ++++ #  ",
541             "  # +==+ #  ",
542             "   # ++ #   ",
543             "    #  #  %s",
544             "     ##    Q" },
545         { "K           ",
546             "%s _'~~`_   ",
547             "   jjjjj$&  ",
548             "   q q uu   ",
549             "   c    &   ",
550             "    v__/  %s",
551             "           K" } };
552     concptr joker_grph[7] = { "            ",
553         "     J      ",
554         "     O      ",
555         "     K      ",
556         "     E      ",
557         "     R      ",
558         "            " };
559 #endif
560
561     for (int i = 0; i < 5; i++) {
562         prt(_("┏━━━━━━┓", " +------------+ "), 5, i * 16);
563     }
564
565     for (int i = 0; i < 5; i++) {
566         for (int j = 0; j < 7; j++) {
567             prt(_("┃", " |"), j + 6, i * 16);
568             if (IS_JOKER(cards[i])) {
569                 c_put_str(TERM_VIOLET, joker_grph[j], j + 6, 2 + i * 16);
570             } else {
571                 c_put_str(suitcolor[SUIT_OF(cards[i])], format(card_grph[NUM_OF(cards[i])][j], suit[SUIT_OF(cards[i])], suit[SUIT_OF(cards[i])]), j + 6, 2 + i * 16);
572             }
573             prt(_("┃", "| "), j + 6, i * 16 + 14);
574         }
575     }
576
577     for (int i = 0; i < 5; i++) {
578         prt(_("┗━━━━━━┛", " +------------+ "), 13, i * 16);
579     }
580 }
581
582 /*!
583  * @brief ポーカーの1プレイルーチン。
584  * @return 1プレイの役の結果
585  */
586 int do_poker(void)
587 {
588     int is_put[5];
589
590     bool done = false;
591     bool decision = true;
592     bool draw = true;
593
594     int deck[53];
595     reset_deck(deck);
596
597     int deck_ptr = 0;
598     for (int i = 0; i < 5; i++) {
599         cards[i] = deck[deck_ptr++];
600         is_put[i] = 0;
601     }
602
603     prt(_("残すカードを決めて下さい(方向で移動, スペースで選択)。", "Keep which cards (direction keys move; space selects)? "), 0, 0);
604
605     display_cards();
606     poker_hand_check();
607
608     int k = 2;
609     char cmd;
610     while (!done) {
611         if (draw) {
612             display_kaeruka(k + decision * 5, is_put);
613         }
614
615         draw = false;
616         cmd = inkey();
617         switch (cmd) {
618         case '6':
619         case 'l':
620         case 'L':
621         case KTRL('F'):
622             if (!decision) {
623                 k = (k + 1) % 5;
624             } else {
625                 k = 0;
626                 decision = false;
627             }
628
629             draw = true;
630             break;
631         case '4':
632         case 'h':
633         case 'H':
634         case KTRL('B'):
635             if (!decision) {
636                 k = (k + 4) % 5;
637             } else {
638                 k = 4;
639                 decision = false;
640             }
641
642             draw = true;
643             break;
644         case '2':
645         case 'j':
646         case 'J':
647         case KTRL('N'):
648             if (!decision) {
649                 decision = true;
650                 draw = true;
651             }
652
653             break;
654         case '8':
655         case 'k':
656         case 'K':
657         case KTRL('P'):
658             if (decision) {
659                 decision = false;
660                 draw = true;
661             }
662
663             break;
664         case ' ':
665         case '\r':
666             if (decision) {
667                 done = true;
668             } else {
669                 is_put[k] = !is_put[k];
670                 draw = true;
671             }
672
673             break;
674         default:
675             break;
676         }
677     }
678
679     prt("", 0, 0);
680
681     for (int i = 0; i < 5; i++) {
682         if (is_put[i] == 1) {
683             cards[i] = deck[deck_ptr++];
684         }
685     }
686
687     display_cards();
688
689     return poker_hand_check();
690 }