หลักการทำงานของความยุติธรรมที่พิสูจน์ได้ใน Limbo

นี่คือวิธีเล่น Limbo บน Cloudbet และวิธีตรวจสอบว่าตัวคูณทุกครั้งเป็นไปตามหลักความยุติธรรมที่พิสูจน์ได้

วิธีเล่น Limbo

Limbo เป็นเกมตัวคูณที่เร็วและเรียบง่าย: ก่อนแต่ละรอบ คุณตั้งตัวคูณเป้าหมาย ซึ่งเป็นเงินรางวัลที่คุณต้องการ วางเดิมพันของคุณ แล้วตัวคูณผลลัพธ์จะถูกสร้างขึ้น หากมันหยุดที่หรือสูงกว่าเป้าหมายของคุณ คุณจะชนะตามตัวคูณเป้าหมายคูณกับเงินเดิมพันของคุณ หากมันหยุดต่ำกว่าเป้าหมาย คุณจะแพ้ในรอบนั้น

ยิ่งคุณตั้งตัวคูณเป้าหมายสูงเท่าไร โอกาสชนะที่เป็นไปได้ก็ยิ่งมากขึ้น แต่โอกาสที่ผลลัพธ์จะไปถึงเป้าหมายนั้นก็ยิ่งน้อยลง คุณสามารถตั้งเป้าหมายต่ำหรือสูงเท่าที่ต้องการก่อนเดิมพันแต่ละครั้ง

Cloudbet Originals Limbo

เกม Limbo ของ Cloudbet Originals มี RTP 99% ตัวคูณสูงสุด x1,000,000 และรับเดิมพันตั้งแต่ $0.01 ถึง $20,000

ตัวเลขสุ่มของ Limbo ถูกสร้างขึ้นด้วยวิธีที่ตรวจสอบได้แบบเดียวกับ Cloudbet Original อื่นๆ ทุกเกม ดูวิธีที่ Server Seed, Client Seed และ Nonce รวมกันเป็น Round Signature แล้วกลายเป็นลำดับตัวเลขสุ่มผ่าน SHAKE256 ได้ที่ระบบความยุติธรรมที่พิสูจน์ได้ของ Cloudbet หน้านี้จะกล่าวถึงสิ่งที่เฉพาะเจาะจงกับ Limbo คือตัวเลขสุ่มนั้นกลายเป็นตัวคูณที่คุณกำลังแข่งกับมันได้อย่างไร

วิธีคำนวณตัวคูณ

Limbo เริ่มจากตัวเลขสุ่ม 32 บิต ที่สร้างโดย SHAKE256 กระจายอย่างสม่ำเสมอ หมายความว่าทุกค่าระหว่าง 0 ถึง 2³²-1 มีโอกาสเกิดขึ้นเท่ากัน

แต่นั่นไม่ใช่รูปแบบที่เราต้องการ ตัวคูณควรตกที่ค่าน้อยบ่อยกว่าค่ามหาศาลมาก โอกาสได้ 1.01 เท่าควรสูงกว่าโอกาสได้ 100,000 เท่ามาก ดังนั้นตัวเลขสุ่มจึงถูกปรับรูปแบบทีละขั้นตอนให้กลายเป็นการกระจายแบบนั้น:

  1. ใช้ Rejection Sampling แต่เพียงเล็กน้อย เพื่อหลีกเลี่ยงการสุ่มได้ตัวเลขที่มากที่สุดเพียงตัวเดียว เนื่องจากตัวเลขนี้กำลังจะถูกเพิ่มค่าอีกหนึ่ง
  2. ตัวเลขจะถูกเพิ่มค่าอีกหนึ่ง (เพื่อไม่ให้เป็นศูนย์เลย ซึ่งสำคัญต่อการหารในขั้นตอนที่ 4)
  3. ปรับสเกลลงเป็นทศนิยมระหว่าง 0 ถึง 1 โดยหารด้วยค่าสูงสุดที่เป็นไปได้
  4. นำ 0.99 (RTP ของ Limbo) มาหารด้วยทศนิยมนั้น นี่คือขั้นตอนที่เปลี่ยนการกระจายแบบสม่ำเสมอให้กลายเป็นแบบที่ตัวคูณน้อยเกิดขึ้นบ่อยกว่าตัวคูณสูงแบบทวีคูณ
  5. ผลลัพธ์จะถูกปัดเศษลงเป็นทศนิยมสองตำแหน่ง
  6. สุดท้าย จะถูก "ตัด" ให้อยู่ในช่วงที่ใช้ได้ของ Limbo: ค่าที่ต่ำกว่า 1 จะกลายเป็น 1 (เดิมพันขั้นต่ำคือ 1.01 ดังนั้นผลลัพธ์ที่ต่ำกว่า 1 ทั้งหมดจะถือเป็นการแพ้) และค่าที่สูงกว่า 1,000,000 จะกลายเป็น 1,000,000 (เงินรางวัลสูงสุดของ Limbo)

แผนผังลำดับแสดงวิธีที่ระบบ Limbo ที่ยุติธรรมพิสูจน์ได้ของ Cloudbet แปลงตัวเลขสุ่ม 32 บิตทีละขั้นตอนให้กลายเป็นตัวคูณสุดท้ายของรอบนั้น

เมื่อสร้างขึ้นแล้ว ตัวคูณจะถูกกำหนดไว้ตายตัวและซ่อนไว้ ไม่สามารถเปลี่ยนแปลงได้หลังจากคุณวางเดิมพันแล้ว การถอนเงิน (หรือไม่ถอน) ก่อนที่จะถึงตัวคูณนั้นคือสิ่งที่ตัดสินผลของรอบนั้น

ตรวจสอบเกม Limbo ของคุณเอง

โค้ดด้านล่างนี้ตรงกับการทำงานของ Limbo บน Cloudbet ใส่ Server Seed, Client Seed และ Nonce ของคุณเพื่อสร้างผลลัพธ์ของคุณเองขึ้นใหม่ อนึ่ง: หากต้องการเปิดเผย Server Seed ของเกมบน Cloudbet คุณต้องเริ่มใช้ Server Seed ตัวใหม่

ไลบรารีที่จำเป็น:

npm install js-sha3

โค้ด:

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

คำอธิบายเกมที่ยุติธรรมที่พิสูจน์ได้เพิ่มเติม:

  1. ความยุติธรรมที่พิสูจน์ได้ใน Mines
  2. ความยุติธรรมที่พิสูจน์ได้ใน Pump
  3. ความยุติธรรมที่พิสูจน์ได้ใน Plinko
  4. ความยุติธรรมที่พิสูจน์ได้ใน Dice
  5. ความยุติธรรมที่พิสูจน์ได้ใน Dice: Golden Ticket
  6. ความยุติธรรมที่พิสูจน์ได้ใน Roulette
  7. ความยุติธรรมที่พิสูจน์ได้ใน Keno