スポンサーリンク
※サイト運営にサーバーは必須です※
~このサイトもエックスサーバーを使用しています~
目次
はじめに
※目次用の記事:ギャンブルの賭け方の種類をまとめてみた
この世には、様々な賭け方が存在する。
そのうちの一つがパーレー法を変形させたグランパーレー法だ。
パーレー法をシミュレーション(c++/c言語)の記事でパーレー法のシミュレーションを取り扱ったが、ここでは、グランパーレー法のシミュレーションを取り扱う。
グランパーレー法とは
最小の賭け金額を自分で設定し、最初はこの最小の賭け金額からスタートする。
また、何連勝したらゲームをリセットするか自分で設定する。
負けた場合:次の勝負の賭け金は、設定した最小の賭け金額に戻す
勝った場合:次の勝負の賭け金は、現在賭けている2倍+αの金額にする(ただし、設定した連勝が達成できた場合、最小の賭け金額に戻す)
+α(アルファ)の部分が加わるのが、パーレー法と異なる部分。
+α(アルファ)の部分は、最もスタンダードな流儀だと+1にする
グランパーレー法の具体例
ルールだけ、説明してもイメージがつかめないと思うので、具体例を挙げる。
勝率が50%で払戻金が2倍の勝負として、コインの表裏の賭けなどをイメージしてください。
また、5連勝したら、いったん賭け金を最小額に戻すとする。
もしも5連勝したら、以下のテーブルのように賭け金を
1→3→7→15→31
と増やしていく
勝敗 | 賭け金 | 累計損益 |
○ | 1 | 1 |
○ | 3 | 4 |
○ | 7 | 11 |
○ | 15 | 26 |
○ | 31 | 57 |
最終的な利益は+57となる
次に、途中で負けた場合を考える。
例として、4連勝した後、負けた時を考察する。
勝敗 | 賭け金 | 累計損益 |
○ | 1 | 1 |
○ | 3 | 4 |
○ | 7 | 11 |
○ | 15 | 26 |
× | 31 | -5 |
このように、万が一途中で負けた場合は、どんなに途中で勝っていても、最終的な損益はマイナスとなる。
つまり、連勝して勝負を一度リセットできれば、利益が十分確保できる。だが、負ければ、途中の過程がどうであれ、今までの利益が吹っ飛んだ上に損がでる。
※どれだけ損がでるかは、直前どれだけ連勝していたかで変化する。下で紹介するテーブルを見ていただくとわかるが、式は(直前で連勝していた回数)+1となる。4連勝した後で負けた場合をこの式に当てはめると、4+1=5だけ損を出す
期待値検証
直観的に考えてもわかるが、勝負して得られる利益の期待値は0である。
ここでは、5連勝までの期待値を考えてみる
連勝回数 | 確率 | 累計利益 | 期待値 |
0 | 0.5 | -1 | -0.5 |
1 | 0.25 | -2 | -0.5 |
2 | 0.125 | -3 | -0.375 |
3 | 0.0625 | -4 | -0.25 |
4 | 0.03125 | -5 | -0.15625 |
5 | 0.03125 | 57 | 1.78125 |
期待値合計 | 0 |
連勝回数0は負けを意味し、確率は1/2
連紹回数1は、2連勝ではないが、1度勝利する確率を意味し
1/2-1/4で1/4(0.25)となる
連勝回数4は、5連勝ではないが、4連勝する確率を意味し、
1/32-1/16=1/32
最後の5連勝の部分は、そのまま5連勝できる確率。
(正確に言えば5連勝以上できる確率)
1/2を5乗した1/32
それぞれの事象が起こる確率に累計利益をかけて、その期待値を取るとゼロになる。
グランパーレー法の検証
以下では2つのプログラムを紹介する。
言語はC++で作ったが、C言語としてコンパイルしても動くと思う
※このプログラムを組んだ人間は、大学時代に少しプログラムをかじった程度の戦闘能力しかない
グランパーレー法個別シミュレーション
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> int main() { int i=0; int i_max=100000;//勝負回数 double w=2.0; //賭け金の変換率(2倍以上)(win) double p=50; //勝率(50%以下)(probability) double m_min=1;//最小の賭け金額(money) double m_int=1000;//最初の手持ちの資金(money_intial) int c; c=0;//初期化 int c_max=5;//何連勝でおりるか?(count) //乱数(時間による変化) srand((unsigned)time(NULL)); //ファイルの出力準備 FILE *sf; sf = fopen("simulation.dat","w");//出力するファイルの名前を指定 //エラー if(sf==NULL){ printf("ファイルオープンエラー\n"); return -1; } //初期条件の表示 printf("#倍率は%lf\t勝率は%lf\t最小の賭け金は%lf\t手持ちのお金は%lf\n",w,p,m_min,m_int); fprintf(sf,"#倍率は%lf\t勝率は%lf\t最小の賭け金は%lf\t手持ちのお金は%lf\n",w,p,m_min,m_int); double m_now;//現在の資金 double m_bet;//賭け金 //初期化 m_bet=m_min;//最初は最小の賭け金でスタート m_now=m_int;//最初は最初の手持ちの資金でスタート for(i=1;i<=i_max;i++) { double r;//乱数(rand) r=100.0*rand()/(RAND_MAX+1.0);//0から100の乱数を出す printf("%d回目\t賭け金は%lf\t",i,m_bet); fprintf(sf,"%d回目\t賭け金は%lf\t",i,m_bet); if (p<=r){//負けの場合 m_now=m_now-m_bet; m_bet =m_min;//賭け金を最小額に戻す c=0; printf("lose\t"); fprintf(sf,"lose\t"); } else{//勝ちの場合 m_now =m_now+m_bet*(w-1.0); m_bet =m_bet*2+1;//賭け金を2倍+1に c+=1; printf("win(%d連勝)\t",c); fprintf(sf,"win(%d連勝)\t",c); } printf("手持ちのお金は%lf\n",m_now); fprintf(sf,"手持ちのお金は%lf\n",m_now); if(c==c_max){ m_bet =m_min; c=0; } if(m_now<m_bet){//手持ちの金より賭けるお金が高い場合 printf("%d回目で手持ちのお金が足りません\n",i); fprintf(sf,"%d回目で手持ちのお金が足りません\n",i); break; } }//for(i)文の終わり //sfクローズ fclose(sf); return 0; }//プログラムの終わり |
プログラムで使用している変数の説明
※マーチンゲール法(2倍賭け)の破綻までのシミュレーションで紹介したプログラムと同じ変数の置き方をしている
i_max:勝負の回数
w:賭けたお金の戻る倍率を指定。ここでは2倍を指定
p:勝率を指定。ここでは1/2の確率なので50。
m_min:かけ金を指定
m_int:で手持ちの軍資金を指定
※ここではm_min=1でm_int=1000と、最小の賭け金の1000倍を所持していると考えている。
例えば、最小の賭け金が1000円(千円)だとするなら、手元の軍資金は、1000000円(百万円)。割と現実的な設定だと思われる。
r:乱数(0~100の乱数)
※乱数rが勝率pより下の数で収まるなら勝ちの判定がでる。
そして、勝負を続けていくうちに、負け続けることもあるだろう。
そしてついに、賭けしようにも手持ちのお金が足りなくなるかもしれない。
この場合、これ以上勝負ができなくなり、プログラムは終了する。(破綻判定)
つまり、借金はNG
c_max:何連勝したら、いったん最小の賭け金に戻すか?
※ここではc_max =5として、5連勝した場合いったんリセットする。
※(グラン)マーチンゲールとパーレー法で作ったプログラムが微妙に不便だった以下の点を改善している。
- 表示される「賭け金」の意味を「今回の勝負に必要な賭け金」に変更。(以前のプログラムは、「次の勝負に必要な賭け金」という意味で使われていたので、ちょっとわかりづらかった)
- 勝ち(win)か負け(lose)かわかるように表示
- 何連勝しているかわかるように表示される
実際にプログラムを走らせると以下のような結果となる
勝負回数i_maxは100000(10万回)までとする
#倍率は2.000000 勝率は50.000000 最小の賭け金は1.000000 手持ちのお金は1000.000000
1回目 賭け金は1.000000 lose 手持ちのお金は999.000000
2回目 賭け金は1.000000 win(1連勝) 手持ちのお金は1000.000000
3回目 賭け金は3.000000 win(2連勝) 手持ちのお金は1003.000000
(省略)
43280回目 賭け金は15.000000 win(4連勝) 手持ちのお金は34.000000
43281回目 賭け金は31.000000 lose 手持ちのお金は3.000000
43282回目 賭け金は1.000000 win(1連勝) 手持ちのお金は4.000000
43283回目 賭け金は3.000000 lose 手持ちのお金は1.000000
43284回目 賭け金は1.000000 lose 手持ちのお金は0.000000
43284回目で手持ちのお金が足りません
※srand((unsigned)time(NULL));の部分で時間を参照した上で乱数を発生させている。
そのため、実行するタイミングで結果が変化する。
グランパーレー法の期待値シミュレーション
上のプログラムを何度も走らせて期待値や破綻する率をもとめたい
そのためのプログラムは以下のようになる
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> int main() { int k; int k_max=20000;//試行回数 int i=0; int i_max=100000;//勝負回数 double w=2.0; //賭け金の変換率(2倍以上)(win) double p=50; //勝率(50%以下)(probability) double m_min=1;//最小の賭け金額(money) double m_int=1000;//最初の手持ちの資金(money_intial) int b;//破たん回数のカウント(Bankruptcy) b=0;//初期化 int i_sum;//勝負回数の合計 double m_sum;//最終的なお金の合計 i_sum=0;//初期化 m_sum=0.0; //乱数(時間による変化) srand((unsigned)time(NULL)); //ファイルの出力準備 FILE *sf; sf = fopen("simulation.dat","w");//出力するファイルの名前を指定 //エラー if(sf==NULL){ printf("ファイルオープンエラー\n"); return -1; } //初期条件の表示 printf("#倍率は%lf\t勝率は%lf\t最小の賭け金は%lf\t手持ちのお金は%lf\n",w,p,m_min,m_int); fprintf(sf,"#倍率は%lf\t勝率は%lf\t最小の賭け金は%lf\t手持ちのお金は%lf\n",w,p,m_min,m_int); for(k=1;k<=k_max;k++) { int i_cout;//勝負回数のカウント i_cout=0; int c; c=0;//初期化 int c_max=5;//何連勝でおりるか?(count) double m_now;//現在の資金 double m_bet;//賭け金 //初期化 m_bet=m_min;//最初は最小の賭け金でスタート m_now=m_int;//最初は最初の手持ちの資金でスタート for(i=1;i<=i_max;i++) { double r;//乱数(rand) r=100.0*rand()/(RAND_MAX+1.0);//0から100の乱数を出す if (p<=r){//負けの場合 m_now=m_now-m_bet; m_bet =m_min;//賭け金を最小額に戻す c=0; } else{//勝ちの場合 m_now =m_now+m_bet*(w-1.0); m_bet =m_bet*2+1;//賭け金を2倍+1にする c+=1; } if(c==c_max){ m_bet =m_min; c=0; } i_cout=i;//i_coutを定義しないと破たんしない(セーフ)場合、iと値が1ずれてしまうため if(m_now<m_bet){//手持ちの金より賭けるお金が高い場合 break; } }//for(i)文の終わり if(i_cout<i_max) { printf("%d番目%d回目で破たん\t手持ちのお金は%lf\n",k,i_cout,m_now); fprintf(sf,"%d番目%d回目で破たん\t手持ちのお金は%lf\n",k,i_cout,m_now); b=b+1; } else{ printf("%d番目\t%d回目までセーフ\t手持ちのお金は%lf\n",k,i_cout,m_now); fprintf(sf,"%d番目\t%d回目までセーフ\t手持ちのお金は%lf\n",k,i_cout,m_now); } i_sum=i_sum+i_cout; m_sum=m_sum+m_now; }//for(k)文の終わり //破たん率 printf("勝負回数は%d\n",i_max); printf("試行回数は%d\n",k_max); printf("破たん回数は%d\n",b); fprintf(sf,"勝負回数は%d\n",i_max); fprintf(sf,"試行回数は%d\n",k_max); fprintf(sf,"破たん回数は%d\n",b); double b_pro= (double)b/(double)k_max*100.0;//(double)を抜くとb/k_maxがゼロと評価されてしまう printf("破たん率は%lf%\n",b_pro); fprintf(sf,"破たん率は%lf%\n",b_pro); double i_exp=(double)i_sum/(double)k_max; double m_exp=(double)m_sum/(double)k_max; printf("破たんするまでに行える勝負回数の期待値(i_exp)は%lf\n",i_exp); printf("破たんする直前で持っているお金の期待値(m_exp)は%lf\n",m_exp); fprintf(sf,"破たんするまでに行える勝負回数の期待値(i_exp)は%lf\n",i_exp); fprintf(sf,"破たんする直前で持っているお金の期待値(m_exp)は%lf\n",m_exp); //sfクローズ fclose(sf); return 0; }//プログラムの終わり |
プログラムで使用している変数の説明
b_pro:破綻率
※ここでいう破綻率とは手持ちのお金が、2倍賭けに耐えられない状況を意味する。借金してお金を用意することはできないとする。
i_exp: 破綻するまで何回勝負ができるかの期待値
m_exp: 勝負が終わった段階で持っているお金の期待値
k_max:試行回数。
※k_maxを大きくすればするほど、正確な期待値が求まる。
以下では、k_max=20000、i_max=100000で指定。
試行回数2万回、勝負回数10万回。
手持ちのお金は1000でスタート(最小の賭け金額は1)
c_max=5の場合(5連勝でストップをかける)
勝負回数は100000
試行回数は20000
破たん回数は13350
破たん率は66.750000%
破たんするまでに行える勝負回数の期待値(i_exp)は52511.154300
破たんする直前で持っているお金の期待値(m_exp)は997.185200
破綻率は66.75%
※参考:パーレー法(5連勝でストップをかける)で破たん率は42.36%
c_max=3の場合(3連勝でストップをかける)
勝負回数は100000
試行回数は20000
破たん回数は6418
破たん率は32.090000%
破たんするまでに行える勝負回数の期待値(i_exp)は84669.842800
破たんする直前で持っているお金の期待値(m_exp)は1001.777100
破綻率は32.090000%
※参考:パーレー法(3連勝でストップをかける)で破たん率は11.485%
当たり前だが、単なるパーレー法と比べて、+αされている分、破綻率が高い。これは、早く資金が尽きて破綻しやすくなることを意味する。
書籍の紹介
『ギャンブルの必勝法が本当に儲かるかプログラミングで検証してみた』は以下の疑問にお答えします。
●勝率が50%の場合、利益を生み出す必勝法は存在するか?
●勝率が60%の場合、どのように賭けるのが最適か?
必勝法と思われている手法を15種類紹介します。必勝法には、例えば、マーチンゲール法(負けた時に2倍賭ける手法)などがあります。これらの手法が本当に儲かるかプログラミングを使用して検証します。また、検証するために必要なプログラミングの知識(C#)も紹介しています。
ギャンブルの必勝法が本当に儲かるかプログラミングで検証してみた
関連記事
※目次用の記事:ギャンブルの賭け方の種類をまとめてみた
~プログラミングを勉強してみませんか?~
TechAcademy [テックアカデミー] は無料の体験講座が用意されているので、気軽に体験できます。
※私(サイト主)も無料体験講座を実際に受けてみました(→感想)
コメント