前回の続きとして手札の交換を作ります。
作る前にゲームの流れをもう一度書いておきます。
<ゲームの流れ>
デッキを初期化する ↓ デッキをシャッフルする ↓ 手札としてデッキの先頭から5枚配る ↓ 変更するカードを選択する ↓ カードを変更する ↓ 手役を判定する ↓ 終了 |
手札の交換は、
変更するカードを選択する
と
カードを変更する
という部分になります。
まずは、変更するカードを選択しなければ交換できません。
選択する方法はいくつもありますが、その内の1つの方法を考えてみます。
選択しているかしていないかという状態を表す変数としてselectFlagを構造体に追加します。
デッキの初期化の際にselectFlagを0に設定しておきます。
<sample program 106-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; /* 入れ替え用 */ 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); } return 0; } |
配列の添え字を入力することで後の処理が楽になるので0〜4までの数値を入力させます。
入力用の変数としてselectを準備します。
<sample program 106-02>
#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); } /* 入れ替えるカードの選択 */ do { scanf("%d", &select); } while (select < 0 || select > HAND_NUM - 1); return 0; } |
<実行結果1 正常な範囲の数値を入力>
スペード: 4 スペード: 8 ハ ー ト: 8 ク ラ ブ: 8 ダ イ ヤ:11 0 続行するには何かキーを押してください・・・
<実行結果2 範囲外の数値を入力後、正常な数値を入力>
スペード: 1 ク ラ ブ: 3 ダ イ ヤ: 5 ク ラ ブ:10 ハ ー ト:11 -1 5 2 続行するには何かキーを押してください・・・
do〜whileを使って範囲外の数値が入らないようにしておきましょう。
ただ、このままでは1枚しか選択出来ないため、入力をループさせなければなりません。
do〜whileの範囲設定で0〜4までしか入力出来なくなっているため、範囲も変更する必要があります。
<sample program 106-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; /* カード選択用 */ 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; } } return 0; } |
<実行結果1 全て選択して終了>
スペード: 2 ク ラ ブ: 3 スペード: 3 ク ラ ブ: 5 ダ イ ヤ: 6 0 1 2 3 4 5 続行するには何かキーを押してください・・・
<実行結果2 全く選択せず終了>
ハ ー ト: 1 ダ イ ヤ: 4 ハ ー ト: 4 ク ラ ブ: 7 スペード: 9 5 続行するには何かキーを押してください・・・
入力と入力完了は出来るようになりましたが、肝心のフラグが変更されていません。
気を付けたいのは、selectに入力される数値の範囲は0〜5ですが、手札の配列の添え字は0〜4までということ。
5が入力された時に、手札の5番目(hand[5])の数値を変更するとバグの元となります。
そのため、フラグの変更はbreak文が入ったif文の後でなければなりません。
<sample program 106-04>
#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;
}
hand[select].selectFlag = 1;
}
return 0;
}
|
<実行結果>
ハ ー ト: 2 スペード: 3 スペード: 9 ク ラ ブ:10 ハ ー ト:12 3 5 続行するには何かキーを押してください・・・
選択するプログラムは出来ましたが、選択されたかどうか表示上は分かりません。
せめて、どのカードを選択したか↓のように何か「印」を付けたいところです。
<実行結果>
ハ ー ト: 2 スペード: 3 スペード: 9 ク ラ ブ:10 * ←印 ハ ー ト:12 続行するには何かキーを押してください・・・
上記のように、選択したカードに*印を付けたいと思います。
すでに表示してある文字に追加して表示は(特殊なことをしない限り)出来ませんので、再度手札を表示するプログラムを追加します。
カードを選択する度に表示を更新する必要がありますから、無限ループの中に追加します。
<sample program 106-05>
#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;
}
hand[select].selectFlag = 1;
/* 選択した手札の表示 */
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");
}
}
}
return 0;
}
|
<実行結果 VC++ 2枚交換して終了>
ハ ー ト: 2 ダ イ ヤ: 2 スペード: 9 スペード:11 ク ラ ブ:13 2 ハ ー ト: 2 ダ イ ヤ: 2 スペード: 9 * スペード:11 ク ラ ブ:13 3 ハ ー ト: 2 ダ イ ヤ: 2 スペード: 9 * スペード:11 * ク ラ ブ:13 5 続行するには何かキーを押してください・・・
見た目は出来ているように見えますが、1つ問題点があります。
何か分かりますか?
何度も書いてきましたが、書いてあることを打ち込んで、実行例のまま「正しく」実行しているだけではいけません。
色々試して、気づいた点を直したり、もっと便利な機能を追加したりすることを考えながらやってみてください。
さて、答えは分かりますか?
答え:
間違えて選択してしまったカードの選択解除が出来ない
これに対応するため、フラグを循環(1と0を切り替え)出来るように変更します。
<sample program 106-06>
#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");
}
}
}
return 0;
}
|
<実行結果>
ダ イ ヤ: 1 ハ ー ト: 8 ハ ー ト: 9 スペード:11 ハ ー ト:12 0 ←0番を選択 ダ イ ヤ: 1 * ハ ー ト: 8 ハ ー ト: 9 スペード:11 ハ ー ト:12 0 ←0番を選択解除 ダ イ ヤ: 1 ハ ー ト: 8 ハ ー ト: 9 スペード:11 ハ ー ト:12 5 続行するには何かキーを押してください・・・
これでカードを選択するプログラムが完成しました。
次回は選択したカードを交換するプログラムを作りましょう。