Skip to main content

Provably Fair - Game Event

Updated this week

Instant Game Implementation

Overview

This document builds upon previously explained RNG (Random Number Generation) principles to show how individual game results are produced using random integers and floating-point numbers.


Game-by-Game Breakdown


☄️ Plinko

In Plinko, the player chooses the number of rows (between 8 and 16) and a risk profile. The number of rows determines the number of buckets: X rows produce X+1 buckets.

Each possible path the ball can take corresponds to a unique trajectory, and there are 2^X total trajectories.


The random number generator (RNG) selects an integer between 0 and 2^X – 1. This integer represents a trajectory. To find the bucket:

  1. Convert the integer to binary.

  2. Count the number of 1s in the binary representation.

  3. That count is the bucket index.

The risk profile does not affect which bucket is chosen—it only determines the payout for that bucket.
Example (8 rows):

  • Total trajectories = 2^8 = 256

  • RNG generates a number between 0 and 255

  • RNG = 0 → binary 00000000 → sum of 1s = 0 → bucket index = 0

  • RNG = 200 → binary 11001000 → sum of 1s = 3 → bucket index = 3

  • RNG = 255 → binary 11111111 → sum of 1s = 8 → bucket index = 8

Pseudocode:

generatePlinkoResult(rows, riskProfile)
{
// Generate a number between 0 and 2 ^ Rows
let bucketIndex = generateInteger(2 ^ Rows)

// Get the payout for the given bucket index.
let payout = getPayout(bucketIndex, riskProfile)

return payout
}


🎲 Dice

  • Goal: Produce a number between 0.00 and 100.00 with two decimal places

  • Approach:

    • Generate a random integer between 0 (inclusive) and 10001 (exclusive)

    • Divide the result by 100

Pseudocode:

generateDiceResult() {
let randomInteger = generateInteger(10001)
let result = randomInteger / 100
return result
}


💣 Mines

  • Goal: Reveal gems while avoiding mines

  • Approach:

    • Use RNG to randomly assign numberOfMines positions on a board

    • The rest of the tiles are considered "gems"

Pseudocode:

generateMinesBoard(edgeSize, numberOfMines) {
let totalTiles = edgeSize * edgeSize
let minesPositions = []

while minesPositions.Count < numberOfMines:
let currentPosition = generateInteger(totalTiles)
if currentPosition not in minesPositions:
minesPositions.add(currentPosition)

let board = []
for index in 0 to totalTiles - 1:
if index in minesPositions:
board.add("mine")
else:
board.add("gem")

return board
}


📈 Limbo

  • Goal: Generate a multiplier > 1 (user wins if the rolled multiplier exceeds their guess)

  • Approach:

    • Generate a random float

    • Apply a hyperbolic curve to determine payout

    • Truncate to two decimal places

Formula Explanation:

  • houseEdge = 2.0 - rtp (e.g., if RTP is 0.99, house edge is 1.01)

  • multiplier = 1.0 / ((1.0 - randomFloat) * houseEdge)

Pseudocode:

generateLimboMultiplier(rtp) {
let multiplierDecimalPlaces = 2
let randomFloat = generateDouble()
let houseEdge = 2.0 - rtp
let multiplier = 1.0 / ((1.0 - randomFloat) * houseEdge)
let roundedMultiplier = truncate(multiplier, multiplierDecimalPlaces)
return roundedMultiplier
}


🎱 Keno

  • Goal: Randomly draw a set of unique numbers from a board (usually 1–40)

  • Approach:

    • Randomly select numbers, ensuring they:

      • Are not zero

      • Are not duplicates

Pseudocode:

generateKenoDraw(boardSize, drawCount) {
let numbersDrawn = []

while numbersDrawn.Count < drawCount:
let currentDraw = generateInteger(boardSize + 1)
if currentDraw == 0 or currentDraw in numbersDrawn:
continue
numbersDrawn.add(currentDraw)

return numbersDrawn
}


🃏 Blackjack

Blackjack is a card game, in which the RNG is used to draw a set of random cards. For a single seat game, four cards are initially drawn in the following order: Player, Dealer, Player, Dealer. Other cards can be drawn according to the subsequent player's actions.

At the beginning of every Blackjack round the nonce of the Provably Fair Seed is incremented. For each card dealt (initial or as a result of a player action - split, hit, double) a random number is generated between 0 and 51 and the cursor is increased. The number generated indicates the index of a card in an ordered deck (from Ace to King, suit order is: Hearts, Diamonds, Clubs, Spades). Dealer cards are drawn the same way after user actions had concluded. For reference, 0 is Ace of Hearts, 51 is King of Spades.Pseudo code:

dealCard() 
{
// Generate a random number from 0 .. 51
// Every time generateInteger is called, the cursor is incremented. let cardIndex = generateInteger(52)
// This gets the card object from the index of the card.   
return Card.FromIndex(cardIndex); }

Did this answer your question?