4.1.4.1 Gambler's Ruin

  1. Description of the Coin Game
  2. Flipping the Coin
  3. Repetition
  4. The Game as a Procedure
  5. Statistical Analysis of the Simulation

Description of the Coin Game

John and Sarah are flipping a coin. This coin is supposed to be fair, i.e., the probability that it comes up head equals one half. Each time it comes up head, John pays Sarah one dollar; if it comes up tail, Sarah pays John one dollar. The game is over when one player is broke. At the beginning of the game John has five dollars to play with and Sarah has ten dollars. The questions that we want to answer via simulation of the gambling game are

Flipping the Coin

When flipping the coin, Sarah's profit is one dollar if it comes up head and minus one dollar if it comes up tail. So, from her point of view, it is convenient to let a result head correspond to a value of 1 (one dollar gain) and to let a result tail correspond to a value of -1 (one dollar loss). Then, flipping the coin is a random generation of 1s and -1s with equal probability and Sarah's amount of dollars at each step is obtained by adding the random number to her current amount.

There are two possible ways to randomly generate numbers:

  1. The Java class java.lang.Math contains the method random() that returns a uniformly distributed pseudorandom float value between 0.0 and 1.0.
  2. The Java class java.util.Random provides methods to generate pseudorandom numbers. You first create a new random generator with the Random method. This makes available methods to compute the next element in the current random number generator's sequence. Commonly used methods are the following:
public static int[] toss1() {
  Random R = new Random();
  int number;
    number = (R.nextInt() % 2 == 0) ? -1 : 1;
  }
  return number;
}

public static int toss2() {
  if (Math.random() < 0.5) {
    return -1;
  } 
  else {
    return 1;
  }
}
In the first method we generate each time a new integer, carry out integer division with 2, and replace a reminder of 0 by -1. The keyword static turns both methods in what is called a class method, which is discussed later.

With these utilities we can easily implement a method to randomly generate 1s and -1s. Below we present a method to generate an array of randomly chosen 1s and -1s. Experimentation reveals that in this case you better use the java.util.Random class for efficiency reasons.

Random R = new Random();

public static int[] toss(int n) {
  int[] numbers = new int[n];
  for (int i=0; i < numbers.length; i++) {
    numbers[i] = (R.nextInt() % 2 == 0) ? -1 : 1;
  }
  return numbers;
}

Now that we know how 1s and -1s can be generated efficiently, we can concentrate on the gambling game itself. In this section we write down the kind of lines of Java code that correspond with different phases in the simulation of one game. We start with initializing John's and Sarah's amount of money:

int johnsDollars = 5,  sarahsDollars = 10;
We flip the coin once and update the amount of money John and Sarah have:
Random R = new Random();
int profit;
profit = (R.nextInt() % 2 == 0) ? -1 : 1;
johnsDollars  -= profit;
sarahsDollars += profit;

Repetition

We repeat the previous step until the gambling game is over. The game goes on if none of the players is broke at the particular moment. In the Java application, this condition can be implemented as follows:
johnDollars > 0  &&  sarahsDollars > 0
Because we are interested in the length of the game, we introduce the variable numberOfTosses that counts the number of times the coin is flipped. This variable is initialized at value 0 and is updated during the repetitive process. The repetition is the following while-loop:
while (johnDollars > 0  &&  sarahsDollars > 0) {
  profit = (R.nextInt() % 2 == 0) ? -1 : 1;
  johnDollars -= profit;
  sarahsDollars += profit;
  numberOfTosses++;
}

The Game as a Procedure

We collect all commands into a procedure. Let us call this procedure game and assume that it is called with the initial amounts of money of the players as actual arguments and returns the length of the game.
import java.util.*;

public class OneGame1stVersion {

  static Random R = new Random();

  public static void main(String[] args) {
    int onegame = game(5,10);
    System.out.println("Game Length is " + onegame);
  }

