Pular para o conteúdo

· 16 min de leitura

Soccer Deal: um manager de futebol em que a IA conversa e as regras decidem

Do Elifoot e do Brasfoot ao Soccer Deal: como construí um manager de futebol que roda no navegador, as ferramentas, a mecânica do jogo, o motor de decisão da partida e a IA por baixo das negociações, com a arquitetura explicada em C4.

Do Elifoot ao Brasfoot

Muita gente da minha geração aprendeu o que era um computador escalando um time de futebol. O Elifoot nasceu em Portugal, em 1987, criado por André Elias quando ainda era adolescente, e atravessou o oceano: as versões dos anos 90, como o Elifoot 98, rodavam em muito PC de escola, lan house e escritório no Brasil. Telas simples, nomes de clubes trocados, e horas e horas tentando levar um time pequeno à primeira divisão.

No começo dos anos 2000 veio o Brasfoot, com a cara do futebol brasileiro: campeonatos estaduais, Copa do Brasil, as séries do Brasileirão, salários, bilheteria, mercado. Foi o jogo de uma geração inteira, e muita amizade passou por discussões sobre qual era o melhor esquema para o time do coração.

Eu queria estudar mais e testar coisas novas, e um jogo assim era o projeto perfeito para isso. Além disso, havia algo nesses clássicos que sempre me incomodou: a contratação era um formulário. Você digitava um valor, o clube aceitava ou recusava, e pronto.

No futebol de verdade, contratar é conversar. O presidente do outro clube pechincha, blefa, faz drama, lembra que você o deixou na mão da última vez. Foi dessa vontade que nasceu o Soccer Deal: um manager de futebol em que cada contratação é uma negociação, uma homenagem a esses jogos com uma ferramenta que eles não tinham.

Um laboratório para a IA

O Soccer Deal também foi o meu laboratório para uma pergunta que me interessa como líder de tecnologia: onde a IA generativa realmente melhora um produto, e onde ela atrapalha? A resposta que encontrei virou a regra de ouro do projeto:

A IA conversa, as regras decidem.

Neste artigo eu conto como o jogo foi construído: as ferramentas, a mecânica, o motor que decide as partidas e a IA por baixo das conversas. Para a arquitetura, uso o modelo C4, do contexto até o código, sempre com diagramas.

As ferramentas

Assim como este site e o amardoar, o Soccer Deal foi construído em sessões com o Claude Code, o agente de programação da Anthropic, trabalhando direto no repositório. Eu descrevia a intenção e revisava cada entrega; a IA propunha, implementava, testava no navegador e abria o pull request. Foram mais de 50 pull requests em pouco mais de uma semana, cada um pequeno e revisado antes do merge.

A pilha é deliberadamente simples:

  • Eleventy 3 gera o site estático. Um passo depois do build dá a cada arquivo de estilo e de script um endereço que muda quando o conteúdo muda, para o cache nunca servir arquivo velho.
  • JavaScript puro, com módulos e sem framework. São cerca de 4.300 linhas divididas em telas, regras e motor da partida.
  • PHP 8.2 e MySQL na Hostinger para a pequena parte que precisa de servidor: o premium com IA, a conta e o jogo salvo na nuvem, com o SDK oficial da Anthropic e o PHPMailer.
  • Claude, pela API da Anthropic, para as falas dos presidentes, da imprensa e da diretoria. O modelo é configurável sem novo deploy; comecei com o Claude Opus em esforço baixo.
  • ElevenLabs para tudo o que é som e imagem gerada: efeitos do estádio, a música da abertura, o narrador com marcações de emoção, o vídeo da abertura e as ilustrações dos lances.
  • ffmpeg e cwebp para tratar esses arquivos: medir o volume de cada som, achar o ponto alto da música para sincronizar o escudo, comprimir o vídeo de 12,9 MB para 1,1 MB e recortar as ilustrações.
  • Testes automatizados da API, rodando o fluxo inteiro de conta, IA simulada e limites num servidor local, sem tocar em produção.

Arquitetura: o contexto

No nível mais alto do C4, o Soccer Deal tem uma pessoa e poucos vizinhos. O jogador usa o jogo no navegador. O jogo conversa com a API da Anthropic, manda o e-mail de entrada pelo SMTP da Hostinger e mede visitas no Google Analytics, só com consentimento.

