Guia de Simulacao de RTP/GGR
O que e RTP?
RTP (Return to Player) e a porcentagem do dinheiro apostado que retorna aos jogadores ao longo do tempo.
| RTP | Significado | Exemplo |
|---|---|---|
| 100% | Break Even | Jogador aposta R$ 100, recebe R$ 100 em media |
| 95% | Casa lucra 5% | Jogador aposta R$ 100, recebe R$ 95 em media |
| 80% | Casa lucra 20% | Jogador aposta R$ 100, recebe R$ 80 em media |
| 120% | Casa perde 20% | Jogador aposta R$ 100, recebe R$ 120 em media |
House Edge = 100% - RTP (margem da casa)
GGR (Gross Gaming Revenue) = Total Apostado - Total Ganho
RTPs Tipicos da Industria
| Tipo de Jogo | RTP Tipico |
|---|---|
| Slots Online | 94-98% |
| Blackjack | 99%+ |
| Roleta | 94-97% |
| Sites de Caixas CS | 70-85% |
Script de Simulacao
Arquivo: scripts/rtp-simulation.ts (TypeScript, executado via tsx)
Parametros
const SIMULATIONS_PER_CASE = 10000; // Aberturas por caixa
const UPGRADE_SIMULATIONS = 10000; // Upgrades por faixa de ratio
const BATTLE_SIMULATIONS = 500; // Batalhas por combinacao
const BATTLE_SIMULATIONS_HEAVY = 200; // Cenarios pesados (4+ players, 3+ rounds)
const HASH_MAX = 10000000; // Range provably fair
const UPGRADE_HOUSE_EDGE = 0.08; // House edge de upgrades (8%)
const UPGRADE_MIN_CHANCE = 0.5; // Chance minima de upgrade
const UPGRADE_MAX_CHANCE = 75; // Chance maxima de upgrade
const PENALTY_EXPONENT = 0.2; // Expoente do penalty factor
const PENALTY_MULTIPLIER = 0.28; // Multiplicador do penalty factorComo Executar
npx tsx scripts/rtp-simulation.tsGera docs/RTP_ANALYSIS.md com o relatorio completo.
Metodologia
1. Calculo do Roll (Identico ao Servico Real)
O roll e calculado de forma identica ao provably-fair.service.ts:
function calculateRoll(
serverSeed: string,
clientSeed: string,
nonce: number,
max: number = 10000000,
): number {
const hmac = crypto.createHmac('sha256', serverSeed);
hmac.update(`${clientSeed}:${nonce}`);
const hash = hmac.digest('hex');
const hashPrefix = hash.substring(0, 13); // 13 chars hex = 52 bits
const decimal = parseInt(hashPrefix, 16);
const maxSafeValue = Math.floor(Number.MAX_SAFE_INTEGER / max) * max;
let result = decimal;
if (result >= maxSafeValue) {
// Retry com sufixo ':retry' na mensagem (overflow protection)
const hash2 = crypto
.createHmac('sha256', serverSeed)
.update(`${clientSeed}:${nonce}:retry`)
.digest('hex');
result = parseInt(hash2.substring(0, 13), 16);
}
return (result % max) + 1; // Range 1-based: 1 a 10.000.000
}Diferencas criticas vs script antigo:
substring(0, 13)(52 bits) ao inves desubstring(0, 8)(32 bits)- Retry com sufixo
:retryna mensagem para overflow (maxSafeValue) - Resultado 1-based (
+1), nao 0-based - Mensagem HMAC =
${clientSeed}:${nonce}(sem serverSeed na mensagem)
2. Selecao de Item
function selectItemByRoll(caseItems: CaseItemWithItem[], roll: number) {
return caseItems.find(
(ci) => roll >= Number(ci.hashRangeStart) && roll <= Number(ci.hashRangeEnd),
);
}3. Sistema FLIP
O FLIP e uma flag cosmetica para o frontend. O item ganho e SEMPRE determinado pelo roll principal:
// flipThreshold = menor hashRangeStart dos itens raros (COVERT/EXTRAORDINARY)
const flipThreshold = getFlipThreshold(caseItems);
const isFlip = roll >= flipThreshold; // Se true, item ja e raro por definicaoNAO existe segundo roll para FLIP. Se roll >= flipThreshold, o item selecionado por selectItemByRoll() ja e um item raro. O frontend apenas mostra uma animacao especial.
4. Simulacao de Upgrades
Formula identica ao upgrade-probability.service.ts:
function calculateUpgradeChance(investedCentsBrl: number, targetCentsBrl: number): number {
const ratio = investedCentsBrl / targetCentsBrl;
const baseChance = ratio * (1 - UPGRADE_HOUSE_EDGE) * 100;
const penaltyFactor = Math.pow(ratio, PENALTY_EXPONENT) * PENALTY_MULTIPLIER;
let chancePercent = baseChance * (1 - penaltyFactor);
chancePercent = Math.max(UPGRADE_MIN_CHANCE, Math.min(UPGRADE_MAX_CHANCE, chancePercent));
return chancePercent;
}
// Sucesso: roll >= threshold
const successThreshold = HASH_MAX - (chancePercent / 100) * HASH_MAX;
const success = roll >= successThreshold;Faixas testadas: 10%, 25%, 40%, 50%, 60%, 75% (ratio investido/alvo)
5. Simulacao de Batalhas
Simula 11 cenarios de batalha cobrindo todos os modos, tipos e configuracoes de bots:
Cenarios simulados:
| Cenario | Tipo | Modo | Bots | Descricao |
|---|---|---|---|---|
| 1v1 PvP NORMAL | 1v1 | NORMAL | 0 | Player vs Player, maior vence |
| 1v1 PvP FLIP | 1v1 | FLIP | 0 | Player vs Player, menor vence |
| 1v1 vs Bot NORMAL | 1v1 | NORMAL | 1 | Player vs Bot, maior vence |
| 1v1 vs Bot FLIP | 1v1 | FLIP | 1 | Player vs Bot, menor vence |
| 3v3 PvP NORMAL | 3v3 | NORMAL | 0 | 3 vs 3 players |
| 3v3 PvP FLIP | 3v3 | FLIP | 0 | 3 vs 3 players |
| 3v3 vs Bots NORMAL | 3v3 | NORMAL | 5 | 1 real + 5 bots |
| 3v3 vs Bots FLIP | 3v3 | FLIP | 5 | 1 real + 5 bots |
| SHARED 2v2 PvP | 2v2 | SHARED | 0 | 4 players, todos ganham |
| SHARED 3v3 PvP | 3v3 | SHARED | 0 | 6 players, todos ganham |
| SHARED 3v3 vs Bots | 3v3 | SHARED | 5 | 1 real + 5 bots |
Cada cenario roda com 1 e 3 rounds, e com 2 caixas diferentes (total: 44 combinacoes).
Fluxo de uma batalha simulada:
- Cada player abre 1 case por round (rolls independentes)
- Acumula valor por time (team1 = indices 0..N-1, team2 = indices N..2N-1)
- Determina vencedor baseado no modo:
- NORMAL: time com maior valor total
- FLIP: time com menor valor total
- SHARED: todos os players vencem
- Economia de bots:
realEntryFee = casePrice * rounds * numRealPlayers(bots NAO pagam)- Se time do bot vence:
houseGGR = realEntryFee(100% lucro, nenhum item entregue) - Se player real vence: settlement normal,
houseGGR = realEntryFee - itensEntregues
- Settlement (2+ winners):
fairShare = totalValue / numWinners- Itens com valor > fairShare: removidos para pool da casa (REMOVED_TO_POOL)
- Deficit: compensado via busca binaria no pool de 21.000+ itens (ADDED_FROM_POOL)
- Apenas winners reais (nao-bots) recebem itens
6. Valores em BRL
Todos os calculos usam valueCentsBrl (centavos de real), nunca valueCents (USD).
Interpretacao dos Resultados
RTP Saudavel para Caixas
| Faixa | Status | Acao |
|---|---|---|
| RTP > 100% | CRITICO | Ajustar probabilidades imediatamente |
| RTP > 95% | ATENCAO | Margem muito baixa |
| RTP 65-85% | SAUDAVEL | Margem ideal para a industria |
| RTP < 60% | AGRESSIVO | Pode afugentar jogadores |
RTP de Upgrades
O RTP teorico de upgrades varia por faixa de ratio:
- Ratios baixos (10%): RTP ~75% (penalty factor menor)
- Ratios altos (75%): RTP ~68% (penalty factor maior)
- Media geral: ~71%
House Edge de Batalhas
O house edge em batalhas vem de duas fontes:
- RTP dos itens: Itens dropados valem ~70% do entry fee (mesmo RTP das caixas)
- Economia de bots: Quando bot ganha (~50% das vezes), casa lucra 100% do entry fee real
| Categoria | House Edge Medio |
|---|---|
| PvP (sem bots) | 26.63% |
| vs Bots | 26.85% |
| SHARED | 27.49% |
FLIP vs NORMAL nao muda o house edge significativamente. Multi-round tem variance maior mas EV similar.
Arquivos Relacionados
| Arquivo | Descricao |
|---|---|
scripts/rtp-simulation.ts | Script de simulacao (TypeScript) |
docs/RTP_ANALYSIS.md | Relatorio gerado pela simulacao |
src/application/services/provably-fair.service.ts | calculateRoll real |
src/application/services/upgrade-probability.service.ts | Formula de upgrade real |
src/application/services/flip.service.ts | FLIP threshold e selecao |
src/application/use-cases/battle/execute-battle.use-case.ts | Settlement de batalhas |
src/application/services/probability.service.ts | HASH_MAX e ranges |
