หลักการทำงานของความยุติธรรมที่พิสูจน์ได้ใน Plinko
นี่คือวิธีเล่น Plinko บน Cloudbet และวิธีตรวจสอบว่าเส้นทางของลูกบอลแต่ละลูกเป็นไปตามหลักความยุติธรรมที่พิสูจน์ได้
วิธีเล่น Plinko
Plinko เป็นเกมแห่งโชคที่คุณปล่อยลูกบอลลงมาตามพีระมิดของหมุด แล้วดูมันกระเด้งไปเรื่อยๆ จนได้เงินรางวัล ก่อนปล่อยลูกบอล คุณจะตั้งค่าจำนวนเงินเดิมพัน จำนวนแถวของพีระมิด และระดับความเสี่ยง ยิ่งมีแถวมากและความเสี่ยงสูง ตัวคูณที่เป็นไปได้ก็ยิ่งสูงขึ้น แต่ก็ยิ่งยากที่จะได้มาด้วย เมื่อคุณปล่อยลูกบอลแล้ว มันจะกระเด้งซ้ายหรือขวาออกจากหมุดแต่ละแถว จนกว่าจะตกลงในช่องใดช่องหนึ่งด้านล่าง แต่ละช่องมีตัวคูณของตัวเอง เกม Plinko หลายเกมให้คุณปล่อยลูกบอลได้หลายลูกพร้อมกันเพื่อความรวดเร็ว
Cloudbet Originals Plinko
เกม Plinko ของ Cloudbet Originals ให้คุณเลือกได้ 8, 10, 12 หรือ 16 แถว ระดับความเสี่ยงสี่ระดับ (Low, Medium, High, Extreme) และ 1, 5, 10, 20, 50 หรือ 100 ลูกบอลต่อการปล่อยหนึ่งครั้ง มี RTP 99% ฟีเจอร์ BOOST ที่เลือกใช้ได้ (ค่าธรรมเนียมเพิ่ม 20% จากเงินเดิมพันของคุณ) จะเพิ่มตัวคูณลูกบอลพิเศษ 2 เท่า 5 เท่า และ 10 เท่า ทำให้ตัวคูณสูงสุดพุ่งไปถึง 100,000 เท่า โดยจำกัดเงินรางวัลรวมสูงสุดไว้ที่ $1,000,000
สำหรับความรู้เบื้องต้นทั่วไปเกี่ยวกับความยุติธรรมที่พิสูจน์ได้ ทั้ง Server Seed, Client Seed, Nonce, การแฮช และวิธีตรวจสอบผลลัพธ์ ดูได้ที่ระบบความยุติธรรมที่พิสูจน์ได้ของ Cloudbet ด้านล่างนี้คือวิธีที่มันนำไปใช้กับ Plinko โดยเฉพาะ
เส้นทางของลูกบอลกลายเป็นช่องรางวัลได้อย่างไร
เส้นทางของลูกบอลแต่ละลูกที่ตกลงมาตามพีระมิดคือชุดของการกระเด้งออกจากหมุด และการกระเด้งแต่ละครั้งจะเป็นไปทางซ้ายหรือทางขวา

การเลือกนั้นสามารถเข้ารหัสเป็น "0" (ซ้าย) หรือ "1" (ขวา) เส้นทางแบบ "ซ้าย ซ้าย ขวา" จะกลายเป็นรหัส "001" และเมื่อเดินตามเส้นทางนี้ ลูกบอลจะตกลงในช่องที่ #2

นี่คือรูปแบบสำคัญ: เส้นทางจะตกลงในช่องที่ตรงกับจำนวนครั้งที่กระเด้งไปทางขวา บวกด้วยหนึ่ง ดังนั้น "100", "010" และ "001" ซึ่งมี "1" อยู่เพียงตัวเดียวเท่ากัน จะตกลงในช่องที่ #2 (1 + 1)

ซึ่งหมายความว่าเส้นทางแบบสุ่มสามารถสร้างและเข้ารหัสได้ในขั้นตอนเดียว: นำตัวเลขสุ่ม 32 บิต อ่าน N บิตแรกของมัน (โดยที่ N คือจำนวนแถว) แล้วนับว่ามีกี่บิตที่เป็น "1" บวกด้วยหนึ่ง นั่นคือช่องที่ลูกบอลจะตก ช่องนี้จะถูกคำนวณและล็อกไว้บนเซิร์ฟเวอร์ก่อนที่รอบจะเริ่ม และถูกซ่อนไว้จนกว่ารอบจะจบแล้วจึงเปิดเผย
ตรวจสอบความยุติธรรมที่พิสูจน์ได้ของเกม Plinko ของคุณเอง
โค้ดด้านล่างนี้ตรงกับการทำงานของ Plinko บน Cloudbet ใส่ Server Seed, Client Seed, Nonce จำนวนลูกบอล และจำนวนแถวของคุณ ติดตั้งไลบรารีที่จำเป็นหนึ่งตัว แล้วรันโปรแกรมนี้
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 = 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);
})();
หมายเหตุ: หากต้องการเปิดเผย Server Seed ของเกมบน Cloudbet คุณต้อง Rotate ไปเป็น Server Seed ใหม่ก่อน
