Game
게임 이벤트는 무작위로 생성된 플로트를 게임에 특정한 관련 결과로 변환하는 것입니다. 여기에는 주사위 굴리기의 결과부터 덱에서 카드의 순서까지, 또는 지뢰 게임에서 모든 폭탄의 위치까지 포함됩니다.
아래는 우리 플랫폼의 각 특정 게임에 대해 플로트를 이벤트로 변환하는 방법에 대한 자세한 설명입니다.
히로
일반 카드 덱에서는 52개의 고유한 가능한 결과가 있습니다. 우리 플랫폼에서 블랙잭, 하일로 및 바카라를 플레이할 때, 우리는 게임 이벤트를 생성할 때 무한한 양의 덱을 사용하므로 카드의 각 턴은 항상 동일한 확률을 가집니다. 이를 계산하기 위해 각 무작위로 생성된 플로트를 52로 곱한 다음, 다음 인덱스를 기준으로 해당 결과를 특정 카드로 변환합니다:
// 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)];
이러한 게임에서 유일한 차별화 요소는 Hilo 및 블랙잭에서 13의 커서가 있어 플레이어에게 많은 카드를 배포해야 하는 경우 52개의 가능한 게임 이벤트를 생성하는 반면, 바카라의 경우에는 가능한 한 많은 플레이 가능한 카드를 커버하기 위해 6개의 게임 이벤트만 생성하면 됩니다.
다이아몬드
다이아몬드를 플레이할 때 7가지 가능한 결과가 보석의 형태로 있습니다. 이를 달성하기 위해 각 생성된 부동 소수점 수를 7로 곱한 다음 다음 인덱스를 사용하여 해당 보석으로 변환합니다:
// 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)];
주사위
우리 주사위 버전에서는 00.00에서 100.00까지의 가능한 주사위 굴림 범위를 다루며, 이 범위에는 10,001가지 가능한 결과가 있습니다. 게임 이벤트 번역은 부동 소수점을 가능한 결과 수로 곱한 다음 100으로 나누어 결과 숫자가 명시된 주사위 범위의 제약에 맞도록 합니다.
// Game event translation
const roll = (float * 10001) / 100;
동전 뒤집기
동전 뒤집기를 할 때 동전의 형태로 가능한 결과가 2가지 있습니다. 이를 달성하기 위해 각 생성된 부동 소수점 수를 2로 곱한 다음 다음 인덱스를 사용하여 해당 보석으로 변환합니다.
// Index of 0 & 1 : batman & joker
const COINS = [ 0, 1 ];
// Game event translation
const coin = COINS[Math.floor(float * 2)];
림보
림보에 관해서는 두 단계 프로세스를 사용합니다. 먼저, 우리는 플로트를 최대 가능한 배수와 하우스 엣지 모두로 곱합니다. 그런 다음, 게임 이벤트를 생성하기 위해 확률 분포 최대 가능한 배수를 첫 번째 단계의 결과로 나누어 충돌 지점 형태의 게임 이벤트를 생성합니다.
// 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);
플inko
플린코 게임의 경우, 생성된 결과는 떨어지는 공의 경로를 기반으로 합니다. 게임 이벤트는 낙하 과정에서 각 레벨에 대해 떨어지는 공의 방향을 결정합니다. 플레이어는 8개에서 16개의 핀 중에서 선택할 수 있으며, 이는 위에서 아래로의 전체 경로를 생성하는 데 필요한 게임 이벤트 수를 결정합니다. 가능한 방향이 두 개(왼쪽 또는 오른쪽)만 있기 때문에 번역은 각 플로트를 2로 곱하여 수행되며, 이는 다음 인덱스에 매핑됩니다:
// Index of 0 to 1 : left to right
const DIRECTIONS = [ left, right ];
// Game event translation
const direction = CARDS[Math.floor(float * 2)];
케노
전통적인 Keno 게임은 보드에서의 히트 형태로 10개의 가능한 게임 이벤트를 선택해야 합니다.
// 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)];
Fisher-Yates 셔플 구현은 중복 가능한 히트가 생성되지 않도록 하는 데 사용됩니다.
광산
24개의 개별 게임 이벤트 형태로 광산이 생성됩니다. 각 플로트는 보드에 남아 있는 고유한 타일의 수에 곱해집니다. 이는 각 게임 이벤트 결과를 생성하기 위해 제공된 해당 플로트를 사용하여 남은 타일 수에서 1을 빼는 방식으로 이루어집니다. 광산의 위치는 왼쪽에서 오른쪽, 위에서 아래로 그리드 위치를 사용하여 플로팅됩니다.
Fisher-Yates 셔플 구현은 중복 가능한 히트가 생성되지 않도록 하는 데 사용됩니다. 선택한 설정에 따라 1에서 24개의 게임 이벤트 결과가 사용됩니다.
휠
게임 이벤트 번호는 플로트를 세그먼트의 가능한 결과로 곱하여 계산됩니다. 그런 다음 멀티플라이어로서 게임 이벤트 결과를 결정하는 데 사용되며, 다음 인덱스를 사용합니다:
// 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];
크래시
우리의 공정성을 증명하기 위해, 우리는 10,000,000 SHA256 해시 체인을 생성했습니다. 여기서 각 해시는 이전 해시의 16진수 표현의 해시입니다. 체인의 마지막 해시는 다음과 같습니다: 78a9757d3be42b74a3f70239078ad9317125fe9ee630d5bdada46de963e56752
게임 결과를 생성하는 공식:
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))
더블
우리의 더블은 바퀴가 0에서 14까지 15개의 서로 다른 포켓으로 구성된 유럽 버전에서 파생됩니다. 게임 이벤트는 float에 15를 곱하여 계산되며, 다음 인덱스를 사용하여 해당 포켓으로 변환됩니다:
// 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)];
타워
타워 게임은 9개의 개별 게임 이벤트로 생성되며, 이는 타워의 레벨 형태입니다. 각 레벨의 난이도에 따라 알의 수를 생성하고, 알이 놓일 수 있는 타일의 범위는 정수로 표현됩니다.
생성된 각 플로트는 각 행의 알 위치를 결정하기 위해 정수로 변환됩니다. 예를 들어, 쉬운 난이도에서는 다음과 같이 표시됩니다: [0, 1, 3] - 알은 타일 1, 2 및 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 },}
피셔-예이츠 셔플 구현은 한 행에 중복 계란이 나타나는 것을 방지하는 데 사용됩니다.