2

Pitch: Achei o Filipe Deschamps recriando o Akinator da bolha dev

Eu queria entender melhor como um jogo no estilo Akinator poderia funcionar por trás. Você pensa em uma pessoa, responde algumas perguntas e o sistema tenta adivinhar. Mas, na prática, não precisa de IA para isso. O Devkinator foi criado usando lógica booleana, banco de dados, pesos, eliminação de possibilidades e um pouco de matemática simples. A stack usada foi Next.js 15 com App Router, TypeScript, PostgreSQL via Docker Compose, Prisma 6 e CSS Modules sem Tailwind.

Devkinator

A ideia do projeto

O Devkinator é uma versão inspirada no Akinator, mas focada na bolha dev. Em vez de tentar adivinhar personagens, ele tenta descobrir qual influencer dev o usuário está pensando — nomes como Filipe Deschamps, Mano Deyvin, Akita, Lucas Montano, Rocketseat e outros da comunidade.

O usuário responde perguntas como: a pessoa fala muito sobre JavaScript? Produz conteúdo no YouTube? Fala sobre carreira? É mais ligada ao backend? Tem presença forte no LinkedIn? Costuma falar sobre IA? Com base nas respostas, o sistema reduz a lista de possibilidades até chegar no candidato mais provável.

Não tem IA

O ponto mais importante é que o Devkinator não chama API de IA, não usa modelo de linguagem, não faz prompt e não "pensa". Ele apenas cruza respostas com dados salvos no banco. A inteligência está na modelagem das perguntas, nas características dos personagens e na forma de calcular a pontuação.

Como os dados são organizados

O sistema precisa conhecer duas coisas: quem ele pode tentar adivinhar e quais características cada pessoa tem. Cada influencer possui um conjunto de características booleanas, e cada pergunta está ligada a uma dessas características. Quando o usuário responde, o sistema compara a resposta com os dados de cada candidato.

const characters = [
  {
    name: "Filipe Deschamps",
    traits: {
      talks_about_javascript: true,
      has_youtube_channel: true,
      talks_about_career: true,
      backend_focus: false,
      talks_about_ai: true
    }
  },
  {
    name: "Outro Dev",
    traits: {
      talks_about_javascript: false,
      has_youtube_channel: true,
      talks_about_career: false,
      backend_focus: true,
      talks_about_ai: false
    }
  }
];

Uma pergunta pode ser definida assim:

{
  id: "has_youtube_channel",
  text: "Essa pessoa produz conteúdo no YouTube?",
  traitKey: "has_youtube_channel"
}

Se o usuário responder "sim", os candidatos que também possuem has_youtube_channel: true ganham pontos. Se responder "não", os candidatos com has_youtube_channel: false ganham pontos. É uma lógica simples, mas funciona muito bem quando os dados estão bem modelados.

Lógica booleana e pontuação

A base do jogo usa valores true e false. Quando o usuário responde uma pergunta, a resposta vira um booleano e é comparada diretamente com a característica do personagem. Se os dois valores forem iguais, existe compatibilidade e o personagem ganha um ponto. Quanto mais respostas compatíveis, maior a chance daquele personagem ser o escolhido.

function calculateScore(character, answers) {
  let score = 0;

  for (const answer of answers) {
    const traitValue = character.traits[answer.traitKey];

    if (traitValue === answer.value) {
      score += 1;
    }
  }

  return score;
}

Se o Filipe Deschamps bate com 8 respostas e outro candidato bate com 4, o Filipe fica na frente. Simples assim.

Melhorando com pesos

Nem toda pergunta tem a mesma importância. "Essa pessoa tem canal no YouTube?" pode eliminar muitos candidatos de uma vez. Já "Essa pessoa fala sobre carreira?" é mais genérica e menos decisiva. Por isso cada pergunta pode ter um peso, e perguntas mais importantes influenciam mais no resultado final.

{
  text: "Essa pessoa tem canal no YouTube?",
  traitKey: "has_youtube_channel",
  weight: 3
}

Imagine três perguntas com pesos 3, 2 e 1. Se o personagem combina com a primeira, ele ganha 3 pontos. Se combina só com a terceira, ganha 1. Isso deixa o jogo muito mais preciso do que uma contagem simples.

Motor de decisão

O motor de decisão é a parte mais importante do projeto. Ele recebe os personagens, as perguntas respondidas e as características de cada personagem, e devolve o candidato mais provável junto com sua pontuação e nível de confiança.

