Bỏ qua đến nội dung chính

Provably Fair - Game Events

Game Event là gì?

Đã cập nhật cách đây hơn 1 tuần

Trước đó, chúng ta đã tạo ra các số thực ngẫu nhiên trong khoảng từ 0 đến 1 bằng cách sử dụng các hàm generateFloatsbyteGenerator. Game events sẽ chuyển đổi các giá trị float này thành kết quả trò chơi thực tế.
Việc này được thực hiện theo nhiều cách khác nhau tùy thuộc vào từng trò chơi.

Ví dụ:

  • Trong Plinko, các float xác định hướng rơi của quả bóng.

  • Trong Dice, float xác định kết quả xúc xắc.

Dưới đây là mô tả chi tiết cách chúng tôi chuyển đổi float thành kết quả công bằng cho từng trò chơi gốc trên nền tảng.


Plinko

Trong Plinko, người chơi có thể chọn chiều cao của kim tự tháp từ 8 đến 16. Mỗi khi bóng rơi xuống, nó sẽ đi trái hoặc phải tại mỗi chốt, tổng cộng 8 đến 16 lần.
Game event trong Plinko là xác định hướng rơi của bóng ở mỗi tầng (0 = trái, 1 = phải).

// Tạo nhiều float trong khoảng từ 0 đến 1
const floats = generateFloats({ serverSeed, clientSeed, nonce, cursor, count });

// Ví dụ: [1, 1, 0, 1, 0, 1, 1, 0]
const dropDirections = floats.map(val => Math.floor(val * 2));

// Tính vị trí cuối cùng của bóng tính từ bên trái
const finalPositionFromLeft = dropDirections.reduce((cur, acc) => cur + acc, 0)

Dice

Trong Dice, kết quả là một số từ 0.00 đến 100.00.
Có tổng cộng 10,001 kết quả khả thi (vì bao gồm 0.00 và làm tròn đến 2 chữ số thập phân).

const floats = generateFloats({ serverSeed, clientSeed, nonce, cursor: 0, count: 1 });

const resultValue = floats.map(val => Math.floor(floats * 10001) / 100);
return resultValue[0]; // Ví dụ: 43.05

Limbo

Trong Limbo, người chơi đặt cược vào một hệ số nhân >1.
Nếu kết quả lớn hơn hệ số đó, người chơi thắng. Game sử dụng phân phối hyperbolic.

const floats = generateFloats({ serverSeed, clientSeed, nonce, cursor: 0, count: 1 });
const float = floats[0];

const MAX_VALUE = 2 ** 24;
const rtp = 0.99;

const rawValue = (rtp * MAX_VALUE) / (MAX_VALUE * float + 1);
const resultValue = rawValue.toFixed(2, ROUND_DOWN);
return resultValue;

Keno

Trong Keno, cần xác định 10 viên đá quý tại 10 vị trí duy nhất trên bảng 1–40.

const floats = generateFloats({ serverSeed, clientSeed, nonce, cursor: 0, count: 10 })
.map((val, index) => Math.ceil(val * (40 - index)))

const gemLocations: number[] = [];

for (const val of floats) {
let currentGem = val;
let i = 0;
while (i <= currentGem) {
if (gemLocations.includes(i)) {
currentGem++;
}
i++;
}
gemLocations.push(currentGem);
}
return gemLocations; // Ví dụ: [18, 27, 7, 24, 35, 11, 28, 9, 31, 16]

Mines

Trong Mines, cần xác định vị trí của mìn trên bảng 5x5 (25 ô).

const floats = generateFloats({ serverSeed, clientSeed, nonce, cursor: 0, count: numberOfBombs })
.map((val, index) => Math.floor(val * (25 - index)));

const mineLocations: number[] = [];

for (const val of floats) {
let currentMine = val;
let i = 0;
while (i <= currentMine) {
if (mineLocations.includes(i)) {
currentMine++;
}
i++;
}
mineLocations.push(currentMine);
}
return mineLocations; // Ví dụ: [20, 21, 4]

Roulette

Dựa theo kiểu roulette châu Âu với 37 ô từ 0 đến 36.

