Game
Os eventos de jogo são a tradução dos floats gerados aleatoriamente em um resultado relacionado que é específico do jogo. Isso inclui qualquer coisa, desde o resultado de um lançamento de dados até a ordem das cartas em um baralho, ou até mesmo a localização de cada bomba em um jogo de minas.
Abaixo está uma explicação detalhada de como traduzimos floats em eventos para cada jogo específico em nossa plataforma.
Hilo
Em um baralho padrão de cartas, existem 52 resultados únicos possíveis. Quando se trata de jogar Blackjack, Hilo e Baccarat em nossa plataforma, utilizamos uma quantidade ilimitada de baralhos ao gerar o evento do jogo, e, portanto, cada jogada de carta sempre tem a mesma probabilidade. Para calcular isso, multiplicamos cada float gerado aleatoriamente por 52 e, em seguida, traduzimos esse resultado em uma carta específica, com base no seguinte índice:
// 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)];
O único fator diferenciador envolvido nesses jogos é que, no Hilo e no Blackjack, existe um cursor de 13 para gerar 52 possíveis eventos de jogo para os casos em que uma grande quantidade de cartas precisa ser distribuída ao jogador, enquanto que, no Baccarat, precisamos gerar apenas 6 eventos de jogo para cobrir a maior quantidade possível de cartas jogáveis.
Diamantes
Ao jogar Diamonds, existem 7 resultados possíveis na forma de gemas. Para isso, multiplicamos cada float gerado por 7 antes de traduzi-lo em uma gema correspondente usando o seguinte índice:
// 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)];
Dados
Na nossa versão de dados, cobrimos uma possível faixa de rolagem de 00,00 a 100,00, que tem uma gama de 10.001 resultados possíveis. A tradução do evento de jogo é feita multiplicando o float pelo número de resultados possíveis e depois dividindo por 100, de modo que o número resultante se encaixe nas restrições da faixa de dados declarada.
// Game event translation
const roll = (float * 10001) / 100;
Lançamento de Moeda
Ao jogar Coinflip, existem 2 resultados possíveis na forma de moedas. Para isso, multiplicamos cada float gerado por 2 antes de traduzi-lo em uma gema correspondente usando o seguinte índice:
// Index of 0 & 1 : batman & joker
const COINS = [ 0, 1 ];
// Game event translation
const coin = COINS[Math.floor(float * 2)];
Limbo
Quando se trata de Limbo, usamos um processo de duas etapas. Primeiro, pegamos o float e o multiplicamos pelo máximo multiplicador possível e pela margem da casa. Em seguida, para gerar um evento de jogo que tenha Distribuição de Probabilidade Dividimos o multiplicador máximo possível pelo resultado da primeira etapa para criar o evento do jogo na forma de um ponto de colapso.
// 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
Para qualquer jogo de Plinko, o resultado gerado é baseado no caminho da bola que cai. O evento do jogo determina a direção da bola que cai para cada nível no processo de queda. Os jogadores podem escolher entre 8 e 16 pinos de jogo, o que determina o número de eventos de jogo necessários para gerar um caminho completo de cima para baixo. Como há apenas duas direções possíveis (esquerda ou direita), a tradução é feita multiplicando cada float por 2, que mapeia para o seguinte índice:
// Index of 0 to 1 : left to right
const DIRECTIONS = [ left, right ];
// Game event translation
const direction = CARDS[Math.floor(float * 2)];
Keno
Jogos tradicionais de Keno exigem a seleção de 10 eventos de jogo possíveis na forma de acertos em um tabuleiro.
// 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)];
A implementação do embaralhamento Fisher-Yates é utilizada para evitar a geração de acertos duplicados.
Minas
Um jogo de mina é gerado com 24 eventos de jogo separados, na forma de minas no tabuleiro. Cada float é multiplicado pelo número de azulejos únicos possíveis que ainda restam no tabuleiro. Isso é feito subtraindo o número de azulejos restantes por 1 para cada iteração do resultado do evento de jogo gerado usando o float correspondente fornecido. A localização da mina é plotada usando uma posição de grade da esquerda para a direita, de cima para baixo.
A implementação do embaralhamento Fisher-Yates é utilizada para evitar a geração de acertos duplicados. Entre 1 e 24 resultados de eventos de jogo são usados, com base nas configurações escolhidas.
Roda
O número do evento do jogo é calculado multiplicando o float pelos possíveis resultados no segmento. Ele é então usado para determinar o resultado do evento do jogo como um multiplicador, usando o seguinte índice:
// 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];
Queda
Para provar nossa imparcialidade, geramos uma cadeia de 10.000.000 de hashes SHA256, onde cada hash é o hash da representação hexadecimal do hash anterior. O último hash na cadeia é: 78a9757d3be42b74a3f70239078ad9317125fe9ee630d5bdada46de963e56752
Gerar o resultado do jogo:
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))
Duplo
Nosso Double é derivado da versão europeia do jogo, onde a roda consiste em 15 bolsos diferentes possíveis, variando de 0 a 14. O evento do jogo é calculado multiplicando o float por 15 e, em seguida, traduzido em um bolso correspondente usando o seguinte índice:
// 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)];
Torre
Um jogo de Torre é gerado com 9 eventos de jogo separados, na forma dos níveis da torre. Geramos uma certa quantidade de ovos dependendo da dificuldade de cada nível e temos uma faixa de azulejos em que o ovo também pode ser representada por um número inteiro.
Cada float gerado é convertido em inteiros para determinar a localização dos ovos em cada linha. Por exemplo: Um nível com dificuldade fácil seria representado assim: [0, 1, 3] - os ovos estariam presentes nas peças 1, 2 e 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 },}
A implementação do embaralhamento de Fisher-Yates é utilizada para evitar ovos duplicados em uma linha.