Limbo'da provably fair nasıl çalışır

Cloudbet'te Limbo'yu nasıl oynayacağınızı ve her çarpanın provably fair olduğunu nasıl kontrol edeceğinizi burada bulabilirsiniz.

Limbo nasıl oynanır

Limbo, hızlı ve basit bir çarpan oyunudur: her turdan önce, hedeflediğiniz kazancın büyüklüğünü belirten bir hedef çarpan belirlersiniz. Bahsinizi yerleştirin, ardından bir sonuç çarpanı üretilir. Hedefinize eşit veya üzerinde bir değere ulaşırsa, hedef çarpanınızı bahsinizle çarparak kazanırsınız. Hedefinizin altında kalırsa, turu kaybedersiniz.

Belirlediğiniz hedef çarpan ne kadar yüksek olursa, potansiyel kazancınız o kadar büyük olur — ama sonucun ona ulaşma olasılığı o kadar düşer. Her bahisten önce hedefinizi istediğiniz kadar düşük veya yüksek belirleyebilirsiniz.

Cloudbet Originals Limbo

Cloudbet'in kendi Originals Limbo'su %99 RTP, x1.000.000'luk bir maksimum çarpana sahiptir ve 0,01 $ ile 20.000 $ arasında bahisleri kabul eder.

Limbo'nun rastgele sayıları, diğer her Cloudbet Original'ı gibi aynı doğrulanabilir şekilde üretilir — Sunucu Tohumu, Müşteri Tohumu ve Nonce'un bir Tur İmzasına ve ardından SHAKE256 aracılığıyla bir rastgele sayı akışına nasıl birleştiğini görmek için Cloudbet'in provably fair sistemine bakın. Bu sayfa Limbo'ya özgü olanı ele alır: bu rastgele sayının, karşı yarıştığınız çarpana nasıl dönüştüğünü.

Çarpan nasıl hesaplanır

Limbo, SHAKE256 tarafından üretilen ve düzgün dağılmış rastgele 32 bitlik bir sayıyla başlar; yani 0 ile 2³²-1 arasındaki her değer eşit olasılıklıdır.

Ancak bu, ihtiyacımız olan şekil değildir. Bir çarpan, çok büyük değerlere göre çok daha sık küçük değerlere düşmelidir — 1,01x olasılığı 100.000x olasılığından çok daha yüksek olmalıdır. Bu yüzden rastgele sayı, adım adım bu dağılıma dönüştürülür:

  1. Reddetme örneklemesi kullanılır, ama hafifçe — yalnızca mümkün olan tek en büyük sayının çekilmesinden kaçınmak için, çünkü sayı bir sonraki adımda bir artırılacaktır.
  2. Sayı bir artırılır (böylece asla sıfır olmaz, bu da 4. adımdaki bölme için önemlidir).
  3. Olası maksimum değerine bölünerek 0 ile 1 arasında bir ondalık sayıya küçültülür.
  4. 0,99 (Limbo'nun RTP'si), bu ondalık sayıya bölünür — düzgün bir dağılımı, küçük çarpanların büyük çarpanlardan katlanarak daha yaygın olduğu bir dağılıma dönüştüren adım budur.
  5. Sonuç aşağı doğru iki ondalık basamağa yuvarlanır.
  6. Son olarak, Limbo'nun geçerli aralığına "kırpılır": 1'in altındaki her şey 1 olur (minimum bahis 1,01'dir, bu yüzden 1'in altındaki sonuçlar tamamen bir kayıptır) ve 1.000.000'un üzerindeki her şey 1.000.000 olur (Limbo'nun maksimum ödemesi).

Cloudbet'in kanıtlanabilir adil Limbo sisteminin, rastgele bir 32 bitlik sayıyı adım adım turun nihai çarpanına nasıl dönüştürdüğünü gösteren akış şeması.

Üretildikten sonra, çarpan sabitlenir ve gizlenir — bahsiniz yerleştirildikten sonra değiştirilemez. Ona ulaşılmadan önce nakde çevirip çevirmemeniz turu belirler.

Kendi Limbo oyunlarınızı doğrulayın

Aşağıdaki kod, Cloudbet'in Limbo uygulamasıyla birebir aynıdır. Kendi sonucunuzu yeniden oluşturmak için Sunucu Tohumunuzu, Müşteri Tohumunuzu ve Nonce'unuzu girin. Not: Cloudbet'te bir oyunun Sunucu Tohumunu açığa çıkarmak için başka bir Sunucu Tohumu kullanmaya başlamanız gerekir.

Bağımlılıklar:

npm install js-sha3

Kod:

// 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           = 0;                  // ✍️YOUR_INPUT✍️: Enter your Nonce 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 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); // 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: Draw from the random number sequence to calculate the game result
function getGameResult(rng) {
  let randomInt32 = rng.next().value;               // 'randomInt32' ranges from 0 and 4294967295
  while (randomInt32 == 0xFFFFFFFF) { randomInt32 = rng.next().value; } // This can basically be ignored

  const fraction = (randomInt32 + 1) / 0xFFFFFFFF;  // 'fraction' ranges from 0 to 1
  const inverse = 0.99 / fraction;                  // 'inverse' ranges from 0 to (basically) infinity
  let crashPoint = Math.floor(inverse * 100) / 100; // Cut off everything past the second decimal place
  // We force the crashpoint to range from 1 to 1,000,000
  if (crashPoint < 1.0) {
    crashPoint = 1.0;
  }
  if (crashPoint > 1000000) {
    crashPoint = 1000000;
  }

  return crashPoint;
}

// Example usage
(function main() {
  let nonce = 1;
  if (usingCustomData) { nonce = myNonce; }

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

  const roundSignature = createRoundSignature(serverSeed, clientSeed, nonce);
  const numbersToGenerate = 1 * 2; // We need 1 random number, but there is an improbable case we'll need two
  const rng = createRandomNumberSequence(numbersToGenerate, roundSignature);

  const value = getGameResult(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('⛓️‍💥 Break Point:', value);
})();

Diğer provably fair oyun anlatımları:

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