はじめに
人気大食い系 YouTuber のしのけん氏が最近開設したサブチャンネルの動画で,丸美屋のプリキュアカレーのシール全 30 種のコンプリートに挑戦する動画を上げています。メインチャンネルのほうでは,いつも凛々しいスーツ姿で大食いチャレンジするしのけん氏ですが,サブチャンネルのほうでは自宅(自室?)ということもあってカジュアルな姿でチャレンジする方針のようです。
プリキュアカレーのシールコンプするまで限界食いするも一生ダブり続けて絶望する漢 - しのけんの別腹
一食あたりの価格は安価ですが,全種類コンプリートしようとすると途方もない努力を必要とするコレクターズアイテム・・・古くは永谷園のお茶漬けの「東海道五拾三次カード」が思い出されますが,家族全員で(お年寄りでも)食せるお茶漬けと異なり,小児用のカレーとなると消費するのが大変です。
世の中の親御さんたちへ,もしも自分の子供たちが全種コンプリートに挑戦しようとしたら,それは果たして確率的に実現可能なのか?事前に*よおく*考える必要がありますよ,という記事です。
問題の定義
プリキュアカレー(小売用)には一箱につきシールが一枚入っているとします。シールは全 30 種類あり,ランダムかつ等確率であるとします。シール全 30 種類をコンプリートするためには,何箱必要になるでしょうか?
シミュレーションプログラム
手計算で解こうかと思いましたが,それは後回しにします。まずはシミュレーションで概要を把握しましょう。
プログラムは C# で作ります。採用の理由はまず乱数の品質です。C# の乱数ジェネレータ Random()
の品質についてはいろいろ議論されているようですが,C 言語の標準ライブラリの rand()
よりは格段にマシと判断しました。そして何よりも手軽さです。Windows PC であれば内蔵の C# コンパイラがあるので別途開発ツールをインストールしなくて済むからです。また実行スピードもネイティブコンパイラ並みに速いのも利点です。
ソースコードを以下に示します。シールは全 30 種ですから,1 種類 を 1bit として 32bit 整数型変数 flag
に収まります。何箱食したかのカウントはヒストグラムの配列変数 hist[]
でカウントします。C# の配列は 0-origin ですので,n + 1
箱食した場合は hist[n]
でカウントします。配列 hist[]
の要素数は 1000 なので 1000 箱以上になるとエラーになりますが,まあ確率的に起こらないだろうという判断です。
これを $10^9$ 回,すなわち 10 億回試行してみます。
using System;
using System.IO;
class PRECURE {
static long MAX_LOOP = 1000*1000*1000;
static int Main() {
var hist = new int[1000];
// var seal = new long[30];
var rand = new Random(0);
for(long i = 0; i < MAX_LOOP; i++) {
for(int n = 0, flag = 0; n < hist.Length; n++) {
int x = rand.Next(30);
// seal[x]++;
if((flag |= (1 << x)) == 0x3FFFFFFF) {
hist[n]++;
goto BREAK;
}
}
Console.Error.WriteLine("TABLE OVERFLOW ERROR!!");
return -1;
BREAK:
;
}
// for(int i = 0; i < seal.Length; i++)
// Console.Out.WriteLine("{0}\t{1}", i, seal[i]);
for(int i = 0; i < hist.Length; i++)
Console.Out.WriteLine("{0}\t{1}", i + 1, (double)hist[i] / MAX_LOOP);
return 0;
}
}
ビルド方法
下記のバッチファイル BUILD.CMD
と上記の C# プログラム PRECURE.CS
を同じフォルダに保存します。その後,エクスプローラから下記のバッチファイル BULID.CMD
をダブルクリックします。
ビルド用のバッチファイル BUILD.CMD はコチラ
※バッチファイルの文字コードは Shift-JIS で保存して下さい。
@echo off
setlocal
rem ----------------------------------------------------------------------------
rem ターゲットプログラム
rem ----------------------------------------------------------------------------
set TARGET=precure
rem ----------------------------------------------------------------------------
rem csc.exe にパスが通っているかどうかの確認
rem ----------------------------------------------------------------------------
set DOTNETPATH=
for %%I in ( csc.exe ) do set DOTNETPATH=%%~$PATH:I
if defined DOTNETPATH goto LETS_COMPILE
rem ----------------------------------------------------------------------------
rem .NET Framework のインストールパスを探す
rem ----------------------------------------------------------------------------
for /F "usebackq tokens=1,2,*" %%I in (
`reg query "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" /v InstallPath`
) do (
if "%%I"=="InstallPath" set "DOTNETPATH=%%K"
)
if defined DOTNETPATH goto APPEND_PATH
echo .NET Framework のインストールパスが見つかりません!
pause
exit /b
:APPEND_PATH
echo パスに %DOTNETPATH% を追加します。
set "PATH=%PATH%;%DOTNETPATH%"
:LETS_COMPILE
rem ----------------------------------------------------------------------------
rem コンパイル
rem ----------------------------------------------------------------------------
echo %TARGET%.cs をコンパイルします。
if exist %TARGET%.exe del %TARGET%.exe
csc -nologo -o -w:4 %TARGET%.cs
if exist %TARGET%.exe goto SUCCESS
echo %TARGET% のコンパイルに失敗しました!
pause
exit /b
:SUCCESS
echo %TARGET% のコンパイルに成功しました。
pause
exit /b
ビルドに成功すると下記のメッセージが表示されます。実行ファイル PRECURE.EXE
が作られているはずです。
パスに C:\Windows\Microsoft.NET\Framework64\v4.0.30319\ を追加します。
precure.cs をコンパイルします。
precure のコンパイルに成功しました。
続行するには何かキーを押してください . . .
実行方法
コマンドプロンプトを開き,シミュレーションプログラムが作られたフォルダに移動して PRECURE.EXE
を実行します。データは標準出力に出力されるので,適当なファイルにリダイレクトして下さい。
precure > DATA
計算結果
計算結果をグラフにまとめました。ちなみに ThinkPad X280 で約 25 分間かかりました。最新の PC なら半分の時間で済むでしょう。
確率のピーク(最頻値)は 101 箱,中央値は 113 箱,平均値は約 120 箱となりました。ちなみに最小値は 33 箱,最大値は 719 箱でした。つまり,しのけん氏が 10 億人いたとして,たった 33 箱でコンプリート出来る人が一人いた一方,719 箱までかかる人も一人いたということです。
- 最頻値の意味
- これは見てすぐ分かるように 102 箱でコンプリートできたしのけん氏が一番多かったという意味です。
- 中央値の意味
- 少ない箱数でコンプリートできた順に並べて,ちょうど半分の 5 億番目のしのけん氏が 113 箱だったということです。
- 平均値の意味
- このシミュレーションを行うのにプリキュアカレーが計 1200 億箱必要でした。これを 10 億人で割ると一人当たり 120 箱になります。また,これはこのチャレンジにおける期待値でもあります。
まとめ
全 30 種をコンプリートするための期待値は 120 箱になりました。
普通の人が個人で挑戦するとしたら一か月以上にわたり毎日三食カレー三昧になりそうですが,学校の一学年全員の協力を得られたら何とかなりそうです。
なお,今回のシミュレーションを手計算,あるいは解析的に解こうとすると非常に難しいので,次回に回します。