Simultaneous, continuous, 2-gambler poker

Each gambler is dealt a private hand, a uniform random variable between 0 and 1. Each gambler simultaneously bets between ante and all-in (normalized to $a$ and 1). The pot is the sum of the two bets. The higher bet wins the pot. If the bets are equal, the higher hand wins the pot.

$$\begin{aligned} a &= \text{ante} \\ i &\in \{1,2\} \\ g_i &= \text{gambler} \\ x_i &= \text{hand} \sim \mathbb{U}_{[0,1]}\\ b_i &= \text{bet} \in [a,1]\\ u_i &= \text{expected profit} \end{aligned}$$

In the following sections, we will:

  • show the failure of some suboptimal strategies
  • derive an optimal strategy
  • prove the strategy is optimal (by showing no response has positive expected profit)

Play the game

Ante for next hand: 0.1


Bet: 0.1

Suboptimal strategy 1: always all-in

Let's say $g_2$ decides to always bet 1, regardless of their hand. $$b_2(x_2) = 1 $$ The optimal response will be for $g_1$ to bet $a$ on low hands and $1$ on high hands.

The critical hand is shown to be $\frac{1-a}{2}$. We expect the optimal strategy will have a critical hand $c$. $$b_1(x_1) = \begin{cases}a & x_1 < c \\ 1 & x_1 \ge c \end{cases}$$ The critical hand, $c$, is optimized. The expected profit can be calculated by considering the following outcomes. - $x_1
$$b_1(x_1) = \begin{cases}a & x_1 < \frac{1-a}{2} \\ 1 & x_1 \ge \frac{1-a}{2} \end{cases}$$
Sagemath algebra
In [1]:
var("u1 a c")
u1(a,c) = -a*c+(1-c)*c
pretty_print(solve(derivative(u1(a,c),c),c)[0])

Suboptimal stategy 2: all or ante

Perhaps $g_2$ decides to bet ante on low hands and all-in on high hands. $$b_2(x_2) = \begin{cases}a & x_2<r \\ 1 & x_2 \ge r \end{cases}$$ Then, the optimal response would be to bet marginally higher than ante on low hands and all-in on high hands. $$b_1(x_1) = \begin{cases}a+\delta & x_1<q \\ 1 & x_1 \ge q \end{cases}$$

There are 5 important possibilities to consider.

  • $x_2<r$
    • $g_1$ profits $a$
  • $x_2\ge r$ and $x_1<q$
    • $g_1$ loses $a+\delta$
  • $q<r$ and $q \le x_1<r$ and $x_2\ge r$
    • $g_1$ loses 1.
  • $q>r$ and $r \le x_2<q$ and $x_1\ge q$
    • $g_1$ profits 1.
  • $x_1 \ge \max(q,r)$ and $x_2 \ge \max(q,r)$
    • The expected profit is 0.

The expected profit depends on whether $q$ or $r$ is larger. $$u_1 = ra - (1-r)q(a+\delta) + (1-\max(q,r))(q-r)$$ It is reasonable to expect $g_1$ to be pickier, such that $q>r$. Indeed, if $r>q$, then $u_1$ is linear in terms of $q$ with positive slope; thus $g_1$ would increase $q$ to be larger than $r$.

$$\text{if } q<r:$$$$\frac{du_1}{dq}~~=~~ (1-r)(1-a-\delta)~~>~~0$$
In [97]:
var("u1 a q r delta")
equ_linear = (u1==r*a-(1-r)*q*(a+delta)+(1-r)*(q-r))
show(diff(equ_linear,q).rhs().factor())

However, if $q>r$, then we find the nash equilibrium by $g_2$ minimizing the maximum profit available to $g_1$.

In [3]:
var("u1 a q r delta")
equ1 = (u1 == r*a-(1-r)*q*(a+delta)+(1-q)*(q-r))
eqq1 = solve(diff(equ1,q),q)[0]
equ2 = equ1.substitute(eqq1)
eqr = solve(diff(equ2,r),r)[0].simplify_full()
eqq = eqq1.substitute(eqr).simplify_full()
equ = equ2.substitute(eqr).simplify_full()
show(eqq1.simplify_full())
show(eqq1.simplify_full().substitute(delta=0))
show(eqr)
show(eqq)
show(equ)

