#include <Wire.h>
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
//bzucak je vsecko
const int piezoPin = 10;
unsigned long lastBeepTime = 0;
//ledky definice
const int ledPin = 11;
unsigned long lastLedMillis = 0;
int ledBlinkInterval = 1000; // defaultně 1 sekunda
bool ledState = false;
// Inicializace I2C LCD (adresa 0x27, 16 znaků x 2 řádky)
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Nastavení klávesnice
const byte ROWS = 4; // 4 řádky
const byte COLS = 4; // 4 sloupce
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {2, 3, 4, 5}; // Piny řádků
byte colPins[COLS] = {6, 7, 8, 9}; // Piny sloupců
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// Globální proměnné
String securityCode = ""; // Nastavený bezpečnostní kód
int hours = 0, minutes = 0, seconds = 0; // Nastavený časovač
int attemptsLeft = 0; // Počet pokusů pro režim B
char selectedMode = 0; // Vybraný režim ('A', 'B', 'C' nebo 'D')
bool countdownStarted = false;
bool bombDefused = false;
unsigned long previousMillis = 0; // Pro neblokující časovač
bool timerRunning = false;
unsigned long remainingTime = 0;
//víherní melodie
void victoryMelody() {
int melody[] = { 262, 294, 330, 349, 392, 440, 494, 523 }; // C D E F G A B C
int noteDurations[] = { 4, 4, 4, 4, 4, 4, 4, 4 }; // Čtvrtky (můžeš upravit tempo)
for (int i = 0; i < 8; i++) {
int noteDuration = 1000 / noteDurations[i];
tone(piezoPin, melody[i], noteDuration);
delay(noteDuration * 1.3);
}
}
// Jedno krátké pípnutí
void shortBeep() {
tone(piezoPin, 1500, 100); // 1500 Hz na 100 ms
}
// Dlouhé pípnutí
void longBeep() {
tone(piezoPin, 1000, 1000); // 1000 Hz na 1s
}
// Pípání podle rychlosti (pro odpočet)
void tickingBeep() {
tone(piezoPin, 3000, 50); // 3000 Hz na 50 ms
}
//clear tone
void cleartone() {
tone(piezoPin, 400, 50);
}
//určení blikání červená
void ledBlink() {
unsigned long currentMillis = millis();
if (currentMillis - lastLedMillis >= ledBlinkInterval) {
lastLedMillis = currentMillis;
ledState = !ledState;
digitalWrite(ledPin, ledState ? HIGH : LOW);
}
}
// Zobrazení času na LCD
void displayTime() {
lcd.setCursor(0, 0);
lcd.print("Cas: ");
lcd.print((hours < 10 ? "0" : "") + String(hours) + ":");
lcd.print((minutes < 10 ? "0" : "") + String(minutes) + ":");
lcd.print((seconds < 10 ? "0" : "") + String(seconds));
}
// Validace času (HHMMSS)
bool isValidTime(String timeInput) {
if (timeInput.length() != 6) return false;
int h = timeInput.substring(0, 2).toInt();
int m = timeInput.substring(2, 4).toInt();
int s = timeInput.substring(4, 6).toInt();
return (h < 24 && m < 60 && s < 60);
}
// Neblokující odpočet času
void countdownNonBlocking() {
unsigned long currentMillis = millis();
// LEDky červené nefacha opravit
if (timerRunning) {
// Určím interval blikání podle zbývajícího času
if (remainingTime <= 5 * 60 * 1000) {
ledBlinkInterval = 500; // 2x za sekundu
} else {
ledBlinkInterval = 1000; // 1x za sekundu
}
ledBlink();
}
// Nezávisle běží pípání
unsigned long totalSeconds = hours * 3600L + minutes * 60L + seconds;
unsigned long beepInterval;
if (totalSeconds <= 300) { // když zbývá 5 minut nebo méně
beepInterval = 500; // 2x za sekundu
} else {
beepInterval = 1000; // normální pípání
}
if (currentMillis - lastBeepTime >= beepInterval) {
tickingBeep();
lastBeepTime = currentMillis;
}
// Každou vteřinu aktualizuj čas
if (currentMillis - previousMillis >= 1000 && !bombDefused) {
previousMillis = currentMillis;
if (seconds > 0) {
seconds--;
} else if (minutes > 0) {
minutes--;
seconds = 59;
} else if (hours > 0) {
hours--;
minutes = 59;
seconds = 59;
} else {
lcd.clear();
lcd.print("!Bomba vybuchla!");
longBeep(); // dlouhé pípnutí při výbuchu
countdownStarted = false;
while (1) { /* Nekonečná smyčka */ }
}
// Vypíšeme čas
displayTime();
}
}
// Funkce pro zadání počtu pokusů (režim B)
void setupAttempts() {
lcd.clear();
lcd.print("Nastav pokusy:");
String attemptsInput = "";
while (true) {
char key = keypad.getKey();
if (key >= '0' && key <= '9') {
attemptsInput += key;
lcd.setCursor(0, 1);
lcd.print(attemptsInput);
} else if (key == '#') {
if (attemptsInput.length() > 0) {
cleartone();
attemptsInput.remove(attemptsInput.length() - 1);
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(attemptsInput);
}
} else if (key == '*' && attemptsInput.length() > 0) {
attemptsLeft = attemptsInput.toInt();
if (attemptsLeft > 0) {
shortBeep();
lcd.clear();
lcd.print("Pokusy: " + String(attemptsLeft));
delay(1000);
lcd.clear();
break;
} else {
lcd.clear();
lcd.print("Min 1 pokus");
delay(1000);
lcd.clear();
lcd.print("Nastav pokusy:");
attemptsInput = "";
}
}
}
}
// Zpracování vstupu během odpočtu (zadávání bezpečnostního kódu)
void handleKeyDuringCountdown() {
// Statická proměnná pro uchování vstupu kódu
static String codeEntry = "";
char key = keypad.getKey();
if (key >= '0' && key <= '9') {
codeEntry += key;
lcd.setCursor(0, 1);
lcd.print(codeEntry);
}
else if (key == '*') { // Potvrzení kódu
if (codeEntry == securityCode) {
bombDefused = true;
shortBeep();
lcd.clear();
// První řádek: "Bomba"
lcd.setCursor((16 - 5) / 2, 0); // 5 znaků, takže levý okraj = (16-5)/2 = 5 (zaokrouhleno dolů)
lcd.print("Bomba");
// Druhý řádek: "zneskodnena!"
lcd.setCursor((16 - 12) / 2, 1); // "zneskodnena!" má 12 znaků, tedy levý okraj = (16-12)/2 = 2
lcd.print("zneskodnena!");
victoryMelody();
while (1) { /* Nekonečná smyčka */ }
} else {
// Špatný kód, zpracování dle režimu
if (selectedMode == 'C') {
// Režim C: zobrazí se hláška a hráč může zkusit znovu
shortBeep();
lcd.clear();
lcd.print("Spatny kod");
delay(1000);
lcd.clear();
displayTime();
codeEntry = "";
}
else if (selectedMode == 'A') {
// Režim A: špatný kód vede k okamžitému výbuchu
longBeep();
lcd.clear();
lcd.print("!Bomba vybuchla!");
while (1) { /* Nekonečná smyčka */ }
}
else if (selectedMode == 'B') {
// Režim B: odečte se jeden pokus
attemptsLeft--;
if (attemptsLeft <= 0) {
longBeep();
lcd.clear();
lcd.print("!Bomba vybuchla!");
while (1) { /* Nekonečná smyčka */ }
} else {
lcd.clear();
lcd.print("Pokusy: " + String(attemptsLeft));
delay(1000);
lcd.clear();
displayTime();
codeEntry = "";
}
}
else if (selectedMode == 'D') {
// Režim D: zkrátí se aktuální čas na polovinu
long totalSeconds = hours * 3600L + minutes * 60L + seconds;
totalSeconds /= 2; // Polovina zbývajícího času
hours = totalSeconds / 3600;
totalSeconds %= 3600;
minutes = totalSeconds / 60;
seconds = totalSeconds % 60;
shortBeep();
lcd.clear();
lcd.print("Cas zkracen!");
delay(1000);
lcd.clear();
displayTime();
codeEntry = "";
}
}
}
else if (key == '#') {
if (codeEntry.length() > 0) {
cleartone();
codeEntry.remove(codeEntry.length() - 1);
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(codeEntry);
}
}
}
// Zobrazení popisu režimu (A, B, C, D)
void displayModeDescription(char mode) {
lcd.clear();
switch (mode) {
case 'A':
lcd.print("Mod A: BUM");
lcd.setCursor(0, 1);
lcd.print("Potvrd *");
break;
case 'B':
lcd.print("Mod B: Pokusy");
lcd.setCursor(0, 1);
lcd.print("Potvrd *");
break;
case 'C':
lcd.print("Mod C: Cas");
lcd.setCursor(0, 1);
lcd.print("Potvrd *");
break;
case 'D':
lcd.print("Mod D: Zkraceni");
lcd.setCursor(0, 1);
lcd.print("Potvrd *");
break;
}
}
void setup() {
lcd.begin(16, 2);
lcd.backlight();
// Výběr režimu (A, B, C nebo D)
lcd.print("Vyber mod:");
lcd.setCursor(0, 1);
lcd.print("A B C D");
while (true) {
char key = keypad.getKey();
if (key == 'A' || key == 'B' || key == 'C' || key == 'D') {
selectedMode = key;
displayModeDescription(key);
}
else if (key == '*' && (selectedMode == 'A' || selectedMode == 'B' || selectedMode == 'C' || selectedMode == 'D')) {
shortBeep();
lcd.clear();
lcd.print("Potvrzeno!");
delay(1000);
lcd.clear();
break;
}
}
// Pokud byl vybrán režim B, nastav počet pokusů
if (selectedMode == 'B') {
setupAttempts();
}
// Nastavení bezpečnostního kódu
lcd.clear();
lcd.print("Nastav kod:");
{
String codeInput = "";
while (securityCode == "") {
char key = keypad.getKey();
if (key >= '0' && key <= '9') {
codeInput += key;
lcd.setCursor(0, 1);
lcd.print(codeInput);
}
else if (key == '#') {
if (codeInput.length() > 0) {
cleartone();
codeInput.remove(codeInput.length() - 1);
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(codeInput);
}
}
else if (key == '*') {
shortBeep();
securityCode = codeInput;
lcd.clear();
lcd.print("Kod nastaven");
delay(1000);
lcd.clear();
break;
}
}
}
//LED setup
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
// Nastavení času
lcd.clear();
lcd.print("Nastav cas:");
{
String timeInput = "";
while (hours == 0 && minutes == 0 && seconds == 0) {
char key = keypad.getKey();
if (key >= '0' && key <= '9') {
if (timeInput.length() < 6) { // Max 6 číslic (HHMMSS)
timeInput += key;
// Formátování: vytvoříme řetězec ve formátu HH:MM:SS
String formattedTime = "";
int len = timeInput.length();
if (len >= 1) {
// Vložení hodin (max 2 číslice)
formattedTime = timeInput.substring(0, min(2, len));
}
if (len > 2) {
formattedTime += ":";
// Vložení minut (další 2 číslice, pokud existují)
formattedTime += timeInput.substring(2, min(4, len));
} else if (len == 2) {
formattedTime += ":";
}
if (len > 4) {
formattedTime += ":";
// Vložení sekund (zbytek)
formattedTime += timeInput.substring(4);
} else if (len == 4) {
formattedTime += ":";
}
lcd.setCursor(0, 1);
lcd.print(" "); // Vymazání řádku
lcd.setCursor(0, 1);
lcd.print(formattedTime);
}
}
else if (key == '#') {
cleartone();
if (timeInput.length() > 0) {
timeInput.remove(timeInput.length() - 1);
// Znovu formátovat čas po smazání
String formattedTime = "";
int len = timeInput.length();
if (len >= 1) {
formattedTime = timeInput.substring(0, min(2, len));
}
if (len > 2) {
formattedTime += ":";
formattedTime += timeInput.substring(2, min(4, len));
} else if (len == 2) {
formattedTime += ":";
}
if (len > 4) {
formattedTime += ":";
formattedTime += timeInput.substring(4);
} else if (len == 4) {
formattedTime += ":";
}
lcd.setCursor(0, 1);
lcd.print(" "); // Vymazání řádku
lcd.setCursor(0, 1);
lcd.print(formattedTime);
}
}
else if (key == '*') { // Potvrzení času
shortBeep();
if (timeInput.length() == 6 && isValidTime(timeInput)) {
hours = timeInput.substring(0, 2).toInt();
minutes = timeInput.substring(2, 4).toInt();
seconds = timeInput.substring(4, 6).toInt();
lcd.clear();
lcd.print("Cas nastaven!");
delay(1000);
lcd.clear();
break; // Ukončí zadávání času
} else {
lcd.clear();
lcd.print("Neplatny cas!");
delay(1000);
lcd.clear();
lcd.print("Nastav cas:");
timeInput = "";
}
}
}
}
// Zahájení odpočtu
countdownStarted = true;
}
void loop() {
if (countdownStarted) {
countdownNonBlocking();
handleKeyDuringCountdown();
}
}