DocsGames
Roulette
One float, one multiplication, a pocket from 0 to 36. The shortest mapper in the library.
pocket = floor(float × 37)
That's the mapper. European wheel, single zero, 37 pockets. With the public inputs (server seed 5c1f…1c2d, client seed galabet, nonce 42) the first float is 0.5611712262034416, the product is 20.76, and the ball lands on 20.
This page is short because there isn't much more to say. If the float itself is new to you, the Dice page takes it apart byte by byte, and Roulette uses the very same float.
import { play } from '@galabet/fair';
const round = await play({
game: 'roulette',
serverSeed: '5c1f7d3e8a2b4c6d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d',
clientSeed: 'galabet',
nonce: 42,
});
console.log(round.result, round.cursor, round.floats);
20 0 [ 0.5611712262034416 ]
No parameters, cursor always 0, params: {} in the record.
Colours, Bets and Payouts
Everything a croupier would call the game. The mapper returns a number. It doesn't know 20 is black, that it sits in the second dozen and the second column, or what a straight-up bet pays. Red and black aren't arithmetic, they're a printed layout, and your code has to carry the list:
const RED = new Set([1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36]);
const colour = (pocket) => (pocket === 0 ? 'green' : RED.has(pocket) ? 'red' : 'black');
for (const pocket of [0, 20, 32]) console.log(pocket, colour(pocket));
0 green
20 black
32 red
Zero belongs to no colour, no parity, no dozen and no column. It beats every outside bet, and that single pocket is the whole house edge of the classic table: 35 to 1 on a straight number returns 36/37, about 97.3%. Galabet's demo pays those classic odds and declares that return. It doesn't shave the multipliers further.
Distribution
Every pocket is backed by almost exactly the same number of floats.
const floats = 2 ** 32;
const first = (pocket) => Math.ceil((pocket * floats) / 37);
const counts = Array.from({ length: 37 }, (_, pocket) => first(pocket + 1) - first(pocket));
console.log(Math.min(...counts), Math.max(...counts), counts.reduce((a, b) => a + b) === floats);
116080197 116080198 true
Thirty-seven doesn't divide 2³², so some pockets get one more float than others, out of about 116 million each.
Double-Zero Wheels
roulette is fixed at 37 and won't do it. wheel with segments: 38 will, since it's the same formula with the 37 turned into a parameter. Which index you call 00 is then your table to publish. See Wheel.
Python Implementation
The key is the hex string as text. Don't decode it.
import hashlib
import hmac
seed = "5c1f7d3e8a2b4c6d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d"
digest = hmac.new(seed.encode(), b"galabet:42:0", hashlib.sha256).digest()
print(int.from_bytes(digest[:4], "big") * 37 // 2**32)
20
vectors/gfs-1.0.json has 112 Roulette rounds to run a port against.
