Now that I finally understand the problem, I have a suggestion for approximating a solution. Change the rules so that the game ends either when the player goes bankrupt or when he has played $N$ times. Now the chain is finite, with two absorbing states, and we can compute the time to absorption and the probability of absorption in each state by standard methods. Since we know that the number of steps to absorption in the second absorbing state is $N$, and we also know the probability of absorption in that state, we can easily compute the average time to absorption in the first state.
The transient states are of the form $(w,\ell)$ meaning $\ell$ losses and $w$ wins, where $w+\ell<N$. Not all possibilities appear, because $\left(\frac35\right)^5<\frac1{10}$ so any player who has lost $5$ times more than he has won has gone bankrupt.
My thought is to try it for various values of $N$, until it stops changing. The main programming challenge is constructing the transition matrix.
Thanks for this programming problem. It will help beguile my isolation today.
Suppose we make a cutoff of
$M$ rolls. Let
$X$ be the average number of rolls until the game ends, whether by bankruptcy or cutoff, let
$B$ be the event of bankruptcy, and
$C$ the event of cutoff. We have
$$\begin{align}
E(X)&=\Pr(B)E(X|B)+\Pr(C)E(X|C)\\
&=(1-\Pr(C))E(X|B)+\Pr(C)M
\end{align}$$
My program uses standard method to compute
$E(X)$ and
$\Pr(C)$ and then uses the above equation to solve for
$E(X|B)$ the average time to bankruptcy among those players who went broke.
Here are the outputs from some successive runs:
50 21.7034134587 .7138047863
100 31.2102201519 .8850110529
150 36.8849173664 .9436954032
200 40.4551201780 .9692561812
250 42.9567867921 .9828229050
300 44.6233194430 .9900053029
The first number is the cutoff value, the second is the average time to bankruptcy, and the third is the probability of bankruptcy. It's starting to level off, and it's also starting to take a few minutes to run. I'll try to run it overnight with large cutoffs, and let you know what happens tomorrow.
EDIT
Since I first posted this, I realized that there were a lot of superfluous states in my original script. For example, with $M=100$, a player who wins $54$ games and loses $46$ does not go bankrupt, so once a player wins $54$ games, we know he will not go broke. To compute the number of steps to absorption correctly, we just keep track of the number of games such players have played. When $M=100$, this reduced the number of transient states from $2488$ to $1453$. Of course, we could compute the average time to bankruptcy, by eliminating the cutoff state, and forcing players to go bankrupt, so that any player with $53$ wins would lose from then on. This would reduce the number of transient states, by another $46$, but it would not allow computation of the probability of bankruptcy, which is nice to know. The script below is the revised one.
Here's my script, if you want to check it, which I would appreciate.
'''
Player starts with bankroll of $100. A fair coin is tossed;
if it comes up heads, bankroll increases by 50%. If tails,
bankroll decreases by 40%. Game ends if bankroll is less
than $1, or after M plays. What is the expected time
to bankruptcy?
In order to economize on the number of states, we compute
the number of wins W that will ensure the player from going
broke. Once a player has W wins, we only track how many
games he's played.
Usage: python bankrupt.py M
'''
import numpy as np
from scipy import linalg
from sys import argv
import math
from resource import getrusage, RUSAGE_SELF
def bankrupt(state):
win, lose = state
if lose - win >= 5: return True
return (3/2)**win * (3/5)**lose < 1/10
def maxWins(M):
# player with this may wins won't go broke in M rolls
alpha = math.log(3/2)
beta = math.log(3/5)
gamma = math.log(1/10)
return math.ceil((gamma-beta*M)/(alpha-beta))
def test(M):
count = 0
states = []
index = { }
W = maxWins(M)
for wins in range(W):
for losses in range(M-wins):
state = (wins, losses)
if bankrupt(state):
index[state] =-1
else:
states.append(state)
index[state] = count
count += 1
for s in range(W, M):
states.append((s,0))
index[s,0] = count
count += 1
S = len(states)
P = np.zeros((S+2, S+2))
for i, (wins, losses) in enumerate(states):
if W <= wins < M-1:
P[i, index[wins+1,0]] = 1
continue
if wins == M-1:
P[i, S+1] = 1
continue
w = (wins+1, losses)
if wins == W-1 and sum(w) < M:
P[i, index[W+losses,0]] = .5
elif sum(w)== M:
P[i,S+1] = .5
else:
P[i,index[w]] = .5
loss = (wins, losses+1)
if sum(loss)== M:
# bankruptcy on roll N
# counts as a bankruptcy
if bankrupt(loss):
P[i,S] = .5
else:
#stop whether a win or a loss
P[i,S+1] = 1
else:
idx = index[loss]
if idx == -1:
P[i, S] = .5
else:
P[i, idx] = .5
R = P[:S, S:]
P = np.eye(S) - P[:S, :S]
N = linalg.inv(P) # fundamental matrix
MEG =1024**2
print(f"{S} states, {getrusage(RUSAGE_SELF)[2]//MEG} MB")
# Expected time to absorption is sum of first row
steps = sum(N[0,:])
# Probability of N rolls is the (0,1) element of NR
stop = N[0,:] @ R[:, 1]
answer = (steps - M*stop)/(1-stop)
return answer, 1-stop
M = int(argv[1])
steps, prob = test(M)
print(M, steps, prob)