Skip to content

Repository files navigation

Flip 7 simulator

A complete Flip 7 model in Python: the deck, the full multiplayer rules, a set of playable strategies, an exact optimal-stopping solver, and a command line to run it all. No dependencies beyond the standard library.

See blog post at https://stevemurch.com/flip-7-card-game-optimal-strategies/2026/08

Files

file what it holds
deck.py card model, the 94-card deck, draw/discard/reshuffle, one player's line and its score
sim.py the game engine: turns, action cards, Flip 7, round and game end
strategies.py decision policies, including a human prompt
dp.py exact single-player optimal-stopping DP and the solved policy cache
advice.py boils the solved table down to a rule a person can use
main.py command line: play, sim, round, watch, rules
test_flip7.py 17 checks, including a DP against simulation cross-check
runlog.py tees every run into results/

Run it

python3 main.py play                          # you against three bots
python3 main.py sim -n 4000 -p dp,ev,bust:0.25,sum:20
python3 main.py round -n 20000 -p ev,dp       # one-round score distribution
python3 main.py watch -p ev,ev,ev             # one game, card by card
python3 main.py rules                         # deck and scoring reference
python3 dp.py                                 # solve the single-player game
python3 dp.py --all                           # every policy, exactly (~3 min)
python3 advice.py                             # the optimal rule, in one table
python3 odds.py                               # the full odds reference
python3 test_flip7.py

Every run also writes what it printed to results/<command>-<timestamp>.txt. Use -o PATH to choose the file or --no-file to skip it.

Policies

python3 main.py rules prints this list too.

policy how it decides
sum:N Hit until the face values in front of you total N or more, then stay. The classic table rule. Cheap, and hard to beat by much.
count:N Hit until you hold N distinct numbers. Worse than the sum rule: a line of 0 1 2 3 is safe and nearly worthless.
bust:P Hit while the chance that the next card duplicates a number you already show stays under P. Risk-based, and blind to what is at stake.
bustc:P The same rule, counting the discard pile exactly instead of only reading the table.
ev Hit whenever taking one more card, then stopping, beats standing right now. One-step lookahead over the unseen cards, and it lands within a whisker of the exact optimum.
evc The same one-step rule with perfect card counting.
dp The exact solo optimum, looked up in a solved table of 1.8M states. Plans to the end of the round instead of one card ahead.
endgame Wraps ev with race awareness: once someone is within 60 of the target it gambles when trailing and coasts when ahead.
human Prompts you at the terminal, showing the table, your bust risk, and the value of one more card.

All of them share the same targeting heuristics for the action cards: freeze yourself when you are sitting on points and the next flip is dangerous, otherwise freeze whoever is closest to Flip 7; take a Flip Three yourself only when your line is short and safe, otherwise hand it to the biggest threat; pass a spare Second Chance to whoever is furthest behind.

The rules as implemented

The deck is 94 cards: 79 numbers (one 0, one 1, two 2s, up to twelve 12s), six modifiers (+2 +4 +6 +8 +10 and x2), and nine actions (three each of Freeze, Flip Three, Second Chance).

Every player is dealt one face-up card, then each turn you Hit or Stay. Flip a number you already show and you bust for zero, unless you hold a Second Chance, which is discarded along with the duplicate. Seven distinct numbers is a Flip 7: +15, and the round ends at once for everyone, with the other unbusted players banking what they show.

Score is sum(numbers) * (2 if x2) + sum(pluses) + 15 if Flip 7. The order matters: x2 doubles the numbers only, so 5 + 7 with x2 and +10 is 34, not 44.

Action cards resolve the instant they are flipped:

  • Freeze — give it to any player still in the round, yourself included. They bank what they have and are out.
  • Flip Three — give it to any player still in the round. They flip three cards one at a time, stopping early on a bust or a Flip 7. An action flipped during those three resolves immediately, then the remaining flips continue.
  • Second Chance — keep it. If you already hold one you must pass the spare to another player in the round who has none; if nobody qualifies it is discarded.

The game ends after the round in which someone reaches 200. Highest total wins.

What the model says

One round, played alone, is worth 22.23 points under exact optimal play. That is dp.py on its 88-card model deck (Freeze and Flip Three are neutral for a solo player who can pass them on, so they drop out of the model). Optimal play busts 31.7% of the time and reaches Flip 7 on 1.55% of rounds. The reachable state space is 1.83M states.

