#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define LCD_ADDR 0x27
LiquidCrystal_I2C lcd(LCD_ADDR, 20, 4);
const int buttonPins[4] = {15, 2, 4, 16}; // Buttons for options A-D
const int buzzerPin = 17; // Buzzer pin
// RGB LED pins
const int redPin = 5;
const int greenPin = 18;
const int bluePin = 19;
const int TOTAL_QUESTIONS = 20;
int currentQuestion = 0;
int score = 0;
int selectedOption = -1;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50;
struct Question {
String question;
int options[4];
int answerIndex;
};
Question questions[TOTAL_QUESTIONS];
// Generate random math question with 4 options
Question generateQuestion() {
Question q;
int a = random(1, 21);
int b = random(1, 21);
int op = random(0, 3);
if (op == 0) {
q.question = String(a) + " + " + String(b) + " = ?";
q.options[0] = a + b;
} else if (op == 1) {
if (a < b) { int t = a; a = b; b = t; }
q.question = String(a) + " - " + String(b) + " = ?";
q.options[0] = a - b;
} else {
q.question = String(a) + " * " + String(b) + " = ?";
q.options[0] = a * b;
}
for (int i = 1; i < 4; i++) {
int val;
do {
val = q.options[0] + random(-10, 11);
} while (val == q.options[0] || val < 0);
q.options[i] = val;
}
// Shuffle options
for (int i = 3; i > 0; i--) {
int j = random(0, i + 1);
int temp = q.options[i];
q.options[i] = q.options[j];
q.options[j] = temp;
}
for (int i = 0; i < 4; i++) {
if (q.options[i] == q.options[0]) {
q.answerIndex = i;
break;
}
}
return q;
}
void setup() {
Serial.begin(115200);
lcd.init();
lcd.backlight();
for (int i = 0; i < 4; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
}
pinMode(buzzerPin, OUTPUT);
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
digitalWrite(redPin, LOW);
digitalWrite(greenPin, LOW);
digitalWrite(bluePin, LOW);
randomSeed(analogRead(0));
for (int i = 0; i < TOTAL_QUESTIONS; i++) {
questions[i] = generateQuestion();
}
displayQuestion();
}
void displayQuestion() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Q"); lcd.print(currentQuestion + 1);
lcd.print(": ");
lcd.print(questions[currentQuestion].question);
for (int i = 0; i < 4; i++) {
lcd.setCursor(0, i + 1);
lcd.print(char('A' + i));
lcd.print(") ");
lcd.print(questions[currentQuestion].options[i]);
if (i == selectedOption) lcd.print(" <");
}
}
void beep(int freq, int duration) {
tone(buzzerPin, freq, duration);
delay(duration);
noTone(buzzerPin);
}
void setRGB(bool r, bool g, bool b) {
digitalWrite(redPin, r ? HIGH : LOW);
digitalWrite(greenPin, g ? HIGH : LOW);
digitalWrite(bluePin, b ? HIGH : LOW);
}
void showFeedback(bool correct) {
if (correct) {
setRGB(false, true, false); // Green ON
beep(1000, 200);
} else {
setRGB(true, false, false); // Red ON
beep(400, 500);
}
delay(1000);
setRGB(false, false, false); // Turn off all
}
void loop() {
for (int i = 0; i < 4; i++) {
if (digitalRead(buttonPins[i]) == LOW) {
if (millis() - lastDebounceTime > debounceDelay) {
selectedOption = i;
displayQuestion();
delay(200);
lastDebounceTime = millis();
}
}
}
static unsigned long selectStart = 0;
static bool timing = false;
if (selectedOption != -1) {
if (!timing) {
selectStart = millis();
timing = true;
}
if (millis() - selectStart > 1000) {
bool correct = (selectedOption == questions[currentQuestion].answerIndex);
if (correct) score++;
showFeedback(correct);
currentQuestion++;
if (currentQuestion >= TOTAL_QUESTIONS) {
showResults();
while (1) {}
}
selectedOption = -1;
displayQuestion();
timing = false;
}
} else {
timing = false;
}
}
void showResults() {
lcd.clear();
lcd.setCursor(0, 1);
lcd.print("Quiz Completed!");
lcd.setCursor(0, 2);
lcd.print("Score: ");
lcd.print(score);
lcd.print("/");
lcd.print(TOTAL_QUESTIONS);
}