C4 nível 1, contexto: o jogador usa o Soccer Deal, que conversa com a API da Anthropic, envia e-mail pelo SMTP da Hostinger e mede visitas no Google Analytics com consentimento. O ElevenLabs gera os sons, a música, os vídeos e as ilustrações antes, fora do jogo. Jogador [Pessoa] navegador ou celular Soccer Deal [Sistema de software] manager de futebol em que cada contratação é uma conversa joga Anthropic API [Sistema externo] modelos Claude SMTP da Hostinger [Sistema externo] e-mail do link de entrada Google Analytics [Sistema externo] só com consentimento fala dos personagens envia link visitas ElevenLabs [Ferramenta, fora do jogo] sons, música, vídeo e imagens arquivos gerados uma vez
Figura 1. C4, nível 1 (contexto): quem usa o Soccer Deal e com quais sistemas ele conversa. O ElevenLabs aparece tracejado porque trabalha antes, gerando arquivos, e não durante o jogo.

O ElevenLabs aparece tracejado de propósito. Ele não participa do jogo: trabalha antes, gerando arquivos que viram parte do site. Nenhum som é gerado enquanto você joga, o que deixa o custo do ElevenLabs fixo, e não proporcional ao número de jogadores.

Arquitetura: os contêineres

A decisão mais importante do projeto está no segundo nível: o jogo inteiro roda no navegador. Calendário, elenco, finanças, mercado, motor da partida e jogo salvo vivem no próprio navegador. Dá para jogar uma temporada inteira sem nenhuma chamada ao servidor.

C4 nível 2, contêineres: o site estático entrega o app que roda no navegador; o app guarda o jogo no localStorage e chama a API em PHP só para IA, conta e jogo salvo; a API usa o MySQL, a API da Anthropic e o SMTP. Soccer Deal [Sistema de software] App no navegador [JavaScript, módulos ES] telas, regras, motor da partida e jogo salvo no localStorage sem servidor de jogo Site estático [Eleventy, arquivos na Hostinger] HTML, CSS, JS com hash, sons, vídeos e ilustrações API [PHP 8.2, SDK oficial da Anthropic] premium com IA, limites, conta e jogo na nuvem JSON por HTTPS Banco de dados [MySQL; SQLite nos testes] contas (e-mail em hash), sessões, saves, uso da IA Anthropic API [Sistema externo] SMTP da Hostinger [Sistema externo] Messages API, saída em JSON Schema link de entrada Jogador [Pessoa] joga no navegador
Figura 2. C4, nível 2 (contêineres): o jogo inteiro roda no navegador. O servidor só entra no premium com IA, na conta e no jogo salvo na nuvem.

O servidor só aparece em três casos: quando a IA precisa falar, quando você entra na conta e quando a carreira sobe para a nuvem. Isso tem três consequências que eu queria:

  1. Custo perto de zero. Hospedar arquivos estáticos é barato, e o servidor não gasta nada com quem joga sem conta e sem premium.
  2. Velocidade. Cada clique responde na hora, porque não espera rede.
  3. A IA é opcional. Se a API da Anthropic sair do ar, o jogo continua, com falas prontas.

A mecânica do jogo

Você escolhe um clube da Série A, recebe a meta da diretoria e joga a temporada: Brasileirão com 38 rodadas, Série B com acesso e rebaixamento, o estadual do seu clube e a Copa do Brasil em mata-mata, com pênaltis. Os elencos partem de dados públicos; os clubes usam nomes alternativos e os presidentes são personagens fictícios, como nos clássicos que inspiraram o jogo.

Por baixo da tela, quatro sistemas se alimentam:

  • Elenco: cada jogador tem força, posição, condição física, moral e fase recente.
  • Dinheiro: bilheteria por jogo, direitos de TV, salários pagos todo mês, premiações e obras no estádio.
  • Confiança: quatro termômetros de 0 a 100, para diretoria, torcida, elenco e imprensa.
  • Mercado: janelas de transferência, com cada presidente tendo uma de seis personalidades (raposa velha, pragmático, vaidoso, pão-duro, endividado e emotivo) e uma memória de como você negociou com ele.

O motor de decisão da partida

A partida é decidida por um motor simples e explicável, que segue cinco etapas.

