#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <EEPROM.h>
// LCD setup (common I2C addresses: 0x27 or 0x3F)
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Keypad setup
const byte ROWS = 4, COLS = 4;
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// Game state
int a, b, correctAnswer;
char operation;
String userInput = "";
int difficulty = 0; // 0: easy, 1: medium, 2: hard
int score = 0, total = 0;
int highScore = 0;
int strikes = 0;
void setup() {
Wire.begin();
lcd.init();
lcd.backlight();
randomSeed(analogRead(0));
highScore = EEPROM.read(0);
showMenu();
}
void loop() {
char key = keypad.getKey();
if (key) {
if (key == 'A') { difficulty = 0; startGame(); }
else if (key == 'B') { difficulty = 1; startGame(); }
else if (key == 'C') { difficulty = 2; startGame(); }
if (key >= '0' && key <= '9') {
userInput += key;
lcd.setCursor(0, 1);
lcd.print("Ans: " + userInput + " ");
} else if (key == '#') {
int userAnswer = userInput.toInt();
total++;
lcd.setCursor(0, 1);
if (userAnswer == correctAnswer) {
score++;
lcd.print("Correct! ");
} else {
lcd.print("Wrong! " + String(correctAnswer));
strikes++;
}
if (score > highScore) {
highScore = score;
EEPROM.update(0, highScore);
}
delay(2000);
if (strikes >= 3) {
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("GAME OVER");
lcd.setCursor(1, 1);
lcd.print("Score: " + String(score));
delay(3000);
showMenu();
return;
}
askNewQuestion();
} else if (key == '*') {
userInput = "";
lcd.setCursor(0, 1);
lcd.print("Ans: ");
}
}
}
void startGame() {
score = 0;
total = 0;
strikes = 0;
askNewQuestion();
}
void askNewQuestion() {
int minVal = 1, maxVal;
byte opCount;
if (difficulty == 0) {
maxVal = 9;
opCount = 1; // only +
} else if (difficulty == 1) {
maxVal = 99;
opCount = 2; // + and -
} else {
maxVal = 999;
opCount = 4; // + - * /
}
a = random(minVal, maxVal + 1);
b = random(minVal, maxVal + 1);
int op = random(0, opCount); // Only from allowed ops
switch (op) {
case 0: operation = '+'; correctAnswer = a + b; break;
case 1: operation = '-'; correctAnswer = a - b; break;
case 2: operation = '*'; correctAnswer = a * b; break;
case 3:
b = random(1, maxVal);
correctAnswer = random(1, maxVal / b);
a = b * correctAnswer;
operation = '/';
break;
}
userInput = "";
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(String(a) + operation + String(b) + " = ?");
lcd.setCursor(0, 1);
lcd.print("Ans: ");
showScore();
}
void showScore() {
lcd.setCursor(9, 1);
lcd.print("S:");
lcd.print(score);
lcd.print("/");
lcd.print(total);
// Show strikes in top-right corner
lcd.setCursor(13, 0);
for (int i = 0; i < 3; i++) {
if (i < strikes) lcd.print("X");
else lcd.print(" ");
}
}
void showMenu() {
userInput = "";
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Press A/B/C to");
lcd.setCursor(0, 1);
lcd.print("Choose Level");
}