<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ankit Mishra</title>
    <description>The latest articles on DEV Community by Ankit Mishra (@aaklon).</description>
    <link>https://dev.to/aaklon</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4009469%2Fee1adad9-6266-4c2d-b759-f328bb50583e.jpeg</url>
      <title>DEV Community: Ankit Mishra</title>
      <link>https://dev.to/aaklon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aaklon"/>
    <language>en</language>
    <item>
      <title>Built an Anime Akinator that tries to guess your character</title>
      <dc:creator>Ankit Mishra</dc:creator>
      <pubDate>Tue, 30 Jun 2026 11:08:49 +0000</pubDate>
      <link>https://dev.to/aaklon/built-an-anime-akinator-that-tries-to-guess-your-character-37o9</link>
      <guid>https://dev.to/aaklon/built-an-anime-akinator-that-tries-to-guess-your-character-37o9</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa9dycf07sfsliq67fcxu.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa9dycf07sfsliq67fcxu.jpeg" alt="Sensei Knows Banner" width="800" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Sensei Knows: The Akinator Engine
&lt;/h1&gt;




&lt;p&gt;&lt;strong&gt;Sensei Knows&lt;/strong&gt; is an Akinator engine that powers our official &lt;a href="https://anime-akinator.vercel.app/" rel="noopener noreferrer"&gt;Anime Akinator&lt;/a&gt;. If you've ever wondered how Akinator works or wanted to build your own 20 Questions character guessing game, this repository is for you.&lt;/p&gt;

&lt;p&gt;Repository Link : &lt;a href="https://github.com/Aaklon/akinator" rel="noopener noreferrer"&gt;https://github.com/Aaklon/akinator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8tysnngibzm5a8d34btz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8tysnngibzm5a8d34btz.gif" alt="Koro Yeah I did it" width="320" height="228"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Believe me I can do this!&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft9y7b2alugoem90rlo0g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft9y7b2alugoem90rlo0g.gif" alt="Funny mind reading gif" width="320" height="270"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;When you try to pick a totally obscure character, but the engine still reads your mind...&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why we Built It?&lt;/li&gt;
&lt;li&gt;Current Implementation&lt;/li&gt;
&lt;li&gt;
The Architecture

&lt;ul&gt;
&lt;li&gt;Core Philosophy: A Statistical Approach&lt;/li&gt;
&lt;li&gt;The Math &amp;amp; Prediction Logic&lt;/li&gt;
&lt;li&gt;Reinforcement Learning (Self-Correction)&lt;/li&gt;
&lt;li&gt;Anti-Troll &amp;amp; Adversarial Defense&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Dataset Mathematical Blueprint&lt;/li&gt;
&lt;li&gt;Usage &amp;amp; Installation&lt;/li&gt;
&lt;li&gt;License&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Why we Built It?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F105ob24er9r7ncft2bhc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F105ob24er9r7ncft2bhc.gif" alt="Looking at C++ Frameworks" width="320" height="180"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Us looking at C++ backend web frameworks...&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;It all started with a specific goal in mind: we wanted to build an &lt;strong&gt;Anime Akinator&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At first, we engineered the core guessing logic using &lt;strong&gt;C++&lt;/strong&gt; because of its performance. However, when the time came to hook this engine up to a live website as a backend service, that's when we faced many problems. Building a C++ web server was turning into an absolute nightmare as we had no experience with it and could not find any framework which provided all what we needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdpiser74afck6s3q2dqq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdpiser74afck6s3q2dqq.gif" alt="Learning Go" width="498" height="281"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;So we sat down, explored Go, and made the decision to make a switch.&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;We decided to ditch the C++ backend and switch entirely to &lt;strong&gt;Golang&lt;/strong&gt;. Go's built-in concurrency, simple HTTP standard library, and ease of deployment made it the absolute perfect choice for us.&lt;/p&gt;
&lt;h2&gt;
  
  
  Current Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhhhc5kh7w53n0xrhtrfz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhhhc5kh7w53n0xrhtrfz.gif" alt="Showing off the implementation" width="268" height="164"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;I am already live to read your minds!&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;Right now, we have a live instance of this exact engine for our original project running: Sensei Knows. You can play around with it and try to beat the engine here:&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://anime-akinator.vercel.app/" rel="noopener noreferrer"&gt;anime-akinator.vercel.app&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's a sneak peek of the frontend we hooked up to our Go engine:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw82sdmaqlasag4qkyybl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw82sdmaqlasag4qkyybl.png" alt="Demo 1" width="800" height="357"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fks09u93ci6dgt4vfbhyu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fks09u93ci6dgt4vfbhyu.png" alt="Demo 2" width="800" height="347"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4119lmi311lwsg4xiyfe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4119lmi311lwsg4xiyfe.png" alt="Demo 3" width="800" height="347"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa4d9zlc816d6m676vkyd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa4d9zlc816d6m676vkyd.png" alt="Demo 4" width="800" height="347"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk1a3pbndq64g8aeg9z1x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk1a3pbndq64g8aeg9z1x.png" alt="Demo 5" width="800" height="347"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnf3mdmd01v4sotqatrr7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnf3mdmd01v4sotqatrr7.png" alt="Demo 6" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But here is the best part: &lt;strong&gt;this engine is completely dataset-agnostic.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can literally just swap out the dataset to make it guess Hollywood actors, cars, programming languages, or even your own friends.&lt;/p&gt;

