Game
Các sự kiện trò chơi là sự dịch chuyển của các giá trị float được tạo ra ngẫu nhiên thành một kết quả có thể liên quan đến trò chơi cụ thể. Điều này bao gồm bất cứ điều gì từ kết quả của một cú gieo xúc xắc đến thứ tự của các lá bài trong một bộ bài, hoặc thậm chí vị trí của mọi quả bom trong một trò chơi mines.
Dưới đây là một giải thích chi tiết về cách chúng tôi dịch chuyển các giá trị float thành các sự kiện cho từng trò chơi khác nhau trên nền tảng của chúng tôi.
Hilo
Trong một bộ bài tiêu chuẩn, có 52 kết quả có thể duy nhất. Khi chơi Blackjack, Hilo & Baccarat trên nền tảng của chúng tôi, chúng tôi sử dụng một số lượng không giới hạn các bộ bài khi tạo ra sự kiện trò chơi, vì vậy mỗi lần rút bài luôn có cùng xác suất. Để tính toán điều này, chúng tôi nhân mỗi giá trị float được tạo ngẫu nhiên với 52, và sau đó dịch kết quả đó thành một lá bài cụ thể, dựa trên chỉ số sau:
// Index of 0 to 51 : ♦2 to ♣A
const CARDS = [
♦2, ♥2, ♠2, ♣2, ♦3, ♥3, ♠3, ♣3, ♦4, ♥4,
♠4, ♣4, ♦5, ♥5, ♠5, ♣5, ♦6, ♥6, ♠6, ♣6,
♦7, ♥7, ♠7, ♣7, ♦8, ♥8, ♠8, ♣8, ♦9, ♥9,
♠9, ♣9, ♦10, ♥10, ♠10, ♣10, ♦J, ♥J, ♠J,
♣J, ♦Q, ♥Q, ♠Q, ♣Q, ♦K, ♥K, ♠K, ♣K, ♦A,
♥A, ♠A, ♣A
];
// Game event translation
const card = CARDS[Math.floor(float * 52)];
Yếu tố phân biệt duy nhất liên quan đến các trò chơi này là với Hilo và Blackjack có một con trỏ 13 để tạo ra 52 sự kiện trò chơi có thể cho những trường hợp mà một lượng lớn bài cần phải được chia cho người chơi, trong khi đối với Baccarat, chúng tôi chỉ cần tạo ra 6 sự kiện trò chơi để bao phủ số lượng bài có thể chơi nhiều nhất có thể.
Kim cương
Khi chơi Diamonds, có 7 kết quả có thể dưới dạng viên đá quý. Để đạt được điều này, chúng tôi nhân mỗi giá trị float được tạo ra với 7 trước khi nó được dịch thành viên đá quý tương ứng, sử dụng chỉ số sau:
// Index of 0 to 51 : ♦2 to ♣A
const CARDS = [
♦2, ♥2, ♠2, ♣2, ♦3, ♥3, ♠3, ♣3, ♦4, ♥4,
♠4, ♣4, ♦5, ♥5, ♠5, ♣5, ♦6, ♥6, ♠6, ♣6,
♦7, ♥7, ♠7, ♣7, ♦8, ♥8, ♠8, ♣8, ♦9, ♥9,
♠9, ♣9, ♦10, ♥10, ♠10, ♣10, ♦J, ♥J, ♠J,
♣J, ♦Q, ♥Q, ♠Q, ♣Q, ♦K, ♥K, ♠K, ♣K, ♦A,
♥A, ♠A, ♣A
];
// Game event translation
const card = CARDS[Math.floor(float * 52)];
Xúc xắc
Trong phiên bản xúc xắc của chúng tôi, chúng tôi bao gồm một phạm vi gieo có thể từ 00.00 đến 100.00, có 10.001 kết quả có thể. Việc dịch sự kiện trò chơi được thực hiện bằng cách nhân giá trị float với số lượng kết quả có thể và sau đó chia cho 100 để số kết quả phù hợp với các ràng buộc của phạm vi xúc xắc đã nêu của chúng tôi.
// Game event translation
const roll = (float * 10001) / 100;
Lật đồng xu
Khi chơi Coinflip, có 2 kết quả có thể dưới dạng đồng xu. Để đạt được điều này, chúng tôi nhân mỗi giá trị float được tạo ra với 2 trước khi nó được dịch thành viên đá quý tương ứng, sử dụng chỉ số sau:
// Index of 0 & 1 : batman & joker
const COINS = [ 0, 1 ];
// Game event translation
const coin = COINS[Math.floor(float * 2)];
Limbo
Khi nói đến Limbo, chúng tôi sử dụng một quy trình hai bước. Đầu tiên, chúng tôi lấy số float và nhân nó với cả hệ số nhân tối đa có thể và lợi nhuận của nhà cái. Sau đó, để tạo ra một sự kiện trò chơi có phân phối xác suất, chúng tôi chia hệ số nhân tối đa theo kết quả của bước đầu tiên để tạo ra sự kiện trò chơi dưới dạng điểm va chạm. Phân phối xác suất chúng tôi chia hệ số nhân tối đa theo kết quả của bước đầu tiên để tạo ra sự kiện trò chơi dưới dạng điểm va chạm.
// Game event translation with houseEdge of 0.99 (1%)
const floatPoint = 1e8 / (float * 1e8) * houseEdge;
// Crash point rounded down to required denominator
const crashPoint = Math.floor(floatPoint * 100) / 100;
// Consolidate all crash points below 1
const result = Math.max(crashPoint, 1);
Plinko
Đối với bất kỳ trò chơi Plinko nào, kết quả được tạo ra dựa trên con đường của quả bóng rơi. Sự kiện trò chơi xác định hướng đi của quả bóng rơi ở mỗi cấp độ trong quá trình rơi. Người chơi có thể chọn giữa 8 và 16 chốt chơi, điều này xác định số lượng sự kiện trò chơi cần thiết để tạo ra một con đường hoàn chỉnh từ trên xuống dưới. Vì chỉ có hai hướng có thể (trái hoặc phải), nên việc dịch được thực hiện bằng cách nhân mỗi số thực với 2, điều này ánh xạ đến chỉ mục sau:
// Index of 0 to 1 : left to right
const DIRECTIONS = [ left, right ];
// Game event translation
const direction = CARDS[Math.floor(float * 2)];
Keno
Các trò chơi Keno truyền thống yêu cầu chọn 10 sự kiện trò chơi có thể xảy ra dưới dạng các ô được đánh dấu trên bảng. Để đạt được điều này, chúng tôi nhân mỗi số thực với số lượng ô duy nhất có thể có. Khi một ô đã được đánh dấu, nó không thể được chọn lại, điều này làm thay đổi kích thước của tập hợp các kết quả có thể xảy ra. Việc này được thực hiện bằng cách trừ đi kích thước của các kết quả tối đa có thể xảy ra 1 cho mỗi lần lặp kết quả sự kiện trò chơi được tạo ra bằng cách sử dụng số thực tương ứng, bằng cách sử dụng chỉ mục sau:
// Index of 0 to 39 : 1 to 40
const SQUARES = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40
];
const hit = SQUARES[Math.floor(float * 40)];
Việc triển khai xáo trộn Fisher-Yates được sử dụng để ngăn chặn việc tạo ra các cú đánh trùng lặp có thể xảy ra.
Mines
Một trò chơi mìn được tạo ra với 24 sự kiện trò chơi riêng biệt, dưới dạng các mìn trên bảng. Mỗi số thực được nhân với số lượng ô duy nhất vẫn còn trên bảng. Việc này được thực hiện bằng cách trừ đi số ô còn lại 1 cho mỗi lần lặp kết quả sự kiện trò chơi được tạo ra bằng cách sử dụng số thực tương ứng. Vị trí của mìn được xác định bằng cách sử dụng vị trí lưới từ trái sang phải, từ trên xuống dưới.
Việc triển khai xáo trộn Fisher-Yates được sử dụng để ngăn chặn việc tạo ra các cú đánh trùng lặp có thể xảy ra.
Wheel
Số sự kiện trò chơi được tính bằng cách nhân số thực với các kết quả có thể trong phân khúc. Sau đó, nó được sử dụng để xác định kết quả sự kiện trò chơi dưới dạng hệ số nhân, sử dụng chỉ số sau:
// Index per payout configuration
const PAYOUTS = {
'10': {
low: [ 1.5, 1.2, 1.2, 1.2, 0, 1.2, 1.2, 1.2, 1.2, 0 ],
medium: [ 0, 1.9, 0, 1.5, 0, 2, 0, 1.5, 0, 3 ],
high: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 9.9 ]
},
'20': {
low: [
1.5, 1.2, 1.2, 1.2, 0, 1.2, 1.2, 1.2, 1.2, 0,
1.5, 1.2, 1.2, 1.2, 0, 1.2, 1.2, 1.2, 1.2, 0
],
medium: [
1.5, 0, 2, 0, 2, 0, 2, 0, 1.5, 0,
3, 0, 1.8, 0, 2, 0, 2, 0, 2, 0
],
high: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 19.8
]
},
'30': {
low: [
1.5, 1.2, 1.2, 1.2, 0, 1.2, 1.2, 1.2, 1.2, 0,
1.5, 1.2, 1.2, 1.2, 0, 1.2, 1.2, 1.2, 1.2, 0,
1.5, 1.2, 1.2, 1.2, 0, 1.2, 1.2, 1.2, 1.2, 0
],
medium: [
1.5, 0, 1.5, 0, 2, 0, 1.5, 0, 2, 0,
2, 0, 1.5, 0, 3, 0, 1.5, 0, 2, 0,
2, 0, 1.7, 0, 4, 0, 1.5, 0, 2, 0
],
high: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 29.7
]
},
'40': {
low: [
1.5, 1.2, 1.2, 1.2, 0, 1.2, 1.2, 1.2, 1.2, 0,
1.5, 1.2, 1.2, 1.2, 0, 1.2, 1.2, 1.2, 1.2, 0,
1.5, 1.2, 1.2, 1.2, 0, 1.2, 1.2, 1.2, 1.2, 0,
1.5, 1.2, 1.2, 1.2, 0, 1.2, 1.2, 1.2, 1.2, 0
],
medium: [
2, 0, 3, 0, 2, 0, 1.5, 0, 3, 0,
1.5, 0, 1.5, 0, 2, 0, 1.5, 0, 3, 0,
1.5, 0, 2, 0, 2, 0, 1.6, 0, 2, 0,
1.5, 0, 3, 0, 1.5, 0, 2, 0, 1.5, 0
],
high: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 39.6
]
},
'50': {
low: [
1.5, 1.2, 1.2, 1.2, 0, 1.2, 1.2, 1.2, 1.2, 0,
1.5, 1.2, 1.2, 1.2, 0, 1.2, 1.2, 1.2, 1.2, 0,
1.5, 1.2, 1.2, 1.2, 0, 1.2, 1.2, 1.2, 1.2, 0,
1.5, 1.2, 1.2, 1.2, 0, 1.2, 1.2, 1.2, 1.2, 0,
1.5, 1.2, 1.2, 1.2, 0, 1.2, 1.2, 1.2, 1.2, 0
],
medium: [
2, 0, 1.5, 0, 2, 0, 1.5, 0, 3, 0,
1.5, 0, 1.5, 0, 2, 0, 1.5, 0, 3, 0,
1.5, 0, 2, 0, 1.5, 0, 2, 0, 2, 0,
1.5, 0, 3, 0, 1.5, 0, 2, 0, 1.5, 0,
1.5, 0, 5, 0, 1.5, 0, 2, 0, 1.5, 0
],
high: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 49.5
]
}
};
// Game event translation
const spin = PAYOUTS[segments][risk][float * segments];
Crash
Để chứng minh sự công bằng của chúng tôi, chúng tôi đã tạo ra một chuỗi 10.000.000 băm SHA256, trong đó mỗi băm là băm của biểu diễn thập lục phân của băm trước đó. Băm cuối cùng trong chuỗi là: 78a9757d3be42b74a3f70239078ad9317125fe9ee630d5bdada46de963e56752
Công thức để tạo ra kết quả trò chơi:
const gameHash = hashChain.pop()
const hmac = createHmac('sha256', gameHash);
// blockHash is the hash of bitcoin block 584,500
hmac.update(blockHash);
const hex = hmac.digest('hex').substr(0, 8);
const int = parseInt(hex, 16);
// 0.01 will result in 1% house edge with a lowest crashpoint of 1
const crashpoint = Math.max(1, (2 ** 32 / (int + 1)) * (1 - 0.01))
Double
Double của chúng tôi được lấy từ phiên bản Châu Âu của trò chơi, trong đó bánh xe bao gồm 15 túi khác nhau có thể, từ 0 đến 14. Sự kiện trò chơi được tính bằng cách nhân số thực với 15 và sau đó được chuyển đổi thành một túi tương ứng sử dụng chỉ số sau:
// Index of 0 to 14
const POCKETS = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14
];
// Game event translation
const pocket = POCKETS[Math.floor(float * 15)];
Tower
Một trò chơi Tower được tạo ra với 9 sự kiện trò chơi riêng biệt, dưới dạng các cấp độ lên tháp. Chúng tôi tạo ra một số trứng tùy thuộc vào độ khó cho mỗi cấp độ, và có một loạt các ô mà trứng có thể nằm, cũng được biểu diễn bằng một số nguyên.
Mỗi số thực được tạo ra sau đó được chuyển đổi thành số nguyên để xác định vị trí của trứng trên mỗi hàng. Ví dụ: Một cấp độ ở độ khó dễ sẽ được biểu diễn như thế này: [0, 1, 3] - trứng sẽ có mặt tại ô 1, 2 và 4.
// count represents the number of eggs
// size represents the number of possible squares
const LEVEL_MAP = {
easy: { count: 3, size: 4 },
medium: { count: 2, size: 3 },
hard: { count: 1, size: 2 },
expert: { count1, size: 3 },
master: { count: 1, size: 4 },}
Việc triển khai xáo trộn Fisher-Yates được sử dụng để ngăn chặn việc tạo ra các trứng trùng lặp trên một hàng.