#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define NUM_LEDS 4
#define BLUELED_PIN 13
#define REDLED_PIN 12
#define YELLOWLED_PIN 11
#define GREENLED_PIN 10
#define BTN_BLUE 5
#define BTN_RED 4
#define BTN_YELLOW 3
#define BTN_GREEN 2
#define BTN_MENU_UP 6
#define BTN_MENU_DOWN 7
#define BTN_SELECT 8
#define DELAY 1000
#define TIMEOUT 2000
// ---- ДОБАВЛЕНО ----
#define PHOTO_PIN A0
int lightValue = 0;
bool secretMode = false;
// -------------------
int leds[] = {BLUELED_PIN, REDLED_PIN, YELLOWLED_PIN, GREENLED_PIN};
int btns[] = {BTN_BLUE, BTN_RED, BTN_YELLOW, BTN_GREEN};
int activeLED;
unsigned long startTime;
unsigned long endTime;
unsigned long reactionTime;
int score = 0;
const char* modeNames[] = {
"Reaction Game",
"Memory Game"
};
int currentMode = 0;
bool modeSelected = false;
const int maxSequenceLength = 10;
int memorySequence[maxSequenceLength];
int sequenceLength = 0;
int playerStep = 0;
unsigned long lastBtnMenuUpTime = 0;
unsigned long lastBtnMenuDownTime = 0;
unsigned long lastBtnSelectTime = 0;
const unsigned long debounceDelay = 200;
void setup() {
lcd.init();
lcd.backlight();
Serial.begin(9600);
for (int i = 0; i < NUM_LEDS; i++) {
pinMode(leds[i], OUTPUT);
pinMode(btns[i], INPUT_PULLUP);
}
pinMode(BTN_MENU_UP, INPUT_PULLUP);
pinMode(BTN_MENU_DOWN, INPUT_PULLUP);
pinMode(BTN_SELECT, INPUT_PULLUP);
randomSeed(analogRead(A0));
// ---- СЕКРЕТНЫЙ РЕЖИМ ----
lightValue = analogRead(PHOTO_PIN);
if (lightValue > 200) { // Темно → Секретный вход
secretMode = true;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" SECRET MODE ");
lcd.setCursor(0, 1);
lcd.print(" BOMB GAME ");
delay(1500);
debugMode(); // запускаем секретное меню
secretMode = false;
}
// --------------------------
showMenu();
}
void showMenu() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Mode:");
lcd.setCursor(0, 1);
lcd.print(modeNames[currentMode]);
}
void loop() {
// ---- ПРОВЕРКА СЕКРЕТНОГО РЕЖИМА В ЛЮБОЕ ВРЕМЯ ----
lightValue = analogRead(PHOTO_PIN);
if (lightValue > 200 && !secretMode) { // Темно → включаем секретный режим
secretMode = true;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" SECRET MODE ");
lcd.setCursor(0, 1);
lcd.print(" BOMB GAME ");
delay(1000);
debugMode(); // запускаем секретное меню
secretMode = false;
showMenu(); // возвращаемся к обычному меню после выхода
}
// ---------------------------------------------------
if (!modeSelected) {
handleMenuSelection();
} else {
if (currentMode == 0) reactionGame();
else if (currentMode == 1) memoryGame();
modeSelected = false;
showMenu();
}
}
void handleMenuSelection() {
unsigned long currentMillis = millis();
if (digitalRead(BTN_MENU_UP) == LOW && currentMillis - lastBtnMenuUpTime > debounceDelay) {
currentMode--;
if (currentMode < 0) currentMode = 1;
showMenu();
lastBtnMenuUpTime = currentMillis;
}
if (digitalRead(BTN_MENU_DOWN) == LOW && currentMillis - lastBtnMenuDownTime > debounceDelay) {
currentMode++;
if (currentMode > 1) currentMode = 0;
showMenu();
lastBtnMenuDownTime = currentMillis;
}
if (digitalRead(BTN_SELECT) == LOW && currentMillis - lastBtnSelectTime > debounceDelay) {
modeSelected = true;
lastBtnSelectTime = currentMillis;
lcd.clear();
}
}
bool checkExitButton() {
unsigned long currentMillis = millis();
if (digitalRead(BTN_SELECT) == LOW && (currentMillis - lastBtnSelectTime > debounceDelay)) {
lastBtnSelectTime = currentMillis;
return true;
}
return false;
}
bool anyGameButtonPressed() {
for (int i = 0; i < NUM_LEDS; i++) {
if (digitalRead(btns[i]) == LOW) return true;
}
return false;
}
// ------------------------------------------------------------
// СЕКРЕТНЫЙ РЕЖИМ DEBUG MODE
// ------------------------------------------------------------
void debugMode() {
bool lastDarkState = false; // для отслеживания изменения света
// Показываем начальный экран один раз
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Mode:");
lcd.setCursor(0,1);
lcd.print("Defuse bomb");
while (true) {
int lvl = analogRead(PHOTO_PIN);
bool dark = lvl > 200; // темно → секретный режим
// если свет изменился на светлый, выходим
if (!dark) {
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Exiting ");
delay(1000);
return;
}
// запускаем игру кнопкой, если темно
if (dark && digitalRead(BTN_SELECT) == LOW) {
delay(300);
bombTimerGame();
// После игры можно снова показать меню debug
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Mode:");
lcd.setCursor(0,1);
lcd.print("Defuse bomb");
}
delay(150); // небольшая пауза для кнопок
}
}
// ------------------------------------------------------------
void bombExplosion() {
lcd.clear();
lcd.print("BOOM!!!");
for (int i = 0; i < 8; i++) {
for (int l = 0; l < NUM_LEDS; l++) digitalWrite(leds[l], HIGH);
delay(120);
for (int l = 0; l < NUM_LEDS; l++) digitalWrite(leds[l], LOW);
delay(80);
}
delay(900);
}
int waitDebugButton() {
while (true) {
for (int i = 0; i < NUM_LEDS; i++) {
if (digitalRead(btns[i]) == LOW) return btns[i];
}
}
}
const char bombColors[4] = {'R','G','B','Y'}; // Цвета
const int bombButtons[4] = {BTN_RED, BTN_GREEN, BTN_BLUE, BTN_YELLOW}; // соответствие кнопок
void bombTimerGame() {
const int numRounds = 5;
const int roundLengths[numRounds] = {3, 4, 5, 6, 7}; // длина последовательности
const int roundTimes[numRounds] = {3000, 4000, 5000, 6000, 6000}; // миллисекунды на раунд (-1 секунда)
lcd.clear();
lcd.print("BOMB ARMED!");
delay(1000);
for (int round = 0; round < numRounds; round++) {
int seqLen = roundLengths[round];
char combo[seqLen];
// создаём случайную комбинацию
for (int i = 0; i < seqLen; i++) {
int idx = random(0,4);
combo[i] = bombColors[idx];
}
lcd.clear();
lcd.print("Round ");
lcd.print(round + 1);
unsigned long startTime = millis();
for (int step = 0; step < seqLen; step++) {
int pressed = -1;
while (pressed == -1) {
// всегда показываем комбинацию на LCD
lcd.setCursor(0,1);
for (int i = 0; i < seqLen; i++) lcd.print(combo[i]);
for (int i = 0; i < 4; i++) {
if (digitalRead(bombButtons[i]) == LOW) {
pressed = i;
break;
}
}
// проверка времени
if (millis() - startTime > roundTimes[round]) {
lcd.clear();
lcd.print("TIME OUT!");
for (int i = 0; i < 6; i++) {
for (int l = 0; l < NUM_LEDS; l++) digitalWrite(leds[l], HIGH);
delay(120);
for (int l = 0; l < NUM_LEDS; l++) digitalWrite(leds[l], LOW);
delay(80);
}
return; // конец игры
}
delay(5);
}
// визуальная подсветка кнопки
digitalWrite(leds[pressed], HIGH);
delay(300);
digitalWrite(leds[pressed], LOW);
// проверка правильности
if (bombColors[pressed] != combo[step]) {
lcd.clear();
lcd.print("WRONG! BOOM!");
for (int i = 0; i < 6; i++) {
for (int l = 0; l < NUM_LEDS; l++) digitalWrite(leds[l], HIGH);
delay(120);
for (int l = 0; l < NUM_LEDS; l++) digitalWrite(leds[l], LOW);
delay(80);
}
delay(1000);
return; // конец игры
}
}
// успех раунда
lcd.clear();
lcd.print("Round ");
lcd.print(round + 1);
lcd.setCursor(0,1);
lcd.print("DEFUSED!");
for (int i = 0; i < NUM_LEDS; i++) digitalWrite(leds[i], HIGH);
delay(700);
for (int i = 0; i < NUM_LEDS; i++) digitalWrite(leds[i], LOW);
delay(300);
}
// победа во всех раундах
lcd.clear();
lcd.print("ALL DEFUSED!");
for (int i = 0; i < NUM_LEDS; i++) digitalWrite(leds[i], HIGH);
delay(1500);
for (int i = 0; i < NUM_LEDS; i++) digitalWrite(leds[i], LOW);
}
void reactionGame() {
score = 0;
for (int round = 0; round < 5; round++) {
lcd.setCursor(5, 0);
lcd.print("Ready?");
delay(DELAY);
lcd.clear();
lcd.setCursor(7, 0);
lcd.print("Go");
while (true) {
bool released = true;
for (int i = 0; i < NUM_LEDS; i++) {
if (digitalRead(btns[i]) == LOW) released = false;
}
if (released) break;
delay(5);
}
activeLED = random(0, NUM_LEDS);
digitalWrite(leds[activeLED], HIGH);
unsigned long start = millis();
int pressedButton = -1;
bool timeout = false;
while (pressedButton == -1 && !timeout) {
if (checkExitButton()) {
digitalWrite(leds[activeLED], LOW);
return;
}
for (int i = 0; i < NUM_LEDS; i++) {
if (digitalRead(btns[i]) == LOW) {
pressedButton = i;
break;
}
}
if (millis() - start > TIMEOUT) timeout = true;
delay(5);
}
digitalWrite(leds[activeLED], LOW);
if (timeout) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Time's up!");
lcd.setCursor(0, 1);
lcd.print("Game Over");
delay(1500);
return;
}
if (pressedButton != activeLED) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Wrong Button!");
lcd.setCursor(0, 1);
lcd.print("Game Over");
delay(1500);
return;
}
unsigned long reaction = millis() - start;
if (reaction < 500) score += 2;
else if (reaction < 2000) score += 1;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Time:");
lcd.print(reaction);
lcd.print("ms");
lcd.setCursor(0, 1);
lcd.print("Score:");
lcd.print(score);
delay(1000);
lcd.clear();
}
lcd.setCursor(0, 0);
lcd.print("Game Over");
lcd.setCursor(0, 1);
lcd.print("Score: ");
lcd.print(score);
delay(2000);
}
void memoryGame() {
score = 0;
sequenceLength = 1;
bool gameOver = false;
while (!gameOver && sequenceLength <= maxSequenceLength) {
for (int i = sequenceLength - 1; i < sequenceLength; i++) {
memorySequence[i] = random(0, NUM_LEDS);
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Memorize...");
delay(1000);
for (int i = 0; i < sequenceLength; i++) {
if (checkExitButton()) return;
digitalWrite(leds[memorySequence[i]], HIGH);
delay(500);
digitalWrite(leds[memorySequence[i]], LOW);
delay(250);
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Your turn:");
playerStep = 0;
while (playerStep < sequenceLength) {
if (checkExitButton()) return;
int pressedButton = -1;
while (pressedButton == -1) {
if (checkExitButton()) return;
for (int i = 0; i < NUM_LEDS; i++) {
if (digitalRead(btns[i]) == LOW) {
pressedButton = i;
break;
}
}
delay(5);
}
unsigned long relWaitStart = millis();
while (digitalRead(btns[pressedButton]) == LOW) {
if (millis() - relWaitStart > 1000) break;
delay(5);
}
if (pressedButton == memorySequence[playerStep]) {
score++;
playerStep++;
} else {
gameOver = true;
break;
}
delay(200);
}
if (!gameOver) {
sequenceLength++;
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Good!");
delay(1000);
lcd.clear();
}
}
lcd.clear();
lcd.setCursor(0, 0);
if (gameOver) lcd.print("Wrong! Score:");
else lcd.print("You Win! Score:");
lcd.setCursor(0, 1);
lcd.print(score);
delay(3000);
}