昨日の続きですが、数学というよりもプログラミングの話しになります。
使う言語はC言語です。
では、どこから行きましょうか。
まずは、どんな仕様にするのがいいのか。
カードは全部で53枚、0から52を割り当てるのが良さそうだろう。
52をジョーカーにするのか、0をジョーカーにするのか、一般的に考えれば、52をジョーカーにするかと思います。
私も散々トランプなどのゲームをプログラミングしてきてますが、ジョーカーは1枚とは限らないので、52をジョーカーとすることが多かったです。
とりあえず、stock[]という配列に格納しておきます。
カードゲームでは必ず行われる行為のシャッフルのサブルーチンを作っておこう。
#define CARD_MAX 53
int stock[CARD_MAX];
void initial()
{
int i;
for (i=0; i<CARD_MAX; i++) {
stock[i] = i;
}
}
void shuffle()
{
for i, j, k;
for (i=0; i<CARD_MAX-1; i++) {
j = rand()%(CARD_MAX-i)+i;
k = stock[i];
stock[i] = stock[j];
stock[j] = k;
}}
とりあえず、こんな感じで。
さて、
誰かが上がったら、カードを抜くという作業をどういう風にするのがベストなのだろうか。
そもそも、試行回数を沢山やることになるので、余計な作業はプログラムを遅くするのでしたくない。
例えば、符号を変えるだけで、無くなったことにするのはどうだろうか。
そうすると…
0は符号を変えても0です。
ならば、今回は0をジョーカーにすると都合が良いですね。
#define JOKER 0
では、m番目のカードとn番目のカードのシーケンスが同じとは、プログラム的にはどうなるのか。
if ( stock[m] != JORKER && stock[n] != JOKER && stock[m]%13 == stock[n]%13 ) {
// m番目のカードとn番目のカードのシーケンスが同じ
stock[m] *= -1; // 上がったのでカードを取り除く
stock[n] *= -1; // 上がったのでカードを取り除く
}
ゲームが終わると、符号が逆転しているので、次のゲームはシャッフルして、符号を戻す作業を入れるのもなんなんで、…
フラグの変数を作っておくかな。
if ( stock[m] != JORKER && stock[n] != JOKER && (flag*stock[m])%13 == (flag*stock[n])%13 ) {
// m番目のカードとn番目のカードのシーケンスが同じ
stock[m] *= -1; // 上がったのでカードを取り除く
stock[n] *= -1; // 上がったのでカードを取り除く
}
ゲーム終了で、
flag *= -1;
とすれば、次のゲームは符号が逆転した状態で行える。
さて、いちいち52人に配るという作業をする必要性もないので、
2枚持っている人の2枚目のカードが入っている場所を保持しておけば良さそう。
引かれる人番号a1、引く人番号bとして、実際に引くところを考えると、
stock[a1]、stock[a2]とのどちらかを引くことになる。
bがa1を引いた場合、a1とa2の中身を入れ替える必要があり、
bがa2を引いた場合は、特になにもせず、
こんな感じで頭のなかで想像してみて、行けそうだなとなります。
さて、モンテカルロ法で試行回数を何回くらいにすればよいのだろうか。
これも確率論をやっていないので、まったくわかりません。
ただ、プログラミングの観点から言えば、先の記事で分母に現れた、53、52、51。
あとは百分率なので、100くらいは約数に持ちたいところではある。
53×52×51×100=14055600
小数点以下5桁くらいは出したいから、0を5個追加しますかね。
1405560000000
1兆4055.6億回もループさせれば、かなり良い制度の結果が出るのではないだろうか。
まぁ、多すぎたら0を削ろうかな。
仕様が固まってきたので、その2はこのへんで。
ではでは