Published Date : 2020年7月28日12:37

【Processing, プログラミング】を使ったギャンブルの確率の簡単なシュミレーション
A simple simulation of the probability of gambling using [Processing, programming]


This blog has an English translation


YouTubeにアップした動画、「【Processing, プログラミング】を使ったギャンブルの確率の簡単なシュミレーション」の補足説明の記事です。

Here's a little more about the 「A simple simulation of the probability of gambling using [Processing, programming]」 video I uploaded to YouTube.

【Processing, プログラミング】を使ったギャンブルの確率の簡単なシュミレーション


目次

Table of Contents




① 基本条件
① Basic condition



京都産業大学のページにあった、

I tried to simulate "Gambling always loses."

「ギャンブルは必ず負ける」をProcessingを使ってシュミレーションしてみました。

introduced on the page of Kyoto Sangyo University by using Processing.

ランダムにギャンブルの勝敗を決め、プレイヤーまたは胴元の所持金が0となるまで続けて、

The winning or losing of the gambling is determined at random, and it continues until the money possessed by the player or the manager becomes 0,

プレイヤーの所持金が0になったら「負け」、胴元の所持金が0、

and when the money possessed by the player becomes 0 [lose], and when the money possessed by the manager becomes 0,

つまりプレイヤーの所持金が「胴元の最初の所持金」を上回ると「勝ち」とする。

that is, when the money possessed by the player exceeds [initial funds for managers], it is set to [win].

今回は条件を単純にするため、勝敗は一回ずつランダムな確率によって決定し、

In order to simplify the conditions this time, the winning or losing is determined by a random probability for each match,

一回の勝負における負けは「-10」、勝ちは「+10」とします。

with the loss in each match [-10] and the win [+10].

さらに計算量増大によって時間がかかるのを避けるため、勝負の回数は1000回とし、

To avoid the extra computation time involved, the number of trials should be 1000,

1000回カウントして勝ち負けがはっきりしない場合は「ノーカウント」とします。

If it is not clear whether player win or lose after counting 1000 times, no count will be used.

そして、大体のケースの場合、普通は圧倒的に胴元の所持金のほうが多い。

And in most cases, the manager usually has more money than the player.

胴元の所持金とプレイヤーの所持金との差が大きいほど、

The greater the gap between the manager's money and the player's money,

つまり、圧倒的に資金力がある胴元が運営するギャンブルは、

in other words, the more money the manager has,

プレイヤーが一時的に儲けても、試行回数を重ねればプレイヤーが勝つ確率は低下し、

the less likely a player will win, and the less likely a player will lose,

プレイヤーは損をするような仕組みになっています。


Responsive image

if the number of trials is increased, even if the player gains temporarily.

この時のプレイヤーが「負ける確率」は[ 1 - (プレイヤーの最初の所持金 / 胴元の所持金) ]となります。

At this time, [odds of losing] is set to [1 - (Player's first money / Manager's money)].

これは一回ずつの損得の確率が「同じ」、つまり、一回の勝負で損する確率が「2分の一」、得する確率が「2分の一」の今回のモデルケースの場合です。

This is the case with the current model case where the probability of loss for each match is Same, that is, the probability of loss for each match is 1/2 and the probability of gain is 1/2.

一回の勝負の損得の確率が違う場合は「損する確率/得する確率」の値が大きいほど、プレイヤーが「負ける確率」が高くなります。

If the odds of winning or losing a match are different, the higher the value of [odds of losing a game / odds of losing a game], the higher the player's [odds of losing].

今回のシュミレーションは[ 1 - (プレイヤーの最初の所持金 / 胴元の所持金) ]を確かめるために行いました。

The purpose of this simulation was to confirm the [ 1 - (First money of the player / Money of the manager) ].

またProcessingを使う意味は視覚化したほうが、より感覚的に理解しやすいと思ったからです。

I also used Processing because I thought it would be easier to understand the results of each calculation visually.




② コーディング
② Coding



ではProcessingのコードを書いていきます。

Now let's write the Processing code.

プレイヤーの所持金、胴元の所持金、プレイヤーの現在の所持金を表すX座標、試行回数を表すY座標、XとYをラインで繋ぐために必要な直前のX座標とY座標

