Cum funcționează Provably Fair în Plinko

Iată cum se joacă Plinko pe Cloudbet și cum poți verifica dacă traiectoria fiecărei bile este provably fair.

Cum se joacă Plinko

Plinko este un joc de noroc în care lași o bilă să cadă printr-o piramidă de știfturi și o urmărești cum ricoșează spre o plată. Înainte de a arunca bila, îți stabilești suma pariului, câte rânduri are piramida și un nivel de risc. Cu cât sunt mai multe rânduri în joc și riscul este mai mare, cu atât multiplicatorii posibili sunt mai mari — dar mai greu de atins. Odată ce arunci bila, aceasta ricoșează stânga sau dreapta la fiecare rând de știfturi, până când aterizează într-una dintre casetele de la bază, fiecare cu propriul multiplicator. Multe jocuri Plinko îți permit să arunci mai multe bile deodată, pentru un joc mai rapid.

Cloudbet Originals Plinko

Plinko-ul propriu al Cloudbet Originals îți permite să alegi 8, 10, 12 sau 16 rânduri, patru niveluri de risc (Low, Medium, High, Extreme) și 1, 5, 10, 20, 50 sau 100 de bile per aruncare. Are un RTP de 99%. O funcție opțională BOOST (o suprataxă de 20% pe pariul tău) adaugă multiplicatori speciali de bilă de 2x, 5x și 10x, ducând multiplicatorul maxim la 100.000x — plafonat la o plată totală de 1.000.000 $.

Pentru o introducere generală în provably fair — semințe server, semințe client, nonce-uri, hash și cum să verifici un rezultat — vezi sistemul de corectitudine demonstrabilă al Cloudbet. Mai jos vezi cum se aplică acesta specific la Plinko.

Cum devine traiectoria unei bile o casetă

Traiectoria fiecărei bile prin piramidă este o serie de ricoșeuri pe știfturi, iar fiecare ricoșeu este fie spre stânga, fie spre dreapta.

Diagramă care arată cum fiecare ricoșeu din jocul cu corectitudine demonstrabilă Plinko de la Cloudbet este codificat ca o alegere spre stânga sau spre dreapta.

Această alegere poate fi codificată ca „0” (spre stânga) sau „1” (spre dreapta). O traiectorie precum „stânga, stânga, dreapta” devine codul „001”, iar urmând-o, bila aterizează în Caseta #2.

Exemplu care arată traiectoria unei bile Plinko codificată ca o secvență de 0 și 1 în sistemul cu corectitudine demonstrabilă al Cloudbet, aterizând în Compartimentul nr. 2.

Iată tiparul cheie: o traiectorie aterizează în caseta care corespunde numărului său de ricoșeuri spre dreapta, plus unu. Așadar „100”, „010” și „001” — toate cu exact un singur „1” — aterizează în Caseta #2 (1 + 1).

Diagramă care arată mai multe traiectorii diferite ale bilelor Plinko, cu corectitudine demonstrabilă, care ajung matematic în același compartiment.

Asta înseamnă că o traiectorie aleatorie poate fi generată și codificată într-un singur pas: se ia un număr aleatoriu de 32 de biți, se citesc primii N biți (unde N este numărul de rânduri) și se numără câți dintre acei biți sunt „1”. Se adaugă unu, iar acesta este numărul casetei în care aterizează bila. Caseta este calculată și blocată pe server înainte de începerea rundei, ascunsă până la finalul rundei și dezvăluită apoi.

Verifică corectitudinea demonstrabilă a propriilor tale jocuri Plinko

Codul de mai jos este fidel implementării Plinko de pe Cloudbet. Introdu Server Seed-ul, Client Seed-ul, Nonce-ul, numărul de bile și numărul de rânduri, instalează singura dependență și rulează-l.

npm install js-sha3

După instalarea dependenței, introdu propriile date în blocul de cod de mai jos.

// 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);
})();

Notă: pentru a dezvălui Server Seed-ul unui joc pe Cloudbet, trebuie mai întâi să rotești către un nou Server Seed.

Mai multe ghiduri Provably Fair pentru jocuri:

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