Jogo #16

Power Bingo

Volatilidade
Alta (Jackpots progressivos)
Grid
RTP

Game Design Document (GDD)

Jogo 16 - Power Bingo

Versão: 1.0 Data: 2026-04-03 Mercado: Brasil (Paraná - Lottopar) Referência Zitro: Power Mania (Bingo 4 Cartelas) Desenvolvedor: Oktop.AI - BuildSense Vertical


1. Resumo Executivo

Power Bingo é um jogo de vídeo-bingo de alta velocidade focado em jogadores "High Rollers" e veteranos que buscam ritmo acelerado de jogo (Game Pace). O tema industrial/elétrico cria uma atmosfera de tensão e adrenalina.

Classificação


2. Identidade Visual e Atmosfera

Tema

Eletricidade Industrial - "A Máquina do Destino" - Referência: Cassinos de Las Vegas dos anos 1980, máquinas caça-níqueis clássicas com relés elétricos. - Cores Predominantes: Amarelo Neon, Preto Profundo, Vermelho Elétrico, Branco Brilhante. - Materiais Visuais: Metal cromado, vidro fumê, LED piscante.

Elementos Visuais Principais

  1. Fundo: Oficina de máquinas caça-níqueis clássicas. Paredes com painéis de controle. Luz vermelha piscante no canto superior (alerta de prêmio).
  2. Cartelas: Apresentadas em grade 5x3 (5 colunas x 3 linhas = 15 números cada). Números em fonte Sans-Serif Bold Tamanho 32px. Fundo cinza-escuro com borda dourada. Números marcados em Neon Verde ou Vermelho que pisca.
  3. Bolas: Animadas caindo em cascata. Som de bolas de plástico colidindo (ASMR). Tamanho da bola: escala visual que ocupa ~8% da tela.
  4. Painel de Sorteio: Display digital acima das cartelas mostrando o número sorteado em grande (Tamanho 48px). Animação de "pulse" (pulsação).

Paleta de Cores

Amarelo Neon: #FFFF00 Preto: #0A0A0A Vermelho Elétrico: #FF0033 Branco: #FFFFFF Verde Neon: #00FF00 Azul Profundo: #001A4D


3. Mecânica Core

3.1 Estrutura do Jogo

Cartelas Ativas: - 4 Cartelas Simultâneas - Formato: Grade 5×3 (5 colunas × 3 linhas) - Total: 15 números por cartela - Universo de Bolas: 90 (1 a 90)

Sorteio Inicial (Base): - 30 bolas sorteadas em 3.0 segundos (Modo Turbo Fixo) - Velocidade: 10 bolas por segundo (animação contínua) - Som de contagem de moedas paralelo à animação

Fase de Bolas Extras: - Disponível quando há chance de prêmio > 10x a aposta inicial - Máximo permitido: 10 bolas extras - Custo por bola extra: Dinâmico (Vide seção 3.4) - Cada bola extra é um "Mini-Bet" independente no Pool

3.2 Padrões Vencedores e Tabela de Pagamentos

Padrão Descrição Multiplicador Prêmio (Base R$10)
Bingo Completo Cartela inteira preenchida 1500x R$ 15.000,00
Perímetro (Moldura) 12 números da borda 500x R$ 5.000,00
Linha Dupla 2 linhas completas (6 números) 100x R$ 1.000,00
Linha Simples 1 linha completa (3 números) 50x R$ 500,00
Diagonal Completa 5 números (cantos + centro) 25x R$ 250,00
Quadra (4 Cantos) Cantos: posição [0,0], [0,4], [2,0], [2,4] 15x R$ 150,00
Coluna (3 números verticais) 3 números em coluna 10x R$ 100,00

3.3 Bolas Extras (Critical Revenue Driver)

Trigger de Oferta: O jogo oferece Bolas Extras quando: - Jogador está "armado" (faltando apenas 1-2 números para prêmio > 50x) - Cartela em padrão "Near Miss" controlado - Nunca oferecido se a probabilidade matemática de ganho é baixa

Custo Dinâmico - Fórmula de Precificação:

``` PreçoBola = (PrêmioEmRisco × ProbabilidadeGanho) × (1 + MargemVolatilidade)

Onde: - PrêmioEmRisco: Prêmio se a bola extra completar o padrão - ProbabilidadeGanho: Probabilidade de a bola necessária sair (1 / NúmerosBallasRestantes) - MargemVolatilidade: Fator ajustável (0.20 a 0.50, default 0.35) ```

Exemplos Práticos: 1. Jogador falta 1 número para Bingo (Prêmio R$ 1.500,00) - Bolas restantes no universo: 60 - Prob: 1/60 = 1.67% - Custo = (1.500 × 0.0167) × 1.35 = R$ 33,75

  1. Jogador falta 1 número para Linha Dupla (Prêmio R$ 100,00)
  2. Bolas restantes: 50
  3. Prob: 1/50 = 2%
  4. Custo = (100 × 0.02) × 1.35 = R$ 2,70

Processamento da Bola Extra (Backend):

Cada compra de bola extra é tratada como uma Nova Aposta Independente no Pool Lottopar:

  1. Sistema debita do saldo do jogador: Valor da bola
  2. Sistema sorteia um Novo Bilhete do Pool
  3. Três Cenários Possíveis:

Cenário A (Bilhete Perdedor): - O sistema sorteia qualquer bola que NÃO seja a necessária - Jogador vê frustração visual (animação de "falha") - Pode comprar outra bola (até 10 no total)

Cenário B (Bilhete Vencedor - Jackpot): - O sistema sorteia exatamente o número faltante - Jogador ganha o acumulado (prêmio base + multiplicador de cascata)

Cenário C (Bilhete Pequeno - Proteção Matemática): - Se o jogador comprou bola para completar Jackpot, o bilhete sorteia perdedor - A máquina NUNCA libera a bola necessária se não houver bilhete de Jackpot - Comportamento: Oferece bolas inúteis até atingir limite de 10

Proteção contra Fraude (Constraint Validation): IF PrizeValue(CompletingPattern) > TicketWinAmount THEN NeverReturnRequiredBall() AND DistributeLossingBalls() ELSE ReturnBallWithProperOdds()

3.4 Bola Z (Coringa - Wildcard)

