スポンサーリンク
※サイト運営にサーバーは必須です※
~このサイトもエックスサーバーを使用しています~
目次
はじめに
※目次用の記事:ギャンブルの賭け方の種類をまとめてみた
この記事では、31システムの紹介と、そのシミュレーション結果を示す
31システムとは
次のような4つのセクションに分かれた、9の数字を用意
(1,1,1/2,2/4,4/8,8)
左側の数字から賭けていく。(最初なら一番左端の1)
負けた場合:一つ右側の数字に移る
勝った場合:次のセクションの一番左側の数字に移る
以下の場合、リセットする(一番左端の1から再スタート)
- 2連勝した場合
- 最後の数字の8まで到達して勝負を終えた場合
<概略図>
1→1→1→(2へ)
↓(勝ち)
2→2→(4へ)
↓
4→4→(8へ)
↓
8→8→(1から再スタート)
↓
(1から再スタート)
31システムの具体例
ルールだけ、説明してもイメージがつかめないと思うので、具体例を挙げる。
勝敗 | 賭け金 | 累計賭け金 | 最終利益 |
× | 1 | 1 | -1 |
×× | 1 | 2 | -2 |
××× | 1 | 3 | -3 |
×××× | 2 | 5 | -5 |
××××○ | 2 | 7 | -3 |
××××○× | 4 | 11 | -7 |
××××○×○ | 4 | 15 | -3 |
××××○×○○ | 8 | 23 | 5 |
31システムの特徴
- 9回のうち、2連勝できれば、収益は最低でも+1される
- 9回のうち、1度も連勝できなかった場合、最大で-31の損失
※2連勝できない場合で一番得なパターンは+1かな?(○×○×○×○のパターン)
※資金が31(1+1+1+2+2+4+4+8+8)必要なシステムなので31システムと呼ばれているらしい
2連勝すれば、収益がプラスになる説明
2連勝して、ゲームがリセットされる場合で、ギリギリのパターンを考えると、以下のパターンが考えられる。どのパターンも、損失を上回っていることがわかる
(損失)<(収益)
1<1+1:(1<2)
1+1<1+2:(2<3)
1+1+1<2+2:(3<4)
1+1+1+2<2+4:(5<6)
1+1+1+2+2<4+4: (7<8)
1+1+1+2+2+4<4+8: (11<12)
1+1+1+2+2+4+4<8+8: (15<16)
どこかで2連勝すれば、最低でも+1の利益が得られる
正確には、
1+(途中の単発勝利分)×2
(×2するのは、負けたのが裏返って勝ったと考えているので、「負けた分」と「勝った分」で2倍になるから。上の具体例では、賭け金額が2の時に単発の勝利をしているので1+2×2=5が最終的な収益となっている)
※上の考察から、「2連勝すれば、収益がプラスになる」システムを作りたいなら、「勝った時に、次のセクションに移る」というルールは必須でないことがわかる。
※31システムは、賭け金額は8でストップしているが、8で止めずに、16,16,32,32と増やしていくことも考えられる。数列の増え方が約2倍遅くて、2連勝して、ゲームをリセットできるマーチンゲール法と捉えることもできる。
マーチンゲールと31システムの対応
- マーチンゲール:1/2/4/8/16
- 31システム:1/1,1/2,2/4,4/8,8
31システムの検証
以下では2種類のプログラムを紹介する。
言語はC++で作ったが、C言語としてコンパイルしても動くと思う
※このプログラムを組んだ人間は、大学時代に少しプログラムをかじった程度の戦闘能力しかない
31システムの個別シミュレーション
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 |
#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_ini=1000;//最初の手持ちの資金(money_initial) int c;//勝ち負け差のカウント(count) c=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_ini); fprintf(sf,"#倍率は%lf\t勝率は%lf\t最小の賭け金は%lf\t手持ちのお金は%lf\n",w,p,m_min,m_ini); double m_now;//現在の資金 double m_bet;//賭け金 //初期化 m_now=m_ini;//最初は最初の手持ちの資金でスタート m_bet=m_min;//賭け金は最小の賭け金額でスタート int w_str;//連勝カウント用 w_str=0; int step_a;//stepカウント用 int step; step_a=1; step=0; 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); printf("step:%d-%d\t",step_a,step); fprintf(sf,"step:%d-%d\t",step_a,step); if (p<=r){//負けの場合 m_now-=m_bet; c-=1; w_str=0; step+=1; if(step>=3){ step_a+=1; step=1; } printf("lose\t"); fprintf(sf,"lose\t"); } else{//勝ちの場合 m_now +=m_bet*(w-1.0); c+=1; w_str+=1; step_a+=1; step=1; printf("win(%d連勝)\t",w_str); fprintf(sf,"win(%d連勝)\t",w_str); } if(w_str>=2||step_a>=5){//2連勝かすべての賭けが終わった場合初期化 step_a=1; step=0; w_str=0;//連勝カウント初期化 } if(step_a==1){ m_bet=m_min; } if(step_a==2){ m_bet=m_min*2; } if(step_a==3){ m_bet=m_min*4; } if(step_a==4){ m_bet=m_min*8; } printf("勝敗差%d\t手持ちのお金は%lf",c,m_now); fprintf(sf,"勝敗差%d\t手持ちのお金は%lf",c,m_now); printf("\n"); fprintf(sf,"\n"); if(m_now<m_bet){//手持ちの金より賭けるお金が高い場合 printf("次の勝負に必要な金額は%lfです。%d回目でゲームを終了します\n",m_bet,i); fprintf(sf,"次の勝負に必要な金額は%lfです。%d回目でゲームを終了します\n",m_bet,i); break; } }//for(i)文の終わり //sfクローズ fclose(sf); return 0; }//プログラムの終わり |
プログラムで使用している変数の説明
※マーチンゲール法(2倍賭け)の破綻までのシミュレーションで紹介したプログラムと同じ変数の置き方をしている
i_max:勝負の回数
w:賭けたお金の戻る倍率を指定。ここでは2倍を指定
p:勝率を指定。ここでは1/2の確率なので50を指定。
m_min:かけ金を指定
m_ini:最初の資金を指定
※ここではm_min=1でm_ini=1000と、最小の賭け金の1000倍を所持していると考えている。
例えば、最小の賭け金が1000円(千円)だとするなら、手元の軍資金は、1000000円(百万円)。割と現実的な設定だと思われる。
r:乱数(0~100の乱数)
※乱数rが勝率pより下の数で収まるなら勝ちの判定がでる。
そして、勝負を続けていくうちに、負け続けることもあるだろう。
そしてついに、賭けしようにも手持ちのお金が足りなくなるかもしれない。
この場合、これ以上勝負ができなくなり、プログラムは終了する。(破綻判定)
つまり、借金はNG
c:トータルの勝ち負けの差がどのくらいあるか調べる用
w_str;連勝カウント用
step_a:4つのセクションの内、何番目か
step:セクション内で、左から何番目か?(1が三つあるセクションは、プログラムの都合で、0、1、2番目とカウントしている。残りは1、2番目とカウント)
実際にプログラムを走らせると以下のような結果となる
勝負回数i_maxは100000(10万回)までとする
#倍率は2.000000 勝率は50.000000 最小の賭け金は1.000000 手持ちのお金は1000.000000
1回目 賭け金は1.000000 step:1-0 win(1連勝) 勝敗差1 手持ちのお金は1001.000000
2回目 賭け金は2.000000 step:2-1 lose 勝敗差0 手持ちのお金は999.000000
3回目 賭け金は2.000000 step:2-2 win(1連勝) 勝敗差1 手持ちのお金は1001.000000
4回目 賭け金は4.000000 step:3-1 lose 勝敗差0 手持ちのお金は997.000000
5回目 賭け金は4.000000 step:3-2 lose 勝敗差-1 手持ちのお金は993.000000
6回目 賭け金は8.000000 step:4-1 lose 勝敗差-2 手持ちのお金は985.000000
7回目 賭け金は8.000000 step:4-2 win(1連勝) 勝敗差-1 手持ちのお金は993.000000
8回目 賭け金は1.000000 step:1-0 lose 勝敗差-2 手持ちのお金は992.000000
(省略)
55931回目 賭け金は4.000000 step:3-1 win(1連勝) 勝敗差-259 手持ちのお金は13.000000
55932回目 賭け金は8.000000 step:4-1 lose 勝敗差-260 手持ちのお金は5.000000
次の勝負に必要な金額は8.000000です。55932回目でゲームを終了します
※srand((unsigned)time(NULL));の部分で時間を参照した上で乱数を発生させている。そのため、実行するタイミングで結果が変化する。
31システムの期待値シミュレーション
上のプログラムを何度も走らせて期待値や破綻する率をもとめたい
そのためのプログラムは以下のようになる
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 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
#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_ini=1000;//最初の手持ちの資金(money_initial) int b;//破たん回数のカウント(Bankruptcy) b=0;//初期化 int i_sum;//勝負回数の合計 double m_sum;//最終的なお金の合計 i_sum=0;//初期化 m_sum=0.0; int c_sum;//勝負差の合計 c_sum=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_ini); fprintf(sf,"#倍率は%lf\t勝率は%lf\t最小の賭け金は%lf\t手持ちのお金は%lf\n",w,p,m_min,m_ini); for(k=1;k<=k_max;k++) { int i_count;//勝負回数のカウント i_count=0; double m_now;//現在の資金 double m_bet;//賭け金 //初期化 m_now=m_ini;//最初は最初の手持ちの資金でスタート m_bet=m_min;//賭け金は最小の賭け金額でスタート int c;//勝ち負け差のカウント(count) c=0;//初期化 int w_str;//連勝カウント用 w_str=0; int step_a;//stepカウント用 int step; step_a=1; step=0; 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_bet; c-=1; w_str=0; step+=1; if(step>=3){ step_a+=1; step=1; } } else{//勝ちの場合 m_now +=m_bet*(w-1.0); c+=1; w_str+=1; step_a+=1; step=1; } if(w_str>=2||step_a>=5){//2連勝かすべての賭けが終わった場合初期化 step_a=1; step=0; w_str=0;//連勝カウント初期化 } if(step_a==1){ m_bet=m_min; } if(step_a==2){ m_bet=m_min*2; } if(step_a==3){ m_bet=m_min*4; } if(step_a==4){ m_bet=m_min*8; } i_count=i;//i_countを定義しないと破たんしない(セーフ)場合、iと値が1ずれてしまうため if(m_now<m_bet){//手持ちの金より賭けるお金が高い場合 break; } }//for(i)文の終わり if(i_count<i_max) { printf("%d番目%d回目で破たん\t手持ちのお金は%lf\n",k,i_count,m_now); fprintf(sf,"%d番目%d回目で破たん\t手持ちのお金は%lf\n",k,i_count,m_now); b=b+1; } else{ printf("%d番目\t%d回目までセーフ\t手持ちのお金は%lf\n",k,i_count,m_now); fprintf(sf,"%d番目\t%d回目までセーフ\t手持ちのお金は%lf\n",k,i_count,m_now); } i_sum=i_sum+i_count; m_sum=m_sum+m_now; c_sum=c_sum+c; }//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); double c_exp=(double)c_sum/(double)k_max; printf("破たんした時の勝負差の期待値は%lf\n",c_exp); fprintf(sf,"破たんした時の勝負差の期待値は%lf\n",c_exp); //sfクローズ fclose(sf); return 0; }//プログラムの終わり |
プログラムで使用している変数の説明
b_pro:破綻率
※ここでいう破綻率とは手持ちのお金が、賭けに耐えられない状況を意味する。借金してお金を用意することはできないとする。
i_exp: 破綻するまで何回勝負ができるかの期待値
m_exp: 勝負が終わった段階で持っているお金の期待値
k_max:試行回数。
※k_maxを大きくすればするほど、正確な期待値が求まる。
c_exp:勝敗差の期待値
以下では、k_max=20000、i_max=100000で指定。
試行回数2万回、勝負回数10万回。
結果は以下のようになった
勝負回数は100000
試行回数は20000
破たん回数は7562
破たん率は37.810000%
破たんするまでに行える勝負回数の期待値(i_exp)は80337.882000
破たんする直前で持っているお金の期待値(m_exp)は995.947450
破たんした時の勝負差の期待値は-1.423400
書籍の紹介
『ギャンブルの必勝法が本当に儲かるかプログラミングで検証してみた』は以下の疑問にお答えします。
●勝率が50%の場合、利益を生み出す必勝法は存在するか?
●勝率が60%の場合、どのように賭けるのが最適か?
必勝法と思われている手法を15種類紹介します。必勝法には、例えば、マーチンゲール法(負けた時に2倍賭ける手法)などがあります。これらの手法が本当に儲かるかプログラミングを使用して検証します。また、検証するために必要なプログラミングの知識(C#)も紹介しています。
ギャンブルの必勝法が本当に儲かるかプログラミングで検証してみた
関連記事
目次用の記事:ギャンブルの賭け方の種類をまとめてみた
~Webサイトを自分で作ってみませんか?~
Webサイトを運営するにはサーバーが必須です。
このサイトは、エックスサーバー のサーバーを使用しています。
エックスサーバーは無料で10日間お試しができます。