O motor da partida em cinco etapas: o rendimento de cada jogador, as forças do time por setor, os gols esperados de cada lado, o sorteio dos lances por tempo e a partida ao vivo, que encena esse plano. 1. Jogador força × condição × fase × moral cansado: até −20% fora de posição: −10% a −20% 2. Time três forças: ataque, meio e defesa o esquema define quem soma em cada uma 3. Gols esperados ataque contra a defesa rival, ao cubo mando de campo conforme a torcida e a postura 4. Sorteio Poisson, por tempo gols, chances, escanteios e faltas cada lance ganha o seu minuto 5. Ao vivo a partida encena o plano trocou postura ou jogador? o resto é replanejado mudanças durante o jogo
Figura 3. O motor da partida: do rendimento de cada jogador até o lance que aparece na tela. O mesmo cálculo simula os jogos dos outros clubes em milissegundos.

Primeiro, cada jogador vira um número de rendimento: a força ajustada pela condição física, pela fase recente e pela moral. Um jogador exausto rende até 20% menos; a moral mexe até 3%, e a fase, até 6%. Fora de posição, ele perde de 10% a 20%.

Depois, o time vira três forças: ataque, meio e defesa. O ataque soma atacantes e meias; a defesa soma zagueiros, goleiro e meias. Comparando o ataque de um com a defesa do outro, o motor calcula quantos gols cada time deve fazer em média. Essa comparação é elevada ao cubo, para a diferença de qualidade aparecer no placar. A vantagem de jogar em casa não é fixa: depende do público esperado e da ocupação do estádio, e o incentivo da torcida, que você aciona até três vezes por jogo, empurra o mandante por oito minutos. A postura ofensiva aumenta os gols dos dois lados.

Com a média de gols em mãos, o motor sorteia os lances de cada tempo com uma distribuição de Poisson, a mesma usada para estimar placares no futebol real. É ela que garante que o favorito ganhe mais vezes, sem tornar a zebra impossível:

Chance de cada placar para dois times: o mandante mais forte, com média de 1,6 gol, faz 1 gol em 32% dos jogos e 2 gols em 26%; o visitante mais fraco, com média de 0,9 gol, passa em branco em 41% dos jogos, mas faz pelo menos um gol em quase 6 de cada 10. Mandante forte (média 1,6 gol) Visitante mais fraco (média 0,9) gols do time na partida 20% 41% 0 32% 37% 1 26% 16% 2 14% 5% 3 6% 1% 4 2% 0% 5
Figura 4. Por que a zebra acontece: com a média de gols de cada lado, o sorteio de Poisson dá a chance de cada placar. O time mais fraco passa em branco em 41% dos jogos, mas marca pelo menos um gol em quase 6 de cada 10.

A partida ao vivo que você assiste é a encenação desse plano: gols, chances, escanteios e faltas, cada um no seu minuto. Quando você troca a postura, o esquema ou um jogador, o motor refaz o plano dos minutos que faltam.

Esse formato tem uma vantagem que eu valorizo muito: dá para explicar qualquer resultado. O mesmo cálculo simula os jogos dos outros clubes em milissegundos, o que mantém a tabela inteira coerente.

Confiança, diretoria e demissão

A confiança é o que transforma resultado em história. Cada termômetro volta aos poucos para o seu ponto de equilíbrio, e os resultados o empurram. A diretoria olha a posição em relação à meta e o caixa; a torcida sente mais uma derrota em casa; a imprensa reage ao tom das suas respostas na coletiva.

Quando a confiança da diretoria chega a 10 ou menos, depois de pelo menos seis rodadas, o presidente chama você para uma reunião. Você se defende e pode ganhar um prazo de cinco rodadas, ou sair demitido. Demitido, chegam propostas de outros clubes, e a carreira continua com o seu histórico.

No modo premium, você escreve a sua defesa com as próprias palavras. Mas a IA não decide se você fica. Ela só classifica o argumento, e a regra faz o resto:

Peso de cada tipo de argumento na chance de ganhar prazo na reunião com a diretoria: forte soma 30 pontos percentuais, razoável soma 12, fraco tira 8 e ofensivo tira 40. chance de ganhar prazo (pontos percentuais) Argumento forte +30 Razoável +12 Fraco −8 Ofensivo −40
Figura 5. Na reunião com a diretoria, a IA só escolhe em qual categoria o seu argumento se encaixa. O peso de cada categoria na chance de ganhar prazo é regra do jogo.

