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:

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

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

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):

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:

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ă:

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