Aparição: - Aparece aleatoriamente entre as 10 bolas extras (nunca no sorteio inicial) - Probabilidade: ~15% (1.5 aparições por sessão de 10 extras)

Funcionalidade: - Permite ao jogador escolher manualmente qual número marcar - Efeito visual: Bola brilhante com símbolo de "Z" piscante

Lógica de Validação (Critical): O jogo SÓ permite clicar em números que resultem em prêmios autorizados pelo bilhete: - O UI renderiza apenas números que levam a ganhos válidos - Números que causariam "over-win" aparecem desativados (greyed out)

Preço da Bola Z: PreçoBola_Z = PrêmioEmRisco × 0.85 (Aplicar desconto de 15% pois garante 100% de acerto)


4. Bônus: "Z-Power" (Pick'em com Modificador)

4.1 Gatilho

Formar o padrão Perímetro (moldura completa: 12 números da borda da cartela).

4.2 Mecânica

Fase 1 - Apresentação: - Tela fica escura. Som de "relé elétrico" ativa. - Painel de controle aparece com 12 botões iluminados (estilo botão de máquina de pinball). - Narrador grita: "PODER ATIVADO! ESCOLHA SUA SORTE!"

Fase 2 - Pick'em: - Jogador clica em 4 dos 12 botões sequencialmente - Cada botão revela: - Valor instantâneo em dinheiro (R$ 20 a R$ 500) - Símbolo especial: "⚡ MULTIPLICADOR" (dobrará todos os valores seguintes) - Símbolo de "FIM" (CAVEIRA ou BOBO DA CORTE) - Encerra o bônus

Fase 3 - Acumulação: - Os valores selecionados são somados com aplicação de multiplicadores - Total do bônus adicionado ao prêmio base

4.3 Estrutura de Valores (Exemplo)

``` Botões Ordenados (servidor define previamente): [20, 20, MULT_2x, MULT_3x, 50, 50, 100, GAME_OVER, 200, 500, 10, MULT_5x]

Exemplo de Sequência Vencedora: 1. Clique 1: Revela "50" → Total = 50 2. Clique 2: Revela "MULT_2x" → Multiplicador ativo 3. Clique 3: Revela "100" → Total = 50 + (100 × 2) = 250 4. Clique 4: Revela "GAME_OVER" → Bônus Encerra

Final: R$ 250,00 adicionados ao saldo ```

4.4 Áudio do Bônus


5. Engenharia de RTP e Volatilidade

5.1 Target RTP

5.2 Decomposição de RTP

``` RTP Total = 94%

Componentes: ├─ Prêmios Base (Padrões): 75% ├─ Bolas Extras (Vendidas): 12% ├─ Bônus Z-Power: 5% └─ Efeito de Acumulação: 2% ```

5.3 Volatilidade Controlada

O jogo usa "Near Miss" controlado para induzir compra de bolas:

Algoritmo de Tensão: 1. Se bilhete do Pool = R$ 0,00 (Perdedor): - Gerador de cartelas preenche propositalmente a cartela - Após 30 bolas iniciais, falta apenas 1 número para prêmio grande - Trigger: Máquina oferece Bola Extra 2. Se bilhete do Pool = Valor Alto (Vencedor): - Gerador assegura que o padrão alvo seja completado naturalmente - Bolas extras são "graça" adicional


6. Simulação Financeira (30 Dias)

Perfil de Jogador

Métricas Operacionais

Duração do Sorteio: 3.0 segundos (Turbo Mode) Intervalo entre Sorteios: 2.0 segundos (Pausa + UI) Ciclo Total por Rodada: 5.0 segundos Rodadas por Sessão (45 min): 540 rodadas Rodadas por Mês (2-3 vezes/semana): 7.560 rodadas

Projeção Mensal

``` Aposta Média por Rodada: R$ 20,00 Total de Rodadas (30 dias): 7.560 Coin-In Mensal (Rotação): R$ 151.200,00

Bolas Extras (15% das rodadas): └─ Rodadas com Extra: 1.134 └─ Bolas por Rodada: 2,5 (média) └─ Valor Médio por Bola: R$ 5,50 └─ Revenue Bolas: R$ 15.618,00

TOTAL COIN-IN: R$ 166.818,00

GGR (Gross Gaming Revenue) @ 94% RTP: └─ GGR = Coin-In × (1 - RTP) └─ GGR = 166.818 × 0.06 └─ GGR MENSAL: R$ 10.009,08

GGR ANUAL (12 meses): R$ 120.108,96 ```

Comparativo com Outros Jogos (Portfolio Context)


7. Áudio Design (O "Canto" das Bolas)

7.1 Voz e Narração (Critical Component)

Ator de Voz: Homem grave (40-50 anos), tom empolgado, sotaque misto (PR/SP)

Frases-Chave (Gravadas): ``` Sorteio Inicial: ├─ "COMEÇOU! TRINTA BOLAS CAINDO!" ├─ "NÚMERO VINTE E CINCO!" ├─ "QUARENTA E DOIS!" └─ "SORTEIO COMPLETO!"

Padrões Vencedores: ├─ "LINHA SIMPLES!" (tom médio) ├─ "COLUNA PRONTA!" (tom elevado) ├─ "DIAGONAL!" (tom muito elevado) ├─ "LINHA DUPLA!" (grito entusiasmado) ├─ "PERÍMETRO ATIVO! BÔNUS LIBERADO!" (grito máximo) └─ "BIIIIINGO COMPLETO! JACKPOT!" (grito épico + efeito de sino)

Bolas Extras: ├─ "BOLA EXTRA! VOCÊ ESTÁ ARMADO!" ├─ "PRÓXIMA BOLA... CUSTA DEZ REAIS!" ├─ "BOLA Z! ESCOLHA SEU NÚMERO!" └─ "CONSEGUIU! GANHOU!"

Bônus Z-Power: ├─ "PODER ELÉTRICO ATIVADO!" ├─ "ESCOLHA SEU DESTINO!" └─ "MULTIPLICADOR ATIVO!" ```

7.2 Efeitos Sonoros (SFX)

Som das Bolas: Bolas de plástico colidindo (10-15 repetições, decay natural) Queda de Bola: "Plink!" em nota musical (Fá Sustenido) Marcação na Cartela: "Ding!" agudo (Dó Agudo) Bola Z (Especial): "Bzzzzzzzzt!" + reverb eletrônico Near Miss (Tensão): Buzzer contínuo crescente por 3 segundos Bônus Ativo: "Whoooosh!" + ar comprimido Multiplicador: "Zzzzap!" + efeito de corrente elétrica Jackpot/Bingo: Grande sino (Church Bell de 2 segundos) + aplausos digitais

7.3 Música de Fundo

Gênero: Eletrônico / Síntese Retrô (estilo Kraftwerk, Pin Ball FX) Tempo: 110 BPM Duração: Loop de 30 segundos Dinâmica: Aumenta intensidade quando: - Bola extra disponível - Bônus ativado - Multiplicador em efeito

Elementos: Sintetizador Base: Onda quadrada (80Hz, tom profundo) Hi-Hat Programado: "Tik-tik-tik" metronômico Melódico: Síntese FM (pad épico, tom maior) Dinâmica: Fade in/out com efeito de gate


8. Conformidade Lottopar e Regulatório

8.1 Licença e Certificação

8.2 Mensagens Obrigatórias

``` ANTES DO INÍCIO: "Este é um jogo de azar. Aposte apenas dinheiro que você pode perder. Para jogar é preciso ter 18 anos ou mais."

DURANTE BÔNUS: "Você está entrando em uma fase de bônus. Seus ganhos serão multiplicados. Você pode parar ou continuar."

PÓS-SESSÃO: "Você jogou por XXX minutos. Quer continuar?" (Requerimento de "Responsible Gambling") ```

8.3 Limite de Sessão

8.4 Auditoria de RTP


9. Especificações Técnicas (Resumo)

9.1 Plataforma

9.2 Performance

FPS Mínimo: 60 Latência de Input: < 50ms Tempo de Sorteio: 3.0s ± 0.1s Tempo de Carregamento: < 2s

9.3 Integração VltCore


10. Matriz de Testes (QA)

Critério Condição Resultado Esperado
Hit Rate 7.560 rodadas 45% ± 2%
Bola Extra Offer Armado para prêmio 100x+ Oferecida em 80%+ casos
Bola Z Appearance 10 bolas extras ~1.5 aparições
Bônus Z-Power Perímetro acionado Prêmio > 50 e < 500x
RTP Final 1M rodadas 94% ± 1%

11. Notas de Implementação

  1. Reverse Pattern Mapping: O servidor gera bilhetes PRIMEIRO, depois cartelas que não conflitem.
  2. Constraint Solver: Verificar colisões entre as 4 cartelas ao gerar números.
  3. Audio Sync: Usar FMOD ou Wwise para garantir sincronismo entre som e animação.
  4. Save State: Ao final de cada rodada, salvar estado em banco de dados local (SQLite).
  5. Visual Accessibility: Aumentar contraste de números em cartelas (WCAG AA mínimo).

Versão

v1.0 - 2026-04-03 Autor: BuildSense / Oktop.AI Status: Aprovado para Prototipagem

Technical Design Document (TDD)

Jogo 16 - Power Bingo

Versão: 1.0 Data: 2026-04-03 Mercado: Brasil (Paraná - Lottopar) Plataforma: VLT Cabinet + Hostinger Server Engine: Unity 2022 LTS + C# Backend


1. Visão Geral Técnica

Power Bingo opera sob o modelo Pool Finito (Lottopar), onde o servidor pré-define o prêmio de cada "bilhete" e a máquina cliente renderiza uma experiência aleatória que sempre converge para esse resultado.

Fluxo Crítico

1. Cliente aperta "GIRAR" 2. Cliente envia BET_REQUEST ao servidor 3. Servidor retorna TICKET_RESULT (Prêmio já decidido) 4. Cliente gera CARTELAS & BOLAS usando Constraint Solver 5. Cliente renderiza animação que "descobre" o prêmio pré-definido 6. Cliente registra resultado em AUDIT_LOG local 7. Cliente envia CONFIRMATION ao servidor


2. Sistema de Pool Finito (Reverse Pattern Mapping)

2.1 Arquitetura de Bilhetes

Ticket Structure (JSON) ```json { "ticket_id": "TKT-20260403-00001234", "timestamp": "2026-04-03T14:35:22Z", "session_id": "SESSION-ABC123", "player_id": "PLAYER-XYZ789",

"bet_amount": 20.00, "currency": "BRL",

"prize_tier": "DOUBLE_LINE", "prize_amount": 100.00, "rtp_classification": 0.94,

"winning_pattern": { "type": "DOUBLE_LINE", "cartela_index": 1, "lines": [[0, 1, 2], [3, 4, 5]], "ball_count": 8 },

"extra_ball_metadata": { "allow_extra_balls": true, "max_extra_balls": 10, "extra_ball_cost_formula": "DYNAMIC_ODDS", "z_ball_allowed": true, "z_ball_appearance_chance": 0.15 },

"bonus_metadata": { "bonus_trigger": "PERIMETER_PATTERN", "bonus_prize": null, "bonus_sequence": [] },

"seed": "ABCDEF1234567890", "signature": "SHA256(ticket_json + server_secret_key)" } ```

2.2 Algoritmo de Engenharia Reversa (Reverse Builder)

Cenário Concreto: ``` Entrada: - Bilhete do Pool: Prêmio = R$ 100,00 - Padrão-Alvo: "Linha Dupla" (paga R$ 100,00 exatamente) - Cartelas Disponíveis: 4

Execução (Algoritmo Server-Side): 1. Seleção do Alvo: WINNING_CARTELA = Random(1, 4) = Cartela 2

  1. Geração de Números da Cartela (Aleatória): Cartela 2 = [05, 12, 33, 18, 41, 27, 09, 15, 50, 62, 74, 88, 11, 39, 77]

  2. Identificação do Padrão-Alvo: Linha 1 = [05, 12, 33] Linha 2 = [18, 41, 27] Padrão-Alvo = Linhas 1 e 2 = [05, 12, 33, 18, 41, 27]

  3. Rigging das Bolas (Critical Logic): REQUIRED_BALLS = [05, 12, 33, 18, 41, 27] (6 números) DRAWN_BALLS = [] (começar vazio)

// Garante que as bolas necessárias saem FOR each number IN REQUIRED_BALLS: DRAWN_BALLS.append(number)

// Preenche com bolas aleatórias (sem conflito) REMAINING_BALLS = [01, 02, 03, ... 90] - REQUIRED_BALLS - DRAWN_BALLS FOR i = 1 to (30 - 6): DRAWN_BALLS.append(Random(REMAINING_BALLS))

DRAWN_BALLS = Shuffle(DRAWN_BALLS) // Desordena para parecer aleatório

  1. Validação de Constraint (Anti-Collision): FOR each CARTELA IN [1, 2, 3, 4]: IF CARTELA == WINNING_CARTELA: CONTINUE

    FOR each PATTERN IN ["FULL_BINGO", "PERIMETER"]: IF PatternMatches(CARTELA, DRAWN_BALLS): // ERRO! Outra cartela não deveria vencer // Remover bolas aleatoriamente e recalcular FOR j = 0 to 100: DRAWN_BALLS = RegenerateWithoutConflict(DRAWN_BALLS, CARTELA) IF NOT PatternMatches(CARTELA, DRAWN_BALLS): BREAK

  2. Renderização: Cliente recebe DRAWN_BALLS e renderiza a animação Resultado "aleatório" = R$ 100,00 (Linha Dupla na Cartela 2)

Saída: - 30 bolas são sorteadas na ordem: [07, 45, 05, 23, 12, 61, 33, ...] - Cartela 2 completa as 2 linhas no bola #7 - Jogador vê "LINHA DUPLA!" no visor - Ganho: R$ 100,00 ```

2.3 Constraint Solver (Classe C#)

```csharp public class BingoConstraintSolver { private List[] cartelas = new List[4]; private HashSet drawnBalls = new HashSet(); private int maxRetries = 100;

public List<int> GenerateBallSequence(
    int[] requiredBalls,
    int winningCartelaIndex,
    int totalBallsToGenerate = 30)
{
    List<int> ballSequence = new List<int>();

    // Adiciona as bolas necessárias primeiro
    ballSequence.AddRange(requiredBalls);

    // Preenche com bolas aleatórias
    Random rng = new Random();
    HashSet<int> usedBalls = new HashSet<int>(requiredBalls);

    while (ballSequence.Count < totalBallsToGenerate)
    {
        int randomBall = rng.Next(1, 91);
        if (!usedBalls.Contains(randomBall))
        {
            ballSequence.Add(randomBall);
            usedBalls.Add(randomBall);
        }
    }

    // Embaralha para parecer aleatório
    Fisher_YatesShuffle(ballSequence);

    // Validação de conflitos
    int retryCount = 0;
    while (!ValidateNoAccidentalWins(ballSequence, winningCartelaIndex)
           && retryCount < maxRetries)
    {
        ballSequence.RemoveAt(rng.Next(requiredBalls.Length, ballSequence.Count));
        ballSequence.Add(rng.Next(1, 91));
        Fisher_YatesShuffle(ballSequence);
        retryCount++;
    }

    return ballSequence;
}

private bool ValidateNoAccidentalWins(List<int> balls, int expectedWinner)
{
    for (int i = 0; i < 4; i++)
    {
        if (i == expectedWinner) continue;

        foreach (string pattern in new[] { "FULL_BINGO", "PERIMETER", "DOUBLE_LINE" })
        {
            if (PatternMatches(cartelas[i], balls, pattern))
            {
                return false; // Conflito detectado
            }
        }
    }
    return true;
}

private void Fisher_YatesShuffle(List<int> list)
{
    Random rng = new Random();
    for (int i = list.Count - 1; i > 0; i--)
    {
        int randomIndex = rng.Next(i + 1);
        // Swap
        int temp = list[i];
        list[i] = list[randomIndex];
        list[randomIndex] = temp;
    }
}

} ```


3. Sistema de Bolas Extras (Dynamic Pricing)

3.1 Fórmula de Precificação

``` PreçoBola = (PrêmioEmRisco × ProbabilidadeAcerto) × (1 + MargemVolatilidade)

Definições: - PrêmioEmRisco: Prêmio que será obtido se a bola necessária sair - ProbabilidadeAcerto: 1 / (BolasRestantesNoUniverso) - MargemVolatilidade: Fator de ajuste de rentabilidade (0.20 a 0.50) ```

3.2 Classe de Precificação (C#)

```csharp public class ExtraBallPricingEngine { private const int TOTAL_BALLS = 90; private const float DEFAULT_MARGIN = 0.35f;

public decimal CalculateExtraBallPrice(
    decimal prizeAtRisk,
    int ballsAlreadyDrawn,
    int missingNumbersCount,
    float volatilityMargin = DEFAULT_MARGIN)
{
    // Bolas restantes no universo
    int remainingBalls = TOTAL_BALLS - ballsAlreadyDrawn;

    if (remainingBalls <= 0)
        return 0m; // Segurança

    // Probabilidade de acerto (apenas UM número é necessário)
    float probability = 1f / remainingBalls;

    // Aplicar penalidade se faltam múltiplos números
    if (missingNumbersCount > 1)
    {
        probability /= missingNumbersCount;
    }

    // Fórmula base
    decimal basePrice = prizeAtRisk * (decimal)probability;

    // Aplicar margem de volatilidade
    decimal finalPrice = basePrice * (1m + (decimal)volatilityMargin);

    // Arredondar para centavos (BRL)
    return Math.Ceiling(finalPrice * 100m) / 100m;
}

public Dictionary<string, decimal> GetPriceScenarios(decimal prizeAtRisk)
{
    var scenarios = new Dictionary<string, decimal>();

    // Simulação de diferentes estados
    scenarios["60_balls_drawn_1_missing"] = CalculateExtraBallPrice(prizeAtRisk, 60, 1);
    scenarios["70_balls_drawn_1_missing"] = CalculateExtraBallPrice(prizeAtRisk, 70, 1);
    scenarios["75_balls_drawn_1_missing"] = CalculateExtraBallPrice(prizeAtRisk, 75, 1);
    scenarios["80_balls_drawn_1_missing"] = CalculateExtraBallPrice(prizeAtRisk, 80, 1);
    scenarios["85_balls_drawn_2_missing"] = CalculateExtraBallPrice(prizeAtRisk, 85, 2);

    return scenarios;
}

}

// Exemplos de Uso: var engine = new ExtraBallPricingEngine();

// Cenário 1: Falta 1 para Jackpot (R$ 1.500) decimal price1 = engine.CalculateExtraBallPrice( prizeAtRisk: 1500m, ballsAlreadyDrawn: 60, missingNumbersCount: 1, volatilityMargin: 0.35f); // Resultado: R$ 33.75

// Cenário 2: Falta 1 para Linha Dupla (R$ 100) decimal price2 = engine.CalculateExtraBallPrice( prizeAtRisk: 100m, ballsAlreadyDrawn: 50, missingNumbersCount: 1, volatilityMargin: 0.35f); // Resultado: R$ 2.70 ```

3.3 Lógica de Processamento (Backend - Servidor Lottopar)

```csharp public class ExtraBallTransaction { public async Task ProcessExtraBallPurchase( string sessionId, string playerId, decimal ballCost) { // 1. Debitar do saldo var debitResult = await BankingService.Debit(playerId, ballCost); if (!debitResult.Success) return new ExtraBallResult { Success = false, Reason = "Saldo insuficiente" };

    // 2. Sortear novo bilhete do Pool Finito
    var newTicket = await LottoparPoolService.GetRandomTicket(RTP: 0.94f);

    // 3. Determinar qual bola será sorteada
    // (A bola é determinada pela estrutura do novo bilhete)

    int ballToDraw;

    if (newTicket.PrizeAmount > 0)
    {
        // Caso B: Bilhete Vencedor - Retorna a bola necessária
        ballToDraw = GetRequiredBall(sessionId);
    }
    else
    {
        // Caso A: Bilhete Perdedor - Retorna bola aleatória inútil
        ballToDraw = GetRandomUselessBall(sessionId);
    }

    // 4. Registrar no audit log
    await AuditLog.Record(new
    {
        event_type = "EXTRA_BALL_DRAWN",
        session_id = sessionId,
        player_id = playerId,
        ball_number = ballToDraw,
        ticket_id = newTicket.TicketId,
        prize = newTicket.PrizeAmount,
        timestamp = DateTime.UtcNow
    });

    // 5. Retornar resultado ao cliente
    return new ExtraBallResult
    {
        Success = true,
        BallNumber = ballToDraw,
        PrizeWon = newTicket.PrizeAmount,
        NewBalance = debitResult.NewBalance
    };
}

private int GetRequiredBall(string sessionId)
{
    var session = GameSessionCache.Get(sessionId);
    if (session.MissingNumbers.Count > 0)
    {
        return session.MissingNumbers[0]; // Retorna o número que completa o padrão
    }
    return Random.Next(1, 91); // Fallback
}

private int GetRandomUselessBall(string sessionId)
{
    var session = GameSessionCache.Get(sessionId);
    var allBalls = Enumerable.Range(1, 90).ToList();

    // Remove bolas que já foram sorteadas
    allBalls.RemoveAll(b => session.DrawnBalls.Contains(b));

    // Remove bolas que completariam algum prêmio
    allBalls.RemoveAll(b => WouldCompletePattern(b, session));

    if (allBalls.Count > 0)
    {
        return allBalls[Random.Next(allBalls.Count)];
    }

    // Fallback: Retorna qualquer bola (raro)
    return Random.Next(1, 91);
}

} ```


4. Detecção de Padrões Bingo

4.1 Enum de Padrões

csharp public enum BingoPattern { FULL_BINGO, // Cartela inteira (15 números) PERIMETER, // Moldura (12 números) DOUBLE_LINE, // 2 linhas (6 números) SINGLE_LINE, // 1 linha (3 números) DIAGONAL, // Diagonal (5 números) FOUR_CORNERS, // 4 cantos COLUMN // 1 coluna (3 números) }

4.2 Classe de Detector

```csharp public class BingoPatternDetector { // Representação: Cartela 5x3 (5 colunas, 3 linhas) private bool[,] marked = new bool[3, 5]; // [linha, coluna] private List[] cartelaNumbers = new List[15];

public BingoPattern CheckPattern(List<int> drawnBalls)
{
    // 1. Marcar números nas cartelas
    for (int i = 0; i < drawnBalls.Count; i++)
    {
        int ballNumber = drawnBalls[i];
        for (int pos = 0; pos < 15; pos++)
        {
            if (cartelaNumbers[0][pos] == ballNumber)
            {
                int row = pos / 5;
                int col = pos % 5;
                marked[row, col] = true;
            }
        }
    }

    // 2. Verificar padrões (ordem de importância)
    if (IsFullBingo()) return BingoPattern.FULL_BINGO;
    if (IsPerimeter()) return BingoPattern.PERIMETER;
    if (IsDoubleLine()) return BingoPattern.DOUBLE_LINE;
    if (IsDiagonal()) return BingoPattern.DIAGONAL;
    if (IsFourCorners()) return BingoPattern.FOUR_CORNERS;
    if (IsSingleLine()) return BingoPattern.SINGLE_LINE;
    if (IsColumn()) return BingoPattern.COLUMN;

    return null; // Nenhum padrão
}

private bool IsFullBingo()
{
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 5; j++)
            if (!marked[i, j]) return false;
    return true;
}

private bool IsPerimeter()
{
    // Topo: [0, 0] a [0, 4]
    for (int j = 0; j < 5; j++)
        if (!marked[0, j]) return false;

    // Fundo: [2, 0] a [2, 4]
    for (int j = 0; j < 5; j++)
        if (!marked[2, j]) return false;

    // Esquerda: [1, 0]
    if (!marked[1, 0]) return false;

    // Direita: [1, 4]
    if (!marked[1, 4]) return false;

    return true;
}

private bool IsDoubleLine()
{
    int completeLines = 0;
    for (int i = 0; i < 3; i++)
    {
        bool lineComplete = true;
        for (int j = 0; j < 5; j++)
        {
            if (!marked[i, j])
            {
                lineComplete = false;
                break;
            }
        }
        if (lineComplete) completeLines++;
    }
    return completeLines >= 2;
}

private bool IsSingleLine()
{
    for (int i = 0; i < 3; i++)
    {
        bool lineComplete = true;
        for (int j = 0; j < 5; j++)
        {
            if (!marked[i, j])
            {
                lineComplete = false;
                break;
            }
        }
        if (lineComplete) return true;
    }
    return false;
}

private bool IsDiagonal()
{
    // Diagonal principal: [0,0], [1,2], [2,4]
    return marked[0, 0] && marked[1, 2] && marked[2, 4];
}

private bool IsFourCorners()
{
    return marked[0, 0] && marked[0, 4] && marked[2, 0] && marked[2, 4];
}

private bool IsColumn()
{
    for (int j = 0; j < 5; j++)
    {
        if (marked[0, j] && marked[1, j] && marked[2, j])
            return true;
    }
    return false;
}

} ```


5. Integração VltCore.dll e Lottopar Pool

5.1 Interface de Comunicação

```csharp [DllImport("VltCore.dll")] public static extern int VLT_RequestTicket( int sessionId, decimal betAmount, out TicketResult ticketResult);

[DllImport("VltCore.dll")] public static extern int VLT_ValidateSignature( string ticketJson, string signature);

[DllImport("VltCore.dll")] public static extern int VLT_LogGameResult( int sessionId, string gameResult, decimal prizeAmount);

public struct TicketResult { public string TicketId; public decimal PrizeAmount; public int RTPPercentage; public string Signature; public long Timestamp; } ```

5.2 Fluxo de Requisição de Bilhete

```csharp public class GameLoopManager { private VltCoreInterface vltCore;

public async Task<GameResult> PlayRound(decimal betAmount)
{
    // 1. Solicitar bilhete ao Pool Lottopar via VltCore
    TicketResult ticket = await RequestTicketFromPool(betAmount);

    // 2. Validar assinatura (proteção contra fraude)
    if (!ValidateTicketSignature(ticket))
    {
        return new GameResult { Error = "Invalid ticket signature" };
    }

    // 3. Gerar cartelas e bolas usando Constraint Solver
    var solver = new BingoConstraintSolver();
    var ballSequence = solver.GenerateBallSequence(
        requiredBalls: ExtractWinningPattern(ticket),
        winningCartelaIndex: ticket.WinningCartelaIndex);

    // 4. Renderizar animação
    await AnimateGamePlay(ballSequence);

    // 5. Detectar padrão vencedor
    var detector = new BingoPatternDetector();
    var winningPattern = detector.CheckPattern(ballSequence);

    // 6. Registrar resultado no audit log local
    await SaveGameResultLocally(ticket, winningPattern, ballSequence);

    // 7. Confirmar ao servidor
    await ConfirmGameResultToServer(ticket, winningPattern);

    return new GameResult
    {
        TicketId = ticket.TicketId,
        WinningPattern = winningPattern,
        PrizeAmount = ticket.PrizeAmount,
        Success = true
    };
}

} ```

5.3 Protocolo SAS/G2S

``` Comunicação utiliza SAS (Slot Accounting System) com autenticação por chave pública:

Packet Format: ┌────────┬─────────────┬──────────┬──────────┬─────────┐ │ Header │ Session ID │ Sequence │ Payload │ Checksum│ │ 1 byte │ 4 bytes │ 2 bytes │ Variable │ 2 bytes │ └────────┴─────────────┴──────────┴──────────┴─────────┘

Encriptação: AES-256-CBC Autenticação: HMAC-SHA256

Certificado SSL: Válido por 2 anos, renovado automaticamente ```


6. Banco de Dados Local (SQLite)

6.1 Schema

```sql CREATE TABLE IF NOT EXISTS game_sessions ( session_id TEXT PRIMARY KEY, player_id TEXT NOT NULL, start_time DATETIME DEFAULT CURRENT_TIMESTAMP, end_time DATETIME, total_coin_in DECIMAL(10, 2) DEFAULT 0, total_payout DECIMAL(10, 2) DEFAULT 0, rtp_actual DECIMAL(5, 2), FOREIGN KEY (player_id) REFERENCES players(player_id) );

CREATE TABLE IF NOT EXISTS game_rounds ( round_id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL, ticket_id TEXT UNIQUE NOT NULL, bet_amount DECIMAL(10, 2) NOT NULL, prize_amount DECIMAL(10, 2) NOT NULL, winning_pattern TEXT, cartela_1 TEXT, -- JSON de números cartela_2 TEXT, cartela_3 TEXT, cartela_4 TEXT, drawn_balls TEXT, -- JSON de números em ordem extra_balls_purchased INTEGER DEFAULT 0, extra_balls_cost DECIMAL(10, 2) DEFAULT 0, bonus_triggered BOOLEAN DEFAULT FALSE, bonus_prize DECIMAL(10, 2), timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (session_id) REFERENCES game_sessions(session_id) );

CREATE TABLE IF NOT EXISTS extra_ball_transactions ( transaction_id INTEGER PRIMARY KEY AUTOINCREMENT, round_id INTEGER NOT NULL, ball_number INTEGER, cost DECIMAL(10, 2), result VARCHAR(50), -- "WIN" | "LOSS" timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (round_id) REFERENCES game_rounds(round_id) );

CREATE TABLE IF NOT EXISTS audit_log ( log_id INTEGER PRIMARY KEY AUTOINCREMENT, event_type VARCHAR(50) NOT NULL, session_id TEXT, details TEXT, -- JSON timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (session_id) REFERENCES game_sessions(session_id) );

-- Índices para Performance CREATE INDEX idx_sessions_player ON game_sessions(player_id); CREATE INDEX idx_rounds_session ON game_rounds(session_id); CREATE INDEX idx_audit_timestamp ON audit_log(timestamp); ```

6.2 Classe de Persistência

```csharp public class LocalGameDataStore { private const string DB_PATH = "game_data.db";

public void SaveGameRound(GameRound round)
{
    using (var connection = new SQLiteConnection($"Data Source={DB_PATH}"))
    {
        connection.Open();

        string query = @"
            INSERT INTO game_rounds
            (session_id, ticket_id, bet_amount, prize_amount, winning_pattern,
             cartela_1, cartela_2, cartela_3, cartela_4, drawn_balls,
             extra_balls_purchased, extra_balls_cost, bonus_triggered, bonus_prize)
            VALUES
            (@sessionId, @ticketId, @betAmount, @prizeAmount, @pattern,
             @c1, @c2, @c3, @c4, @balls,
             @extraCount, @extraCost, @bonusTriggered, @bonusPrize)
        ";

        using (var command = new SQLiteCommand(query, connection))
        {
            command.Parameters.AddWithValue("@sessionId", round.SessionId);
            command.Parameters.AddWithValue("@ticketId", round.TicketId);
            command.Parameters.AddWithValue("@betAmount", round.BetAmount);
            command.Parameters.AddWithValue("@prizeAmount", round.PrizeAmount);
            command.Parameters.AddWithValue("@pattern", round.WinningPattern.ToString());
            command.Parameters.AddWithValue("@c1", JsonConvert.SerializeObject(round.Cartelas[0]));
            command.Parameters.AddWithValue("@c2", JsonConvert.SerializeObject(round.Cartelas[1]));
            command.Parameters.AddWithValue("@c3", JsonConvert.SerializeObject(round.Cartelas[2]));
            command.Parameters.AddWithValue("@c4", JsonConvert.SerializeObject(round.Cartelas[3]));
            command.Parameters.AddWithValue("@balls", JsonConvert.SerializeObject(round.DrawnBalls));
            command.Parameters.AddWithValue("@extraCount", round.ExtraballsPurchased);
            command.Parameters.AddWithValue("@extraCost", round.ExtraBallsCost);
            command.Parameters.AddWithValue("@bonusTriggered", round.BonusTriggered);
            command.Parameters.AddWithValue("@bonusPrize", round.BonusPrize ?? (object)DBNull.Value);

            command.ExecuteNonQuery();
        }
    }
}

public void SaveAuditLog(AuditEvent auditEvent)
{
    using (var connection = new SQLiteConnection($"Data Source={DB_PATH}"))
    {
        connection.Open();

        string query = @"
            INSERT INTO audit_log (event_type, session_id, details)
            VALUES (@eventType, @sessionId, @details)
        ";

        using (var command = new SQLiteCommand(query, connection))
        {
            command.Parameters.AddWithValue("@eventType", auditEvent.EventType);
            command.Parameters.AddWithValue("@sessionId", auditEvent.SessionId);
            command.Parameters.AddWithValue("@details", JsonConvert.SerializeObject(auditEvent));

            command.ExecuteNonQuery();
        }
    }
}

} ```


7. Especificações de Hardware

7.1 Requisitos Mínimos

CPU: Intel i5-8400 ou AMD Ryzen 5 2600 (6 cores) RAM: 8 GB DDR4 GPU: NVIDIA GeForce GTX 1050 Ti ou equivalente (Suporta DirectX 11, 2 GB VRAM) Storage: SSD 256 GB (NVMe recomendado) Monitor: 1280×1024 @ 60 Hz (cabine padrão) Conectividade: Gigabit Ethernet (com fallback para WiFi 5GHz) Audio: Stereo Speaker Array (5W RMS)

7.2 Versão Recomendada (Optimizada)

CPU: Intel i7-10700K ou AMD Ryzen 5 5600X RAM: 16 GB DDR4 @ 3200 MHz GPU: NVIDIA GeForce RTX 3060 Ti Storage: 500 GB NVMe SSD Redundância: RAID 1 (Mirror) para dados críticos UPS: Uninterruptível 1000W (15 min autonomia)

7.3 Conectividade

Rede Primária: Ethernet Gigabit (1 Gbps) → Hostinger Server Rede Secundária: WiFi 5GHz 802.11ac (failover automático) VPN: Tailscale Mesh (encriptação automática) Firewall: UFW (Uncomplicated Firewall) Política: Bloqueio de tráfego inbound, liberação de saída para Lottopar


8. Protocolo SAS/G2S Detalhado

8.1 Autenticação

``` Handshake (SSL TLS 1.2+): 1. Client: HELLO + ClientRandom + Supported Ciphers 2. Server: HELLO + ServerRandom + Selected Cipher 3. Client: ClientKeyExchange (RSA 2048-bit) 4. Server: ServerKeyExchange (ECDHE para PFS) 5. Ambos: Finished (HMAC de toda conversa)

Certificado Server: ├─ CN: lottopar-vlt.gameserver.br ├─ SAN: *.gameserver.br ├─ Validade: 2 anos ├─ Assinado por: GeoTrust Global CA └─ Pinning: SHA256 hash salvo no cliente para bypass de MITM ```

8.2 Estrutura de Mensagem

``` ┌─────────────────────────────────────────┐ │ Message Header (12 bytes) │ ├─────────────────────────────────────────┤ │ Byte 0-1: Sync Word (0x4142 = "AB") │ │ Byte 2-3: Message Type (0x0001 = Bet) │ │ Byte 4-7: Sequence Number │ │ Byte 8-11: Message Length │ ├─────────────────────────────────────────┤ │ Message Body (Variable) │ ├─────────────────────────────────────────┤ │ Message Type: BET_REQUEST │ │ { │ │ "session_id": "SES-12345", │ │ "player_id": "PLY-67890", │ │ "game_id": 16, │ │ "bet_amount": 20.00, │ │ "currency": "BRL" │ │ } │ ├─────────────────────────────────────────┤ │ Checksum (4 bytes): CRC-32 │ └─────────────────────────────────────────┘

Resposta (TICKET_RESPONSE): { "status": "OK", "ticket": { "ticket_id": "TKT-20260403-00001234", "prize_amount": 100.00, "timestamp": "2026-04-03T14:35:22Z", "signature": "SHA256(ticket_json + key)" } } ```


9. Performance e Otimização

9.1 Métricas de Teste

FPS Target: 60 fps (16.67 ms por frame) Latência de Input: < 50 ms (entre botão e resposta) Tempo de Sorteio: 3.0 ± 0.1 segundos Tempo de Carregamento: < 2.0 segundos Ping ao Servidor: < 150 ms (critério de gameplay)

9.2 Profiling (Unity Profiler)

Frame Time Budget (16.67 ms): ├─ Rendering: 8.0 ms (48%) ├─ Scripting: 4.5 ms (27%) ├─ Physics: 2.0 ms (12%) ├─ Audio: 1.5 ms (9%) ├─ Garbage: 0.7 ms (4%) └─ Reserve: > 1.0 ms

9.3 Memory Management

Heap Size Requerido: 512 MB GC Frequency: Evitar em loop crítico (Game Pace) GC.Alloc Zones: Pré-alocado em Initialization Object Pooling: BallAnimator (30 instances) Texture Streaming: LOD0 = 256px, LOD1 = 128px


10. Testes de Validação (QA)

10.1 Casos de Teste Críticos

Teste Entrada Saída Esperada Critério Aceição
T001 1M rodadas RTP = 94% Desvio < ±1%
T002 Cartelas com conflito Constraint resolvido 100% sem erros
T003 Bola Extra oferecida Preço dentro ±5% Validação matemática
T004 Padrão detectado Prêmio correto Pagamento = Bilhete
T005 Extra ball ganho Bilhete sorteado vencedor Sincronismo 100%

10.2 Stress Test

Cenário: 24h de jogo contínuo ├─ Rodadas por Segundo: 12 (5s por rodada) ├─ Total de Rodadas: ~1M ├─ Picos de CPU: 70-80% ├─ Vazamento de Memória: < 5 MB/hora └─ Crash Rate: 0%


11. Segurança e Conformidade

11.1 Proteções Implementadas

✓ Validação de assinatura de bilhete (SHA256) ✓ Encriptação AES-256 de transmissão ✓ Audit log imutável (append-only) ✓ Rate limiting: 20 rodadas/min por sessão ✓ Detecção de anomalia: Desvio RTP > 5% ✓ Validação de limites: Máx R$ 5000/dia por jogador

11.2 Requisitos Lottopar

Document: Lottopar Regulation 2024 ├─ RTP: 90%-97% ├─ Auditoria: Semanal (10k rodadas) ├─ Retenção de Dados: 90 dias mínimo ├─ Certificação RNG: INMETRO ou equiv. ├─ Reporte de Incidentes: < 24 horas └─ Inspeção Física: Semestral


12. Plano de Rollout

Fase 1: Prototipagem (Semana 1-2)

Fase 2: Hardening (Semana 3-4)

Fase 3: Closed Beta (Semana 5-6)

Fase 4: Go Live (Semana 7+)


Versão

v1.0 - 2026-04-03 Arquiteto: Backend - Oktop.AI Status: Pronto para Implementação

Prompts de Geração de Arte IA

Clique em qualquer prompt para copiar. Os prompts abaixo são otimizados para Midjourney v6, DALL-E 3, e Stable Diffusion.

🎨 Cenário Principal
Proporção: 16:9
Professional slot game art, High-energy bingo hall, ultra-detailed environment, immersive 3D background, lush vegetation and natural elements, energetic, powerful, winning, cinematic lighting with golden hour sun rays, color palette: electric yellow, power blue, energetic orange, depth of field creating focal point on game area, hyper-realistic textures, trending on ArtStation, Unreal Engine 5 quality, vibrant and saturated colors, --ar 21:9 --quality 2 --style raw
Dica: Use --no 'text, watermark, logo' para melhor resultado
🏷️ Logo/Título
Proporção: 16:9
Logo design for "Power Bingo", ornate and elegant typography, bold letters with gold leaf embossing, luxurious gradient background transitioning from electric yellow to power blue, intricate decorative borders with bingo balls motifs, 3D dimensional effect with shadow depth, cinematic lighting, professional branding, high contrast, designed for high-visibility gaming cabinet, --ar 16:9 --quality 2 --style raw
Dica: Use --no 'text, watermark, logo' para melhor resultado
🎰 Símbolo 1
Proporção: 1:1
Premium game symbol for slot machine, bingo balls creature highly detailed, photorealistic rendering, vibrant colors emphasizing electric yellow, power blue, energetic orange, centered composition with transparent background, dramatic lighting with golden highlights, intricate feather/fur textures, 3D depth, game-ready asset, --ar 1:1 --quality 2 --style raw
Dica: Use --no 'text, watermark, logo' para melhor resultado
🎰 Símbolo 2
Proporção: 1:1
Game symbol: numbers, ornate design with electric yellow, power blue, energetic orange color scheme, highly detailed intricate patterns, luxurious appearance, centered on clean background, dimensional shadow effect, professional slot machine graphics, golden accents, --ar 1:1 --quality 2 --style raw
Dica: Use --no 'text, watermark, logo' para melhor resultado
🎰 Símbolo 3
Proporção: 1:1
Collectible symbol: power symbols, sparkling crystal or gem-like appearance, electric yellow and power blue dominant colors, glowing effect with light rays, highly detailed with reflective surfaces, centered composition, professional gaming asset quality, --ar 1:1 --quality 2 --style raw
Dica: Use --no 'text, watermark, logo' para melhor resultado
🎰 Símbolo 4
Proporção: 1:1
Bonus trigger symbol, lightning, animated energy radiating from center, multiple layers of glow effects in energetic orange, ornate frame decoration, detailed fine art illustration, professional casino game quality, shimmering and ethereal, --ar 1:1 --quality 2 --style raw
Dica: Use --no 'text, watermark, logo' para melhor resultado
🎰 Símbolo 5
Proporção: 1:1
Premium scatter symbol, luxurious golden coin with excitement imagery, embossed surface detail, reflection and dimension, surrounded by floating particles and light, rich electric yellow, power blue, energetic orange palette, high-end game graphics, professional quality, --ar 1:1 --quality 2 --style raw
Dica: Use --no 'text, watermark, logo' para melhor resultado
🎁 Tela de Bônus
Proporção: 16:9
Bonus round screen for slot game, explosive energy and celebration theme, multiple layers of special effects, electric yellow, power blue, energetic orange dominant colors, dramatic lighting with particle effects, progress bars and multiplier counters visible, luxurious animation frames, cinematic composition, game-ready quality, professional casino graphics, --ar 16:9 --quality 2 --style raw
Dica: Use --no 'text, watermark, logo' para melhor resultado
🖥️ Mockup UI
Proporção: 16:9
Complete game UI mockup for slot machine cabinet, professional layout with reels center stage, electric yellow, power blue, energetic orange theme throughout, game statistics visible (RTP, lines, bet), ornate frame decoration, luxury gaming interface, clear typography, buttons and controls well-positioned, premium aesthetic, high contrast readability, arcade cabinet quality, --ar 16:9 --quality 2 --style raw
Dica: Use --no 'text, watermark, logo' para melhor resultado
Tela de Carregamento
Proporção: 21:9
Splash art loading screen for slot game, dramatic cinematic scene featuring bingo balls, intense energetic, powerful, winning atmosphere, electric yellow, power blue, energetic orange color palette, volumetric lighting effects, large title text with "Power Bingo", game studio logo placement, trending on gaming platforms, highly detailed and professionally rendered, advertisement-quality, --ar 21:9 --quality 2 --style raw
Dica: Use --no 'text, watermark, logo' para melhor resultado