スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

トレカを全種集めるのに必要な購入数をモンテカルロ法で推定する

宝くじなんかはさっぱり買わないのですが、ちょっとしたくじ引きやトレーディングカードを時々買ってしまって、
あとになって無駄な出費だったなー、等と後悔してしまうがあります。

以前から気になっていたことなのですが、くじ引きみたいな商品を全種集めるにはいったいどの程度の個数を購入しなければならないのでしょうか。

数学が得意なかたであれば、すぐに数式を出せるのかもしれませんが、今回は手抜きをしてモンテカルロ法で簡単に予測を出してみました。

で、今回の題材はこれ


アイドルマスター シンデレラガールズウエハース


これは要するにおまけ付きお菓子の一種なのですが、ウエハースにランダムでイラストカードが1枚付いてくるという商品です。

サイトを見ると、カードの柄はすべてで32種類で、さらに柄が4つのグループに分かれているということのようです。



・コード

もう少し簡単に書けるような気もするのですが、とにかく今回はこんな感じになりました。

乱数には普通のrand関数を使用して、後は普通にモンテカルロ法で回数を予想するだけのコードです。

#include "stdafx.h"

#include <iostream>
#include <fstream>
#include <vector>
using namespace std;

int variation = 32;
int repeat = 1000;


template<typename T>
void print(const T& val)
{
    static ofstream out("out.txt");
    out << val << endl;
}


template<typename T>
class Average
{
public:
    Average(void) :
        sum(0),
        cnt(0)
    {
    }

    void add(const T& val)
    {
        sum += val;
        cnt++;

        print(val);
    }

    void average(void)
    {
        print(calcAverage());
    }

    double calcAverage(voidconst
    {
        if (cnt == 0)
            return T(0);
        return sum / (double)cnt;
    }

private:
    T sum;
    double cnt;
};

bool IsFilled(vector<int>& bf)
{
    for (int i : bf)
    {
        if (i == 0)
            return false;
    }
    return true;
}

int GetCompCount()
{
    int cnt = 0;

    vector<int> bf(variation, 0);
    while(!IsFilled(bf))
    {
        cnt++;
        bf[rand() % variation]++;
    }

    return cnt;
}

// 全柄コンプリートするまでの平均購入数を求める
void TestA(void)
{
    Average<double> a;
    for (int i = 0; i < repeat; ++i)
    {
        a.add((double)GetCompCount());
    }

    a.average();
}

bool IsFilledSub(vector<int>& bf, int reqcnt)
{
    for (int i = 0; i < reqcnt; ++i)
    {
        if (bf[i] == 0)
            return false;
    }

    return true;
}

int GetSubCompCount(int reqcnt)
{
    int cnt = 0;

    vector<int> bf(variation, 0);
    while(!IsFilledSub(bf, reqcnt))
    {
        cnt++;
        bf[rand() % variation]++;
    }

    return cnt;
}

// 特定の柄をすべて集めるまでの平均購入数を求める
void TestB(void)
{
    Average<double> a;
    for (int i = 0; i < repeat; ++i)
    {
        a.add((double)GetSubCompCount(4));
    }

    a.average();
}

int _tmain(int argc, _TCHAR* argv[])
{
    TestA();
    TestB();
}




・結果

上記のコードで、下記2つの推定値を求めています

  • 全柄がそろうまでに必要な購入数の平均値
  • 特定の7柄がですべてそろうまでに必要な購入数の平均値


尚、7柄というのは、上記のサイトで見ると、スペシャルカード、フォトカードというのがそれぞれ7柄あるようですので、そのどちらかをコンプリートする、という想定です。

で、結果は

全柄 = 129.37 個
7柄 = 66.60 個

となりました。

分布は


全柄
20150725A.png


7柄
20150725B.png


金額の期待値は全柄そろえようと思うと、大体16766円程度のようです。

また、今回のテストでは、最悪の場合370個を超えてしまっていますが、その場合の金額は総額で
なんと47952円と5万円近い出費になってしまいます。


結果をみるとまあそんなもんかな、という気もしますが、全柄集める、とかこれだけは出したい、という思いで挑戦すると
かなりの出費になる遊びのようですので、よほど裕福な方でなければあんまり入れこまないほうがよさそうです。
スポンサーサイト

コメントの投稿

非公開コメント

カレンダー
10 | 2017/11 | 12
- - - 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 - -
最新記事
カテゴリ
Qt (21)
SDL (2)
MFC (2)
検索フォーム
月別アーカイブ
最新コメント
最新トラックバック
RSSリンクの表示
リンク
リンク(管理用)
FC2カウンター
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。