Skip to content

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.

RTPSignificadoExemplo
100%Break EvenJogador 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 JogoRTP Tipico
Slots Online94-98%
Blackjack99%+
Roleta94-97%
Sites de Caixas CS70-85%

Script de Simulacao

Arquivo: scripts/rtp-simulation.ts (TypeScript, executado via tsx)

Parametros

typescript
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 factor

Como Executar

bash
npx tsx scripts/rtp-simulation.ts

Gera 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:

typescript
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 de substring(0, 8) (32 bits)
  • Retry com sufixo :retry na mensagem para overflow (maxSafeValue)
  • Resultado 1-based (+1), nao 0-based
  • Mensagem HMAC = ${clientSeed}:${nonce} (sem serverSeed na mensagem)

2. Selecao de Item

typescript
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:

typescript
// flipThreshold = menor hashRangeStart dos itens raros (COVERT/EXTRAORDINARY)
const flipThreshold = getFlipThreshold(caseItems);
const isFlip = roll >= flipThreshold;  // Se true, item ja e raro por definicao

NAO 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:

typescript
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:

CenarioTipoModoBotsDescricao
1v1 PvP NORMAL1v1NORMAL0Player vs Player, maior vence
1v1 PvP FLIP1v1FLIP0Player vs Player, menor vence
1v1 vs Bot NORMAL1v1NORMAL1Player vs Bot, maior vence
1v1 vs Bot FLIP1v1FLIP1Player vs Bot, menor vence
3v3 PvP NORMAL3v3NORMAL03 vs 3 players
3v3 PvP FLIP3v3FLIP03 vs 3 players
3v3 vs Bots NORMAL3v3NORMAL51 real + 5 bots
3v3 vs Bots FLIP3v3FLIP51 real + 5 bots
SHARED 2v2 PvP2v2SHARED04 players, todos ganham
SHARED 3v3 PvP3v3SHARED06 players, todos ganham
SHARED 3v3 vs Bots3v3SHARED51 real + 5 bots

Cada cenario roda com 1 e 3 rounds, e com 2 caixas diferentes (total: 44 combinacoes).

Fluxo de uma batalha simulada:

  1. Cada player abre 1 case por round (rolls independentes)
  2. Acumula valor por time (team1 = indices 0..N-1, team2 = indices N..2N-1)
  3. Determina vencedor baseado no modo:
    • NORMAL: time com maior valor total
    • FLIP: time com menor valor total
    • SHARED: todos os players vencem
  4. 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
  5. 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

FaixaStatusAcao
RTP > 100%CRITICOAjustar probabilidades imediatamente
RTP > 95%ATENCAOMargem muito baixa
RTP 65-85%SAUDAVELMargem ideal para a industria
RTP < 60%AGRESSIVOPode 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:

  1. RTP dos itens: Itens dropados valem ~70% do entry fee (mesmo RTP das caixas)
  2. Economia de bots: Quando bot ganha (~50% das vezes), casa lucra 100% do entry fee real
CategoriaHouse Edge Medio
PvP (sem bots)26.63%
vs Bots26.85%
SHARED27.49%

FLIP vs NORMAL nao muda o house edge significativamente. Multi-round tem variance maior mas EV similar.


Arquivos Relacionados

ArquivoDescricao
scripts/rtp-simulation.tsScript de simulacao (TypeScript)
docs/RTP_ANALYSIS.mdRelatorio gerado pela simulacao
src/application/services/provably-fair.service.tscalculateRoll real
src/application/services/upgrade-probability.service.tsFormula de upgrade real
src/application/services/flip.service.tsFLIP threshold e selecao
src/application/use-cases/battle/execute-battle.use-case.tsSettlement de batalhas
src/application/services/probability.service.tsHASH_MAX e ranges

Documentação Técnica - ProCases