From a hand-tuned heuristic to a neural network that thinks before it plays — and above all the measurement that says which one wins, and by how much. Every number is a paired gap: at equal game index, the agents get the same dice on the same grid. Play against them →
| agent | idea | vs v3-multi | vs deni-0.8 | time / move | in the game |
|---|---|---|---|---|---|
| search | network + simulating what follows each move | 84.0%* | 74.8% | ~0.5 s | not yet |
| network + denial | network, minus what the dice left behind give the opponent | 73.4% | 55.4% | a few ms | not yet |
| network | value network, plays for the margin | 63.7% | 49.3% | 1.6 ms | not yet |
| deni-0.8 | v3 heuristic + dice denial | 63.6% | — | 1.2 ms | not yet |
| v3-multi | v3 heuristic tuned at a 4-player table | — | 36.4% | 0.18 ms | yes |
* Overstated: the search simulates its opponent as v3-multi, so it knew exactly how that opponent would answer (see below).
The game currently plays v3-multi, weakened more or less depending on the difficulty level. The first three agents are measured but not wired in yet: the search takes half a second per move and will have to run off the main thread so the interface does not freeze.
Single-player does not punish stalling, since the agent alone decides when the game ends. So it had learnt to hoard its 8 exclamation points — +8 points guaranteed at the count — and to pass 12 times a game. At a real table, the others finish the game for it.
Three things only exist in the multiplayer simulator: dice denial (the active player sets their pair aside, the passive players only get the remaining 4), an ending decided by someone else, and the first / others bonuses that reward speed. Everything below is measured there.
Trained on the outcome of simulated games, it predicted the score well and played badly: it had never seen two moves from the same position, and learnt the price of an exclamation point by comparing different games.
Each candidate is played out 8 times to the end with the same dice, by v3-multi, and the network learns the gaps between moves. Better, but still beaten — and the diagnosis below shows why.
Same simulations, but the network keeps its seat until the end: the data says what a move is worth to it. The first network ahead of v3-multi at a 4-player table — and yet 45% head to head.
The network has two outputs: its score, and its margin over the best opponent. Same weights, a different output played. Aiming for points makes a slow player who gets cut off; aiming for the margin makes it race: it ends 62% of games instead of 31%.
All the data came from 4-player tables, and the number of opponents is a network input: head to head, it was extrapolating. New data at 2, 3 and 4 players: it beats v3-multi at every table size (43.0% per seat at 3, 33.5% at 4).
| same positions, same moves | rest played by | network move − v3 move |
|---|---|---|
| the network's games | v3 | +0.10 [−0.10, +0.30] |
| the network's games | the network | −0.55 [−0.81, −0.30] |
The diagnosis of step 2, and the most useful lesson of the project. Its moves were as good as v3's if v3 played the rest — exactly what its training data measured, since every simulation handed control back to v3. Played by itself, they were worth less. It was valuing positions for a player better than itself. Two move-by-move checks under v3 had come out null before this one showed it.
And the caveat of step 5: deni-0.8, a heuristic that also looks at the opponent, beats v3-multi almost as much (63.6%). Most of the gain came from the objective — playing for the margin — more than from the network itself.
| heuristic, 4 players | wins | paired gap |
|---|---|---|
| weight 0 | 19.7% | — |
| weight 0.6 | 23.8% | +1.12 [+0.67, +1.56] |
| weight 0.8 | 26.9% | +1.69 [+1.24, +2.13] |
| weight 1.1 | 29.6% | +1.70 [+1.23, +2.16] |
| weight 1.6 | 27.1% | +1.27 [+0.81, +1.73] |
| network, head to head | vs v3-multi | paired gap |
|---|---|---|
| weight 0 | 63.7% | +3.24 [+2.78, +3.70] |
| weight 0.5 | 71.5% | +5.53 [+5.08, +5.99] |
| weight 1 | 73.4% | +6.00 [+5.53, +6.46] |
| weight 2 | 66.6% | +4.30 [+3.82, +4.78] |
The optimum is interior in both cases: denying too much hurts too. For the network, what the remaining dice give the opponent is valued by the same network from their seat, so in the same unit — and with 2 players, a weight of 1 is exactly the logic of the margin: what they gain, I lose. The gain shrinks with more players (46.1% per seat at 3 players, 34.5% at 4, against 43.0 and 33.5 without denial).
Useless once search is added: over the same 400 games, the gap is −0.98 point [−2.29, +0.33]. The search already simulates what the opponent does with the dice left; adding the denial price counts it twice.
| opponent | table | search wins | paired gap | games |
|---|---|---|---|---|
| deni-0.8 | 2 players | 74.8% | +7.18 [+6.11, +8.25] | 400 |
| deni-0.8 | 3 players | 53.2% / seat | +6.48 [+5.68, +7.27] | 402 |
| deni-0.8 | 4 players, 2 of each | 40.8% / seat | +5.73 [+5.09, +6.37] | 402 |
| network + denial | 2 players | 61.8% | +2.51 [+1.46, +3.56] | 400 |
| v3-multi | 2 players | 84.0% | +10.96 [+9.87, +12.05] | 400 |
The 84% is overstated. In its simulations, the search assumes the opponent plays like v3-multi — which was precisely the opponent of that duel: it knew exactly how it would answer. The other rows are against opponents it does not model, and those are the ones to remember.
At 3 and 4 players, parity would be 33% and 25% per seat: the search reaches 53% and 41%, so the network no longer extrapolates with table size.
Measured time: 0.55 s per move on average head to head, 1.0 s at worst; 0.7 s and 1.4 s at 4 players. A wider search (6 moves, 32 simulations, 6 turns) reached 4.9 s: too slow.
engine/, as plain data, with no Vue or Pinia. The interface, the agents and the training share the same implementation: no agent is tuned on rules other than the ones we play.