はじめに
多くのソーシャルゲームでガチャが実装されていますが、サーバ側で確率を操作されているのではないか、といった疑念を抱く方は多いと思います。
プログラムのバグによって、ユーザごとに異なる確率を誤って表示してしまったゲームでは、多くの批判が集まっていました。
仮にガチャのシステムを含めてすべてのソースコードを開示したとしても、サーバ上で動くソースコードと一致しているか検証することは困難ですから、利用者の信用を得る根本解決にはならないと思います。
そこで、利用者が、ガチャの確率が改ざんされていないことを検証可能である仕組みを考えてみました。
ハッシュ関数を利用することで、以下を実現します。
- 利用者が、ガチャの終了後に確率が不正に操作されていないことを検証できる。
- 利用者は、どのようなアイテムが出るのか、推測することができない。
運用の流れ
ユーザには、ユーザごとに異なるユーザIDを割り当て、利用者に公開します。
フレンドなどの仕組みがあれば、そのIDをそのまま利用することもできます。
(ただし、他人のユーザIDを知ることができる場合、他人に前回のガチャでどんなものがひける/ひけたのかわかってしまいます。それが気になる場合は、他人には見せない形のユーザIDを別途割り当てる必要があります。)
ガチャごとに、アイテムの一覧テーブルを公開します。
テーブルの中に入っているアイテム個数の比率が、そのまま出現確率になります。
利用者はこのテーブルを見ることで確率を確認できますが、本当にそのテーブルが使われたのかは、ガチャが終了するまでは検証できません。
さらに、ガチャの実施ごとに、秘密キーを運用側で生成します。
このキーはガチャが終了するタイミングまでは秘密にしておき、終了後に利用者に公開します。
利用者はガチャ終了後、ユーザID・アイテムの一覧テーブル・秘密キーを入手すれば、そこからガチャの結果を計算でき、実際に得られたアイテムと差異がないか検証ができます。
(なお、もし更にガチャを回していればどんなアイテムが得られたかは、計算できてしまいます。)
常設のガチャの場合は、週次や月次で秘密キーを変えて公開し、そのたびにガチャを引いた回数をリセットすることで対応できます。
アルゴリズム
ユーザIDと、ガチャを回した回数と、秘密キーを使ってHMACを計算し、その剰余を使ってテーブルからアイテムを求めます。
実際に例にして記載します。
Sレアを2%で2種類、レアを8%で2種類、ノーマルを20%で4種類排出するものとします。
提供確率に応じて、IDの範囲を決めておきます。
この場合、全部で50個のアイテムがあり、確率に応じてアイテム数が、Sレアなら1個、レアなら4個、ノーマルなら10個というように変わる形になります。
アイテム | 確率 | ID |
---|---|---|
エンタープライズ(Sレア) | 2.000% | 0 ~ 0 |
フッド(Sレア) | 2.000% | 1 ~ 1 |
赤城(レア) | 8.000% | 2 ~ 5 |
加賀(レア) | 8.000% | 6 ~ 9 |
サンディエゴ(ノーマル) | 20.000% | 10 ~ 19 |
ジュノー(ノーマル) | 20.000% | 20 ~ 29 |
エイジャックス(ノーマル) | 20.000% | 30 ~ 39 |
ヴァンパイア(ノーマル) | 20.000% | 40 ~ 49 |
秘密キーが "00112233445566778899001122334455" だったとすると、ユーザID が "1234-5678-9012" のユーザの1回目のガチャは、メッセージを "1234-5678-9012 1" として計算したHMACの剰余、2回目のガチャは "1234-5678-9012 2" として計算した剰余、といったように求めていきます。
回数 | HMACのメッセージ | ID | アイテム |
---|---|---|---|
1 | 1234-5678-9012 1 | 0 | エンタープライズ(Sレア) |
2 | 1234-5678-9012 2 | 38 | エイジャックス(ノーマル) |
3 | 1234-5678-9012 3 | 14 | サンディエゴ(ノーマル) |
4 | 1234-5678-9012 4 | 39 | エイジャックス(ノーマル) |
5 | 1234-5678-9012 5 | 6 | 加賀(レア) |
シミュレータ
上記のような計算を試せるJavaScriptを組んでみました。
設定をかえて、シミュレートボタンを押すと結果が出ます。
ユーザID、秘密キー、テーブルが同一だったら、結果が一定になることなどが確認できると思います。
まとめ
このような実装であれば、ソースコードを公開する等しなくても、運用が正しくされているか、利用者が検証可能になります。
ガチャだけじゃなくても、ドロップなどでも回ってるのに全然出ない、みたいなこともありますよね。
こういう仕組みを導入してくれたら、安心して課金・周回できるようになりそうです。
(追記)運営側が予測できないようにした修正版アルゴリズム
コメントで、あらかじめ運命が決まっているものを売るのはガチャとはいえないのではないか、という指摘をいただきました。
ごもっともです。
そこで、運営側が結果を予測できないように、利用者側でくじ番号を指定するような形にすると、問題を解消できると思います。
ガチャを引く回数をメッセージに追加するのではなく、ユーザが指定した任意の番号を追加するようにします。
同一番号を複数回指定させないようにする必要はありますが、ユーザに指定させることで、ガチャを引くたびにランダムにできます。
現実でも、ロト6など利用者側がくじの番号を指定するものがありますから、受け入れやすいように思います。
(自分と彼女の誕生日の番号で毎回ガチャを1回引く、みたいな使われ方などもありそうです)
また、多くのガチャは10回連続で引くと、レア保証されるなどのボーナス要素があります。
レア保証のボーナス要素は、10回引いて、レアがでなかった場合に、レアがでるまで一定の法則でメッセージを変えながらガチャを引き、レアがでた段階でその1枚を排出するということにすれば実現できます。
上記の要素を実装したシミュレータを作ってみました。