背景

ソーシャルゲームでよく見かける「ガチャ」ですが、この記事ではその重み付き確率の保証方法を紹介します。

ガチャは売上・ユーザー体験・ゲームバランスに直結するので、意図通りの動作をするか慎重に確認する必要があります。 またアカツキではTDD (Test Driven Development)を採用しているので、 実装したプログラムが想定している確率に従っているかを確認するためのスペックが必要となります。

理論

使用する数理モデルは「離散確率密度変数」です。

例えばガチャで入手できるキャラクターのIDが であり、 その入手確率が (実装の便宜上自然数としますが、非負の実数としても一般性を失いません)によって重み付けされているとします。

このとき、ID のキャラクタが入手できる確率は、

となります。

さて、10000回の試行（ガチャを引くこと）をしたとき、入手できる確率が50%のキャラクタを入手した回数が何回なら、実装したプログラムは「正しい」といえるでしょうか？

実は、0回でも10000回でも正しい 可能性が あります（そのような結果が得られる確率は倍精度浮動小数点型でも表現できないくらい小さいですが）。 ただ、5000回付近のときがプログラムが正しい 可能性が高い だけですね。

このように、プログラムは本当に想定した確率で結果を返しているかは、可能性が高いか低いかでしか議論できません。 ただ、統計学の「区間推定」を使用すると、この「可能性」を定量的に評価でき、保証につなげることができます。

回の試行で、当選確率 のキャラクタが選ばれる回数は二項分布 に従います。 ここで二項分布が正規分布 で近似できるケースを考えます（その条件は統計学の教科書に書いてあります。ちなみに正規分布近似を行わなくてもF分布を使用して厳密な評価ができますが、計算が煩雑なのでこの記事では割愛します）。

すると、次のような区間推定をすることができます。

キャラが選ばれる回数： 回

ここで は信頼係数に応じて正規分布表より定まる係数です (google docsの normsinv という関数が便利です）。

プログラムがこの範囲内でキャラを選べば、「正しく」抽選が行われたと判断します。

具体的な数値をいれてみると、 例えば当選確率50%、試行回数10000回、信頼係数99.99とした場合、 の範囲内でキャラが選ばれれば、実装が正しいことになります。

実装

さて、ここまでは大学の統計学を授業の復習ですが、ここからはコードにどう落としこむかの話です。

筆者は最近ruby (on rails)を始めたばかりですが、前項の保証の話がrspecのフレームワークにぴったりとあてはまり、 "ruby makes programmers happy"ってこういうことかも！と嬉しくなったのでこの記事を書こうと思いました。

もちろん他の言語でも同じことはできますが、保証(spec)まで含めてこれだけ簡潔に書けるっていいですね。

まとめ

前項の実装は信頼係数99.99%を使用しているので、エラーメッセージにも書いてありますが、1/10000の確率でfailします。 ただやみくもに関数を何回か実行してみて「多分あってるだろう」と確認するよりは確度を高く、コードを保証することができますよね。 以前の記事にも書きましたが、コードの品質を保証するためには表現したい対象を数学的・体系的に捉えることが重要な要素の一つであると思います。

参考リンク：https://staff.aist.go.jp/t.ihara/normsdist.html