開発
基礎
トランプのカードをシャッフルするために必要なこと
- カードが重複しないことと、カードの順番を乱数で生成すること
例えば、5枚のカードがあるとして、単純に乱数を使うとカードが重複してしまいます。
そのため順番にすべてのカードを他のカードと差し替えていく必要があります。
差し替えるという考え方で、カードの重複を避けられます。
※実際、カードのシャッフルの方法はいろいろありますよね。
テーブルの上に全部広げてまぜまぜする。
ふた山に分けてお互いをパラパラとまぜる。
カードの一番上と一番下を順番に引き出して混ぜ合わせるなど
カードの混ぜ方によってもカードの混ざり具合はまちまちです。
また、現実では混ぜたはずなのに同じスーツが順番通りに自分のところへ配られたり、同じ数字が配られたり、そういうのもトランプの楽しみだよね。
プログラムも同じ。
今回は一番自然に偶然の並びも許容したランダムになる方法を考えてみました。
- まずは乱数発生のスクリプトから
乱数発生の関数はMath.random() 関数を使用します。また、数値の範囲を決める場合も決まった構文があります。
たとえば1~10までの間で乱数を発生しさせたい場合は、下記の関数へgetRandomNumber(1, 10.)と引数を送ります。function getRandomNumber(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }
- 乱数を生成する時、処理中のカードと同じ順番を避ける
たとえば5枚組のカードの3番目を他のカードと差し替えるため乱数を生成したとします。
その場合5分の1の確率で同じ順番がでます。それだと意味がないので、同じ順番が出た場合は、違う数値が生成されるまで乱数を生成する仕組みが必要です。下記がそのスクリプトになります。違う数値が生成されるまで乱数の生成を繰り返します。do { r = getRandomNumber(1, cardsCount); // 1からカード総数(1, cardsCount)の範囲でランダムな数を生成 } while (r == d);//dは処理中のカードの順番
- 補足
『javascript,シャッフル』で調べるとよくあるのは、配列を順番に他のカードと差し替えるところは同じですが、カードを重複させないために、差し替えるカードの数がどんどん減少していくロジックが多いです。※
これだと最初の方のカードは差し替える対象が50枚とかなのに、最後の方のカードになると残り一枚とだけ差し替えることになりこれじゃあシャッフルじゃあありませんね。
なので常にすべてのカードを対象にし、ランダムに差し替えるようにしました。
また、全部のカードをシャッフル対象とせず、使用する枚数のみシャッフルするという考え方もあるようですが、やはりここはリアルに全てのカードをシャッフルしたいですね。処理時間をかけないという意味があるようですが…。
でも、現実でもシャッフルにじっくり時間をかけてシャッフルしますよね。この待ち時間に期待感が高まるわけですから。
このワクワクこそがロマンなんですから。
※Fisher-Yatesシャッフルがこれですが、確率を計算すると最後の一枚がすでに1/52!(総数52枚の場合)で入れ替わった数なのですべてのカードが均等なランダム確率だそうです。
ただ、これだと面白くない!ちょっと時間はかかっても現実的な偶然も盛り込んだシャッフル(つまり偶然、元と同じカードになってしまうの)が面白いと感じます。
また、 Fisher-Yatesは一枚づつ少なくなるのでループの処理中に結果を返すのが可能ですが、今回のシャッフルは配列全体を入れ替える方法なので処理がすべて終わった段階で、配列ごと結果を返す必要があります。そうしないと重複がでる。
そういう意味ではFisher-Yatesの方が効率よく時間もかからないし、合理的だといえます。
じ、時間を気にするあるいは配列の総数が膨大な状況では重要な点となりますね。。。(汗。
しかし、今回はトランプのシャッフル。
52枚の配列全体を混ぜ混ぜする方が時間はかかるがより面白い!偶然元のままのカードも発生したりするのでそれも面白い!
よね。