DEV Community

Devanshu Biswas
Devanshu Biswas

Posted on

A Grid Search for Kuhn Poker's Optimal Strategy Finds Either q/3 + 1 Answers or Exactly Zero

Kuhn poker is three cards, one bet, and the first game in this series where you cannot see the position. That single change breaks something most game code assumes: with hidden information there is no best move, only a best distribution.

Play it: https://dev48.infy.uk/game/day74-kuhn-poker.html

The optimal strategy is a segment, not a point

The first player's optimal set is a one-parameter family. Bluff the Jack at any rate α in [0, 1/3], provided you bet the King at exactly and call with the Queen at exactly 1/3 + α.

Every member of that family is worth exactly −1/18 a hand, and every one is exactly unexploitable. Not "to within tolerance" — the page certifies it in BigInt rationals.

// value of the game, exactly, for any alpha in [0, 1/3]
// bet K at 3a, bluff J at a, call Q at 1/3 + a  ->  -1/18 for player 1
Enter fullscreen mode Exit fullscreen mode

Now find it the way anyone would

Sweep a grid over the strategy space. Reasonable, and it fails in an interesting way:

A grid of step 1/q contains exactly q/3 + 1 unexploitable strategies when 3 divides q, and exactly zero otherwise.

Not "few". Zero. Every payoff on a rational grid of step 1/q is a multiple of 1/6q, and the game value is not. So the answer your search returns is decided by arithmetic, not by resolution — refining from q = 100 to q = 101 takes you from many exact solutions to none at all, and the search reports its nearest miss with no indication that it stopped being exact.

grid step 3 divides q? unexploitable strategies found
1/99 yes 34
1/100 no 0
1/101 no 0
1/102 yes 35

Why this generalises

Any solver that discretises a continuous strategy space inherits the arithmetic of its grid. If the quantity you are solving for is not representable on that grid, a finer grid does not help — it just moves the miss around. The fix is not more resolution; it is solving in the field where the answer lives.

Verified against an independently written implementation, 0 failures. Vanilla JavaScript, one file, no build step.

Top comments (0)