前回作成したshuffle.c
を元に、トランプらしいルールを付け加えて行こう。なお、今回から
ルールを付け加えて行くので、ジョーカーなしに単純化して考える。
人間とコンピュータが対戦できるように、人間の持ち札とコンピュータの 持ち札を変数として用意しよう。どんなゲームをする場合でもトランプ全部の 枚数よりも手札が多くなることはないだろう。ただ、「今何枚手札があるか」 という情報はつねに把握しておく必要がある。
これを踏まえて、トランプのカードを53枚持てる構造体を作ると 持ち札の管理がしやすそうである。つまり、1枚のトランプの構造体が
typedef struct { /* 1枚のカードの構造体 */
char *suit; /* スート */
int number; /* 数字 */
char *name; /* 読み名 */
} aCard;
のように定義されたものとすると、これを最大53枚持てる構造体、
typedef struct { /* 山、手札などカードの集合体 */
aCard card[CARDS]; /* 単一カードが52枚 */
int n; /* 今何枚あるか */
} Cards;
を定義すると、山と手札の管理を一つの構造体変数で行なえるようになる。 このように、構造体のメンバに更に構造体を含めても良い。
上記の構造体 Cards
を利用する場合、ハートのAから
クラブのKまでカードを作る方法を考えよう。先週の
initcard2.c
では
カード1枚を保持する構造体Card
の配列を受け取って
初期化したのだが、今週は一つの構造体が山(または手札)全体を保持することに
なるので、それに注意して初期化関数を書くと以下のようになる。
void initialize(Cards *d) /* Cards構造体のポインタ */
{
static char *suits[] = {
"ハート", "スペード", "ダイヤ", "クラブ", "ジョーカー"
};
static char *numbers[] = {
"JOKER", "A", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"J", "Q", "K"
}; /* ここまでは initcard2 と同じ*/
int s, n, i;
for (i=0; i<CARDS; i++) {
s = i/13; /* 13で割ると切捨て */
n = i%13 + 1; /* 13で割った余り+1 */
/* d->card がaCard構造体の配列メンバになる。
d->cardは配列なので d->card[x] でアクセスする。 */
d->card[i].suit=suits[s];
d->card[i].number = n;
d->card[i].name = numbers[n];
}
d->n = 52; /* この山が持っている枚数をセット */
}
同様にシャッフルのための関数は以下のように書き換えられる。
void shuffle(Cards *d)
{
int i, pair;
int length=d->n;
srandom(time(NULL));
aCard work;
for (i=0; i<length; i++) {
pair = random()%length; /* 交換相手の決定 */
memcpy(&work, &d->card[i], sizeof work);
memcpy(&d->card[i], &d->card[pair], sizeof work);
memcpy(&d->card[pair], &work, sizeof work);
}
}
initialize, shuffle
を利用して、52枚のカードを
シャフルした状態で山に積む部分は以下のようになる。
Cards deck;
initialize(&deck);
shuffle(&deck);