Simple thresholds give up less than you would guess. These are exact figures from python3 dp.py --all, not simulations:

policy                    EV      sd    bust   flip7
optimal               22.232   17.47   31.7%   1.55%
stand on sum 16       18.559    8.92   13.7%   0.00%
stand on sum 20       20.251   12.05   21.5%   0.00%
stand on sum 24       20.977   15.51   31.6%   0.01%
stand on 3 cards      19.705   12.91   24.1%   0.00%
stand on 4 cards      19.669   18.58   43.0%   0.00%
stand on 5 cards      16.462   22.16   61.6%   0.00%
bust risk < 0.25      20.988   15.89   32.9%   0.03%
bust risk < 0.35      18.773   21.92   55.1%   0.61%
bust risk < 0.45      14.058   24.71   73.8%   4.01%

The best simple rules — stand on a sum of 24, or hit while the bust risk is under 25% — are worth about 20.98, some 5.6% below perfect play. Stopping rules based on the sum of your numbers beat rules based on the count of your cards, because a line of 0, 1, 2, 3 is both very safe and nearly worthless. Chasing Flip 7 on purpose is a trap: the policies that reach it most often (bust risk under 0.45, 4% of rounds) are the worst policies in the table.

Optimal play scores 0 on 31.7% of rounds and otherwise piles up around 25-33. There is no useful middle: you bust, or you bank roughly thirty.

More points per round is not the same as more wins, and it gets worse as the table fills up. bust:0.25 scores measurably fewer points a round than the EV-maximizing ev bot, about 0.15. Whether that costs it anything depends entirely on how many people it is playing against:

players   games     ev win%   bust:0.25 win%   ev pts/rd   bust pts/rd
      2  100,000       50.4%            49.6%       20.63         20.52
      4   60,000       24.5%            25.6%       20.90         20.73
      6   42,000       15.9%            17.4%       20.97         20.76

Heads-up, maximizing value wins. At four players it loses. At six it loses clearly, by about twelve standard errors. Nothing about the policies changed — only the number of people you have to beat. A bigger field raises the score you need, and the higher-variance bot reaches it more often, even while averaging less.

The lesson is about objectives, not about Flip 7. The solver answers "how many points will I score?" The game asks "will I finish first?" Those come apart, and they come apart further the more opponents you have.

A caution on method: the first version of this result came from a single 24,000-game run, looked significant at three standard errors, and did not replicate on a second seed. The field-size experiment above is what actually settled it.

Card counting is worth less than you would hope. In a single round off a fresh deck it is worth nothing at all: over 100,000 rounds, ev and evc scored 20.21 each, because at that point the discard pile is almost empty and the table tells you everything. Across a full game, where discards pile up, tracking them gains about 0.2 points a round and about a point of win rate.

The whole optimal policy fits on a beer mat. advice.py weights every state by how often it comes up and finds the best bust-risk cut-off for each hand size:

 numbers showing     hit while bust risk is under
               0                       always hit
               1                       always hit
               2                              22%
               3                              23%
               4                              24%
               5                              25%
               6                              34%

That rule is worth 21.02, within 5.5% of a solved 1.8M-state table. Hit while the next card has under about a one-in-four chance of duplicating you, and push to one-in-three when a single card would give you Flip 7. Everything the exact solution knows beyond that — which modifiers you hold, which specific numbers are showing, whether a Second Chance is out — is worth about one point a round.

The risks above are quoted against the real 94-card deck, which is what you can count at a table. The solver works on its 88-card model deck, so advice.py converts.

Assumptions and known gaps

  • The DP solves one player in isolation. It treats Freeze and Flip Three as neutral, and it leaves the duplicate card in the deck when a Second Chance saves you (at most 3 cards in ~80). sim.py implements both rules exactly, and test_flip7.py checks the simulated mean against the DP's 22.23.
  • No strategy plays the multiplayer game optimally. The targeting heuristics for Freeze and Flip Three are reasonable, not solved.
  • dp_hit.bin (4MB) is a generated cache of the solved policy, one byte per state. Delete it or run python3 dp.py --rebuild-cache to rebuild (~13s).

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages