Guessatron

by Arnov Sharma in Circuits > Gadgets

35 Views, 3 Favorites, 0 Comments

Guessatron

Guessatron—20 Question Guessing Game - ESP32 S3 Display
34.gif
37.gif
40.gif
thumbb.JPG

Greetings, everyone!

Meet Guessatron—a pocket-sized marvel that plays 20 Questions and tries to guess what you're thinking. Just think of anything—a mango, a microscope, maybe even Mars—and Guessatron will interrogate your imagination one question at a time, narrowing down possibilities until it locks onto your answer.

Guessatron is like the OG Akinator; you think of something and this device will guess that thing!

This tiny device fits comfortably in the palm of your hand. Housed in a custom-designed, 3D-printed enclosure, it’s powered by a 3.7V 2000mAh LiPo cell, making it fully portable and self-sufficient.

Inside, it runs a smart logic tree capable of guessing up to 70 different objects—and the best part? You can expand its database to include even more.

This Instructables is about the complete build guide of this project, so let's get started with the project.

Supplies

These were the materials used in this project:

  1. Waveshare ESP32-S3-LCD-1.69 Screen (provided by PCBWAY)
  2. LiPo Cell 3.7V 2000mAh
  3. Slide Switch
  4. Push Buttons
  5. Perf Board
  6. Connecting Wires
  7. 3D Printed Parts

CONCEPT

Screenshot 2025-08-25 124245.jpg
hq720.jpg

Guessatron is based on the well-known online guessing game Akinator, which amazes players by using AI and huge datasets to guess what they are thinking. However, I wanted to create something that seemed solid, grounded, and local rather than depending on machine learning or cloud-based intelligence. A guessing game that only uses embedded logic and doesn't use the internet or artificial intelligence.

Guessatron makes no claim of being intelligent, in contrast to Akinator. It isn't real-time adaptation or learning from millions of players. It does, however, provide a delightful, standalone experience: an ESP32-powered guessing game that selects your object from a carefully selected library of 70 objects (and counting) and poses yes/no questions.

This project is also a technical playground—combining a custom 3D-printed enclosure, onboard power via a 3.7V 2000mAh LiPo cell, and a crisp display interface. It’s designed to be held, played with, and expanded. Guessatron may not be as smart as Akinator, but it’s something you can build, hold, and proudly show off.

DESIGN

20.220.png
20.218.png
42.gif
07.gif
08.gif
20.217.png
20.219.png
20.221.png
41.gif

We began the project's design or development process by first importing the screen into Fusion360, along with the models for the slide switch, lithium battery, and switchboard with three push buttons.

The objective was to design a very portable and robust device that anyone could hold in their hand. It will include three buttons that users can press to operate the device.

Following the guidelines, we positioned the switchboard below the display with a slight leftward shift and the display in the center. The sliding switch was positioned on the right side of the model, aligned with the switchboard, and the lithium battery was positioned on the opposite side of the display.

Now comes the design part; We created a shape that resembles a cuboid with rounded corners, drawing inspiration from an old television. The ESP32 display was raised just above the switchboard's level, and we created a box-like part around it that creates an illusion that the screen is positioned slightly outside. This created an intriguing design element and enhanced the device's visual appeal.

Similarly, we modeled the buttons that are positioned above the enclosure boundary for switch actuators.

The Entire device is split into two parts: the front and back enclosures, shelling out both bodies, creating ribs that line up with the display and switchboard, and even creating a holding part for the slide switch.

The front and rear enclosures were joined together by three holes on each body; we essentially assembled them and fastened them together with three M2 screws. Since we didn't have much room for screw bosses, we decided to use hot glue to secure the remaining components in place.

By the way, if you're diving into plastic part design, I strongly recommend checking out design guides from companies like DuPont, 3M, and GE Plastics. These resources offer deep insights into the entire engineering process—from proper part construction to critical factors like shrinkage, tooling, and material behavior. Studying these guides can significantly simplify the design workflow and help you avoid common pitfalls.