export function guessCharacter(characters: Character[], answers: Answer[]) {
  const ranking = characters.map((character) => {
    let score = 0;
    let maxScore = 0;

    for (const answer of answers) {
      maxScore += answer.weight;

      const traitValue = character.traits[answer.traitKey];

      if (traitValue === answer.value) {
        score += answer.weight;
      }
    }

    const confidence = maxScore === 0 ? 0 : score / maxScore;

    return { character, score, confidence };
  });

  ranking.sort((a, b) => b.score - a.score);

  return ranking[0];
}

A matemática é básica: se o personagem fez 8 pontos de um total possível de 10, a confiança é 8 / 10 = 0.8, ou seja, 80%.

Por que isso funciona?

O jogo não precisa saber tudo. Ele só precisa fazer boas perguntas. No começo, todos os personagens são possíveis. Depois da primeira resposta, alguns ficam mais fortes. Depois da segunda, outros perdem força. Depois de várias respostas, um candidato começa a se destacar. É um processo de eliminação por pontuação — cada pergunta reduz a incerteza.

Por exemplo, se o usuário respondeu que a pessoa tem canal no YouTube (peso 3), fala sobre JavaScript (peso 2) e não tem foco em backend (peso 1), e o Filipe Deschamps combina com tudo isso, ele marca 3 + 2 + 1 = 6 pontos. Um personagem que combina com apenas uma resposta fica bem atrás.

Como o banco aprende sem IA

O Devkinator também pode aprender com as escolhas dos usuários, mas aprender aqui não significa IA — significa atualizar estatísticas no banco. Se muitos usuários pensam no Filipe Deschamps e confirmam que ele fala sobre JavaScript, essa característica fica mais confiável. Se muitos usuários discordam de uma característica, talvez o dado inicial esteja errado.

Com isso, o banco guarda estatísticas simples:

traitKey: talks_about_javascript
positiveAnswers: 120
negativeAnswers: 15

Depois, o sistema pode usar isso para ajustar pesos ou revisar características. Isso é aprendizado estatístico simples — o banco registrando padrões, nada mais.

O modelo do Prisma que sustenta isso fica assim:

model Character {
  id        String   @id @default(uuid())
  name      String
  slug      String   @unique
  imageUrl  String?
  traits    CharacterTrait[]
  guesses   Guess[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model Question {
  id        String   @id @default(uuid())
  text      String
  traitKey  String
  weight    Int      @default(1)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model CharacterTrait {
  id          String  @id @default(uuid())
  characterId String
  traitKey    String
  value       Boolean
  character   Character @relation(fields: [characterId], references: [id])
  @@unique([characterId, traitKey])
}

model Guess {
  id          String   @id @default(uuid())
  characterId String
  success     Boolean
  character   Character @relation(fields: [characterId], references: [id])
  createdAt   DateTime @default(now())
}

Estrutura do projeto

No Next.js 15, a lógica principal fica separada da interface. O motor de decisão vai em src/lib/engine.ts para não misturar regra de negócio com tela. As rotas da API ficam em src/app/api/, e os componentes isolam seu próprio estilo com CSS Modules.

import styles from "./QuestionCard.module.css";

export function QuestionCard() {
  return (
    <section className={styles.card}>
      <h2>Essa pessoa produz conteúdo no YouTube?</h2>
      <div className={styles.actions}>
        <button>Sim</button>
        <button>Não</button>
      </div>
    </section>
  );
}

CSS Modules mantém o estilo isolado por componente, sem Tailwind, sem dependência visual desnecessária.

O fluxo do jogo

O fluxo completo é direto: o usuário inicia a partida, o sistema mostra uma pergunta, o usuário responde sim ou não, a resposta é salva temporariamente, o sistema recalcula os candidatos, e depois de algumas perguntas faz um palpite. O usuário confirma se acertou ou errou, e o resultado é salvo no banco — esse último passo é o que permite melhorar o jogo com dados reais ao longo do tempo.

Conclusão

O Devkinator parece inteligente, mas a base dele é simples: perguntas bem escolhidas, características booleanas, banco de dados, pontuação, pesos e estatísticas de acerto e erro. A parte mais difícil não é o código — é modelar bons dados. Se as perguntas forem ruins, o jogo erra. Se os personagens forem mal cadastrados, o jogo erra. Se as características forem boas, o sistema parece muito mais inteligente do que realmente é. No fim, o Devkinator é um bom exemplo de que nem todo produto interativo precisa de IA — às vezes, só lógica já resolve.

Se quiser jogar https://treta.dev/devkinator

Carregando publicação patrocinada...