今回は、麻雀ゲームを作るときに発生するかもしれないプ:「配牌バリエーション少なくね?」という問題点の解決方法を提示。
前回のやりかたのままだと、136!種類あるはずの山のうちのほんのちょっと、(10の200乗)分の1ほどしかバリエーションがない。
これを解決するのは、難しいことではなく・・・。
■解決法1
// 初期化で一旦配ったら
// まず0~135を行儀よくつめて
void init()
{
for(i=0;i<1
table[i]=i
}
}
// 前回のtableの内容は残しておいて毎回シャッフル
// 基本どおり丁寧にシャッフル。
void nokoshite_kubar
{
for(int i=0; i<136; i++) {
int nokori=136
int pos= i + (rand30000
swap(i, pos); // box[i]とbox[pos]の内容を交換
}
}
///////////////
全体の流れ
// 最初に初期化したら、半荘が終わっても2度と呼ぶ必要なし。
init();
nokoshite_kubar
対局(); // 1局目
nokoshite_kubar
対局(); // 2局目
nokoshite_kubar
対局(); // 3局目
・・・・・・
とすればよい。「なぁんだ、当たり前ジャン」という話。これで136!に手が届いた。時間等での乱数の揺らしを時々入れてあげて完成。
これができてない場合。乱数側をちょっと弄って、例えば、64ビット数4個使用などとしても、(10の*00乗)分の1レベルからは脱却していない。また、それに気づいていないところが重要な問題。
■解決法2
解決法1とは効果的には似てるけど、別な方法を提示。それは、tableの中を前回の捨て牌の順で詰めて行くという方法。その後でシャッフル。
これは電動卓や手積み卓をシミュレートしているカタチ。ある意味、一番すなお。
また、解決法1の「時間等の乱数の揺らしを時々入れてあげる」という部分を「捨て牌を使う」というところまで拡大したという見方もできる。
・コメントありがとうございます。メルセンヌ・ツイスター、良さそうです。勉強になります。
・但し、「時間等での揺すり方」を間違わないようにする必要はあります。
・今回の記事の方法は「周期30000の擬似乱数」でも大丈夫という方法でした。
・メルセンヌ・ツイスタでの大きい「内部ベクトル」のかわりに、アプリ側で既に用意されているtableを流用しているカタチともとれます。
ダイレクトな解決法で、メルセンヌ・ツイスターを使うのはどうでしょう。0
.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html
周期2^19937-1>10^600
#Cソース
http://www.math