We exported the mesh files for every component after finishing the design; the front enclosure was printed in transparent PLA. The back enclosure and switch actuators were printed using our Creality K10 Max with orange PLA.

ESP32 S3 Display

IMG_7750.JPG
04.gif
05.gif
06.gif
ESP32-S3-LCD-1.69_240718_001.png
ESP32-S3-LCD-1.69-details-size.jpg
IMG_6481.JPG

The ESP32-S3-LCD-1.69 is the real star of this setup. Despite its small size, it is incredibly powerful. Its dual-core Xtensa LX7 processor, which can run at up to 240 MHz, provides seamless performance for everything from input handling to display rendering. With its integrated Wi-Fi and Bluetooth 5, it can connect without the need for additional modules or complicated wiring.

Memory-wise, it’s stacked: 512KB of SRAM, 384KB of ROM, plus 8MB of onboard PSRAM and 16MB of external Flash.

This board is loaded with features that enhance our Guessatron, including a 1.69-inch capacitive LCD screen, a lithium battery charging chip, and a six-axis sensor with a three-axis accelerometer and gyroscope.

It has an ETA6098 lithium battery charging chip for long-term power management, a QMI8658 inertial measurement unit (IMU) for motion tracking, and an RTC chip for clock functions.

Audio feedback can be provided by the integrated buzzer; demo flashing is made simple by the Type-C interface. Furthermore, the BOOT and RST buttons make firmware downloads and resets easier, and a function button that may be customized allows for single, double, and long pushes, among other input ways.

Although the ST7789V2 LCD controller's active display area is 240(H) × RGB × 280(V), it offers a 240 × RGB × 320 resolution. It is compatible with RGB444, RGB565, and RGB666 color formats; for best visual results, our project uses RGB565.

The display's smooth corners add to its elegant, small appearance, and the four-wire SPI interface guarantees effective GPIO usage and quick communication speed.

You can check out more about this display from its Wiki page: https://www.waveshare.com/wiki/ESP32-S3-LCD-1.69

PCBWAY GIFTSHOP

Screenshot 2025-08-25 123246.jpg
01.gif
02.gif
Screenshot 2025-08-25 123158.jpg

As for sourcing the ESP32-S3-LCD-1.69 we use in our project, we got it from PCBWAY's Giftshop.

https://pcbway.com/s/cr77wO

PCBWAY gift shop is an online marketplace where you can get a variety of electronics modules and boards for their genuine price, or you could use the PCBWAY currency, which is called beans.

You get beans after ordering something from PCBWAY as reward points, or you can also get them by posting any project in the PCBWAY community.

Over the past ten years, PCBWay has distinguished themselves by providing outstanding PCB manufacturing and assembly services, becoming a trusted partner for countless engineers and designers worldwide.

You guys can check out PCBWAY if you want great PCB service at an affordable rate.

PUSH BUTTON PCB & ESP32 S3 DISPLAY ASSEMBLY

11.gif
12.gif
13.gif
14.gif
15.gif
  1. A custom three-button PCB made on a Perf board will be used for the inputs. The GPIO Pins of the ESP32 S3 Board will be linked to this Perfboard button PCB.
  2. First, we link all three push button pins 3 together; this common connection will be connected to GND.
  3. By connecting the NO button to GPIO13, the YES button to GPIO12, and the SOMETIMES button to GPIO14, we link the Button PCB to the ESP32 S3 board's GPIO Pins.

POWER SOURCE WIRING

Wiring.jpg
16.gif
17.gif
  1. Connecting the LiPo cell's positive to the ESP32 S3 board's battery connector's positive pin starts the power source wiring process.
  2. The LiPo cell's GND is linked to the COM terminal of a slide switch, and the NC terminal is then connected to the GND pin of the battery connector. We can turn the device on or off with this slide switch.

SLIDE SWITCH PLACEMENT

18.gif

We now start the enclosure assembly process by installing the slide switch into its designated location within the front enclosure part.

DISPLAY & BODY ASSEMBLY

19.gif
20.gif
21.gif
  1. Making sure the USB type C is facing the top, we now place the ESP32 S3 Board in its proper location.
  2. The slide switch and the display are then secured in place by applying hot glue using a hot glue gun, first over the slide switch and then over the display.

SWITCH ACTUATORS ASSEMBLY

22.gif
23.gif
24.gif
25.gif
  1. The three 3D-printed switch actuators are now positioned in the proper mounting holes on the front end.
  2. Making sure the actuators touch the push button, we now place the Switch PCB above the Switch actuators.
  3. The Switch PCB is mounted in place using hot glue.

FINAL ASSEMBLY

26.gif
27.gif
28.gif
29.gif
30.gif
  1. We Place the Lipo cell inside the front enclosure for the final assembly and then add the back enclosure from the back side.
  2. We now secure the front and back enclosures together with three M2 screws by screwing them into the three mounting holes that were added to the top and bottom faces of the enclosure.

Now that our device has been assembled, let's go to the most critical stage of the project: the coding stage.

CODE BREAKDOWN

Here's the code we have developed for this project, and it's not exactly simple, but with a solid logic table ready and help from my new friend, Mr. AI, i was able to complete this project.

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define BUTTON_YES 12
#define BUTTON_NO 13
#define BUTTON_SOMETIMES 14
struct QuestionNode {
String text;
int yesNext = -1;
int noNext = -1;
int sometimesNext = -1;
int index;
};
struct Object {
String name;
int answers[20];
};
#include "objects_70.h"
const int objectCount = sizeof(objects) / sizeof(objects[0]);
QuestionNode questionTree[] = {
{"Is it alive?", 1, 2, 3, 0},
{"Is it an animal?", 4, 5, 6, 1},
{"Is it man-made?", 7, 8, 9, 2},
{"Can it be alive sometimes?", 10, 11, 12, 3},
{"Does it live with humans?", 13, 14, 15, 4},
{"Does it have a screen?", 16, 17, 18, 5},
{"Is it used in work?", 19, 20, 21, 6},
{"Is it electronic?", 22, 23, 24, 7},
{"Is it used for cooking?", 25, 26, 27, 8},
{"Can it be used outside?", 28, 29, 30, 9},
{"Does it grow?", 31, 32, 33, 10},
{"Does it walk?", 34, 35, 36, 11},
{"Does it swim?", 37, 38, 39, 12},
{"Is it a pet?", -1, -1, -1, 13},
{"Is it a wild animal?", -1, -1, -1, 14},
{"Is it a farm animal?", -1, -1, -1, 15},
{"Is it a phone?", -1, -1, -1, 16},
{"Is it a computer?", -1, -1, -1, 17},
{"Is it a television?", -1, -1, -1, 18},
{"Is it used in office?", -1, -1, -1, 19},
{"Is it used in school?", -1, -1, -1, 20},
{"Is it used in kitchen?", -1, -1, -1, 21},
{"Is it a gadget?", -1, -1, -1, 22},
{"Is it a tool?", -1, -1, -1, 23},
{"Is it a vehicle?", -1, -1, -1, 24},
{"Is it an appliance?", -1, -1, -1, 25},
{"Is it edible?", -1, -1, -1, 26},
{"Is it found outdoors?", -1, -1, -1, 27},
{"Is it used for exercise?", -1, -1, -1, 28},
{"Is it used for fun?", -1, -1, -1, 29},
{"Can it float?", -1, -1, -1, 30},
{"Is it a plant?", -1, -1, -1, 31},
{"Is it a tree?", -1, -1, -1, 32},
{"Does it need water?", -1, -1, -1, 33},
{"Is it a mammal?", -1, -1, -1, 34},
{"Is it a bird?", -1, -1, -1, 35},
{"Is it an insect?", -1, -1, -1, 36},
{"Is it a fish?", -1, -1, -1, 37},
{"Is it a reptile?", -1, -1, -1, 38},
{"Is it an amphibian?", -1, -1, -1, 39},
};
int answers[20];
bool asked[40];
int answerIndex = 0;
int currentNodeIndex = 0;
void showQuestion(String q) {
display.clearDisplay();
display.setCursor(0, 0);
display.println("Q" + String(answerIndex + 1) + ": " + q);
display.display();
}
int readButton() {
while (true) {
if (digitalRead(BUTTON_YES) == LOW) {
delay(250); while (digitalRead(BUTTON_YES) == LOW); return 1;
}
if (digitalRead(BUTTON_NO) == LOW) {
delay(250); while (digitalRead(BUTTON_NO) == LOW); return 0;
}
if (digitalRead(BUTTON_SOMETIMES) == LOW) {
delay(250); while (digitalRead(BUTTON_SOMETIMES) == LOW); return 2;
}
delay(10);
}
}
String guessObject() {
int bestScore = -1;
String bestMatch = "Not sure!";
for (int i = 0; i < objectCount; i++) {
int score = 0;
for (int j = 0; j < 20; j++) {
if (objects[i].answers[j] == answers[j]) score++;
}
if (score > bestScore) {
bestScore = score;
bestMatch = objects[i].name;
}
}
return bestMatch;
}
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("20Q Game Loading...");
display.display();
pinMode(BUTTON_YES, INPUT_PULLUP);
pinMode(BUTTON_NO, INPUT_PULLUP);
pinMode(BUTTON_SOMETIMES, INPUT_PULLUP);
for (int i = 0; i < 40; i++) asked[i] = false;
for (int i = 0; i < 20; i++) answers[i] = -1;
}
void loop() {
if (answerIndex >= 20) {
String guess = guessObject();
display.clearDisplay();
display.setCursor(0, 0);
display.println("You are thinking of:");
display.println(guess);
display.display();
delay(8000);
currentNodeIndex = 0;
answerIndex = 0;
for (int i = 0; i < 20; i++) answers[i] = -1;
for (int i = 0; i < 40; i++) asked[i] = false;
return;
}
showQuestion(questionTree[currentNodeIndex].text);
int response = readButton();
answers[questionTree[currentNodeIndex].index] = response;
asked[currentNodeIndex] = true;
answerIndex++;
int next = -1;
if (response == 1) next = questionTree[currentNodeIndex].yesNext;
else if (response == 0) next = questionTree[currentNodeIndex].noNext;
else next = questionTree[currentNodeIndex].sometimesNext;
if (next != -1 && !asked[next]) {
currentNodeIndex = next;
return;
}
bool found = false;
for (int i = 0; i < 40; i++) {
if (!asked[i]) {
currentNodeIndex = i;
found = true;
break;
}
}
if (!found) {
answerIndex = 20;
}
}