These variables are the player's initial cash, the manager's cash, the player's current cash X coordinate, the number of attempts Y coordinate, and the previous N-1 X and Y coordinates needed to connect the Nth and Y coordinates with a line.

float playersmoney, managersmoney, x, y, px, py;

最終的に勝ったか、それとも負けたか、そして何回ギャンブルを行うかの回数を格納する変数。

these are variables that stores the number of times player finally won or lost and how many times player gambling.

int win, lose, count;

いくつか勝負がついた後に、平均してどれだけの勝率があったかを確認する変数。

a variable that determines the average winning rate after several rounds.

float probability;

ギャンブルを数百回から数千回行って、それを1セットとして、何回試行するかを決める変数。

A variable that determines how many sets of hundreds or 1000 gambles to try.

int numberOfTrials;

勝敗を決める配列。1だと時間がかかるのでオフセットを10にしました。

A winning or losing arrangement. The offset should be 10 instead of 1 in order to decide the winner quickly.

int[] wlarr = {-10, 10};

プログラム内で初期化を何度も行うため、用意した変数の初期化用関数。

A function for initializing a prepared variable to perform initialization many times in a program.

void initialize(){

胴元の所持金を画面の幅から-100を引いた数にする。

The manager's money is the width of the screen minus 100.

  managersmoney = width-100;

賭けをするプレイヤーの所持金はデフォルトで胴元の総資産の10分の1とします。(現実としては大分多めですが…)

By default, the player's cash has 1/10 of the manager's total assets. (And if you think about it realistically, the players are very rich, but ...)

  playersmoney = managersmoney/10;

変数Xにプレイヤーの初期金額を格納します。変数Xは、最終的にプレイヤーの総所得額になるように計算していきます。

First, the variable X stores the player's initial cash. The variable X is calculated to be the total income of the player.

  x = playersmoney;

変数Yの初期値は視覚化のためのグラフのX軸上に設定します。

The initial value of the Y variable is set to the coordinate position on the X axis of the graph prepared for visualization.

  y = 90;

勝ち負けの結果の数を示す変数の初期値は0

The initial value of the variable indicating the number of wins and losses is 0.

  win = 0;
  lose = 0;

ギャンブルの勝負の回数は1000回

set the number of gambling games to 1000

  count = 1000;

プレイヤーが勝つ確率を初期値として0にする。そして何回試行するかを決める変数を0にする。

The probability of the player winning is set to 0 as the initial value. It then sets the number of trials to 0.

  probability = 0;
  numberOfTrials = 0;
}

setup関数内では、画面サイズを960×960に設定して、初期化関数で計算に必要な値を初期化する。

Within the setup function, set the screen size to 960 x 960 and use the initialization function to initialize the values needed for computation.

void setup(){
  size(960, 960);
  initialize();
}

draw関数内で、グラフのテキストと棒線を描き、ギャンブルの結果を可視化する。

In the draw function, draw the text and bar lines of the graph and visualize the results of gambling.

