Cum funcționează Provably Fair în Pump

Iată cum se joacă Pump pe Cloudbet și cum poți verifica dacă pompa defectă a fiecărei runde este provably fair.

Cum se joacă Pump

Pump este un joc de tipul „împinge-ți norocul”: pompezi ceva (un balon, în versiunea Cloudbet) care crește un multiplicator cu fiecare pompare. Încasează oricând pentru a-ți asigura câștigurile — dar dacă mergi prea departe, balonul se sparge și îți pierzi miza. Înainte de a începe, de obicei alegi un nivel de dificultate care echilibrează cât de departe poți merge în siguranță cu cât de repede crește multiplicatorul.

Odată ce plasezi pariul, apasă Pump pentru a umfla balonul pas cu pas. Fiecare pompare reușită îți crește câștigul potențial. Poți apăsa Încasează după orice pompare pentru a încasa multiplicatorul curent — sau poți continua să pompezi pentru unul mai mare. Dacă următoarea ta pompare se dovedește a fi cea defectă a rundei, balonul se sparge imediat, iar runda se încheie fără nicio plată.

Cloudbet Originals Pump

Pump-ul propriu al Cloudbet Originals are cinci niveluri de dificultate — Easy, Medium, Hard, Expert și Master — care controlează câte dintre cele 25 de pompări ale rundei sunt „defecte” (cele care sparg balonul). Are un RTP de 99%, un câștig maxim de 1.000.000 $ și acceptă pariuri de la 0,01 $. Modul Autobet îți permite să configurezi suma pariului, numărul de pompări per rundă, limitele de profit/pierdere și numărul de runde de jucat automat — jocul manual („Pump așteaptă INPUT-UL tău”) este mereu disponibil, de asemenea.

Pentru mecanica generală a provably fair — server seed, client seed, nonce, hash și modul în care este creat Round Signature — vezi ghidul Cloudbet despre provably fair. Mai jos vezi cum devine acea secvență de numere aleatorii rezultatul specific al unei runde de Pump.

Transformarea numerelor aleatorii într-un aspect al jocului

Cele 25 de pompări ale Pump sunt etichetate de la A la Y, pentru a le putea urmări:

Diagramă care arată cele 25 de pompe din jocul Pump, etichetate de la A la Y, folosite pentru a urmări selecția cu corectitudine demonstrabilă a pompei defecte de la Cloudbet.

Toate pompele încep nedefecte. Folosind primul număr din secvența aleatorie a jocului, alegem o pompă nedefectă după index și o facem defectă:

Exemplu practic al algoritmului cu corectitudine demonstrabilă al jocului Pump: prima pompă defectă este selectată aleatoriu dintre toate cele 25 de pompe funcționale.

Acea pompă este apoi eliminată din lista de pompe nedefecte, astfel încât următoarea selecție se face doar din cele rămase:

Diagramă care arată cum sistemul cu corectitudine demonstrabilă al jocului Pump de la Cloudbet elimină din listă o pompă defectă selectată, înainte de a extrage următoarea.

Acest lucru se repetă până când este atins numărul de pompe defecte al nivelului de dificultate al rundei (medium = 3, ca exemplu aici):

Exemplu practic care arată algoritmul cu corectitudine demonstrabilă al jocului Pump selectând o a doua pompă defectă dintre pompele funcționale rămase.

Odată ce toate pompele defecte ale rundei sunt alese, numerele folosite pentru a le selecta nu mai sunt necesare — rămâne doar care pompe sunt defecte:

Diagramă care arată configurația completă a pompelor defecte dintr-o rundă, înainte ca sistemul de calcul cu corectitudine demonstrabilă al Cloudbet să o simplifice la singura pompă relevantă.

Deoarece pompele sunt declanșate una câte una, în ordine (A, apoi B, apoi C…), doar prima pompă defectă la care ajunge jucătorul contează cu adevărat — orice de după ea nu este niciodată declanșat. Astfel, aspectul se simplifică la acea singură pompă relevantă:

