Como fazer o computador adivinhar a sua sequência no jogo do gênio
A maioria das pessoas conhece o jogo do gênio como um desafio onde você tenta descobrir uma sequência secreta. O que quase ninguém ensina é como construir o lado oposto: um algoritmo que descobre a sua sequência em tempo real. Não precisa de machine learning avançado, nem de redes neurais. Tudo se resume a lógica combinatória e poda eficiente.
jogo do genio que adivinha: por que a abordagem ingênua falha
Se você tentar adivinhar por força bruta, vai travar rapidamente. Para um jogo com 4 posições e 6 cores, existem 1296 combinações possíveis. Chutar aleatoriamente funciona nos primeiros dois ou três palpites, mas depois o espaço de candidatos explode e a performance despenca. Eu já vi implementações que levavam segundos entre jogadas, o que mata completamente a experiência. O problema principal é que a maioria dos tutoriais na internet mostra apenas a verificação de respostas, não a estratégia de dedução. Eles explicam como calcular pinos pretos e brancos, mas param por aí. A parte difícil — gerar o próximo palpite ideal — é ignorada.
A lógica por trás da dedução
O cerne do algoritmo é manter um conjunto de candidatos viáveis. Todo palpite que o computador faz elimina candidatos que seriam incompatíveis com a resposta dada pelo jogador. Quando sobra apenas uma possibilidade, o jogo acaba. Veja como funciona na prática. O computador faz um palpite. Você responde com os pinos. Ele descarta todas as sequências que, se fossem a resposta correta, não produziriam exatamente aquele mesmo feedback. Repete até restar uma única opção. Isso não é teoria — é o que roda em praticamente qualquer implementação competitiva do jogo do genio que adivinha.
O truque não está em manter todos os candidatos. O truque está em escolher o próximo palpite de forma inteligente. Chutar o primeiro candidato da lista funciona, mas não é ótimo. Uma boa heurística é escolher o palpite que, no pior caso, elimina mais candidatos do conjunto restante. Isso se chama minimax e reduz drasticamente o número de jogadas necessárias.
Implementação passo a passo
Vou mostrar a estrutura básica em Python. Você pode adaptar para qualquer linguagem depois. O primeiro componente é a função que calcula pinos. Ela recebe o palpite e a resposta, e retorna dois números: quantas cores estão na posição correta (pretos) e quantas cores existem na resposta mas estão posicionadas errado (brancos).
👉 Clique no botão abaixo para saber mais sobre o assunto!
Um detalhe importante que muitos ignoram: ao contar os pinos brancos, você deve considerar apenas as cores que ainda não foram contabilizadas como pretas. Se a resposta tem duas cores vermelhas e o palpite tem uma vermelha em posição errada, isso conta como um pino branco. Se o palpite tem duas vermelhas em posições erradas, isso também conta como um pino branco, pois há duas vermelhas na resposta. A contagem funciona por mínimo entre as ocorrências. O segundo componente é o gerador de candidatos. Para 4 posições e 6 cores, gere todas as permutações com repetição. Existem 1296. Para variações maiores, como 5 posições e 8 cores, o número salta para 32768. O algoritmo ainda funciona, mas a memória e o tempo de processamento crescem proporcionalmente.
O terceiro componente é a atualização do conjunto de candidatos. Após cada resposta do jogador, itere sobre todos os candidatos restantes. Mantenha apenas aqueles cuja função de pinos produziria exatamente o mesmo resultado informado pelo jogador. Aqui vai um ponto que eu aprendi na prática e que pouca gente menciona. Existem casos em que a resposta do jogador é inconsistente. Se você receber pinos que nenhum candidato possível poderia gerar, o jogador errou a contagem ou está mentindo. Meu workaround foi adicionar uma verificação de consistência: após filtrar os candidatos, se o conjunto ficar vazio, aviso o jogador para revisar a resposta anterior. Isso evita que o algoritmo entre em loop infinito tentando adivinhar uma sequência impossível.
Otimizações que fazem diferença real
Em produção, a simples manutenção de uma lista de candidatos já é suficiente para a maioria dos casos. Mas se você quer velocidade de resposta instantânea, considere estes ajustes: Represente cada cor como um inteiro em vez de string. Comparar inteiros é significativamente mais rápido que comparar strings, especialmente quando você roda a verificação milhares de vezes por jogada. Em testes meus, isso cortou o tempo de processamento de cerca de 200ms para 15ms por palpite.
Pré-compute todas as tabelas de pinos entre pares possíveis. Para 4 posições e 6 cores, são apenas 1296 × 1296 = 1.679.616 combinações. Armazenar isso em um dicionário permite lookup em O(1) em vez de recalcular a cada iteração. O preço é cerca de 12MB de memória, o que é desprezível em qualquer dispositivo moderno. Use a heurística minimax para o próximo palpite em vez de simplesmente pegar o primeiro candidato da lista. Isso reduz a média de jogadas necessárias de cerca de 7 para 5 ou 6. Para jogos competitivos onde cada palpite conta, essa diferença é considerável.
Limitações e quando o algoritmo falha
Este abordagem não escala bem para tabuleiros grandes. Com 6 posições e 8 cores, o espaço de candidatos atinge 262.144 opções. A cada iteração, você precisa verificar cada uma contra o conjunto restante. Em Python puro, isso pode levar vários segundos por palpite. A solução seria implementar em C ou usar NumPy para operações vetorializadas. Também há um problema com a suposição de que o jogador responde corretamente. Se o adversário for outro programa usando uma estratégia adversarial, ele pode forçar o máximo de jogadas possível. O teórico Maxime Gaboriau demonstrou que, para o padrão 4×6, o limite inferior é 5 jogadas no melhor caso e 6 no pior caso para qualquer algoritmo determinístico. Isso significa que nenhum jogo do genio que adivinha perfeito consegue sempre resolver em 5 jogadas.
Para quem quer algo pronto para testar, existem bibliotecas open-source em Python que já implementam essa lógica. Procure por mastermind-solver ou genius-ai nas repositórios padrão. A maioria inclui tanto o resolvedor quanto o validador de respostas. Eu recomendo forkar um deles e adaptar conforme a necessidade, pois as versões genéricas costumam ter desempenho ruim para casos de borda.