So funktioniert Provably Fair bei Plinko

So spielst du Plinko auf Cloudbet, und so überprüfst du, dass der Weg jedes Balls provably fair ist.

So spielst du Plinko

Plinko ist ein Glücksspiel, bei dem du einen Ball eine Pyramide aus Stiften hinabfallen lässt und beobachtest, wie er sich seinen Weg zu einer Auszahlung bahnt. Vor dem Abwurf legst du deinen Einsatz, die Anzahl der Reihen der Pyramide und ein Risikoniveau fest. Je mehr Reihen im Spiel sind und je höher das Risiko, desto größer die möglichen Multiplikatoren — aber desto schwerer zu treffen. Sobald du den Ball fallen lässt, springt er bei jeder Stiftreihe nach links oder rechts, bis er in einem der Fächer am unteren Rand landet, jedes mit seinem eigenen Multiplikator. Viele Plinko-Spiele erlauben es dir, mehrere Bälle gleichzeitig fallen zu lassen, um schneller zu spielen.

Cloudbet Originals Plinko

Cloudbets eigenes Originals Plinko lässt dich zwischen 8, 10, 12 oder 16 Reihen wählen, bietet vier Risikostufen (Niedrig, Mittel, Hoch, Extrem) und 1, 5, 10, 20, 50 oder 100 Bälle pro Drop. Es hat einen RTP von 99 %. Eine optionale BOOST-Funktion (ein Aufschlag von 20 % auf deinen Einsatz) fügt spezielle 2x-, 5x- und 10x-Ballmultiplikatoren hinzu und erhöht den maximalen Multiplikator auf 100.000x — begrenzt auf eine Gesamtauszahlung von 1.000.000 $.

Eine allgemeine Einführung in Provably Fair — Server-Seeds, Client-Seeds, Nonces, Hashing und wie man ein Ergebnis verifiziert — findest du unter Cloudbets Provable-Fairness-System. Im Folgenden erfährst du, wie es speziell auf Plinko angewendet wird.

Wie der Weg eines Balls zu einem Fach wird

Der Weg jedes Balls die Pyramide hinab ist eine Reihe von Abprallern an Stiften, und jeder Aufprall geht entweder nach links oder nach rechts.

Diagramm, das zeigt, wie jeder Aufprall in Cloudbets nachweisbar fairem Plinko-Spiel als Wahl nach links oder rechts codiert wird.

Diese Entscheidung lässt sich als „0" (links) oder „1" (rechts) codieren. Ein Weg wie „links, links, rechts" wird zum Code „001", und ihm zu folgen lässt den Ball in Fach #2 landen.

Beispiel, das den Weg einer Plinko-Kugel zeigt, codiert als Folge von Nullen und Einsen im Rahmen von Cloudbets nachweisbar fairem System, wobei die Kugel in Fach Nr. 2 landet.

Hier ist das entscheidende Muster: Ein Weg landet in dem Fach, das seiner Anzahl an Rechtsabprallern plus eins entspricht. Also landen „100", „010" und „001" — alle mit genau einer „1" — in Fach #2 (1 + 1).

Diagramm, das mehrere verschiedene, nachweisbar faire Plinko-Kugelwege zeigt, die alle mathematisch im gleichen Fach landen.

Das bedeutet, dass ein zufälliger Weg in einem einzigen Schritt generiert und codiert werden kann: Nimm eine zufällige 32-Bit-Zahl, lies ihre ersten N Bits (wobei N die Anzahl der Reihen ist), und zähle, wie viele dieser Bits „1" sind. Addiere eins, und das ist das Fach, in dem der Ball landet. Das Fach wird auf dem Server berechnet und festgelegt, bevor die Runde beginnt, und bleibt verborgen, bis die Runde endet und dann offengelegt wird.

Überprüfe die Provable Fairness deiner eigenen Plinko-Runden

Der folgende Code entspricht exakt Cloudbets Plinko-Implementierung. Gib deinen Server-Seed, Client-Seed, Nonce, die Anzahl der Bälle und die Anzahl der Reihen ein, installiere die eine Abhängigkeit, und führe ihn aus.

npm install js-sha3

Gib nach der Installation der Abhängigkeit deine eigenen Daten in den untenstehenden Code-Block ein.

// If you are running this yourself, then you can input your own data here
// You can then compare:
// 1) Cloudbet's provided Commitment to the Commitment outputted here. This proves that the Server Seed was not altered during gameplay.
// 2) Cloudbet's provided game outcome to the game outcome outputted here. This proves that your game's outcome was determined solely by the pre-game seeds and was not altered afterwards.
let myServerSeed      = 'your_server_seed'; // ✍️YOUR_INPUT✍️: Enter your (unhashed) Server Seed here
let myClientSeed      = 'your_client_seed'; // ✍️YOUR_INPUT✍️: Enter your Client Seed here
let myNonce           = 1;                  // ✍️YOUR_INPUT✍️: Enter your Nonce here
let myNumberOfBalls   = 1;                  // ✍️YOUR_INPUT✍️: Enter your number of balls here
let myNumberOfRows    = 12;                 // ✍️YOUR_INPUT✍️: Enter your number of rows here
const usingCustomData = false;              // Change this to true if you are using your own data

