スポンサーリンク

ピックアップ2.5%でも100回まわして全部ハズレる人が100人中8人くらいいる

ガチャとプログラムの話なんですけど、(スマホゲー等の)出現率1%なら100回まわしたら1回は当たるだろ、という思考が危険なのはわりと有名な話かと思います。

もし、え?と疑問に感じた方のために軽く説明するとスマホゲー等のデジタルゲームはリアル世界のカプセルトイとは異なり在庫が無限だからです。

例えば、カプセルが100個しか入らないガチャガチャ本体に1個だけアタリが入っている場合、100回まわせば必ず1個はアタリがもらえます。これはガチャガチャのハンドルをまわせばまわすほど在庫が減るから。

初回は1/100だった確率が2回目は1/99に、3回目は1/98、4回目は1/97…..最終的には1/1=当選確率100%になるわけですね。

一方、在庫無限なデジタルゲームにおいては何十回、何百回、何億回まわそうと1/100は1/100です。試行回数が増えれば増えるほど当選確率に近づきますが、決して100%になることはありません。

スポンサーリンク

〇%のガチャを〇回まわしたときに当たる確率を計算してみる

実際にJavaScriptで計算するプログラムを書いてみました。計算式は、

1 - (100% - [出現率])^試行回数

です。要は失敗する確率を試行回数分掛け算するだけ。

出現率%のガチャを回まわして当たる確率は%である

ガチャの確率計算をするJavaScript

HTMLソース

先にHTMLから。

<p>
	出現率
	<input type="number" id="a_rate" value="2.5" min="0" max="100">%
	のガチャを
	<input type="number" id="count" vmin="0" max="1000" value="10">
	回まわして当たる確率は
	<span id="result"></span>%である
</p>
<p>
	<button id="trial">実際にまわしてみる</button>
	<button id="reset">リセット</button>
</p>
<div id="trial_result"></div>

<style>
#a_rate,#count {
	width:3em;
}
#ads {
	display:block;
	color:red;
}
#trial_result {
	flex-wrap:wrap;
	display:flex;
}
#trial_result span {
	border:1px solid gray;
	display:flex;
	justify-content:center;
	align-items:center;
	width:40px;
	height:40px;
	margin:0 1px 1px 0;
}
.win {
	color:red;
}
.lose {
	color:gray;
}
</style>

出現率のIDを”a_rate”、回数のIDを”count”、結果のIDを”result”として後はJavaScript任せです。

確率計算についてはそれだけで、スタイルシートの大部分は「実際にまわしてみる」ボタンを押したときの枠線などの描画ですね。わりとどうでもいい部分で長くなりました。

JavaScriptソース

<script>
let trial_count = 0;
let win_count = 0;
window.addEventListener('load', function () {
	document.getElementById('a_rate').onchange = calcWin;
	document.getElementById('count').onchange = calcWin;
	document.getElementById('trial').onclick = trialButton;
	document.getElementById('reset').onclick = resetButton;
	calcWin();
});
//[実際にまわしてみる]ボタン
function trialButton()
{
	trial_count++;
	let count = document.getElementById('count');
	let a_rate = document.getElementById('a_rate').value / 100;
	let result = '';
	for (let i = 0; i < count.value; i++) {
		if (Math.random() <= a_rate) {
			result += '<span class="win">●</span>';
			win_count++;
		} else {
			result += '<span class="lose">×</span>';
		}
	}
	result += '<div style="width:100%;">' + trial_count + '回目 (取得数:' + win_count + '個)</div>';
	document.getElementById('trial_result').innerHTML = result;
}
//[リセット]ボタン
function resetButton()
{
	trial_count = 0;
	win_count = 0;
	document.getElementById('trial_result').innerHTML = '';
}
//当選確率
function calcWin()
{
	let a_rate = document.getElementById('a_rate');
	let count = document.getElementById('count');
	if (parseInt(a_rate.value) < a_rate.min) a_rate.value = a_rate.min;
	if (parseInt(a_rate.value) > a_rate.max) a_rate.value = a_rate.max;
	if (parseInt(count.value) < count.min) count.value = count.min;
	if (parseInt(count.value) > count.max) count.value = count.max;
	let winrate = 1 - (1 - a_rate.value / 100) ** count.value;
	if (winrate > 0.9999) winrate = 0.9999;
	document.getElementById('result').textContent = (winrate * 100).toFixed(2);
}
</script>

こちらも長くなりましたが、実際に確率計算している部分は

let winrate = 1 - (1 - a_rate.value / 100) ** count.value;

この1行で終わり。

出現率や回数を変更(onchange)したときに呼ばれるcalcWin関数でやっている大部分は数値の範囲チェックですね。出現率が100%を超えないようにしたり、浮動小数点の桁あふれで0.99999999999999が100%と表示されてしまうのを防いだり…………そんな感じ。

[実際にまわしてみる]ボタンの処理では設定された試行回数分、Math.random()を実行しています。JavaScriptのMath.random()は0~1までの(0は含み1は含まない)ランダムな浮動小数点数を返すので、その値が出現率(2.5%なら0.025)以下ならアタリと判定しています。

まとめ

確率1%なら100回に1回は当たるはず! → うっそで~す♪そのとき100回まわして当たる人は6割くらいで、残り4割の人は100回全部ハズレなのでしたぁ~www

ということを知ったのは随分前ですが、数学の授業なんてまともに受けたことがなかったぼくとしては計算式を見て、あぁ~なるほど!と感動したのをよく覚えています。

しかし鳥頭なぼくはまたすぐ忘れてしまうので、こうしてコード化&記事化して、未来のぼく用に残しておくことにしました。



……………………スマホゲーの課金はほどほどにねっ!

コメント

タイトルとURLをコピーしました