Diagramă care arată configurația cu corectitudine demonstrabilă a pompelor defecte din Pump, simplificată la singura pompă defectă pe care jucătorul ar atinge-o efectiv.

Detalii tehnice

Numim numărul de pompe nedefecte P. Octeții aleatorii de la SHAKE256 sunt împărțiți în numere întregi fără semn de 4 octeți (0 până la 2³²−1). Pentru a alege corect care pompă este defectă, folosim rejection sampling în raport cu P, apoi luăm restul (+1) ca index al pompei nedefecte care va deveni defectă. Dacă mai sunt necesare pompe defecte, pompa selectată este eliminată din listă, P este redus cu 1, iar un număr nou este eșantionat — repetat până când este atins numărul de pompe defecte al rundei.

Aspectul final al pompelor defecte este generat și salvat pe server înainte de începerea rundei și nu poate fi schimbat ulterior fără a încălca Commitment-ul deja transmis jucătorului. Fiecare pompă apăsată de jucător este verificată în raport cu acest aspect angajat în prealabil.

Verifică singur

Am scris un mic program Node.js fidel implementării Pump de pe Cloudbet — introdu Server Seed-ul, Client Seed-ul, Nonce-ul și nivelul de dificultate pentru a reproduce rezultatul rundei tale. (Notă: pentru a dezvălui Server Seed-ul unei runde pe Cloudbet, trebuie să fi rotit deja către o nouă pereche de semințe.)

// 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 myDifficultyLevel = 'easy';             // ✍️YOUR_INPUT✍️: Enter your difficulty level here (easy, medium, hard, expert, or master)
const usingCustomData = false;              // Change this to true if you are using your own data

// These are the possible difficulty levels (and how many faulty pumps there are per difficulty level)
const faultyPumpsPerDiff = {
  'easy':       1,
  'medium':     3,
  'hard':       5,
  'expert':     9,
  'master':     12
};

// 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 of 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); // shaker256 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: Generate indices of the faulty pumps
function pickUniquePositions(numOfFaultyPumps, totalPumps, rng) {
  const available = Array.from({ length: totalPumps }, (_, i) => i);
  const faultyPumps = [];

  for (let i = 0; i < numOfFaultyPumps; ++i) {
    const index = sample(available.length, rng);

    faultyPumps.push(available[index]);
    available.splice(index, 1); // Remove chosen pump from list of non-faulty pumps
  }
  return faultyPumps;
}
// Rejection sampling for fair results
function sample(P, rng) {
  const maxAcceptable = Math.floor(0x100000000 / P) * P;

  // Rejection sampling
  let rand;
  do {
    rand = rng.next().value;
  } while (rand >= maxAcceptable);
  // Modulo operation
  const sampled_number = rand % P;

  return sampled_number;
}

// Example usage
(function main() {
  const totalPumps = 25;
  let difficultyLevel = 'easy';
  let nonce = 1;
  if (usingCustomData) { difficultyLevel = myDifficultyLevel; nonce = myNonce; }

  const numOfFaultyPumps = faultyPumpsPerDiff[difficultyLevel];

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

  const roundSignature = createRoundSignature(serverSeed, clientSeed, nonce);
  const numbersToGenerate = 12 * 2;                 // We have at most 12 faulty pumps, however due to rejection sampling we may need more numbers
  const rng = createRandomNumberSequence(numbersToGenerate, roundSignature);

  const faultyPumps = pickUniquePositions(numOfFaultyPumps, totalPumps, rng);
  let firstFaultyPump = Math.min(...faultyPumps);  // Select the smallest/first faulty pump
  firstFaultyPump += 1;                            // Increment the index so that it starts with 1, 2, 3, ... instead of 0, 1, 2

  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('🎯 Difficulty level:', difficultyLevel);
  console.log('💣 First faulty pump (zero-indexed, i.e., 1, 2, 3, ...):', firstFaultyPump);
})();

Instalează mai întâi singura dependență:

npm install js-sha3

Mai multe ghiduri Provably Fair pentru jocuri:

  1. Provably Fair la Mines
  2. Provably Fair la Plinko
  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