Furthermore, we expect $\delta\to0$, so these simplify.

In [103]:
eqr0 = eqr1.substitute(delta=0)
eqq0 = eqq2.substitute(delta=0)
equ0 = equ3.substitute(delta=0)
show(LatexExpr("\\delta\\to0"))
show(eqr0)
show(eqq0)
show(equ0)

Optimal strategy

An optimal strategy is shown, with player index suppressed for legibility. $$b(x) = \begin{cases}\frac{a}{(1-x)^2} & x<1-\sqrt{a} \\ 1 & x\ge 1-\sqrt{a} \end{cases}$$

We will first prove an optimal strategy cannot be bested. Then, we will see how this optimal strategy was derived.

Proof of optimal strategy

In a symmetric game, an optimal strategy must be an optimal response to itself. We can hope to find an optimal strategy such that the bet is a nondecreasing function of the hand. Let's assume $g_2$ is using the optimal strategy shown above. We show if $x_1<(1-\sqrt{a})$ then $u_1=-a$ regardless of $b_1$.

In [55]:
var("a x b")
b(a,x) = min_symbolic(a/(1-x)^2,1)
a0 = 0.1
b1 = a0/(1-0.4)^2
p = plot(b(a0,x),(0,1),ymin=0,ymax=1,xmin=0,xmax=1,aspect_ratio=1,axes_labels=['$x_2$','$b_2$'],color="black")
L = [[0,0]]+[[i/200,min_symbolic(1,a0/(1-i/200)^2)] for i in range(200+1)]+[[1,0]]
p += polygon(L, edgecolor="white", color=Color(0.96,0.96,0.96))
L = [[0,0]]+[[i/100,a0/(1-i/100)^2] for i in range(40+1)]+[[0.4,0]]
p += polygon(L,color="limegreen", edgecolor="black")
p += polygon([[0.4,b1],[1,b1],[1,0],[0.4,0]],color="red", edgecolor="black")
p += text("gain",(0.2,0.07),fontsize=18,color="black")
p += text("loss",(0.7,0.07),fontsize=18,color="black")
p += text("$b_1$",(-0.07,b1),fontsize=16,vertical_alignment="center")
p += line([(-0.02,b1),(0,b1)],thickness=2)
p += line([(0,b1),(0.4,b1)],linestyle="--")
p += circle((0.4,b1),0.018,fill=True,edgecolor="black")
p += text("($x$,$b$)",(0.4,b1+0.1),fontsize=16)
show(p)
In [64]:
a = var("a")
x = var("x")
b = a/(1-x)^2
u1 = function("u1")(x)
assume(x>0)
assume(x<1)
eq = (u1(x) == integrate(b,x,0,x)-(1-x)*b)
show(eq.simplify_full())

If $x_1\ge(1-\sqrt{a})$ then $g_1$ optimizes with $b_1=1$. If $b_1<1$ then $u_1=-a$. Only by going all-in can $g_1$ take advantage of high hands.

In [73]:
var("a x b")
b(a,x) = min_symbolic(a/(1-x)^2,1)
a0 = 0.1
xx = 0.8
b1 = 1 #a0/(1-0.4)^2
p = plot(b(a0,x),(0,1),ymin=0,ymax=1,xmin=0,xmax=1,aspect_ratio=1,axes_labels=['$x_2$','$b_2$'],color="black")
L = [[0,0]]+[[i/200,min_symbolic(1,a0/(1-i/200)^2)] for i in range(200+1)]+[[1,0]]
p += polygon(L, edgecolor="white", color=Color(0.96,0.96,0.96))
L = [[0,0]]+[[i/100,b(a0,i/100)] for i in range(int(xx*100)+1)]+[[xx,0]]
p += polygon(L,color="limegreen", edgecolor="black")
p += polygon([[xx,b1],[1,b1],[1,0],[xx,0]],color="red", edgecolor="black")
p += text("gain",(0.4,0.1),fontsize=18,color="black")
p += text("loss",(0.9,0.1),fontsize=18,color="black")
p += circle((xx,b1),0.018,fill=True,edgecolor="black")
p += text("($x_1$,$1$)",(xx,b1+0.07),fontsize=16)
show(p)

