Cinco papéis pra julgar uma luta de robô
O que tem que estar definido antes de escrever a primeira linha de código de um app pra contabilizar combate de robô. Quem usa, em quantos dispositivos, e quem é dono de cada decisão dentro da luta.
Imagina três pessoas com pranchetas assistindo à mesma luta de robô. A primeira anota Significativo. A segunda anota Maior. A terceira tá decidindo. A luta seguinte já era pra ter começado, e ninguém ainda chegou no placar final.
O Pajé, juiz veterano da cena brasileira de combate de robô, juntou esse problema e veio com a ideia de um app pra resolver. Eu tô desenvolvendo o tapout.gg com ele. A gente pensou nele pros amistosos, eventos pequenos, treinos da equipe. Eventos oficiais grandes já usam o sistema da Robocore. O recorte da gente é onde a contagem é manual, todo mundo erra, e o resultado leva mais tempo do que a própria luta.
Esse post é o primeiro de uma série sobre o projeto. Ele cobre o que travamos antes de escrever a primeira linha de código: quem é o usuário, o que cada um vê, e por que algumas decisões parecem estranhas até você entender o domínio.
A regra oficial em uma página
A Robocore publica um PDF de oito páginas descrevendo como pontuar uma luta. Resumindo numa frase: três juízes distribuem 33 pontos entre os dois robôs, e empate é impossível.
Os 33 pontos saem de dois critérios independentes.
Agressividade vale 5 pontos por juiz e olha pra porcentagem de hits (ataques efetivos) que cada robô fez. Acima de 90% pro mesmo robô vira 5×0. Entre 70% e 90% vira 4×1. Entre 50% e 70% vira 3×2. Cada juiz faz a conta do próprio placar, então a soma dos três compõe os 15 pontos totais desse critério.
Dano vale 18 pontos no total, distribuídos por uma matriz de seis por seis. Cada robô termina a luta com um nível de dano que vai de Trivial até Massivo, e a matriz cruza os dois níveis pra dizer quantos pontos cada um leva. Cosmético contra Significativo dá 12×6. Massivo contra Trivial dá 0×18. Diferente da agressividade, o nível de dano tem que ser um único valor consensual dos três juízes.
A parte difícil não é a aritmética. É que três pessoas precisam contar coisas separadas (cada uma tem o próprio placar de agressividade) e concordar sobre o resto (o dano é um valor só pros três). Em papel, isso é um problema de coordenação.
Cinco papéis numa luta
Antes de qualquer tela, a decisão que travamos primeiro foi quantos dispositivos diferentes participam, e o que cada um faz.
O admin é o “big brother” do round. Roda num PC ou tablet, vê tudo, controla o tempo (se tiver), decide quando começa, quando termina, quando alguém ganhou por nocaute. Os três juízes rodam em celulares e só fazem uma coisa: contar hits do robô que viram melhor naquele instante. O live é uma janela separada que dá pra projetar pro público, mostrando só o que faz sentido durante a luta (que é quase nada, mais sobre isso adiante).
Não tem servidor de aplicação entre eles. Os cinco se conectam direto via WebRTC, o mesmo protocolo que o Google Meet ou o Discord usam pra voz e vídeo. O admin gera um código curto, os outros digitam, e a partir daí o tráfego não passa por nenhum servidor que a gente mantenha. Isso resolve dois problemas simultaneamente: o app fica de graça pra sempre, e a latência entre os dispositivos é a menor possível porque todo mundo tá na mesma rede do evento.
O celular do juiz não tem relógio
A primeira tentação ao desenhar a tela do juiz foi mostrar o tempo do round. É uma luta, tem timer, parece útil. Errado.
Quando um juiz de combate de robô tá fazendo o trabalho dele, ele tá olhando pra arena, não pro celular. O celular fica na mão dele, ou encostado na mesa, e ele só olha o suficiente pra acertar o toque cada vez que vê um hit. Botar um relógio nessa tela transforma o celular numa coisa pra ler, e ler compete com o que o juiz precisa estar fazendo, que é prestar atenção na luta. Pior ainda, o cronômetro do app pode descompasar do relógio físico que o staff da arena tá rodando, e dois timers discordando entre si confunde mais do que ajuda.
A tela é só dois botões enormes, um pra cada robô, em landscape. Toque rápido conta um hit. Segurar por meio segundo tira um hit (porque hits errados acontecem, e o juiz tem que conseguir corrigir sem parar de olhar pra arena). O contador aparece gigante no meio da metade correspondente, e isso é literalmente tudo. O timer fica na mesa do admin, no telão pro público, mas nunca na mão do juiz.
A mesa de controle vê tudo
Já o admin tem o problema oposto. Ele precisa ver tudo, porque ele coordena a luta inteira: começa o round, controla o timer, encerra, declara KO, libera o resultado final. O placar parcial dos juízes é informação que ele agrega, mas não corrige.
Cada juiz aparece num cartão próprio com a contagem em tempo real. Status de conexão por juiz, status da rede no canto. Timer (se a luta tiver um). Controles embaixo: pausar, declarar KO, encerrar. Tudo num painel só, porque o admin não tá assistindo a luta diretamente. Ele tá na mesa de controle, olhando pro PC enquanto os juízes contam.
Uma decisão pequena que importou bastante: o admin não pode mudar a contagem de hits de um juiz enquanto o round tá rolando. O juiz é dono do que ele contou. Se a gente deixasse o admin “corrigir” hits ao vivo, estaria assumindo que o admin viu a luta melhor que o juiz, e o admin nem tá olhando pra arena. Só depois que o round termina é que o admin pode editar, pra corrigir um erro óbvio, ou um celular que travou no meio. Durante a luta, juiz manda no que juiz contou.
O telão público não conta nada
A tela do live tem uma regra inegociável: ela nunca mostra placar parcial.
Durante a luta, ela mostra os nomes dos robôs, as cores dos cantos, e o tempo. Mais nada. Sem contagem de hits, sem placar dos juízes, sem indicador de quem tá “ganhando”. Quando a luta termina, ela mostra só o resultado final, ou KO, ou tapout.
Isso é proposital. Se o público vê que um robô tá 5 hits a 1 no meio da luta, dois problemas aparecem. Primeiro, o público pressiona os juízes na cabeça, porque todo mundo torce em voz alta pelo robô da equipe que ele veio assistir, e ver outro placar no telão gera ruído extra. Segundo, o placar parcial não significa o que o público acha que significa. O cálculo final passa pela matriz de dano, e um robô com mais hits pode perder por causa de uma diferença no dano recebido. Mostrar só o placar de hits induz o público ao erro.
O consenso de dano é uma trava no software
A parte mais delicada da regra oficial é o consenso sobre o nível de dano. Em papel, isso vira uma discussão verbal que demora muito quando alguém discorda. Pior, em eventos com várias lutas, o consenso costuma virar “concorda logo pra gente seguir”, o que viola o espírito da regra mesmo se ninguém percebe.
A solução foi transferir a regra do papel pro software.
No fim do round, cada juiz pega o próprio celular (que volta a ficar em retrato) e marca o nível de dano que ele viu pros dois robôs. Se os três marcaram a mesma coisa, todo mundo consegue submeter e o admin libera o resultado. Se um marcou diferente, o botão de submeter fica travado pra ele. O admin também não consegue finalizar o round enquanto a divergência existir.
Os três estão fisicamente juntos, então a conversa é de cinco segundos: “eu tava em Significativo, mas se vocês acham que foi Maior, beleza”. Quem precisa muda, re-submete, e o sistema destrava. A trava existe porque sem ela o consenso vira encenação. Com ela, é impossível registrar um resultado que infringe a regra.
De graça pra sempre
A última decisão arquitetural que vale comentar é o custo de manter o app no ar.
O app inteiro é estático. Não tem banco de dados, não tem servidor de aplicação, não tem nuvem. Os dispositivos se conectam direto entre si via WebRTC, e o histórico de lutas fica salvo no próprio navegador do admin. O site fica hospedado no GitHub Pages, que é gratuito pra sempre pra projetos open source.
Existe um intermediário pequeno: um servidor público de pareamento que serve só pra fazer os dispositivos descobrirem uns aos outros (o “handshake” inicial do WebRTC). Depois que a conexão é feita, o tráfego entre celulares e PC não passa mais por ele. Esse handshake são alguns kilobytes, uma vez por luta. Não custa nada e ninguém precisa manter.
A consequência prática é que o app funciona em qualquer lugar com Wi-Fi local, ou no 4G de qualquer operadora, ou na rede de evento que costuma ser lenta. Não depende de cloud, não tem latência transatlântica, e não cai se a AWS tossir.
A próxima
Esse foi o primeiro post da série sobre o tapout.gg. Cobri o que o Pajé e eu travamos antes de escrever código: quem usa, em quantos dispositivos, o que cada um vê, e quem é dono de cada decisão dentro da luta. Os próximos posts vão entrar nas partes que estão sendo implementadas agora: a matriz de dano e como ela vira código, o protocolo de mensagens entre os cinco dispositivos, e o que acontece quando o celular de um juiz trava no meio do round.
Lá no começo do post tinha três pessoas com pranchetas, sem chegar no placar final. Esse problema tem uma forma específica: três pessoas, uma regra com matemática estranha, e a pressão de não atrasar o evento seguinte. O que resolve não é uma calculadora. É um app que sabe quem manda em cada decisão e trava as transgressões.