#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <EEPROM.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
const byte ROWS = 4;
const byte 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);
const int buzzer = 10;
int score = 0, totalSoal = 10;
int benar = 0, salah = 0, kosong = 0;
int level = 1, topScore = 0;
void setup() {
lcd.init();
lcd.backlight();
pinMode(buzzer, OUTPUT);
randomSeed(analogRead(0));
EEPROM.get(0, topScore);
if(topScore < 0) topScore = 0;
tampilkanMenu();
}
void loop() {
char key = keypad.getKey();
if (key) {
tone(buzzer, 1000, 50);
if (key >= '1' && key <= '3') {
level = key - '0';
mulaiGame();
}
}
}
void tampilkanMenu() {
lcd.clear();
lcd.noCursor();
lcd.setCursor(0,0);
lcd.print("Level: Tekan 1-3");
lcd.setCursor(0,1);
lcd.print("Top Score: ");
lcd.print(topScore);
}
void mulaiGame() {
score = 0; benar = 0; salah = 0; kosong = 0;
lcd.clear();
lcd.print("Apa kamu siap?");
delay(1000); // Delay di luar loop permainan masih aman
for (int i = 3; i > 0; i--) {
lcd.clear();
lcd.setCursor(7,0);
lcd.print(i);
tone(buzzer, 1200, 100);
delay(1000);
}
for (int soalKe = 1; soalKe <= totalSoal; soalKe++) {
mainkanSoal(soalKe);
}
selesaiGame();
}
void mainkanSoal(int nomor) {
int a = random(1, 10);
int b;
if (level == 1) b = random(1, 5);
else if (level == 2) b = random(1, 8);
else b = random(1, 10);
int jawabanBenar = a * b;
String inputUser = "";
lcd.clear();
lcd.print("Soal "); lcd.print(nomor);
lcd.setCursor(0,1);
lcd.print(a); lcd.print(" x "); lcd.print(b); lcd.print(" = ");
int startX = (String(a).length() + String(b).length() + 6);
lcd.setCursor(startX, 1);
lcd.cursor();
unsigned long startTime = millis();
unsigned long timerSatuDetik = 0;
bool answered = false;
// LOOP INI HARUS SANGAT CEPAT
while (millis() - startTime < 3000) {
char key = keypad.getKey(); // Dibaca terus menerus tanpa delay
// Update timer di layar setiap 1 detik tanpa menghentikan loop
if (millis() - timerSatuDetik >= 100) {
lcd.setCursor(15, 0);
lcd.print(3 - ((millis() - startTime) / 1000));
lcd.setCursor(startX + inputUser.length(), 1);
timerSatuDetik = millis();
}
if (key) {
tone(buzzer, 1000, 50); // Beep singkat (non-blocking tone)
if (key >= '0' && key <= '9') {
inputUser += key;
lcd.print(key);
}
else if (key == '*') {
if (inputUser.length() > 0) {
inputUser.remove(inputUser.length() - 1);
lcd.setCursor(startX, 1);
lcd.print(" ");
lcd.setCursor(startX, 1);
lcd.print(inputUser);
}
}
else if (key == '#') {
answered = true;
break;
}
}
}
lcd.noCursor();
lcd.clear();
if (inputUser == "") {
score -= 3; kosong++;
lcd.print("WAKTU HABIS!");
tone(buzzer, 400, 500);
} else {
if (inputUser.toInt() == jawabanBenar) {
score += 1; benar++;
lcd.print("BENAR! (+1)");
tone(buzzer, 1500, 100); delay(100); tone(buzzer, 2000, 100);
} else {
score -= 1; salah++;
lcd.print("SALAH! Jwb:"); lcd.print(jawabanBenar);
tone(buzzer, 300, 400);
}
}
delay(1000); // Jeda singkat setelah jawaban muncul
}
void selesaiGame() {
lcd.clear();
lcd.print("Game Selesai!");
delay(2000);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("B:"); lcd.print(benar);
lcd.print(" S:"); lcd.print(salah);
lcd.print(" K:"); lcd.print(kosong);
lcd.setCursor(0,1);
lcd.print("Score: "); lcd.print(score);
if (score > topScore) {
topScore = score;
EEPROM.put(0, topScore);
delay(1000);
lcd.setCursor(0,0);
lcd.print("NEW TOP SCORE! ");
tone(buzzer, 1000, 500);
}
delay(4000);
tampilkanMenu();
}