#! /usr/bin/env python3
#
def gamblers_ruin_plot ( a_stakes, b_stakes ):
#*****************************************************************************80
#
## gamblers_ruin_plot() plots a game of gambler's ruin.
#
# Discussion:
#
# Two players, A and B, repeatedly toss a coin.
# For heads, A wins one dollar from B
# For tails, B wins one dollar from A.
# Play continues until one player is bankrupt.
#
# The program simulates the game, and then produces a plot of the
# amount of money that A has at each stage of the game. At the end,
# A must have either nothing or all the money.
#
# The program produces a plot of A's money. It also displays the
# initial stakes, the number of steps, and the number of times the
# lead changed.
#
# Licensing:
#
# This code is distributed under the MIT license.
#
# Modified:
#
# 12 November 2022
#
# Author:
#
# John Burkardt
#
# Input:
#
# integer A_STAKES, B_STAKES, the number of dollars that A and
# B have initially.
#
from numpy.random import default_rng
import matplotlib.pyplot as plt
import numpy as np
rng = default_rng ( )
print ( '' )
print ( 'gamblers_ruin_plot():' )
print ( ' Display the bankrolls of two gambling opponents.' )
step_num = 0
leader = '0'
flip_num = -1
a = a_stakes
b = b_stakes
steps = np.array ( [ 0 ] )
value = np.array ( [ a ] )
while ( 0 < a and 0 < b ):
step_num = step_num + 1
r = rng.random ( )
if ( r <= 0.5 ):
a = a + 1
b = b - 1
else:
a = a - 1
b = b + 1
# print ( ' %d %d' % ( a, b ) )
value = np.append ( value, a )
steps = np.append ( steps, step_num )
if ( a_stakes < a and leader != 'A' ):
leader = 'A'
flip_num = flip_num + 1
elif ( a < a_stakes and leader != 'B' ):
leader = 'B'
flip_num = flip_num + 1
#
# Plot the results.
#
plt.clf ( )
plt.plot ( [ 0, step_num], [ a_stakes, a_stakes ], 'r-', linewidth = 2 )
plt.plot ( [ 0, step_num], [ 0, 0 ], 'r-', linewidth = 2 )
plt.plot ( [ 0, step_num], [ a_stakes + b_stakes, a_stakes + b_stakes ], \
'r-', linewidth = 2 )
plt.plot ( steps, value, 'b-', linewidth = 2 )
title_string = ( 'Gambler\'s Ruin - A = %d, B = %d, Steps = %d, Flips = %d' \
% ( a, b, step_num, flip_num ) )
plt.grid ( True )
plt.title ( title_string )
plt.xlabel ( 'Coin Tosses' )
plt.ylabel ( 'A''s Money' )
plt.axis ( 'tight' )
filename = 'gamblers_ruin_simulation.png'
plt.savefig ( filename )
print ( ' Graphics saved as "' + filename + '"' )
plt.close ( )
return
def gamblers_ruin_simulation ( a_stakes, b_stakes, game_num ):
#*****************************************************************************80
#
## gamblers_ruin_simulation() simulates the game of gambler's ruin.
#
# Discussion:
#
# Two players, A and B, repeatedly toss a coin.
# For heads, A wins one dollar from B
# For tails, B wins one dollar from A.
# Play continues until one player is bankrupt.
#
# This program "plays" the game GAME_NUM times, always starting from
# the same initial configuration.
#
# it keeps track of the number of coin tosses required, the number
# of times the lead changes, and the number of times each player wins.
#
# At the end, it prints some statistics, and plots histograms of the
# length of the game, and the number of lead changes.
#
# Licensing:
#
# This code is distributed under the MIT license.
#
# Modified:
#
# 12 November 2022
#
# Author:
#
# John Burkardt
#
# Input:
#
# integer A_STAKES, B_STAKES, the number of dollars that A and
# B have initially.
#
# integer GAME_NUM, the number of games to simulate.
#
from numpy.random import default_rng
import matplotlib.pyplot as plt
import numpy as np
rng = default_rng ( )
print ( '' )
print ( 'gamblers_ruin_simulation():' )
print ( ' Simulate many instances of a two person gambling competition.' )
flip = np.zeros ( game_num )
step = np.zeros ( game_num )
a_wins = 0
b_wins = 0
#
# Play GAME_NUM games.
#
for game in range ( 0, game_num ):
step_num = 0
leader = '0'
flip_num = -1
a = a_stakes
b = b_stakes
while ( 0 < a and 0 < b ):
step_num = step_num + 1
r = rng.random ( )
if ( r <= 0.5 ):
a = a + 1
b = b - 1
else:
a = a - 1
b = b + 1
if ( a_stakes < a and leader != 'A' ):
leader = 'A'
flip_num = flip_num + 1
elif ( a < a_stakes and leader != 'B' ):
leader = 'B'
flip_num = flip_num + 1
if ( b == 0 ):
a_wins = a_wins + 1
else:
b_wins = b_wins + 1
flip[game] = flip_num
step[game] = step_num
#
# Average over the number of games.
#
step_ave = np.sum ( step ) / game_num
prob_a_win = a_wins / game_num
prob_b_win = b_wins / game_num
#
# Print statistics.
#
print ( '' )
print ( ' Number of games in simulation =', game_num )
print ( ' A starts game with', a_stakes )
print ( ' B starts game with', b_stakes )
print ( '' )
print ( ' Average number of steps =', step_ave )
print ( ' Expected number of steps =', a_stakes * b_stakes )
print ( ' Maximum number of steps =', np.max ( step ) )
print ( '' )
print ( ' Average chance of A winning = ', prob_a_win )
print ( ' Expected chance of A winning =', a_stakes / ( a_stakes + b_stakes ) )
print ( ' Average chance of B winning = ', prob_b_win )
print ( ' Expected chance of B winning =', b_stakes / ( a_stakes + b_stakes ) )
print ( '' )
print ( ' Average number of flips = ', np.sum ( flip ) / game_num )
print ( ' Maximum number of flips = ', np.max ( flip ) )
print ( '' )
print ( ' Initial flip table:' )
print ( '' )
print ( ' Number Freq Prob' )
print ( '' )
for flip_num in range ( 0, 11 ):
k = np.sum ( flip == flip_num )
print ( ' %4d %6d %f' % ( flip_num, k, k / game_num ) )
#
# Plot steps.
#
plt.clf ( )
plt.hist ( step, 40 )
plt.title ( 'Gambler''s ruin, number of steps' )
plt.grid ( True )
plt.xlabel ( 'Steps' )
plt.ylabel ( 'Frequency' )
filename = 'gamblers_ruin_steps.png'
plt.savefig ( filename )
print ( ' Graphics saved as "' + filename + '"' )
plt.close ( )
plt.clf ( )
plt.hist ( flip, 40 )
plt.title ( 'Gambler''s ruin, number of changes in the lead (flips)' )
plt.grid ( True )
plt.xlabel ( 'Flips' )
plt.ylabel ( 'Frequency' )
filename = 'gamblers_ruin_flips.png'
plt.savefig ( filename )
print ( ' Graphics saved as "' + filename + '"' )
plt.close ( )
return
def gamblers_ruin_simulation_test ( ):
#*****************************************************************************80
#
## gamblers_ruin_simulation_test() tests gamblers_ruin_simulation().
#
# Licensing:
#
# This code is distributed under the MIT license.
#
# Modified:
#
# 12 November 2022
#
# Author:
#
# John Burkardt
#
import platform
print ( '' )
print ( 'gamblers_ruin_simulation_test():' )
print ( ' Python version: ' + platform.python_version ( ) )
print ( ' Test gamblers_ruin_simulation().' )
#
# Simulate a single short game.
#
a_stakes = 5.0
b_stakes = 7.0
game_num = 1
gamblers_ruin_simulation ( a_stakes, b_stakes, game_num )
#
# Simulate many longer games.
#
a_stakes = 70.0
b_stakes = 70.0
game_num = 1000
gamblers_ruin_simulation ( a_stakes, b_stakes, game_num )
#
# Plot the course of a single game.
#
a_stakes = 70.0
b_stakes = 70.0
gamblers_ruin_plot ( a_stakes, b_stakes )
#
# Terminate.
#
print ( '' )
print ( 'gamblers_ruin_simulation_test():' )
print ( ' Normal end of execution.' )
print ( '' )
return
def timestamp ( ):
#*****************************************************************************80
#
## timestamp() prints the date as a timestamp.
#
# Licensing:
#
# This code is distributed under the MIT license.
#
# Modified:
#
# 21 August 2019
#
# Author:
#
# John Burkardt
#
import time
t = time.time ( )
print ( time.ctime ( t ) )
return
if ( __name__ == '__main__' ):
timestamp ( )
gamblers_ruin_simulation_test ( )
timestamp ( )