花札のシャッフルがひどいという話

www.gamedesign.jp

 これ…少しだけ特殊ルールの「こいこい」をやってみたのだけど、んまぁシャッフルがひどい。

 

f:id:sakurahirosi:20200710172303p:plain

gamedesign.jp/sp/ の花札:ゲーム画面のキャプチャ

  真ん中の左寄りに横4×縦2で並んでいるのが場札。下の8枚がプレイヤーの手札。

 場札を見たらボタン2枚にサクラが2枚、ついでにアヤメも2枚。

 手札はモミジが2枚にウメが2枚。

 

 現実の花札で、こういうことはほぼ絶対に起きない。ところがこのゲームでは、こういうことが普通に起きる。キッチリ並んでる札をザクザクザクと3回ぐらい切った感じ。おかげでゲームバランスが悪いったらありゃしない。

 

 自分のプログラミング経験から、まず乱数を疑ったのね。

 

 私の若い頃、Microsoft 系 BASIC の疑似乱数ってば16ビットの線形合同法で質が悪くて。そのせいで、この手のカードゲームを組むってときシャッフルがどうにもならなかった。

 メルセンヌ・ツイスタのご時世に、こんなシャッフルあるんかい???であって。

 

 そんで調べたら JavaScript の乱数の実装は、仕様上はブラウザ任せだけど、普通は Xorshift らしい(Chrome は32ビットのようだ)。メルセンヌ・ツイスタほどじゃないにしても、16ビット線形合同法よりはるかにマトモであるようだ。

 

 っつーことは、シャッフルのルーチン自体に問題がありそうだ。main.js を見てみる。JavaScript は完全に無経験だけど。

 

 まずメインのところで

function start_oneplay()
{

    (中略)
    // シャッフル
     while( !shuffle() ){
     }

    (後略)

  そいじゃあ shuffle() はと見てみたら

function shuffle(){
    var i;
    for( i=0; i<48; i++ ){
        var r = Math.floor(Math.random()*48);
        var tmp=game.yama[i];
        game.yama[i]=game.yama[r];
        game.yama[r]=tmp;
 }

(後略)

 

   一巡しか入れ替えやってないじゃん  _| ̄|〇

 

 いくら Xorshift が16ビット線形合同法よりマシなアルゴリズムだからって、入れ替えが一巡だけって…普通にありえんわ。

 

 このコードには続きがあって、何をやってんだか読み解くのに苦労したけど、要するに場札・手札に同じ月(植物)の札が3枚あるかどうかをチェックして、3枚あったら false を返し、なかったら true を返すということのようだ。

 そいでメインのところが while ( !shuffle() ) だから、3枚なかったら !shuffle() は false になるからそれでおしまい、あったらまた shuffle() を呼び出すという話。リアルなルールとまったく同じことだ…リアルでは札を配った後、手札あるいは場札に同じ月の札があったら再びシャッフルし直し。

 

 アタマにきたので html やら何やらかんやらを PC にダウンロードして、main.js をいじってみた。いろいろ試行錯誤したけど:

function shuffle(){
    var i, p, s, tmp;
    for( i=0; i<6144; i++ ){
        p = Math.floor(Math.random()*48);
        s = Math.floor(Math.random()*48);
        tmp=game.yama[p];
        game.yama[p]=game.yama[s];
        game.yama[s]=tmp;
    }

  変数 p と s は、この後の3枚チェックの部分で var p= なんて感じで宣言されて使われるので、関数の最初のところで宣言しといた。これで入れ替え48回×128回=6,144回ということになる。

 

 これでどうやらマトモなシャッフルになったわい。やれやれ…とは言えこれ元々スマホ向けであって、これじゃあ回数が多すぎて重たいかも知れない。もっと少なくて良いと思う。

 

 gamedesign.jp様、どうにかしてください。