// Load libraries
const crypto = require('crypto');
const { sha3_256, shake256 } = require('js-sha3');

// Step 1: Generate a Server Seed and Commitment
// And generate a Client Seed - either by player input or by the player's browser
function generateServerSeed() {
  let seed = crypto.randomBytes(32).toString('hex');
  if (usingCustomData) { seed = myServerSeed; }
  const commitment = sha3_256(seed);
  return { 'serverSeed': seed, 'commitment': commitment };
}
function getClientSeed() {
  let seed = crypto.randomBytes(32).toString('hex');
  if (usingCustomData) { seed = myClientSeed; }
  return seed;
}

// Step 2: Create a Round Signature with SHA3 using a Server Seed, Client Seed and Nonce 
function createRoundSignature(serverSeed, clientSeed, nonce) {
  return sha3_256(`${serverSeed}:${clientSeed}:${nonce}`);
}

// Step 3: Create a SHAKE256 stream generator from a Round Signature. 
// To simplify this example program, this function doesn't create a stream, but instead a sequence with a custom length.
function* createRandomNumberSequence(numbersToGenerate, roundSignature) {
  const numOfBytes = 4 * numbersToGenerate;           // 4 bytes (32 bits) per random number we generate
  const byteStream = shake256.create(8 * numOfBytes); // shake takes bits as input
  byteStream.update(roundSignature);                  // Use the Round Signature to seed the generator
  const buf = Buffer.from(byteStream.digest());       // The Buffer class lets us package every 4 bytes into one 32-bit integer
  for (let i = 0; i < numbersToGenerate; i++) {
    yield buf.readUInt32BE(i * 4);                    // Read buf in 4-byte steps
  }
  throw new Error("No more numbers in the random number sequence! Fix: make 'numbersToGenerate' larger.");
}

// Step 4: Sample bits to determine ball paths
function pickBuckets(numOfRows, numOfBalls, rng) {
  let bucketIndices = [];
  for (let i = 0; i < numOfBalls; i++) {
    const rawUint32 = rng.next().value;
    let pathArray = rawUint32.toString(2).padStart(32, '0').split("");  // Convert the number into an array of bits
    pathArray.splice(numOfRows);                                        // Select the the first bits for the number of rows
    bucketIndices.push(getBucketIndexFromPath(pathArray));
  }
  return bucketIndices;
}

// Calculates which bucket the ball would land in an array of 1's and 0's where 0 = leftwards, 1 = rightwards
// In principle it counts the amount of times the ball bounces rightwards
function getBucketIndexFromPath(pathArray) {
  let rightCounter = 0;
  for(let i = 0; i < pathArray.length; ++i) {
    if (pathArray[i] === '1') {
      rightCounter += 1;
    } else {
      rightCounter += 0;
    }
  }
  return rightCounter + 1; // Add one so that the left-most bucket is bucket number one
}

// Example usage
(function main() {
  let numOfRows = 12;
  let numOfBalls = 1;
  let nonce = 1;
  if (usingCustomData) { numOfRows = myNumberOfRows; numOfBalls = myNumberOfBalls; nonce = myNonce; }

  const { serverSeed, commitment } = generateServerSeed();
  const clientSeed = getClientSeed();

  const roundSignature = createRoundSignature(serverSeed, clientSeed, nonce);
  const numbersToGenerate = numOfBalls; // Only need to generate one number per ball
  const rng = createRandomNumberSequence(numbersToGenerate, roundSignature); 

  const bucketIndices = pickBuckets(numOfRows, numOfBalls, rng);

  console.log('📝 Commitment (shown before the game):', commitment);
  console.log('🔒 Server Seed (revealed after the game):', serverSeed);
  console.log('🎲 Client Seed:', clientSeed);
  console.log('🔢 Nonce:', nonce);
  console.log('🔁 Round Signature (can be verified after the game):', roundSignature);
  console.log('📋 Number of rows:', numOfRows);
  console.log('🏁 Buckets landed in (Bucket #1 is the leftern-most bucket):', bucketIndices);
})();

Hinweis: Um den Server-Seed einer Runde auf Cloudbet offenzulegen, musst du zunächst zu einem neuen Server-Seed rotieren.

Weitere Provably-Fair-Spielerklärungen:

  1. Provably Fair Mines
  2. Provably Fair Pump
  3. Provably Fair Dice
  4. Provably Fair Dice: Golden Ticket
  5. Provably Fair Limbo
  6. Provably Fair Roulette
  7. Provably Fair Keno