&lt;p&gt;If you end up using this engine for a different dataset or project, &lt;em&gt;please&lt;/em&gt; let us know! (&lt;em&gt;Do share your project link with us :)&lt;/em&gt;) We'd absolutely love to see what kind of crazy things you build with it.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Core Philosophy: A Statistical Approach
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fykurwkboie5xw53i4on5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fykurwkboie5xw53i4on5.gif" alt="Koro Sensei philosopher" width="450" height="252"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;"I knew I am a philosopher nururufuhuhu"&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;While decision trees and binary search algorithms are foundational to computer science for exact matching, building a robust guessing engine requires dealing with human uncertainty. Standard binary trees fail gracefully; a single incorrect answer or a "Don't Know" response can lead to an unrecoverable collapse of the search space.&lt;/p&gt;

&lt;p&gt;Drawing inspiration from existing literature on probabilistic classifiers (such as Naive Bayes), our engine is built as a &lt;strong&gt;dynamic statistical classification system&lt;/strong&gt;. This allows the engine to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Operate on a continuous probability space (&lt;code&gt;Yes&lt;/code&gt; = 1.0, &lt;code&gt;Probably&lt;/code&gt; = 0.75, &lt;code&gt;Don't Know&lt;/code&gt; = 0.50, &lt;code&gt;Probably Not&lt;/code&gt; = 0.25, &lt;code&gt;No&lt;/code&gt; = 0.0).&lt;/li&gt;
&lt;li&gt;Handle noise and human error. A contradictory answer does not eliminate a candidate; it merely applies a mathematical penalty to their posterior probability.&lt;/li&gt;
&lt;li&gt;Dynamically compute the optimal sequence of questions based on the active state of the knowledge base, rather than relying on a static, pre-computed graph.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  The Math &amp;amp; Prediction Logic
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffm3nv5hb0610qp2321a7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffm3nv5hb0610qp2321a7.gif" alt="Koro Sensei Sweating over math" width="320" height="288"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The engine sweating over probabilities to figure out who you are thinking of...&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;The engine's predictions are powered by several core mathematical concepts:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Probabilistic State Representation&lt;/strong&gt;&lt;br&gt;
Instead of boolean values, the knowledge base stores two parameters for every question associated with a character: a continuous weight 

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;w&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;∈&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;[&lt;/span&gt;&lt;span class="mord"&gt;0&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mclose"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 and a sample size 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Posterior Probability &amp;amp; Beta-Prior Smoothing&lt;/strong&gt;&lt;br&gt;
When a user provides an answer 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
, the posterior probability 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;P&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 for every character 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 is updated. The baseline match score is the absolute distance: 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;w&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
.&lt;/p&gt;

&lt;p&gt;However, to prevent total probability collapse (the zero-frequency problem where one bad answer reduces a character's probability to exactly 0), we apply a &lt;strong&gt;Beta-prior smoothing calibration&lt;/strong&gt;:&lt;/p&gt;


&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;α&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;w&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;⋅&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1.0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;



&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;β&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;w&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;⋅&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1.0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;


&lt;p&gt;We compute a dynamic lower bound (epsilon) based on these Beta parameters. The final match score is bounded by this epsilon, ensuring the engine can always recover from anomalies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Shannon Entropy &amp;amp; Information Gain&lt;/strong&gt;&lt;br&gt;
To determine which question to ask next, the engine does not look at a tree. It computes the current &lt;strong&gt;Shannon Entropy&lt;/strong&gt; (
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;H&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
) of the entire character distribution:&lt;/p&gt;


&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;H&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mop op-symbol large-op"&gt;∑&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;P&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mop"&gt;&lt;span class="mop"&gt;lo&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;P&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;


&lt;p&gt;For every eligible question, the engine simulates the expected entropy 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;E&lt;/span&gt;&lt;span class="mopen"&gt;[&lt;/span&gt;&lt;span class="mord mathnormal"&gt;H&lt;/span&gt;&lt;span class="mclose"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 across all 5 possible answer buckets, weighted by their marginal probabilities. The question that yields the highest &lt;strong&gt;Expected Information Gain (EIG)&lt;/strong&gt; (
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;H&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;E&lt;/span&gt;&lt;span class="mopen"&gt;[&lt;/span&gt;&lt;span class="mord mathnormal"&gt;H&lt;/span&gt;&lt;span class="mclose"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
) is mathematically guaranteed to split the remaining candidates most efficiently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. UCB (Upper Confidence Bound) Exploration&lt;/strong&gt;&lt;br&gt;
To balance exploiting known good questions and exploring new ones, the engine applies a UCB bonus. Questions that have a low selection count receive a slight mathematical boost, ensuring the engine tests new pathways and doesn't get stuck in local optima.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Output Format&lt;/strong&gt;&lt;br&gt;
When the engine has exhausted its question cap or hit its guess threshold, it calculates and outputs the final &lt;strong&gt;Top Candidates List&lt;/strong&gt; along with their exact computed percentage confidence scores directly in the terminal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frnwji3j0q0wsiw75haa7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frnwji3j0q0wsiw75haa7.gif" alt="Koro calculating probabilities" width="320" height="175"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Koro calculating the probabilities for each of your responses...&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Reinforcement Learning (Self-Correction)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fld1kpgocw46dwykp0sdj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fld1kpgocw46dwykp0sdj.gif" alt="Koro Sensei learning" width="320" height="179"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Koro having troubles seeing so much to learn from...&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;A static database quickly becomes outdated. To solve this, the engine employs a continuous reinforcement learning mechanism. Every time a game concludes, whether the engine guessed correctly or was corrected by the user, the system learns from the session.&lt;/p&gt;

&lt;p&gt;For the correct character, the engine updates its stored weights (
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
) and sample sizes (
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
) for every question answered during the session. It calculates a consistency score between the user's answer and the stored weight, then applies an observation weight scaled by the existing data mass (to prevent a single user from drastically altering well-established facts). The character's parameters are thus incrementally refined, allowing the engine to adapt to community consensus over time.&lt;/p&gt;
&lt;h3&gt;
  
  
  Anti-Troll &amp;amp; Adversarial Defense
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F18tsv2nilmce0ex8pvbh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F18tsv2nilmce0ex8pvbh.gif" alt="Koro Sensei dodging bullets" width="320" height="179"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Sensei dodging all the bullets bad players send...&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;One of the biggest challenges in crowdsourced learning is malicious data poisoning (trolls). If users intentionally give wrong answers, they could corrupt the dataset. We built two layers of defense to prevent this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Adversarial Flagging (Z-Collapse Detection)&lt;/strong&gt;&lt;br&gt;
During a session, the engine monitors the sum of probabilities (
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;Z&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
). If a user's answers are statistically inconsistent with the knowledge base, 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;Z&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 collapses. If the collapse fraction exceeds a certain threshold, the session is flagged as "adversarial," and its answers are completely ignored for live training.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Staging &amp;amp; Review System&lt;/strong&gt;&lt;br&gt;
When a user adds a new character or corrects the engine, the change does not go live immediately. Instead, it is pushed to a &lt;code&gt;PendingCorrections&lt;/code&gt; queue. A correction must gather a minimum number of community consensus votes (&lt;code&gt;MinVotesToPromote&lt;/code&gt;) from independent sessions before it is mathematically averaged and officially promoted into the live dataset.&lt;/p&gt;
&lt;h2&gt;
  
  
  Dataset Mathematical Blueprint
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2bnpe9fokm18a5rqv5a8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2bnpe9fokm18a5rqv5a8.gif" alt="Koro loves a good dataset" width="640" height="360"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Koro loves a dataset of his favorite taste, it makes his guessing so much easier!&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;To make the engine guess accurately in under 20 questions, your custom dataset needs a highly efficient structure. Based on our experience, here is what we followed for our own dataset:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The "Golden Ratio" (Questions to Characters)&lt;/strong&gt;&lt;br&gt;
For optimal convergence, you should aim for a &lt;strong&gt;1:2&lt;/strong&gt; or &lt;strong&gt;1:3&lt;/strong&gt; question-to-character ratio. For example, if your dataset has 100 characters, aiming for about 45-50 well-framed questions is the sweet spot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Semantic vs. Specific Questions&lt;/strong&gt;&lt;br&gt;
The secret to a fast guessing engine is maximizing the Expected Information Gain (EIG) early on.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Broad/Semantic Questions:&lt;/strong&gt; Roughly &lt;strong&gt;40-50%&lt;/strong&gt; of your dataset should be broad semantic questions designed to split the candidate pool by at least 20%. These are mathematically vital for early-game variance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specific/Niche Questions:&lt;/strong&gt; Keep highly specific questions to under &lt;strong&gt;10%&lt;/strong&gt; of your dataset. Reserve these exclusively for distinguishing between extremely similar characters deep in the search tree. The rest questions should be category based.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid Too Many Niche Questions:&lt;/strong&gt; Keeping a niche question for each/most character(s) will make it eventually impossible to guess the character within 20 questions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Usage &amp;amp; Installation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyioodzchvzppdym9mcp1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyioodzchvzppdym9mcp1.gif" alt="Koro ready to run" width="320" height="179"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Are we ready to go?&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;If you want to run the engine locally in your terminal, the process is incredibly simple. Make sure you have &lt;strong&gt;Go (1.21+)&lt;/strong&gt; installed.&lt;/p&gt;
&lt;h3&gt;
  
  
  Build the Engine
&lt;/h3&gt;

&lt;p&gt;To compile the &lt;code&gt;akinator-go&lt;/code&gt; binary, simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Play the Game
&lt;/h3&gt;

&lt;p&gt;To run a standard game session where the engine tries to guess your character based on your custom &lt;code&gt;knowledge.json&lt;/code&gt;, pass the file path as an argument to the binary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./akinator-go path/to/your/knowledge.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgkybhud07ni6khzwvuhc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgkybhud07ni6khzwvuhc.png" alt="Engine demo 1" width="799" height="323"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fisoymmuh2a8yw2mh2imt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fisoymmuh2a8yw2mh2imt.png" alt="Engine demo 2" width="799" height="323"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Review Pending Corrections
&lt;/h3&gt;

&lt;p&gt;Remember our Anti-Troll system from the Anti-Troll &amp;amp; Adversarial Defense section? As people play, their corrections get stored in the queue. If you want to review the pending queue and manually promote corrections to the live database, pass the &lt;code&gt;--review&lt;/code&gt; flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./akinator-go &lt;span class="nt"&gt;--review&lt;/span&gt; path/to/your/knowledge.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ⚖️ License
&lt;/h2&gt;

&lt;p&gt;This project is completely open-sourced under the &lt;strong&gt;AGPL 3.0&lt;/strong&gt; License.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqpy4ugku8n9n9rue7hqf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqpy4ugku8n9n9rue7hqf.gif" alt="Koro Sensei goodbye" width="320" height="427"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Koro will meet you soon in any of his other forms! Don't forget to try and beat him at: &lt;a href="https://anime-akinator.vercel.app/" rel="noopener noreferrer"&gt;https://anime-akinator.vercel.app/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>go</category>
      <category>opensource</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>Built an Anime Akinator that tries to guess your character</title>
      <dc:creator>Ankit Mishra</dc:creator>
      <pubDate>Tue, 30 Jun 2026 11:08:49 +0000</pubDate>
      <link>https://dev.to/aaklon/built-an-anime-akinator-that-tries-to-guess-your-character-5fg7</link>
      <guid>https://dev.to/aaklon/built-an-anime-akinator-that-tries-to-guess-your-character-5fg7</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa9dycf07sfsliq67fcxu.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa9dycf07sfsliq67fcxu.jpeg" alt="Sensei Knows Banner" width="800" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Sensei Knows: The Akinator Engine
&lt;/h1&gt;




&lt;p&gt;&lt;strong&gt;Sensei Knows&lt;/strong&gt; is an Akinator engine that powers our official &lt;a href="https://anime-akinator.vercel.app/" rel="noopener noreferrer"&gt;Anime Akinator&lt;/a&gt;. If you've ever wondered how Akinator works or wanted to build your own 20 Questions character guessing game, this repository is for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8tysnngibzm5a8d34btz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8tysnngibzm5a8d34btz.gif" alt="Koro Yeah I did it" width="320" height="228"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Believe me I can do this!&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft9y7b2alugoem90rlo0g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft9y7b2alugoem90rlo0g.gif" alt="Funny mind reading gif" width="320" height="270"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;When you try to pick a totally obscure character, but the engine still reads your mind...&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why we Built It?&lt;/li&gt;
&lt;li&gt;Current Implementation&lt;/li&gt;
&lt;li&gt;
The Architecture

&lt;ul&gt;
&lt;li&gt;Core Philosophy: A Statistical Approach&lt;/li&gt;
&lt;li&gt;The Math &amp;amp; Prediction Logic&lt;/li&gt;
&lt;li&gt;Reinforcement Learning (Self-Correction)&lt;/li&gt;
&lt;li&gt;Anti-Troll &amp;amp; Adversarial Defense&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Dataset Mathematical Blueprint&lt;/li&gt;
&lt;li&gt;Usage &amp;amp; Installation&lt;/li&gt;
&lt;li&gt;License&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Why we Built It?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F105ob24er9r7ncft2bhc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F105ob24er9r7ncft2bhc.gif" alt="Looking at C++ Frameworks" width="320" height="180"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Us looking at C++ backend web frameworks...&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;It all started with a specific goal in mind: we wanted to build an &lt;strong&gt;Anime Akinator&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At first, we engineered the core guessing logic using &lt;strong&gt;C++&lt;/strong&gt; because of its performance. However, when the time came to hook this engine up to a live website as a backend service, that's when we faced many problems. Building a C++ web server was turning into an absolute nightmare as we had no experience with it and could not find any framework which provided all what we needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdpiser74afck6s3q2dqq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdpiser74afck6s3q2dqq.gif" alt="Learning Go" width="498" height="281"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;So we sat down, explored Go, and made the decision to make a switch.&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;We decided to ditch the C++ backend and switch entirely to &lt;strong&gt;Golang&lt;/strong&gt;. Go's built-in concurrency, simple HTTP standard library, and ease of deployment made it the absolute perfect choice for us.&lt;/p&gt;
&lt;h2&gt;
  
  
  Current Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhhhc5kh7w53n0xrhtrfz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhhhc5kh7w53n0xrhtrfz.gif" alt="Showing off the implementation" width="268" height="164"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;I am already live to read your minds!&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;Right now, we have a live instance of this exact engine for our original project running: Sensei Knows. You can play around with it and try to beat the engine here:&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://anime-akinator.vercel.app/" rel="noopener noreferrer"&gt;anime-akinator.vercel.app&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's a sneak peek of the frontend we hooked up to our Go engine:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw82sdmaqlasag4qkyybl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw82sdmaqlasag4qkyybl.png" alt="Demo 1" width="800" height="357"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fks09u93ci6dgt4vfbhyu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fks09u93ci6dgt4vfbhyu.png" alt="Demo 2" width="800" height="347"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4119lmi311lwsg4xiyfe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4119lmi311lwsg4xiyfe.png" alt="Demo 3" width="800" height="347"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa4d9zlc816d6m676vkyd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa4d9zlc816d6m676vkyd.png" alt="Demo 4" width="800" height="347"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk1a3pbndq64g8aeg9z1x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk1a3pbndq64g8aeg9z1x.png" alt="Demo 5" width="800" height="347"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnf3mdmd01v4sotqatrr7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnf3mdmd01v4sotqatrr7.png" alt="Demo 6" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But here is the best part: &lt;strong&gt;this engine is completely dataset-agnostic.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can literally just swap out the dataset to make it guess Hollywood actors, cars, programming languages, or even your own friends.&lt;/p&gt;

&lt;p&gt;If you end up using this engine for a different dataset or project, &lt;em&gt;please&lt;/em&gt; let us know! (&lt;em&gt;Do share your project link with us :)&lt;/em&gt;) We'd absolutely love to see what kind of crazy things you build with it.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Core Philosophy: A Statistical Approach
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fykurwkboie5xw53i4on5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fykurwkboie5xw53i4on5.gif" alt="Koro Sensei philosopher" width="450" height="252"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;"I knew I am a philosopher nururufuhuhu"&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;While decision trees and binary search algorithms are foundational to computer science for exact matching, building a robust guessing engine requires dealing with human uncertainty. Standard binary trees fail gracefully; a single incorrect answer or a "Don't Know" response can lead to an unrecoverable collapse of the search space.&lt;/p&gt;

&lt;p&gt;Drawing inspiration from existing literature on probabilistic classifiers (such as Naive Bayes), our engine is built as a &lt;strong&gt;dynamic statistical classification system&lt;/strong&gt;. This allows the engine to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Operate on a continuous probability space (&lt;code&gt;Yes&lt;/code&gt; = 1.0, &lt;code&gt;Probably&lt;/code&gt; = 0.75, &lt;code&gt;Don't Know&lt;/code&gt; = 0.50, &lt;code&gt;Probably Not&lt;/code&gt; = 0.25, &lt;code&gt;No&lt;/code&gt; = 0.0).&lt;/li&gt;
&lt;li&gt;Handle noise and human error. A contradictory answer does not eliminate a candidate; it merely applies a mathematical penalty to their posterior probability.&lt;/li&gt;
&lt;li&gt;Dynamically compute the optimal sequence of questions based on the active state of the knowledge base, rather than relying on a static, pre-computed graph.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  The Math &amp;amp; Prediction Logic
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffm3nv5hb0610qp2321a7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffm3nv5hb0610qp2321a7.gif" alt="Koro Sensei Sweating over math" width="320" height="288"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The engine sweating over probabilities to figure out who you are thinking of...&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;The engine's predictions are powered by several core mathematical concepts:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Probabilistic State Representation&lt;/strong&gt;&lt;br&gt;
Instead of boolean values, the knowledge base stores two parameters for every question associated with a character: a continuous weight 

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;w&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;∈&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;[&lt;/span&gt;&lt;span class="mord"&gt;0&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mclose"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 and a sample size 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Posterior Probability &amp;amp; Beta-Prior Smoothing&lt;/strong&gt;&lt;br&gt;
When a user provides an answer 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
, the posterior probability 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;P&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 for every character 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 is updated. The baseline match score is the absolute distance: 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;w&lt;/span&gt;&lt;span class="mord"&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
.&lt;/p&gt;

&lt;p&gt;However, to prevent total probability collapse (the zero-frequency problem where one bad answer reduces a character's probability to exactly 0), we apply a &lt;strong&gt;Beta-prior smoothing calibration&lt;/strong&gt;:&lt;/p&gt;


&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;α&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;w&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;⋅&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1.0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;



&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;β&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;w&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;⋅&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1.0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;


&lt;p&gt;We compute a dynamic lower bound (epsilon) based on these Beta parameters. The final match score is bounded by this epsilon, ensuring the engine can always recover from anomalies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Shannon Entropy &amp;amp; Information Gain&lt;/strong&gt;&lt;br&gt;
To determine which question to ask next, the engine does not look at a tree. It computes the current &lt;strong&gt;Shannon Entropy&lt;/strong&gt; (
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;H&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
) of the entire character distribution:&lt;/p&gt;


&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;H&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mop op-symbol large-op"&gt;∑&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;P&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mop"&gt;&lt;span class="mop"&gt;lo&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;P&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;C&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;


&lt;p&gt;For every eligible question, the engine simulates the expected entropy 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;E&lt;/span&gt;&lt;span class="mopen"&gt;[&lt;/span&gt;&lt;span class="mord mathnormal"&gt;H&lt;/span&gt;&lt;span class="mclose"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 across all 5 possible answer buckets, weighted by their marginal probabilities. The question that yields the highest &lt;strong&gt;Expected Information Gain (EIG)&lt;/strong&gt; (
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;H&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;E&lt;/span&gt;&lt;span class="mopen"&gt;[&lt;/span&gt;&lt;span class="mord mathnormal"&gt;H&lt;/span&gt;&lt;span class="mclose"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
) is mathematically guaranteed to split the remaining candidates most efficiently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. UCB (Upper Confidence Bound) Exploration&lt;/strong&gt;&lt;br&gt;
To balance exploiting known good questions and exploring new ones, the engine applies a UCB bonus. Questions that have a low selection count receive a slight mathematical boost, ensuring the engine tests new pathways and doesn't get stuck in local optima.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Output Format&lt;/strong&gt;&lt;br&gt;
When the engine has exhausted its question cap or hit its guess threshold, it calculates and outputs the final &lt;strong&gt;Top Candidates List&lt;/strong&gt; along with their exact computed percentage confidence scores directly in the terminal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frnwji3j0q0wsiw75haa7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frnwji3j0q0wsiw75haa7.gif" alt="Koro calculating probabilities" width="320" height="175"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Koro calculating the probabilities for each of your responses...&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Reinforcement Learning (Self-Correction)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fld1kpgocw46dwykp0sdj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fld1kpgocw46dwykp0sdj.gif" alt="Koro Sensei learning" width="320" height="179"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Koro having troubles seeing so much to learn from...&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;A static database quickly becomes outdated. To solve this, the engine employs a continuous reinforcement learning mechanism. Every time a game concludes, whether the engine guessed correctly or was corrected by the user, the system learns from the session.&lt;/p&gt;

&lt;p&gt;For the correct character, the engine updates its stored weights (
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
) and sample sizes (
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
) for every question answered during the session. It calculates a consistency score between the user's answer and the stored weight, then applies an observation weight scaled by the existing data mass (to prevent a single user from drastically altering well-established facts). The character's parameters are thus incrementally refined, allowing the engine to adapt to community consensus over time.&lt;/p&gt;
&lt;h3&gt;
  
  
  Anti-Troll &amp;amp; Adversarial Defense
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F18tsv2nilmce0ex8pvbh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F18tsv2nilmce0ex8pvbh.gif" alt="Koro Sensei dodging bullets" width="320" height="179"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Sensei dodging all the bullets bad players send...&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;One of the biggest challenges in crowdsourced learning is malicious data poisoning (trolls). If users intentionally give wrong answers, they could corrupt the dataset. We built two layers of defense to prevent this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Adversarial Flagging (Z-Collapse Detection)&lt;/strong&gt;&lt;br&gt;
During a session, the engine monitors the sum of probabilities (
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;Z&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
). If a user's answers are statistically inconsistent with the knowledge base, 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;Z&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 collapses. If the collapse fraction exceeds a certain threshold, the session is flagged as "adversarial," and its answers are completely ignored for live training.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Staging &amp;amp; Review System&lt;/strong&gt;&lt;br&gt;
When a user adds a new character or corrects the engine, the change does not go live immediately. Instead, it is pushed to a &lt;code&gt;PendingCorrections&lt;/code&gt; queue. A correction must gather a minimum number of community consensus votes (&lt;code&gt;MinVotesToPromote&lt;/code&gt;) from independent sessions before it is mathematically averaged and officially promoted into the live dataset.&lt;/p&gt;
&lt;h2&gt;
  
  
  Dataset Mathematical Blueprint
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2bnpe9fokm18a5rqv5a8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2bnpe9fokm18a5rqv5a8.gif" alt="Koro loves a good dataset" width="640" height="360"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Koro loves a dataset of his favorite taste, it makes his guessing so much easier!&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;To make the engine guess accurately in under 20 questions, your custom dataset needs a highly efficient structure. Based on our experience, here is what we followed for our own dataset:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The "Golden Ratio" (Questions to Characters)&lt;/strong&gt;&lt;br&gt;
For optimal convergence, you should aim for a &lt;strong&gt;1:2&lt;/strong&gt; or &lt;strong&gt;1:3&lt;/strong&gt; question-to-character ratio. For example, if your dataset has 100 characters, aiming for about 45-50 well-framed questions is the sweet spot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Semantic vs. Specific Questions&lt;/strong&gt;&lt;br&gt;
The secret to a fast guessing engine is maximizing the Expected Information Gain (EIG) early on.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Broad/Semantic Questions:&lt;/strong&gt; Roughly &lt;strong&gt;40-50%&lt;/strong&gt; of your dataset should be broad semantic questions designed to split the candidate pool by at least 20%. These are mathematically vital for early-game variance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specific/Niche Questions:&lt;/strong&gt; Keep highly specific questions to under &lt;strong&gt;10%&lt;/strong&gt; of your dataset. Reserve these exclusively for distinguishing between extremely similar characters deep in the search tree. The rest questions should be category based.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoid Too Many Niche Questions:&lt;/strong&gt; Keeping a niche question for each/most character(s) will make it eventually impossible to guess the character within 20 questions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Usage &amp;amp; Installation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyioodzchvzppdym9mcp1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyioodzchvzppdym9mcp1.gif" alt="Koro ready to run" width="320" height="179"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Are we ready to go?&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;If you want to run the engine locally in your terminal, the process is incredibly simple. Make sure you have &lt;strong&gt;Go (1.21+)&lt;/strong&gt; installed.&lt;/p&gt;
&lt;h3&gt;
  
  
  Build the Engine
&lt;/h3&gt;

&lt;p&gt;To compile the &lt;code&gt;akinator-go&lt;/code&gt; binary, simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Play the Game
&lt;/h3&gt;

&lt;p&gt;To run a standard game session where the engine tries to guess your character based on your custom &lt;code&gt;knowledge.json&lt;/code&gt;, pass the file path as an argument to the binary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./akinator-go path/to/your/knowledge.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgkybhud07ni6khzwvuhc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgkybhud07ni6khzwvuhc.png" alt="Engine demo 1" width="799" height="323"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fisoymmuh2a8yw2mh2imt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fisoymmuh2a8yw2mh2imt.png" alt="Engine demo 2" width="799" height="323"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Review Pending Corrections
&lt;/h3&gt;

&lt;p&gt;Remember our Anti-Troll system from the Anti-Troll &amp;amp; Adversarial Defense section? As people play, their corrections get stored in the queue. If you want to review the pending queue and manually promote corrections to the live database, pass the &lt;code&gt;--review&lt;/code&gt; flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./akinator-go &lt;span class="nt"&gt;--review&lt;/span&gt; path/to/your/knowledge.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ⚖️ License
&lt;/h2&gt;

&lt;p&gt;This project is completely open-sourced under the &lt;strong&gt;AGPL 3.0&lt;/strong&gt; License.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqpy4ugku8n9n9rue7hqf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqpy4ugku8n9n9rue7hqf.gif" alt="Koro Sensei goodbye" width="320" height="427"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Koro will meet you soon in any of his other forms! Don't forget to try and beat him at: &lt;a href="https://anime-akinator.vercel.app/" rel="noopener noreferrer"&gt;https://anime-akinator.vercel.app/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>go</category>
      <category>opensource</category>
      <category>sideprojects</category>
    </item>
  </channel>
</rss>