Os componentes

No terceiro nível do C4, o app do navegador se organiza em partes com responsabilidade clara. As regras ficam separadas das telas, e tudo o que usa IA passa por um único cliente.

C4 nível 3, componentes do app no navegador: telas e estado; motor da partida; confiança; diretoria; negociação com travas; cliente premium; conta e nuvem; som e abertura. A negociação, a coletiva e a reunião passam pelo cliente premium até a API. App no navegador [Contêiner: JavaScript] Telas e estado JavaScript, módulos elenco, mercado, tabela, finanças Motor da partida regras, sem IA força, gols esperados, Poisson Confiança regras, sem IA diretoria, torcida, elenco, imprensa Negociação + travas regras + IA opcional mínimo secreto e faixa de preço Coletiva e reunião IA opcional efeito decidido por regra Diretoria regras, sem IA reunião, prazo, demissão Cliente premium HTTPS + JSON contexto curto, saldo do dia Conta e nuvem HTTPS + gzip gzip, versão, conflito Som e imagem Web Audio, vídeo sons, abertura e cenas abaixo de 10 API em PHP (Figura 2): IA, conta e jogo salvo
Figura 6. C4, nível 3 (componentes do app): as regras ficam em módulos próprios. Tudo o que usa IA passa por um único cliente, que manda um contexto curto e recebe uma resposta em formato fixo.

Essa separação foi construída aos poucos. O jogo começou num arquivo só e foi sendo dividido conforme crescia: primeiro o estado, depois as abas, depois o motor da partida e as regras de confiança e diretoria. Cada divisão foi um pull request próprio, com o jogo funcionando antes e depois.

A IA por baixo das negociações

Aqui está o coração do projeto. Quando você faz uma proposta, a sequência é sempre a mesma, e a IA ocupa só uma etapa dela.

C4 nível 4, código da negociação: a proposta entra; as regras calculam o mínimo secreto e a faixa; a IA devolve fala e decisão em JSON; as travas corrigem decisões fora da regra; o estado do jogo é atualizado. Sem IA, entra a fala pronta. 1. Proposta dinheiro, troca e o texto livre do técnico 2. Regras mínimo secreto pode / deve aceitar faixa da contra- proposta, paciência 3. IA conversa fala do presidente decisão, novo pedido, persuasão, memória JSON Schema 4. Regras decidem aceitar sem poder? vira contraproposta preço fora da faixa? é cortado 5. Estado caixa, elenco, relação e memória do presidente Fala pronta sem premium, IA fora do ar ou limite do dia persuasão: ±4% no mínimo por mensagem, até ±12%
Figura 7. C4, nível 4 (código): o caminho de uma proposta na negociação. A IA escreve a fala; quem decide o preço e o fechamento são as regras.

Primeiro, as regras calculam os limites. Cada negociação tem um pedido e um mínimo secreto, que dependem do valor do jogador, de ele ser titular, da personalidade do presidente e da relação entre vocês. A partir da proposta, o jogo sabe se o presidente pode aceitar, se deve aceitar e qual é a faixa permitida para uma contraproposta.

Depois, a IA conversa. O Claude recebe a personagem, a situação, as regras secretas e as últimas mensagens. A resposta é obrigada a voltar num formato fixo, validado por um esquema: a fala do presidente, a decisão (aceitar, fazer contraproposta ou encerrar), o novo pedido, uma nota de persuasão (−1, 0 ou 1) e uma frase de memória. Não existe texto solto nem resposta fora do formato.

Por fim, as regras decidem. Antes de aplicar qualquer coisa, o jogo confere a resposta. Se a IA disse "aceitar" e a proposta está abaixo do mínimo, vira contraproposta. Se o novo pedido sai da faixa permitida, ele é cortado. E a persuasão tem limite: um bom argumento baixa o mínimo em 4%, até 12% no total; uma grosseria faz o contrário, custa paciência e piora a relação.

