An exact, computed solution to the single-turn push-your-luck decision and to the full two-player race, each verified against independent Monte Carlo simulation. Generated locally: all numbers below come from farkle_kcd.py, farkle_dp.py, farkle_sim.py, farkle_race.py, race_dp.py, race_compare.py and farkle_report_data.py in this folder.
The rest of this report is the derivation, the exact numbers, and the validation. If you just want the answer: play with the flowchart below, which captures essentially all of the decision quality with none of the exact-threshold bookkeeping.
This collapses the exact per-state thresholds derived later in this report into rule-of-thumb numbers. It intentionally blurs small differences between specific match targets, checked against both commonly-cited defaults for a standard KCD1 match (sources disagree: 2,000 and 4,000 points both appear as "the" default, and real games vary further by opponent and wager; see the note below the chart). The qualitative shape of the decision is the same at either target; only the precise cutoff numbers shift a little.
| Dice left | Rule of thumb |
|---|---|
| 5 or 6 | Keep rolling, essentially always |
| 4 | Keep rolling unless your turn total is already past ~1,000 |
| 3 | Keep rolling unless your turn total is already past ~400 |
| 2 | Bank: unless your total is right at its minimum possible (~200, i.e. four lone 5s and nothing else) |
| 1 | Bank: unless your total is right at its minimum possible (~250, i.e. five lone 5s and nothing else) |
On the realistic target: independent sources disagree on KCD1's default match length:
gamepressure.com states a 2,000-point default, another wiki says "usually 4,000," and several
sources agree the actual target scales with the opponent and the size of the wager. This report's
fully-detailed exact solve below targets G=4,000; race_dp.py takes the target
G as a plain parameter, so re-solving at G=2,000 (or any other target) is a
self-check anyone can run directly rather than a result this report asserts a specific number
for; the flowchart above and the cheat sheet later in this report are intended for either
commonly-cited target, and for stakes in between.
Partly: in two distinguishable senses.
Framed using the taxonomy from L.V. Allis's 1994 PhD thesis Searching for Solutions in Games and Artificial Intelligence (Rijksuniversiteit Limburg, Maastricht), which defines ultra-weakly, weakly, and strongly solved games, this project meets the strongly-solved bar for the ruleset and target (G=4,000) modeled here: every reachable state's exact optimal value is computed, not just the outcome from a fixed starting position. Two caveats apply: that taxonomy was written for deterministic, perfect-information games, so applying it to a dice game borrows the framing rather than claiming a literal fit, and the result is two-player only. 3+ player dynamics are a different, unsolved problem not covered by this work.
Update: the full two-player race has now also been solved exactly: see
§ The full race, solved exactly. It needed a state of
(your score, opponent score) and backward induction over that larger (but still
finite) grid, which correctly produces risk-seeking / risk-averse adjustments near the finish line
that the simpler turn-level solve can't see. Both the turn-level and full-race solutions are
reported below, each checked against independent large-sample Monte Carlo simulation, and the two
are compared head-to-head so you can see exactly how much the harder solve actually buys you.
| Single 1 / single 5 | 100 / 50 |
| Three of a kind (1s / 2s / 3s / 4s / 5s / 6s) | 1000 / 200 / 300 / 400 / 500 / 600 |
| Each additional die beyond 3-of-a-kind | doubles the value |
| Straight 1–5 / 2–6 / full 1–6 | 500 / 750 / 1500 |
| Bust | no scoring die/combo at all → turn's points lost |
| Hot dice | bank all currently-rolled dice → re-roll all 6 |
Devil's-head wildcard dice (special inventory items) are out of scope: this models the default 6 regular dice.
Two rules matter more than they first appear, and both are modeled exactly:
{1,2,3,4,5,5}
lets you bank the 1–5 straight (500) and the spare 5 (+50): the model checks for a
straight pattern inside the roll, not just an exact match of all dice.
The DP and its Monte Carlo cross-checks elsewhere in this report both call the same scoring function
(enumerate_actions in farkle_kcd.py), so agreement between them confirms
the solver's logic, not that the scoring rules themselves were transcribed correctly from the game.
Here's that layer checked by hand against a few specific rolls:
| Roll | Best score available | By hand |
|---|---|---|
| {1,2,3,4,5,5} | straight 1–5 + spare 5 | 500 + 50 = 550 |
| {2,2,2,2} | four 2s (double the three-of-a-kind value) | 200 × 2 = 400 |
| {5,5,5,5,5,5} | six 5s (triple the value three times over) | 500 × 2³ = 4,000 |
| {1,1,1,2,3,4} | three 1s only (2/3/4 don't score alone or as a pair) | 1,000 |
| {2,3,4,6} | nothing scores at all | bust |
Exact combinatorics (not simulated) over all 6k equally likely outcomes for rolling k dice:
Risk climbs steadily as dice run out, and the increments get bigger in absolute terms toward the end: 6→5 only costs 4.6 points, but each subsequent step costs more (+8.0, +12.0, +16.7, +22.2), so the last die you have is the single most dangerous one to risk, not any particular "jump" partway through.
V(k, T) = expected total points this turn, playing optimally, with k dice
left to roll and T already banked this turn. The rule is simply:
keep rolling while T is at or below the threshold for your current dice count;
bank once you're past it. Busting from any state forfeits T entirely: that
asymmetry (lose the whole pile vs. gain a known expected amount) is what produces a finite,
computable cutoff.
| Dice remaining | Keep rolling while turn total ≤ | E[turn value] from 0 |
|---|---|---|
| 6 (opening roll / hot dice) | 12,900 | 564.4 |
| 5 | 3,350 | 359.7 |
| 4 | 1,000 | 235.1 |
| 3 | 400 | 191.0 |
| 2 | 200 | 178.4 |
| 1 | 250 | 208.5 |
The k<6 values in the last column are the DP's boundary condition (starting with that many dice and T=0), a reference point for the solver, not a state you'd actually begin a turn in (a turn always starts at k=6). Don't read V(1,0)=208.5 > V(3,0)=191.0 as "1 die left is a better position than 3": it isn't; see the next callout for why these numbers aren't directly comparable.
The decisive factor isn't how many points your first roll scored: it's how many dice you'd have left after banking the best available combination. Grouping all first-roll outcomes (weighted by true probability) by that remaining-dice count:
| After best action, dice left | P(this happens) | Range of values banked | Recommendation |
|---|---|---|---|
| 0 (outright bust) | 3.09% | n/a | Turn over |
| 6: hot dice immediately | 6.25% | 400 – 8,000 | Keep rolling |
| 5 | 57.10% | 50 or 100 | Keep rolling |
| 4: never happens | 0% | n/a | n/a |
| 3 | 9.26% | 200 – 1,000 | Depends (≤400 go, >400 stop) |
| 2 | 10.93% | 400 – 2,000 | Bank now |
| 1 | 13.37% | 400 – 4,000 | Bank now |
A genuinely surprising, DP-verified result: it is sometimes correct to ignore an available three-of-a-kind and bank only a lone 1 or 5 instead: purely to keep more dice live.
| Roll | Option A: just the stray single | Option B: just the triple | Option C: triple + the stray single too | Best |
|---|---|---|---|---|
| 2,2,2,1,3,4 | bank the 1 (100) → 5 left, V=428 | bank triple 2s (200) → 3 left, V=258 | bank both (300) → 2 left, V=300 | A: decline the triple |
| 3,3,3,5,2,4 | bank the 5 (50) → 5 left, V=392 | bank triple 3s (300) → 3 left, V=330 | bank both (350) → 2 left, V=350 | A: decline the triple |
Option C (take the triple and the stray single: the obvious "greedy" play, and the strongest real competitor) still loses to declining the triple entirely: 428 > 300 and 392 > 350. Banking the smaller amount but keeping 5 dice beats grabbing the bigger score and dropping to only 2–3 dice: the extra survivability of a near-full hand is worth more than the point difference. This only applies to the cheap triples (2s = 200, 3s = 300); triples of 4s/5s/6s and especially 1s are valuable enough that taking them is correct. The lesson generalizes: whenever a combination would strand you below ~4 dice for a modest point gain, check whether banking less and keeping more dice live is better: it often is.
| Strategy | Mean pts / turn | Bust rate |
|---|---|---|
| DP-optimal (exact) | 566.2 | 19.0% |
| Bank everything scoring, stop at DP thresholds | 506.8 | 17.3% |
| Stop once <3 dice remain | 488.5 | 20.0% |
| Stop immediately after any score | 398.4 | 3.2% |
| Stop once <2 dice remain | 396.7 | 44.4% |
| Never stop (push until forced) | 0.0 | 100% |
Playing it maximally safe ("stop after any score") has a low 3.2% bust rate but leaves ~30% of the expected value on the table. "Never stop" guarantees eventual ruin: with bust probability bounded away from zero every roll, the probability of surviving forever is zero.
This is a separate, larger-sample simulation run from the 150,000-turn table above (different seed): it's why 564 / 19.3% here and 566.2 / 19.0% above don't match to the decimal. Turn score has a standard deviation of about 508, so the standard error on a 300,000-turn mean is about ±0.9 (±1.3 at 150,000 turns); both observed means (564.36 and 566.15) are within 1.3 standard errors of the DP's exact value, 564.44.
20,000 full races per matchup, target scores shown; first-mover advantage removed by alternating who rolls first.
| DP-optimal vs. | Race to 1,000 | Race to 4,000 | Race to 10,000 |
|---|---|---|---|
| Bank-max heuristic | 55.4% | 59.5% | 65.2% |
| Stop after first score | 65.8% | 78.5% | 89.1% |
| Stop once <3 dice remain | 57.7% | 62.8% | 68.9% |
Cells show the DP-optimal policy's win rate. The edge compounds over a longer race (more turns = the higher-EV strategy's advantage dominates variance more), which is exactly what you'd expect from a policy that maximizes expected value per turn. This table uses the turn-level policy on both sides with no race-awareness at all: the next section solves the race itself exactly and asks how much further that gets you.
The turn-level DP above maximizes expected points per turn. That is not quite the same
objective as maximizing probability of winning a race to a target: the two diverge near
the finish line, where guaranteeing a win is worth more than squeezing out extra expected points
you'll never get to spend. To fix that, the full race was solved as its own, larger finite Markov
game: state = (your banked score, opponent's banked score), both in steps of 50 up to
target G = 4000. Define
F(x, y) = P(the player about to roll wins the race | own score = x, opponent's score = y)
F is a fixed point: stopping with a new total z = x+T either wins outright
(z ≥ G) or hands the turn to the opponent, who then faces F(y, z), so
stopping is worth 1 − F(y, z) to the active player. Busting hands the turn over with
score unchanged: worth 1 − F(y, x). This couples every (x, y) to every
other (y, x′) pair, so it was solved by Gauss-Seidel value iteration over the whole
80×80 score grid at once (scores 0–3,950 in steps of 50; the 81st value per axis is the absorbing
"already won" boundary, handled separately, not a grid cell), with the within-turn decision vectorized across every
opponent score simultaneously. Unlike the turn-level DP, this needed no arbitrary truncation ceiling:
the natural absorbing boundary is the literal target score G, so the solution is
exact, not approximate, up to the 50-point grid (which is exact anyway, since every achievable score
is a multiple of 50). It converged to a tolerance of 10⁻⁷ in 22 sweeps, about 2.7 minutes on this
machine.
Going first is worth a real, quantifiable edge (about 5.7 percentage points above a coin flip) even between two perfectly-played sides, purely from the extra roll.
| Your score / opponent's score | Exact F(x,y) | Monte Carlo (N=50,000) | Difference |
|---|---|---|---|
| 0 / 0 (game start) | 0.55712 | 0.55722 | 0.00010 |
| 2,000 / 0 (big lead) | 0.90713 | 0.90674 | 0.00039 |
| 0 / 2,000 (big deficit) | 0.16057 | 0.15998 | 0.00059 |
| 3,500 / 0 (almost home) | 0.99508 | 0.99564 | 0.00056 |
| 1,000 / 1,500 (500 behind) | 0.44834 | 0.44998 | 0.00164 |
| 3,000 / 3,500 (500 behind, late) | 0.44828 | 0.44748 | 0.00080 |
This table was re-run at N=50,000 (up from an initial N=10,000) after an independent audit found a
too-tight numerical tolerance in the simulator that could occasionally make it play a slightly
different policy than the one actually solved for; see §Caveats. The exact F column is
completely unchanged by that fix (it only affected the simulator); the Monte Carlo column moved by
less than its own margin of error.
Every difference is well inside its own row's 95% confidence interval (computed per-row from that
row's empirical proportion: these range from about ±0.0006 for the near-certain 0.995 row up to
±0.0044 for the near-50/50 rows at this larger N, not one blanket number). The exact dynamic program
and independent
simulation agree everywhere they were checked: the strongest form of verification available short
of a formal proof, though it's worth being precise about what it verifies: both the DP and
this Monte Carlo check share the same underlying rules engine (farkle_kcd.py), so this
confirms the fixed-point solver was implemented correctly, not that the scoring rules themselves are
modeled correctly (that's checked separately, see §Rules modeled's validation table).
The two 0.448-ish rows above (500-point deficit, at two different points in the game) land within 0.00006 of each other; that's a genuine coincidence of this specific grid, not a hidden symmetry: the same "500 behind" gap computed at (0,500) gives 0.4553 and at (2,500/3,000) gives 0.4176, so the win probability for a fixed deficit does move around depending on absolute score, it just happens to revisit roughly the same value at these two particular points.
Three policies, raced head-to-head 300,000 times each (seat-order balanced), large enough to resolve a sub-percentage-point effect with confidence:
| Matchup | Race-aware exact wins | Other wins |
|---|---|---|
| vs. (a) pure turn-EV-max, completely race-blind | 53.54% ± 0.18% | 46.46% |
| vs. (b) turn-EV-max + the "obvious" patch: stop the instant you'd reach the target | 52.80% ± 0.18% | 47.20% |
± values are 95% confidence intervals from N=300,000 races per matchup. (This table was re-run after an audit-found tolerance bug fix in the simulator. See §Caveats; the corrected numbers are very close to, and the conclusion is unchanged from, the first run.)
Each cell is the race-aware "keep rolling while turn total ≤ X" threshold for that many dice remaining, at that specific (your score, opponent's score). Compare to the fixed, score-blind thresholds from §Optimal thresholds: 6→12,900 · 5→3,350 · 4→1,000 · 3→400 · 2→200 · 1→250.
| Situation | k=1 | k=2 | k=3 | k=4 | k=5 | k=6 |
|---|---|---|---|---|---|---|
| Tied, early (0 / 0) | 250 | 200 | 400 | 950 | 2,100 | 3,100 |
| Far behind (0 / 3,000) | 800 | 600 | 3,950 | 3,950 | 3,950 | 3,950 |
| Far ahead (3,000 / 0) | 150 | 150 | 250 | 950 | 950 | 950 |
| Both near finish, tied (3,500 / 3,500) | 450 | 450 | 450 | 450 | 450 | 450 |
| Behind, near finish (3,000 / 3,900) | 950 | 950 | 950 | 950 | 950 | 950 |
| Ahead, near finish (3,900 / 3,000) | 50 | 50 | 50 | 50 | 50 | 50 |
G − x − 50 (your remaining gap to the target, minus one grid step) is
the largest representable number before the grid saturates into "already won." A cell
showing that number doesn't mean "a generous cap": it means the policy never
voluntarily banks short of the target at all: keep rolling for literally any value up to
the point where you'd either win outright or bust trying. Four of the six rows below hit exactly
this ceiling at every k (far-behind's k=3–6, far-ahead's k=4–6, and both near-finish rows across the
board); check each against the arithmetic: 3,950 = 4000−0−50 is that player's own ceiling
(deficit case, x=0), 950 = 4000−3000−50 (lead case, x=3,000, and separately the near-finish case,
x=3,000), 450 = 4000−3,500−50, 50 = 4000−3,900−50.
With that reading in hand, four clear patterns fall out of the exact numbers:
G = 4,000
specifically (KCD's match length varies by opponent/wager). Re-solving for a different target is a
few minutes of recomputation (race_dp.py, runtime scales worse than linearly with
G: roughly 2 seconds for G=300, 20s for G=1,000, 52s for G=2,000, 162s for G=4,000).
Ask if a specific match target should be solved.
race_dp.py) rather than a fundamentally different method.farkle_dp.py and
race_dp.py directly, though no separate reimplementation script is checked into
this repo. The validation code
had one real bug: a numerical tolerance in the race simulator (1e-9) tighter than the
solver's own convergence tolerance (~8.5e-8), which could make the simulator occasionally
"continue" at a handful of states where the converged policy said "stop." Fixed (raised to
1e-6) and every affected number in this report was re-run and updated; the correction
moved results by less than their own margin of error and changed no conclusion.farkle_kcd.py, farkle_dp.py, farkle_sim.py,
farkle_race.py, farkle_report_data.py, race_dp.py,
race_compare.py) lives alongside this file and regenerates every number shown here.