Thus, there is no benefit for $g_1$ to not using a symmetric strategy, proving the Nash equilibrium.

However, it is also clear that $g_1$ can use any strategy (as long as she goes all-in on good hands) and still have a 0 expected profit. Thus this is a weak Nash equilibrium. Also, if $g_1$ were to change her strategy (while maintaining 0 net profit), then $g_2$ could respond to net a higher profit; thus this is an unstable equilibrium.

Derivation of optimal solution

Assume $b_2(x_2)$ is a continuous increasing function up to the ceiling (at a critical hand) and all-in for hands above critical. If $g_1$ bets below 1, the expected profit can depend on $b_1$, and the corresponding hand that would cause $g_2$ to bet $b_1$. That value will be called $x$. Also, because $b_1=b_2(x)$, we can just use $b$. $$$$ $$\begin{align}\text{if }b_1<1:&\\x &= b_2^{-1}(b_1) \\\\ u_1 &= \int_0^xb_2(x_2) dx_2 - (1-x)b\end{align}$$

The trick is to enforce no profit difference to $g_1$ when changing the bet.

In [2]:
a = var("a")
x = var("x")
c = var("c")
u1 = function("u1")(x)
b = function('b')(x)
eq = (u1(x) == b.integral(x)-(1-x)*b)
eq2 = (0 == diff(eq).rhs())
eq3 = (b == desolve(eq2,b,[0,a]).factor())
show(eq3)
assume(x<1)
show(solve(eq3.rhs()==1,x)[0].substitute(x=c))

Simultaneous, continuous, $n$-gambler poker

A similar logic can find a Nash equilibrium in an $n$-gambler version. We assume all gamblers are using the same strategy, and ask whether $g_1$ can improve by changing strategy.

First, if $x_1<c$, then $g_1$ will pick a bet $b_1$. We will find the $x$ that corresponds to this bet, and call that bet $b$ for simplicity.

$$\text{if }x_1<c: $$$$u_1 = x^{n-1}(n-1)\frac{1}{x}\int_0^x b(x) dx - (1-x^{n-1})b $$
In [26]:
var("a x")
b=function("b")(x)
u1=function("u1")(x)
eq1 = (u1(x)==x^6*6/x*b.integral(x)-(1-x^6)*b)
show(eq1)
show(diff(eq1,x))
bsol = desolve(diff(eq1,x).rhs(),b,ivar=x).log_simplify().simplify_full()
show(bsol.log_simplify().factor())
latex(bsol)
Out[26]:
\frac{C}{x^{42} - 7 \, x^{36} + 21 \, x^{30} - 35 \, x^{24} + 35 \, x^{18} - 21 \, x^{12} + 7 \, x^{6} - 1}
In [21]:
var("a x")
b=function("b")(x)
u1=function("u1")(x)
eq1 = (u1(x)==x^2*2/x*b.integral(x)-(1-x^2)*b)
show(eq1)
show(diff(eq1,x))
bsol = desolve(diff(eq1,x).rhs(),b,ivar=x).log_simplify().simplify_full()
show(bsol.log_simplify().factor())
latex(bsol)
Out[21]:
\frac{C}{x^{6} - 3 \, x^{4} + 3 \, x^{2} - 1}
In [14]:
var("a x n zero")
b=function("b")(x)
u1=function("u1")(x)
zero = 0
eq1 = (u1(x)==x^n*n/x*b.integral(x)-(1-x^n)*b)
show(eq1)
show(diff(eq1,x))
bsol = desolve(diff(eq1,x).rhs(),b,ivar=x).log_simplify().simplify_full()
show(bsol.log_simplify())
latex(bsol)
Out[14]:
C {\left(x^{n} - 1\right)}^{-n - 1}
In [91]:
var("a x")
B=function("B")(x)
u1=function("u1")(x)
nn = 4  ## number of opponents
eq1 = (u1(x)==x^nn*nn/x*B-(1-x^nn)*diff(B,x))
# show(diff(eq1,x))
bsol = desolve(diff(eq1,x).rhs(),B,ivar=x).log_simplify().simplify_full()
# show(bsol)
bs = bsol.substitute(_K2=0)
dbs = diff(bs,x)
# show(dbs)
bb = dbs.substitute(_K1=-a)
show(bb)
# latex(bsol)
# sols = solve(1==bb,x)
# for sol in sols:
#     show(sol)
$$ b(x)= \frac{nax^n}{(1-x^n)^2}+\frac{a}{(1-x^n)} $$
$$ b(x)= \frac{(n-1)ax^n+a}{(1-x^n)^2}$$
$$x_\text{crit}={{\left(-\sqrt{a^2\,n^2-2\,a^2\,n+4\,a\,n+a^2}+a\,n-a+2\right)^{ {{1}\over{n}}}}\over{2^{{{1}\over{n}}}}}$$
In [79]:
sum([plot(min_symbolic(1,((n-1)*0.1*x^n+0.1)/(1-x^n)^2),(x,0,1),ymin=0,ymax=1) for n in range(1,10)])
Out[79]:
$$b(x) = \begin{cases}\frac{(n-1)ax^n+a}{(1-x^n)^2} & x< x_\text{crit}\\ 1 & x \ge x_\text{crit} \end{cases} $$

Proof of $n$-gambler solution

We assume gamblers 2...$n$ all use the optimal solution. When $x_1<x_\text{crit}$ we can show $u_1=-a$ regardless of the strategy.

$$ b(x)= \frac{nax^n}{(1-x^n)^2}+\frac{a}{(1-x^n)} $$
$$ b(x)= \frac{nax^n+(1-x^n)a}{(1-x^n)^2}$$
$$ b(x)= \frac{nax^n+a-ax^n}{(1-x^n)^2}$$
$$ b(x)= \frac{(n-1)ax^n+a}{(1-x^n)^2}$$
In [1]:
var("x n a")
u1 = function("u1")(x)
forget()
assume(n>0)
assume(n,"integer")
assume(a>0)
assume(a<1)
assume(x>0)
assume(x<1)
assume(x>a)
b(x) = n*a*x^n/(1-x^n)^2+a/(1-x^n)
eq1 = (u1(x)==x^(n-1)*n*b.integral(x,0,x)-(1-x^n)*b)
show(eq1(x).simplify_full())

Conclusions

We have proven the Nash-equilibrium strategy in $n$-player simultaneous poker (as defined here). I have never seen this treatment anywhere else, and possibly for good reason. Are any of these insights useful for real poker, with turns and calling? I'd say maybe.

If your opponent ignored your actions and played solely by their hand, then this game could closely resemble 5-card stud. Of course, in real poker, randomization needs to be used to obfuscate. But what is the underlying basic strategy that needs to be obfuscated? I'd guess it looks something like the curves shown here.

Regardless, it is fun to consider this game on its own merits. The two-person version would be more fun if a button was held as the bets climbed until a player folded by releasing the button. This would be equivalent to the game above, but only in the 2-player case. The $n$-player case would become drastically more difficult to analyze.

Also, I like to think this game is somewhat related to dominance displays before fights in the animal kingdom. The connection is not perfect, but it is fun imagery.

There are clear directions for further investigations.

  • Discretize the bets and hands.
  • Have a more complex showdown. For example, the showdown could be a duel, where each player has 0 to 10 bullets, such that a better hand (more bullets) does not guarentee a win.
  • Can the $n$-player strategy be colluded against successfully?