  static int game(int johnsDollars, int sarahsDollars) {
    int numberOfTosses = 0, profit = 0;
    while (johnsDollars > 0  &&  sarahsDollars > 0) {
      profit = (R.nextInt() % 2 == 0) ? -1 : 1;
      johnsDollars  -= profit;
      sarahsDollars += profit;
      numberOfTosses++;
    }
    return numberOfTosses;
  }

}
The creation of the random number generator has been done globally for the class and not inside the game to avoid bias when this method is applied many times in a simulation. To declare such a class variable you use the keyword static. Similarly, with the keyword static, the game method is declared a class method. You do not have to create an object to be able to call this method.

The current application only shows the length of the game, but not who wins. To add this information, we introduce a new class to hold the length of the game and the name of the winner.

class GameResult {
  int gameLength;
  String winner;

  GameResult(int gameLength, String winner) {
    this.gameLength = gameLength;
    this.winner     = winner;
  }
}
The application for one simulation of the game is now as follows:
import java.util.*;

public class OneGame {

  static Random R = new Random();

  public static void main(String[] args) {
    GameResult onegame = game(5,10);
    System.out.println("Game Length is " + onegame.gameLength);
    System.out.println("Winner is " + onegame.winner);
  }

  static GameResult game(int johnsDollars, int sarahsDollars) {
    int numberOfTosses = 0, profit = 0;
    while (johnsDollars > 0  &&  sarahsDollars > 0) {
      profit = (R.nextInt() % 2 == 0) ? -1 : 1;
      johnsDollars  -= profit;
      sarahsDollars += profit;
      numberOfTosses++;
    }
    GameResult result = (sarahsDollars > 0) ? 
      new GameResult(numberOfTosses, "Sarah") :
      new GameResult(numberOfTosses, "John");
    return result;
  }

}

Statistical Analysis of the Simulation

When you analyze Gambler's Ruin statistically you ask yourself questions like: All three questions can be answered theoretically: average game length is 50 (i.e., 5 times 10), the probability that Sarah wins equals 10/15 = 2/3 = 0.6666...., the average length of games won by Sarah is 125/3 = 41.666....., and the average length of games won by John is 200/3 = 66.6666... (John wins less often and has to work harder for success). If you run a large simulation of games you expect to find numeric results close to the theoretical values.
import java.util.*;

public class Simulation {
   
  static Random R = new Random();
  static int numberOfGames = 5000;

  public static void main(String[] args) {
    GameResult[] games = new GameResult[numberOfGames];
    for (int i=0; i 0  &&  SarahsAmountOfMoney > 0) {
      profit = (R.nextInt() % 2 == 0) ? -1 : 1;
      JohnsAmountOfMoney  -= profit;
      SarahsAmountOfMoney += profit;
      numberOfTosses++;
    }
    GameResult result = (SarahsAmountOfMoney > 0) ? 
      new GameResult(numberOfTosses, "Sarah") :
      new GameResult(numberOfTosses, "John");
    return result;
  }
}

One remark about the Java code: Java has a built-in garbage collector that is automatically invoked but runs on low-priority. However, during execution of the for-loop in which all games are simulated the garbage collector may get no chance to remove the objects created by the game method and which are not needed anymore, and program execution may stop because of lack of memory. For this reason we call inside the for-loop each time after 1000 iterations the garbage collector via the gc method of the System class.

The output of a run of three simulations of each 5000 games is shown below:

Average game length = 50.079
Proportion that Sarah won = 0.6654
Average length of games won by Sarah = 42.0171
Average length of games won by John = 66.1112

Average game length = 50.1888
Proportion that Sarah won = 0.6656
Average length of games won by Sarah = 42.2975
Average length of games won by John = 65.8959

Average game length = 49.9364
Proportion that Sarah won = 0.6664
Average length of games won by Sarah = 41.7017
Average length of games won by John = 66.3861
The numerical results are in good comparison with the theoretical results.