ポーカーゲームのラストとして手役の判定を行います。
全体のプログラムも長くなっているので、なるべく手役の判定だけ抜き出して書くように工夫します。
<sample program 108-01>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUMBER 13
#define MARK 4
#define CARD_NUM (NUMBER * MARK)
#define SHUFFLE_TIME 2000 /* 入れ替え回数 */
#define HAND_NUM 5 /* 手札の枚数 */
/* カード構造体 */
typedef struct
{
int number;
int suit;
int selectFlag;
} Card;
int main(void)
{
Card deck[CARD_NUM]; /* デッキ */
Card hand[HAND_NUM]; /* 手札 */
int i, j;
int index1, index2; /* シャッフル用添え字 */
Card work; /* 入れ替え用 */
int select; /* カード選択用 */
srand((unsigned int)time(NULL));
/* デッキの初期化 */
for (i = 0; i < CARD_NUM; i++) {
deck[i].suit = i / NUMBER;
deck[i].number = i % NUMBER + 1;
deck[i].selectFlag = 0;
}
/* デッキのシャッフル */
for (i = 0; i < SHUFFLE_TIME; i++) {
index1 = rand() % CARD_NUM;
index2 = rand() % CARD_NUM;
work = deck[index1];
deck[index1] = deck[index2];
deck[index2] = work;
}
/* 手札を配る */
for (i = 0; i < HAND_NUM; i++) {
hand[i] = deck[i];
}
/* 手札のソート */
for (i = 0; i < HAND_NUM - 1; i++) {
for (j = 0; j < HAND_NUM - 1; j++) {
if (hand[j].number > hand[j + 1].number) {
work = hand[j];
hand[j] = hand[j + 1];
hand[j + 1] = work;
}
}
}
/* 手札の表示 */
for (i = 0; i < HAND_NUM; i++) {
switch (hand[i].suit) {
case 0:
printf("スペード:");
break;
case 1:
printf("ハ ー ト:");
break;
case 2:
printf("ダ イ ヤ:");
break;
case 3:
printf("ク ラ ブ:");
break;
}
printf("%2d\n", hand[i].number);
}
for (;;) {
/* 入れ替えるカードの選択 */
do {
scanf("%d", &select);
} while (select < 0 || select > HAND_NUM);
if (select == HAND_NUM) {
break;
}
if (hand[select].selectFlag == 0) {
hand[select].selectFlag = 1;
}
else {
hand[select].selectFlag = 0;
}
/* 選択した手札の表示 */
for (i = 0; i < HAND_NUM; i++) {
switch (hand[i].suit) {
case 0:
printf("スペード:");
break;
case 1:
printf("ハ ー ト:");
break;
case 2:
printf("ダ イ ヤ:");
break;
case 3:
printf("ク ラ ブ:");
break;
}
printf("%2d", hand[i].number);
if (hand[i].selectFlag == 1) {
printf(" *\n");
}
else {
printf("\n");
}
}
}
/* 手札の交換 */
dealCount = HAND_NUM;
for (i = 0; i < HAND_NUM; i++) {
if (hand[i].selectFlag == 1) {
hand[i] = deck[dealCount];
dealCount++;
}
}
/* 手札のソート */
for (i = 0; i < HAND_NUM - 1; i++) {
for (j = 0; j < HAND_NUM - 1; j++) {
if (hand[j].number > hand[j + 1].number) {
work = hand[j];
hand[j] = hand[j + 1];
hand[j + 1] = work;
}
}
}
/* 手札の表示 */
for (i = 0; i < HAND_NUM; i++) {
switch (hand[i].suit) {
case 0:
printf("スペード:");
break;
case 1:
printf("ハ ー ト:");
break;
case 2:
printf("ダ イ ヤ:");
break;
case 3:
printf("ク ラ ブ:");
break;
}
printf("%2d\n", hand[i].number);
}
/* 手役の判定 */
/* ここに判定プログラムを書く */
return 0;
}
|
手役として、以下の役の判定を行います。
<手役>
フォーカード スリーカード フルハウス ツーペア ワンペア ストレート フラッシュ ストレートフラッシュ |
※ストレートは「10JQKA」のように、13を超えて1に戻るものは無しとします。
最初にフォーカードの判定を行います。
手札はソートされていますので、フォーカードは以下の2パターンの内、どちらかになります。
パターン1(0〜3まで同じ数値) 0 1 2 3 4 +−+−+−+−+−+ 手札|1|1|1|1|2| +−+−+−+−+−+ パターン2(1〜4まで同じ数値) 0 1 2 3 4 +−+−+−+−+−+ 手札|1|2|2|2|2| +−+−+−+−+−+
上の2つのどちらかのパターンに当てはまれば、「フォーカード」と表示することにします。
<sample program 108-02>
/* 手役の判定 */ if (hand[0].number == hand[1].number && hand[1].number == hand[2].number && hand[2].number == hand[3].number) { printf("フォーカード\n"); } if (hand[1].number == hand[2].number && hand[2].number == hand[3].number && hand[3].number == hand[4].number) { printf("フォーカード\n"); } |
ベタなプログラムですが、この2パターンしかありませんので、簡単にチェックしましょう。
とりあえず、上手く動作するかどうかチェックしたいのですが、普通にフォーカードは出ませんよね・・・
このような場合も「デバッグ用コード」で対応します。
手札の交換が終わった後、ソートする前にカードを全部入れ替えます。
<sample program 108-03>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUMBER 13
#define MARK 4
#define CARD_NUM (NUMBER * MARK)
#define SHUFFLE_TIME 2000 /* 入れ替え回数 */
#define HAND_NUM 5 /* 手札の枚数 */
/* カード構造体 */
typedef struct
{
int number;
int suit;
int selectFlag;
} Card;
int main(void)
{
Card deck[CARD_NUM]; /* デッキ */
Card hand[HAND_NUM]; /* 手札 */
int i, j;
int index1, index2; /* シャッフル用添え字 */
Card work; /* 入れ替え用 */
int select; /* カード選択用 */
int dealCount; /* デッキ用 */
srand((unsigned int)time(NULL));
/* デッキの初期化 */
for (i = 0; i < CARD_NUM; i++) {
deck[i].suit = i / NUMBER;
deck[i].number = i % NUMBER + 1;
deck[i].selectFlag = 0;
}
/* デッキのシャッフル */
for (i = 0; i < SHUFFLE_TIME; i++) {
index1 = rand() % CARD_NUM;
index2 = rand() % CARD_NUM;
work = deck[index1];
deck[index1] = deck[index2];
deck[index2] = work;
}
/* 手札を配る */
for (i = 0; i < HAND_NUM; i++) {
hand[i] = deck[i];
}
/* 手札のソート */
for (i = 0; i < HAND_NUM - 1; i++) {
for (j = 0; j < HAND_NUM - 1; j++) {
if (hand[j].number > hand[j + 1].number) {
work = hand[j];
hand[j] = hand[j + 1];
hand[j + 1] = work;
}
}
}
/* 手札の表示 */
for (i = 0; i < HAND_NUM; i++) {
switch (hand[i].suit) {
case 0:
printf("スペード:");
break;
case 1:
printf("ハ ー ト:");
break;
case 2:
printf("ダ イ ヤ:");
break;
case 3:
printf("ク ラ ブ:");
break;
}
printf("%2d\n", hand[i].number);
}
for (;;) {
/* 入れ替えるカードの選択 */
do {
scanf("%d", &select);
} while (select < 0 || select > HAND_NUM);
if (select == HAND_NUM) {
break;
}
if (hand[select].selectFlag == 0) {
hand[select].selectFlag = 1;
}
else {
hand[select].selectFlag = 0;
}
/* 選択した手札の表示 */
for (i = 0; i < HAND_NUM; i++) {
switch (hand[i].suit) {
case 0:
printf("スペード:");
break;
case 1:
printf("ハ ー ト:");
break;
case 2:
printf("ダ イ ヤ:");
break;
case 3:
printf("ク ラ ブ:");
break;
}
printf("%2d", hand[i].number);
if (hand[i].selectFlag == 1) {
printf(" *\n");
}
else {
printf("\n");
}
}
}
/* 手札の交換 */
dealCount = HAND_NUM;
for (i = 0; i < HAND_NUM; i++) {
if (hand[i].selectFlag == 1) {
hand[i] = deck[dealCount];
dealCount++;
}
}
/* デバッグ用コード */
hand[0].number = 1;
hand[1].number = 1;
hand[2].number = 1;
hand[3].number = 1;
hand[4].number = 2;
/* 手札のソート */
for (i = 0; i < HAND_NUM - 1; i++) {
for (j = 0; j < HAND_NUM - 1; j++) {
if (hand[j].number > hand[j + 1].number) {
work = hand[j];
hand[j] = hand[j + 1];
hand[j + 1] = work;
}
}
}
/* 手札の表示 */
for (i = 0; i < HAND_NUM; i++) {
switch (hand[i].suit) {
case 0:
printf("スペード:");
break;
case 1:
printf("ハ ー ト:");
break;
case 2:
printf("ダ イ ヤ:");
break;
case 3:
printf("ク ラ ブ:");
break;
}
printf("%2d\n", hand[i].number);
}
/* 手役の判定 */
if (hand[0].number == hand[1].number &&
hand[1].number == hand[2].number &&
hand[2].number == hand[3].number) {
printf("フォーカード\n");
}
if (hand[1].number == hand[2].number &&
hand[2].number == hand[3].number &&
hand[3].number == hand[4].number) {
printf("フォーカード\n");
}
return 0;
}
|
<実行結果1>
ハ ー ト: 1 スペード: 2 ハ ー ト: 5 ハ ー ト: 8 スペード:10 5 ハ ー ト: 1 スペード: 1 ハ ー ト: 1 ハ ー ト: 1 スペード: 2 フォーカード 続行するには何かキーを押してください・・・
ハートの1が3枚ありますので、実際にはあり得ない状態ですが、きちんと「フォーカード」と表示されました。
どの手役をチェックするにも、デバッグ用コードを変えて実験すればよさそうです。
では、スリーカードについて考えてみましょう。
スリーカードは次の3パターンが考えられます。
パターン1(0〜2まで同じ数値) 0 1 2 3 4 +−+−+−+−+−+ 手札|1|1|1|2|3| +−+−+−+−+−+ パターン2(1〜3まで同じ数値) 0 1 2 3 4 +−+−+−+−+−+ 手札|1|2|2|2|3| +−+−+−+−+−+ パターン3(2〜4まで同じ数値) 0 1 2 3 4 +−+−+−+−+−+ 手札|1|2|3|3|3| +−+−+−+−+−+
とりあえずこの3パターンをフォーカードのチェックの下に書いてみましょう。
<sample program 108-04>
if (hand[0].number == hand[1].number && hand[1].number == hand[2].number) { printf("スリーカード\n"); } if (hand[1].number == hand[2].number && hand[2].number == hand[3].number) { printf("スリーカード\n"); } if (hand[2].number == hand[3].number && hand[3].number == hand[4].number) { printf("スリーカード\n"); } |
デバッグ用コードを書き直し、3パターンともチェックしてみてください。
この時点で抱えている問題点について指摘し、対応策を考えます。
デバッグ用コードをフォーカードの状態にします。
/* デバッグ用コード */ hand[0].number = 1; hand[1].number = 1; hand[2].number = 1; hand[3].number = 1; hand[4].number = 2; |
このまま実行し、すぐに5を入力します。
<実行結果>
ハ ー ト: 1 ク ラ ブ: 4 スペード: 5 ダ イ ヤ: 6 ハ ー ト: 7 5 ハ ー ト: 1 ク ラ ブ: 1 スペード: 1 ダ イ ヤ: 1 ハ ー ト: 2 フォーカード スリーカード スリーカード 続行するには何かキーを押してください・・・
フォーカードの後に続いてスリーカードの表示が2回出ています。
これは、フォーカードのチェックを行った後、スリーカードのチェックも行っていることが原因です。
フォーカードはスリーカードの2つのパターンの条件を満たしています。
これを回避するためフォーカードであれば、他の役のチェックを行わないようにしなければなりません。
方法はいくつかありますが、今回はループを抜けるbreakを使った方法を紹介します。
for (;;) { } |
これは無限ループですが、これを下のように変えると、
for (;;) { break; } |
一度もループしないループ?になります。
これを使って、今までの手役の判定部分を書き換えてみます。
<sample program 108-05>
/* 手役の判定 */ for (;;) { if (hand[0].number == hand[1].number && hand[1].number == hand[2].number && hand[2].number == hand[3].number) { printf("フォーカード\n"); break; } if (hand[1].number == hand[2].number && hand[2].number == hand[3].number && hand[3].number == hand[4].number) { printf("フォーカード\n"); break; } if (hand[0].number == hand[1].number && hand[1].number == hand[2].number) { printf("スリーカード\n"); break; } if (hand[1].number == hand[2].number && hand[2].number == hand[3].number) { printf("スリーカード\n"); break; } if (hand[2].number == hand[3].number && hand[3].number == hand[4].number) { printf("スリーカード\n"); break; } break; } |
どれかの役の条件に当てはまれば、breakして抜け出すため他の役の判定は行われません。
どの役にも当てはまらない場合、最後のbreakで絶対に抜けますので、無限ループにはなりません。
これで先ほどのフォーカードのチェックを行うと。
<実行結果>
スペード: 2 ハ ー ト: 3 ク ラ ブ: 4 ダ イ ヤ: 6 ダ イ ヤ: 8 5 スペード: 1 ハ ー ト: 1 ク ラ ブ: 1 ダ イ ヤ: 1 ダ イ ヤ: 2 フォーカード 続行するには何かキーを押してください・・・
これで上手くいきそうです。
残りのペア系の役を判定しましょう。
フルハウスはスリーカードとワンペアの組み合わせです。
パターンとしては2パターンです。
パターン1(0〜2まで同じ数値、3・4でワンペア) 0 1 2 3 4 +−+−+−+−+−+ 手札|1|1|1|2|2| +−+−+−+−+−+ パターン2(2〜4まで同じ数値、0・1でワンペア) 0 1 2 3 4 +−+−+−+−+−+ 手札|1|1|2|2|2| +−+−+−+−+−+
スリーカードの条件はすでに作ってあるため、これを改良して作りましょう。
<sample program 108-06>
if (hand[0].number == hand[1].number && hand[1].number == hand[2].number) { if (hand[3].number == hand[4].number) { printf("フルハウス\n"); } else{ printf("スリーカード\n"); } break; } if (hand[1].number == hand[2].number && hand[2].number == hand[3].number) { printf("スリーカード\n"); break; } if (hand[2].number == hand[3].number && hand[3].number == hand[4].number) { if (hand[0].number == hand[1].number) { printf("フルハウス\n"); } else{ printf("スリーカード\n"); } break; } |
デバッグ用コードを書き換え、チェックしてみてください。
ツーペアは以下の3パターンです。
パターン1(0・1と2・3がペア) 0 1 2 3 4 +−+−+−+−+−+ 手札|1|1|2|2|3| +−+−+−+−+−+ パターン2(0・1と3・4がペア) 0 1 2 3 4 +−+−+−+−+−+ 手札|1|1|2|3|3| +−+−+−+−+−+ パターン3(1・2と3・4がペア) 0 1 2 3 4 +−+−+−+−+−+ 手札|1|2|2|3|3| +−+−+−+−+−+
<sample program 108-07>
if (hand[0].number == hand[1].number && hand[2].number == hand[3].number) { printf("ツーペア\n"); break; } if (hand[0].number == hand[1].number && hand[3].number == hand[4].number) { printf("ツーペア\n"); break; } if (hand[1].number == hand[2].number && hand[3].number == hand[4].number) { printf("ツーペア\n"); break; } |
ワンペアは以下の4パターンになります。
パターン1(0・1がペア) 0 1 2 3 4 +−+−+−+−+−+ 手札|1|1|2|3|4| +−+−+−+−+−+ パターン2(1・2がペア) 0 1 2 3 4 +−+−+−+−+−+ 手札|1|2|2|3|4| +−+−+−+−+−+ パターン3(2・3がペア) 0 1 2 3 4 +−+−+−+−+−+ 手札|1|2|3|3|4| +−+−+−+−+−+ パターン4(3・4がペア) 0 1 2 3 4 +−+−+−+−+−+ 手札|1|2|3|4|4| +−+−+−+−+−+
<sample program 108-08>
if (hand[0].number == hand[1].number || hand[1].number == hand[2].number || hand[2].number == hand[3].number || hand[3].number == hand[4].number) { printf("ワンペア\n"); break; } |
これでペア系は終わりです。
デバッグ用コードを「無効」にして少し遊んでみてください。
残りの役は次回にしましょう。