A IA ganha poder real, mas limitado. Um elogio que pega ou uma proposta criativa baixam o preço. E a frase de memória que o presidente escreve ao fechar ou encerrar o negócio volta nas próximas conversas com ele. É isso que faz a negociação parecer viva sem deixar o jogo à mercê de uma resposta inesperada.

A coletiva funciona do mesmo jeito: a IA escreve as perguntas e avalia o tom da sua resposta numa categoria; o efeito na confiança da imprensa é regra do jogo.

Custo e segurança da IA

Colocar uma IA paga num site aberto exige travas. Todas ficam no servidor:

  • Contexto validado e recortado. O navegador manda só números limitados e textos curtos; a API monta a instrução para o modelo do lado dela. O jogador não consegue mandar uma instrução própria.
  • Reserva antes da chamada. Antes de chamar o Claude, a API registra o custo máximo possível da mensagem. Se a conexão cair no meio, a reserva fica com esse custo; se a API responder com erro, a reserva é cancelada. O teto de gasto nunca fica frouxo.
  • Limites em camadas: mensagens por dia por convite, mensagens por endereço de rede, bloqueio de tentativas de código e um teto de gasto diário do site inteiro. Ao bater o teto, o jogo volta para as falas prontas até o dia seguinte.
  • Modo simulado para os testes, que segue as mesmas regras sem gastar nada.

Na minha conta, uma negociação inteira custa centavos de dólar. Se o uso crescer, trocar para um modelo menor é uma mudança de configuração.

Conta sem senha e jogo na nuvem

A conta é opcional e não tem senha. Você digita o e-mail e recebe um link que vale por 15 minutos e uma vez só. O banco guarda o e-mail apenas como um código embaralhado, assim como os links, as sessões e os códigos premium.

O jogo salvo sobe comprimido alguns segundos depois de cada mudança. Para lidar com dois aparelhos, cada envio diz de qual versão da nuvem partiu. Se a nuvem já estiver mais nova, porque você jogou no celular, o servidor recusa a gravação e o jogo pergunta qual carreira você quer manter, em vez de sobrescrever em silêncio.

Som e imagem com o ElevenLabs

O som foi a parte mais divertida. Cada efeito nasce de uma descrição: apitos, torcida, vaia, o "uuuh" da chance perdida. A torcida reage ao placar e ao mando de campo. O narrador fala português com emoção, e a música da abertura tem um auge perto dos 9 segundos, onde o escudo aparece.

A abertura é um vídeo gerado no ElevenLabs, comprimido e sincronizado com a música. Os lances da partida ganharam um personagem sem rosto, o mesmo em todas as cenas: o juiz mostrando o cartão ou a placa de substituição, o jogador comemorando o gol. Pedi as imagens com o uniforme num verde puro e o fundo num magenta puro. Com isso, o tratamento consegue tirar o fundo e transformar o uniforme numa máscara, que o jogo pinta com a cor de cada clube:

A mesma ilustração do jogador comemorando um gol, em quatro versões: com o uniforme em tons de cinza, como sai do tratamento, e pintado de vermelho, de branco e de azul, com as sombras preservadas. Antes da cor uniforme em tons de cinza Vermelho Branco Azul
Figura 8. Uma ilustração para os 40 clubes: o uniforme vira uma máscara, e o jogo pinta com a cor de cada clube, preservando as sombras.

O que eu aprendi

A IA funciona melhor como interface do que como juíza. Ela é ótima para entender um texto livre e responder com personalidade. Para decidir preço, resultado ou demissão, regras explícitas são mais justas, mais baratas e mais fáceis de explicar.

Projete a falha antes do sucesso. Cada uso de IA tem uma resposta pronta por trás. A IA é uma camada que enriquece o jogo, nunca uma dependência dele.

Custo é requisito de arquitetura. Rodar o jogo no navegador, gerar os sons uma vez só e reservar o custo antes de chamar a API foram decisões de arquitetura, não otimizações feitas depois.

Pequeno e revisável vence grande e rápido. Mais de 50 pull requests pequenos, cada um com o jogo funcionando, deram um histórico que conta a evolução do projeto e tornaram qualquer erro fácil de desfazer.

O Soccer Deal está na versão 1.0.0 e pode ser jogado agora, de graça, no navegador: fghisi.com.br/soccer-deal. É a minha homenagem ao Elifoot e ao Brasfoot. Bom jogo, professor.