カジノに勝てるか?モンテカルロ・シミュレーションをPythonで実装する。

カジノに勝てるか?モンテカルロ・シミュレーションをPythonで実装する。

リスクは、あなたが何をやっているか理解していない時に起こる
ウォーレン・バフェット

こんにちは。最近は確率的プログラミングにハマっている、機械学習エンジニアのしゅんです。Google Colaboratoryやpymc3使って、分析が楽にできるようになりましたね。

さて、本題ですが、カジノはどうやって利益を上げているのでしょうか?

実は、その秘密は簡単でお客にできるだけ長くプレイさせることです。長くプレイすればするほど、お金を失う確率が上がるのです。今回はその様子をモンテカルロ・シミュレーションを使って可視化したいと思います。

モンテカルロ・シミュレーションとは?

モンテカルロ・シミュレーションは、財務、プロジェクト管理、コスト、のリスクと不確実性を理解するために使用される手法です。モンテカルロ・シュミレーターは、潜在的はリスクや結果を視覚化し、意思決定に役立てます。

今回は1~100数字を使った簡単なゲームをしてみましょう。

ルールは簡単。

・1-51の数字が出たらカジノ勝ち

・52-100が出たらあなたの勝ちです。

ルーレットで言う赤黒を当てるのと同じです。

はたしてあなたはこのゲームに参加すべきでしょうか?

シミュレートする前に、ハウスエッジ(カジノの控除率)を計算しましょう。ハウスエッジとはプレーヤーの賭けに対するカジノ側の平均利益です。

あなたが1ドルかけるとします。

・あなたが勝つ確率 = 49/100

・カジノが勝つ確率 = 51/100

プレーヤーに対する期待値は

1 * (49/100) -1* (51/100) = -0.02   = -2%

今回のゲームのハウスエッジは2%です。比較のためヨーロピアン・ルーレットのハウスエッジは2.7%です。今回のゲームの方がルーレットより利益を出せる可能性が高いです。

しかし、このわずかな差があとでとんでもないことになるのです。

それでは、Pythonで様々なシナリオをシミュレートしてみましょう。プレイヤーが継続的に賭け続けた場合を視覚化します。

1.ライブラリをインポート

import random
import matplotlib.pyplot as plt

2.均一な確率分布で数字をランダムに生成します。プレーヤーが勝てばTrue

カジノが勝った場合はFalseを返します。

def rolldice():

    dice = random.randint(1,100)

    if dice <=51:
        return False
    elif dice >51 & dice <=100:
        return True

3.賭けをシミュレートする関数を作成します。関数に3つの引数を指定します。

引数

・Total funds 総資金 : プレイヤーの総資金($10,000)

・Wager Amout 賭け金:各ゲームでプレイヤーが賭ける金額($100)

・Total plays 総プレイ数:プレイヤーがゲームをプレイした回数。


def play(total_funds, wager_amount, total_plays):

    Play_num = []
    Funds = []
    play = 1

    while play < total_plays:
        #If we win
        if rolldice():
            total_funds = total_funds + wager_amount
            Play_num.append(play)
            Funds.append(total_funds)
        else:
            total_funds = total_funds - wager_amount 
            Play_num.append(play)
            Funds.append(total_funds)
            
        play = play + 1
        
    plt.plot(Play_num,Funds)
    Final_funds.append(Funds[-1])
    return(Final_funds)

4.最後に上記の関数を呼び出し、複数のシナリオでゲームをシミュレートします。ゲームの最終結果に自信をもつために、各シナリオは100回シミュレーションします。

x=1
Final_funds= []

while x<=100:
    ending_fund = play(10000,100,5)
    x=x+1

plt.ylabel('Player Money in $')
plt.xlabel('Number of bets')
plt.show()
print("The player starts the game with $10,000 and ends with $" + str(sum(ending_fund)/len(ending_fund)))

5.次は7つのシナリオをグラフで視覚化してみましょう。ユーザーは各シナリオでn回ベットします。以下のコードの引数のみを変更して、プレーヤーが行う賭けの数を微調整します。

ending_fund = play(10000,100,5)

x軸:ユーザーが行う賭けの数

y軸:各賭け後のユーザーの資金残高

各グラフは、ユーザーがゲームを続けているときのアカウントの残高を示しています。また、ユーザーの最終残高を出すために、100の異なるシミュレーションから残高を平均します。

「ユーザーが$ 10,000から始めて、このゲームをn回プレイした場合(各ゲームに$ 100の賭けをした場合)、平均して、プレーヤーはどのくらいの手持ちで終了しているか?」

シナリオ 1 -> No. of bets : 5

シナリオ 2 -> No. of bets : 10

シナリオ 3 -> No. of bets : 50

シナリオ 4 -> No. of bets: 100

シナリオ 5 -> No. of bets : 500

シナリオ 6 -> No. of bets : 1000

シナリオ 7 -> No. of bets : 10000

シミュレーションから、ユーザーがより少ない賭けをすると、利益を上げる(または損失を最小限に抑える)可能性が高くなることがわかります。

また、すべてのシナリオで失われる金額は、賭け金額の約2%であることがわかります(ハウスエッジと同じ)。たとえば、最後のシナリオでは、ユーザーは10,000回の賭けを行い、それぞれが100ドルでした。したがって、ユーザーは約(10,000)*(0.02 * 100)を失うと予想されます。これは$ 20,000に相当します。

さらに、ユーザーが10,000回プレイした最後のシナリオでは、資金がマイナスになりました。つまり、ユーザーは借金したことを意味します。

要するに、胴元は常に勝つということですね。

エンジョイワークスでは、バックエンドエンジニアを募集しております。空き家問題を、自分のスキルで解決したいエンジニアは、是非ご応募ください!

リクルート情報はこちら!
https://enjoyworks.jp/recruit

一覧へ戻る

最新記事