DocsGames
Mines
Where the mines go on a 25-tile board, and the harder problem of keeping that answer hidden until the round is over.
Most games can hand the player their record the instant the bet is placed. Mines can't. The result is the board, and a player holding the board isn't playing Mines any more.
So this page has two halves. The arithmetic is short. The concealment is where a server gets it wrong.
Mine Positions
import { play } from '@galabet/fair';
const seeds = {
serverSeed: '5c1f7d3e8a2b4c6d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d',
clientSeed: 'galabet',
nonce: 42,
};
const { result, cursor, floats } = await play({ game: 'mines', params: { mines: 3 }, ...seeds });
console.log(result, cursor, floats.length);
const grid = Array.from({ length: 25 }, (_, tile) => (result.includes(tile) ? '*' : '.'));
for (let row = 0; row < 5; row++) console.log(grid.slice(row * 5, row * 5 + 5).join(' '));
[ 9, 17, 22 ] 2 24
. . . . .
. . . . *
. . . . .
. . * . .
. . * . .
Tiles are numbered 0 to 24. The library stops there. Drawing them five to a row, left to right, is this example's choice and the usual one, but nothing in GFS says tile 9 is in the second row. If your client lays them out differently, a player comparing your board with the verifier's will think they've caught you cheating. Publish the layout.
The shuffle is Fisher-Yates over the 25 tiles with a fresh float for every swap, 24 swaps in all. Eight floats to a digest means three digests, so the record's cursor is 2. The first mines entries of the shuffled list are the mines, sorted before they're returned.
Effect of the mines Parameter
import { play } from '@galabet/fair';
const seeds = {
serverSeed: '5c1f7d3e8a2b4c6d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d',
clientSeed: 'galabet',
nonce: 42,
};
for (const mines of [1, 3, 5]) {
const { result } = await play({ game: 'mines', params: { mines }, ...seeds });
console.log(mines, result);
}
1 [ 22 ]
3 [ 9, 17, 22 ]
5 [ 3, 9, 12, 17, 22 ]
Each board contains the one before it. The shuffle depends only on the seeds and the nonce, and mines decides how much of it to read. That's harmless as long as a nonce is used once. Let a player see a finished 1-mine board and then start a 5-mine game on the same nonce, and they already know one tile to avoid.
mines runs from 1 to 24. Outside that the mapper throws mines must be 1 to 24. Left out, it defaults to 3.
Concealing the Board During Play
A round of Mines has a beginning, a middle that can last minutes, and an end. The seed-derived part happens entirely at the beginning. After that the server answers one question over and over, "is tile N a mine?", from a board it must not show.
Galabet's demo API went through a hardening pass on exactly this, and what it fixed is a fair list of what to worry about.
The record is created at the start and stored, but it isn't published to the player's history until the round ends. While the round is live, the API returns the record with result stripped out. An earlier version pushed the full record into history at bet time, which meant the history endpoint was a cheat sheet. The fix also redacts any such record left over from before the change.
Seed rotation is refused while a board is active. Rotation reveals the server seed, and the server seed plus the public client seed and nonce is the board. Changing the client seed is refused for the same reason, since in the demo that triggers a rotation.
Each session's actions run one at a time behind a short lock, so two "pick" requests can't both read the same state. And the cash-out credit is tied to a marker unique to that round, so a retry after a dropped connection can't pay twice.
None of that is cryptography. It's bookkeeping, and the fairness scheme is only as good as it.
After the Round
Hit a mine or cash out, and now the record can go to the player, board included. It still has no serverSeed. That comes at rotation like any other game, and only then can the board be checked against the commitment.
What the player can do immediately is confirm the board they're shown matches the tiles they were told were safe. What they can't do until rotation is confirm the board came from the seeds. Both matter, and the second one is the one the scheme exists for.
Payout is yours to define. The demo multiplies the stake by 0.99 divided by the probability of surviving that many picks, which for three mines and one safe pick is 0.99 ÷ (22/25), or 1.125.
Porting
The thing to match is the shuffle, shared with Keno and the card games: walk i from 24 down to 1, take the next float, swap position i with position floor(float × (i + 1)). One float per swap, in order, never reused. The vectors file has 336 Mines rounds at 1, 3 and 24 mines.