Display & Input Setup

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

We first added the two important libraries required to run our SSD1306 OLED screen. SCREEN HEIGHT, SCREEN WIDTH and OLED RESET have been added, which define the display.

#define BUTTON_YES 12
#define BUTTON_NO 13
#define BUTTON_SOMETIMES 14

These define the GPIO pins for the three buttons.

object70.h

Object objects[] = {
{"Dog", {1,1,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0}},
{"Cat", {1,1,0,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0}},
{"Cow", {1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0}},
{"Horse", {1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0}},
{"Elephant", {1,1,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0}},
{"Human", {1,1,0,0,1,1,1,1,0,1,0,1,0,1,0,0,0,0,0,0}},
{"Tree", {1,0,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0}},
{"Flower", {1,0,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0}},
{"Phone", {0,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,1,0,0,0}},
{"Laptop", {0,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,0,1,0,0}},
{"Television", {0,0,1,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0}},
{"Chair", {0,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Table", {0,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Spoon", {0,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0}},
{"Car", {0,0,1,0,1,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Bicycle", {0,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Fish", {1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1}},
{"Bird", {1,1,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,0,0,0}},
{"Book", {0,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Pen", {0,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Mouse (device)", {0,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Fan", {0,0,1,0,1,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Fridge", {0,0,1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0}},
{"Washing Machine", {0,0,1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0}},
{"Toaster", {0,0,1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0}},
{"Kettle", {0,0,1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0}},
{"Egg", {1,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0}},
{"Rock", {0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Cloud", {0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Sun", {0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Moon", {0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Train", {0,0,1,0,1,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Bus", {0,0,1,0,1,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Airplane", {0,0,1,0,1,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Helicopter", {0,0,1,0,1,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Drone", {0,0,1,0,1,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Bottle", {0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Bag", {0,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Shoe", {0,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Shirt", {0,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Clock", {0,0,1,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Mirror", {0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Key", {0,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Knife", {0,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0}},
{"Camera", {0,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Calculator", {0,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Tablet", {0,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Microwave", {0,0,1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0}},
{"Sandwich", {0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0}},
{"Pizza", {0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0}},
{"Cup", {0,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0}},
{"Toothbrush", {0,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Soap", {0,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Towel", {0,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Glasses", {0,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Ball", {0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Doll", {0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Toy Car", {0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Stuffed Animal", {0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Robot", {0,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Battery", {0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Light Bulb", {0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0}},
{"Umbrella", {0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0}}
};

We have added a custom header file that stores a list of 70 objects, each with a name and a set of expected answers to the 40 questions in our logic tree.

This file is the backbone of the guessing game. It defines a list of 70 objects, each with a name: "Dog," "Cat," "Mouse," etc. Each object’s answer array acts like a fingerprint; it tells the system how that object would respond to each question.

Question Tree Structure

struct QuestionNode {
String text;
int yesNext, noNext, sometimesNext;
int index;
};

Each node represents a question and depending on the user’s answer (yes/no/sometimes), the game navigates to a different next question.

the index maps the question to a position in the answers[] array.

Object Database

#include "objects_70.h"
const int objectCount = sizeof(objects) / sizeof(objects[0]);

This section Loads 70 predefined objects from a separate file. here, each object has a unique answer pattern.

Question Tree

QuestionNode questionTree[] = {
{"Is it alive?", 1, 2, 3, 0},
{"Is it an animal?", 4, 5, 6, 1},
...
{"Is it an amphibian?", -1, -1, -1, 39},
};

This is the full decision tree with 40 questions. Each question leads to another based on YES/NO/SOMETIMES.

Game State Variables

int answers[20]; // Stores user responses
bool asked[40]; // Tracks which questions were asked
int answerIndex = 0; // How many questions answered
int currentNodeIndex = 0; // Current question node

Displaying Questions

void showQuestion(String q) {
display.clearDisplay();
display.setCursor(0, 0);
display.println("Q" + String(answerIndex + 1) + ": " + q);
display.display();
}

This section clears the screen and shows the current question on display.

Reading Button Input

int readButton() {
while (true) {
if (digitalRead(BUTTON_YES) == LOW) { ... return 1; }
if (digitalRead(BUTTON_NO) == LOW) { ... return 0; }
if (digitalRead(BUTTON_SOMETIMES) == LOW) { ... return 2; }
delay(10);
}
}

This part waits for a button press and debounces it, then returns the corresponding answer value.

Guessing the Object

String guessObject() {
int bestScore = -1;
String bestMatch = "Not sure!";
for (int i = 0; i < objectCount; i++) {
int score = 0;
for (int j = 0; j < 20; j++) {
if (objects[i].answers[j] == answers[j]) score++;
}
if (score > bestScore) {
bestScore = score;
bestMatch = objects[i].name;
}
}
return bestMatch;
}

This Section compares user answers to each object’s expected answers, then picks the object with the highest match score.

Setup Function

void setup() {
display.begin(...);
display.println("20Q Game Loading...");
pinMode(BUTTON_YES, INPUT_PULLUP);
pinMode(BUTTON_NO, INPUT_PULLUP);
pinMode(BUTTON_SOMETIMES, INPUT_PULLUP);
for (int i = 0; i < 40; i++) asked[i] = false;
for (int i = 0; i < 20; i++) answers[i] = -1;
}

This part Initializes the display and buttons and then resets the game state.

Main Game Loop

void loop() {
if (answerIndex >= 20) {
String guess = guessObject();
display.println("You are thinking of:");
display.println(guess);
delay(8000);
// Reset game
...
return;
}

showQuestion(questionTree[currentNodeIndex].text);
int response = readButton();
answers[questionTree[currentNodeIndex].index] = response;
asked[currentNodeIndex] = true;
answerIndex++;

int next = (response == 1) ? yesNext : (response == 0) ? noNext : sometimesNext;
if (next != -1 && !asked[next]) {
currentNodeIndex = next;
return;
}

// If no valid next, find any unasked question
for (int i = 0; i < 40; i++) {
if (!asked[i]) {
currentNodeIndex = i;
break;
}
}

// If all questions asked, trigger guessing
if (!found) {
answerIndex = 20;
}
}

The Main Section displays a question, reads input, and stores the answer.

It Navigates the tree or picks the next unasked question and after 20 questions, it guesses the object.

LOGIC TABLE

TREE NAVIGATION TABLE_page-0001.jpg

I created this logic table for my guessing game, and once you get the feel of it, it's actually rather simple. With 40 questions that each function as a node, I created it as a decision tree. There are three alternative answers to each question: YES, NO, and SOMETIMES.

It all starts with the first question: “Is it alive?” If the user says YES, the game jumps to question 2: "Is it an animal?" Another YES takes us to question 5: "Does it live with humans?" And so on.

Until the system generates its best estimate, the options are reduced with each response, which leads the path further into the tree.

Some questions lead directly to an object; those are marked as END in the table, meaning they don’t branch further. But if the user gives answers that don’t follow any valid path in the tree, the system won’t find a match. That’s intentional.

Additionally, certain questions are skipped completely—they are never displayed and the user's answers remain blank—depending on how they answer them early on.

In summary, only relevant questions influence the final guess, and the tree dynamically adjusts to the user's selections.

RESULT

Guessatron&mdash;20 Question Guessing Game - ESP32 S3 Display
20 Question Guessing Game ESP32 S3
31.gif
35.gif
36.gif
37.gif

During early testing, Guessatron was able to correctly identify things like "dog" and "laptop," demonstrating that its question flow and logic tree are operating as planned. The device asks a succession of yes/no questions, and after a few simple steps, it latches onto the right response, making the experience feel remarkably intuitive. It feels like a little magic trick to watch it make the correct prediction, especially since the entire deduction takes place offline on a little embedded device.

The current database includes 70 distinct objects, and the branching logic is designed to guide the user through a streamlined decision path. Each guess feels earned, and the interaction is smooth when the user follows the expected question flow.

Nevertheless, Guessatron isn't flawless just yet. Halting behavior when users deviate from the preset logic tree is one known problem. A response that deviates from the anticipated course could cause the device to halt or fail to come to a conclusion.

This is a natural limitation of static decision trees, and we're already working on refining the code to make it more resilient and adaptive in future revisions.

For now this project has been completed and i will be revisiting this project with a new revision real soon.

In addition, we appreciate PCBWAY's support of this project. Visit them for a variety of PCB-related services, such as stencil and PCB assembly services, as well as 3D printing services

Thanks for reaching this far, and I will be back with a new project pretty soon.

Peace.