void draw(){

バックグランド関数を白にして画面をフレーム毎に塗りつぶしアニメーションを実現させる。

The background function is made to be white, and the screen is filled every frame to realize the animation.

  background(255);

pushStyleメソッドとpopStyleメソッドで囲われた描画スタイルの設定はこのコンテキスト内でのみ適用される。

Drawing style settings enclosed in pushStyle and popStyle methods apply only in this context.

  pushStyle();

strokeWeightメソッドで線の太さを2ピクセルにする。

Set to the line weight to 2 pixels by using the strokeWeight method

  strokeWeight(2);

線の色を黒にする。

Make the line color black.

  stroke(0);

線の始めのX座標を0に、Y座標を90に、そこから線の終わりのX座標を画面幅から30ピクセル引いた数にして、

Y座標は同じ高さにして線を引く。これはプレイヤーと胴元の所持金を表す棒線になる。

The line is drawn with the X coordinate at the beginning of the line at 0, the Y coordinate at 90,

and the X coordinate at the end of the line at the number obtained by subtracting 30 pixels from the screen width,

and the Y coordinate at the same height. This becomes a bar representing the money of the player and the manager.

  line(0, 90, width-30, 90);

線の色を赤にする。

Make the line color red.

  stroke(255, 0, 0);

線の始めのX座標を0に、Y座標を90に、そこから線の終わりのX座標を同じにして、

Y座標は画面の高さから90ピクセル引いた数にして線を引く。これは所持金が0になることを表す棒線になる。

Draw a line with the X coordinate at the beginning of the line at 0, the Y coordinate at 90,

the X coordinate at the end of the line at the same point, and the Y coordinate at the height

of the screen minus 90 pixels. This becomes a bar line to show that the player's money possessed becomes zero.

  line(0, 90, 0, height-90);

線の色を青にする。

Make the line color blue.

  stroke(0, 0, 255);

これはプレイヤーの初期値の所持金を表す棒線になる。

This becomes a bar representing the player's initial amount of money.

  line(playersmoney, 90, playersmoney, height-90);

線の色を緑にする。

Make the line color green.

  stroke(0, 255, 0);

これは胴元の所持金を表す棒線になる。

This becomes a bar representing the manager's amount of money.

  line(managersmoney, 90, managersmoney, height-90);
  popStyle();

pushStyleメソッドとpopStyleメソッドで囲われた描画スタイルの設定はこのコンテキスト内でのみ適用される。

Drawing style settings enclosed in pushStyle and popStyle methods apply only in this context.

  pushStyle();

指定したX座標とY座標をテキストの中央に設定するようにする。

Sets the specified X and Y coordinates to the center of the text.

  textAlign(CENTER, CENTER);

テキストフォントの大きさを21ピクセルにする。

Make the text font size 21 pixels.

  textSize(21);

テキストの色を黒にする。

Make the text color black.

  fill(0);

プレイヤーと胴元のグラフ上の位置を文字で表示する。

The position of the player and the manager on the graph is displayed in letters.

  text("Pl", playersmoney, 75);
  text("Ma", managersmoney, 75);
  textSize(18);
  fill(219, 180, 0);

プレイヤーと胴元の所持金を文字で表示する。

The money possessed by the player and the manager is displayed in letters.

  text(playersmoney, playersmoney+30, 30);
  text(managersmoney, managersmoney, 30);
  textSize(24);
  fill(0);

プレイヤーと胴元の資産の比率を表す。

ratio of the total assets of the manager to the money held by the player

  text("Pl(1.0) : Ma(" + managersmoney/playersmoney + ")", width/2, 15);
  popStyle();

pushStyleメソッドとpopStyleメソッドで囲われた描画スタイルの設定はこのコンテキスト内でのみ適用される。

Drawing style settings enclosed in pushStyle and popStyle methods apply only in this context.

  pushStyle();
  textSize(21);
  textAlign(CENTER, CENTER);
  fill(255, 0, 0);

試行回数を画面に表示させる

Display the number of trials on the screen

  text("number of trials = " + numberOfTrials, (width/4)+10, 75);
  fill(0, 255, 0);

勝った回数を画面に表示させる

Display the number of wins on the screen

  text("win = " + str(win), (width/2), 75);
  fill(0, 0, 255);

負けた回数を画面に表示させる

Display the number of losses on the screen

  text("lose = " + str(lose), width-300, 75);
  popStyle();

ギャンブルを開始する

start gambling

  startGambling();

回数が指定回数に達したら確率を計算する。

Probability is calculated when the specified number of times is reached.

  if( frameCount%count == count-1){
    calculationOfProbability();

もし試行回数が指定の10セット目に達したら画面中央に最終的な確率の平均値を100分率で表す。

If the number of trials reaches the specified 10 sets, the average value of the final probability is shown in the center of the screen as a percentage.

    if (numberOfTrials == 10) {
      pushStyle();
      fill(255, 0, 0);
      textAlign(CENTER, CENTER);
      textSize(60);

勝率

probability of a player winning

      probability = (probability/numberOfTrials)*100;
      text("probability: " + probability + "%", width/2, height/2);
      popStyle();
      noLoop();
    }
  }
}

実際に一回一回のギャンブルの過程を処理する関数

A function that actually handles the process of one gamble at a time