const floats = generateFloats({ serverSeed, clientSeed, nonce, cursor: 0, count: 1 });
const resultValue = floats.map(val => Math.floor(val * 37))[0];
return resultValue; // Ví dụ: 15

Wheel

Trong Wheel, người dùng chọn số lượng phân đoạn. Mỗi phân đoạn có một hệ số nhân.

const floats = generateFloats({ serverSeed, clientSeed, nonce, cursor, count: 1 });
const resultSegment = floats.map(val => Math.floor(val * numberOfSegments))[0];
return resultSegment;

Blackjack

Blackjack sử dụng bộ bài vô hạn. Mỗi lá bài có xác suất bằng nhau.

const floats = generateFloats({ serverSeed, clientSeed, nonce, cursor, count: 52 });

const CARDS = [
♦2, ♥2, ♠2, ♣2, ..., ♦A, ♥A, ♠A, ♣A // 52 lá
];

const cardFloats = floats.map(val => Math.floor(val * 52));
const cards = cardFloats.map(val => CARDS[val]);
return cards; // Ví dụ: [♠7, ♠10, ♥4, ♥9, ♦K]

Hilo

Tương tự Blackjack, sử dụng bộ bài vô hạn.
Người chơi đoán lá tiếp theo là cao hơn hay thấp hơn lá hiện tại.

const floats = generateFloats({ serverSeed, clientSeed, nonce, cursor, count: 52 });

const CARDS = [
♦2, ♥2, ♠2, ♣2, ..., ♦A, ♥A, ♠A, ♣A // 52 lá
];

const cardFloats = floats.map(val => Math.floor(val * 52));
const cards = cardFloats.map(val => CARDS[val]);
return cards;

Crash

Crash sử dụng 2 phần để tính kết quả:

  1. Bitcoin block hash

  2. Seed

Bitcoin Hash

Hash của block 779588 có thể kiểm tra tại:
https://www.blockchain.com/explorer/blocks/btc/779588

Seed

Quy trình tạo seed cho 10 triệu trò chơi Crash được thiết kế để đảm bảo tính công bằng và minh bạch, ngăn chặn mọi khả năng thao túng từ phía Shuffle. Dưới đây là cách các seed được tạo ra và xác minh:

Tạo Seed Ban Đầu:

Seed cho trò chơi thứ 10 triệu được Shuffle chọn ngẫu nhiên.


Băm liên tiếp để tạo seed cho các trò còn lại:

Để tạo seed cho tất cả các trò chơi khác, Shuffle sử dụng phương pháp băm ngược (backward hashing):

  • Seed của mỗi trò chơi được tạo bằng cách SHA256 của seed của trò tiếp theo.
    Cụ thể, seed của trò 9.999.999 là kết quả SHA256 của seed trò 10.000.000.

  • Quá trình này tiếp tục, sao cho seed của mỗi trò được sinh ra từ việc băm seed của trò kế tiếp, cho đến khi seed của trò đầu tiên được tạo ra từ seed của trò thứ hai.


Xác minh tính toàn vẹn của seed:

Bằng cách công khai giá trị băm của seed được dùng trong trò chơi đầu tiên, người chơi có thể tự mình xác minh tính toàn vẹn của tất cả các seed cho đến trò chơi thứ 10 triệu.

Sử dụng phương pháp này, nếu bạn biết seed của một trò chơi bất kỳ, bạn có thể băm seed đó để xác minh seed của trò chơi trước đó.
Ví dụ: nếu bạn biết seed của trò 1323185, bạn có thể băm seed đó và xác minh rằng nó trùng khớp với seed của trò 1323184, và tiếp tục như vậy cho đến trò đầu tiên.


Ví dụ:

Giá trị seed của trò 1323184 chính là kết quả SHA256 của seed của trò 1323185.
Bạn có thể dùng công cụ tính SHA256 online để xác minh:
🔗 https://xorbin.com/tools/sha256-hash-calculator


Tính minh bạch và bảo mật:

Bằng cách sử dụng hash của block Bitcoin trong tương lai (mà Shuffle không thể kiểm soát) và công bố giá trị băm của seed của trò đầu tiên, người dùng có thể chứng minh rằng kết quả trò chơi Crash là công bằng và không bị can thiệp.

Nội dung này có giải đáp được câu hỏi của bạn không?