void startGambling(){
  pushStyle();

始めにライン関数で使用する過去のXとYの値と現在のXとYの値を初期化する。

First, it initializes the current X and Y values used in the line function and the past X and Y values.

  x = playersmoney;
  y = 90;
  px = x;
  py = y;
  for(int i = 0; i < count; i++){

勝った時は+10、負けた時は-10の二択で用意された配列から、ランダム関数を使用してどちらかをランダムで選ぶ。

ランダムに選ばれた配列の長さの2までの数に対してint関数を使い、0か1に変換して配列のインデックス番号として使用する。

A random function is used to randomly select one of the arrays from + 10 for winning and -10 for losing.

Use the int function for a number up to 2 of the length of a randomly selected array, convert it to 0 or 1, and use it as the array index number.

    int index = int(random(wlarr.length));

結果をXに足し合わせていく。つまりプレイヤーの所持金を変動させていく。

Add the results to X. That is, the player's money is changed.

    x += wlarr[index];

ギャンブルの結果をなるべく画面に全て表示させたいので、高さを400分の1にして線の高さを小さく刻ませる。

To display all the results of gambling on the screen as much as possible, set the height to 1/400 and make the height of the line small.

    y += i/400;
    strokeWeight(1);
    stroke(255, 0, 0);
    line(px, py, x, y);

条件式で負けた場合と勝った場合で処理を分けるが、勝敗が決まった時点でギャンブルの処理のループをブレイクさせて、次のギャンブルへ移行させるようにする。

Processing is divided into a case of losing and a case of winning in a conditional expression, and when a win or a loss is decided, a loop of processing of gambling is finished to shift to the next gambling.

    if (0 >= x) {lose+=1;break;}
    if ( x >= managersmoney ) {win+=1;break;}

ループが続く場合は、現在のXとYの値を過去のXとYの値として代入する。

If the loop continues, the current X and Y values are substituted for the past X and Y values.

    px = x;
    py = y;
  }
  popStyle();
}

一回の試行回数でギャンブルが終わった段階の勝率を計算する関数

A function that calculates the probability of winning at the end of a gambling run

void calculationOfProbability(){

ゼロ除算を避けるため分母がゼロなら確率自体をゼロにする。

To avoid division by zero, if the denominator is zero, the probability itself is zero.

  float p;
  if ((win+lose) == 0) {
    p = 0;
  } else {
    p = (float)win / (win+lose);
  }

試行回数毎に確率を足し合わせる。勝敗をリセットして、試行回数をインクリメントする。

The probabilities are added at each trial. The win/loss is reset and the number of trials is incremented.

  probability = probability + p;
  win = 0;
  lose = 0;
  numberOfTrials += 1;
}

1から9までのボタンを押して、胴元に対するプレイヤーの所持金の比率を変化させる。

The ratio of the player's money to the manager is changed by pressing buttons 1 to 9.

void keyPressed(){

まず最初にキーボタンが押された時に全ての値を初期化する。

The first time a key button is pressed, all values are initialized.

  if (keyPressed){
    initialize();
    switch(key){
      case '0':
        playersmoney = managersmoney/10000;
        break;
      case '1':
        playersmoney = managersmoney/1000;
        break;
      case '2':
        playersmoney = managersmoney/100;
        break;
      case '3':
        playersmoney = managersmoney/50;
        break;
      case '4':
        playersmoney = managersmoney/20;
        break;
      case '5':
        playersmoney = managersmoney/9;
        break;
      case '6':
        playersmoney = managersmoney/6;
        break;
      case '7':
        playersmoney = managersmoney/3;
        break;
      case '8':
        playersmoney = managersmoney/2;
        break;
      case '9':
        playersmoney = managersmoney;
        break;

デフォルトに戻す

Restore to the default values

      case 's':
        playersmoney = managersmoney/10;
        loop();
        break;
    }
  }
}


以上です。お疲れ様です。

That's all. Thank you for your hard work.

このような確率モデルをコンピュータで乱数を用いてシミュレーションを繰り返す手法を「モンテカルロ法」と呼びます。

This method of repeating simulations using random numbers in a computer using a stochastic model is called "Monte Carlo method".

この手法は数学者ジョン・フォン・ノイマン(John vonNeumann 1903-1957)が考案しました。

The technique was developed by mathematician John von Neumann (1903-1957).

ちなみに今回行った方法でも様々な因子となる変数が存在しますので、少し条件を変えるだけで違った結果になると思います。

By the way, there are variables that can be various factors in this method, so I think the result will be different by changing the condition a little.

是非色々と試してみてください。

Please try various things.





See You Next Page!