//#include <LiquidCrystal.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // Initialize the LCD
// Pin out
int buzzer = 2;
int btnA = 5;
int btnB = 4;
int redled = 7;
int blueled = 8;
// Variables globales
int gameTime = 60 * 30; // Default game duration (30 minutos)
int timeA = 0; // Time accumulated by Alpha Team
int timeB = 0; // Time accumulated by Bravo Team
bool dominationA = false; // Indicates if the Alpha Team is dominating
bool dominationB = false; // Indicates if Bravo Team is dominating
int gameType = 0; // Game Type
long currentMillis; // Current elapsed milliseconds
long blinkMillisA = 0;
long blinkMillisB = 0;
bool ledStateA = LOW;
bool ledStateB = LOW;
/*
Game Type:
1 - TIME: Over a certain period of time, see which team dominates the most time, only shows the winning team not time earned.
Press both button once in position to start the countdown game timer.
2 - DOMINATION: See which team is the first to dominate a certain amount of time
Press both buttons then prop can be placed at locations.
*/
/**
String getFormattedTime(int totalSeconds)
Receives an integer representing the number of seconds and returns a string in the form "MM:SS".
*/
String getFormattedTime(int totalSeconds) {
int minutes = totalSeconds / 60;
int seconds = totalSeconds - (minutes * 60);
String strMin = minutes < 10 ? "0" + String(minutes) : String(minutes);
String strSec = seconds < 10 ? "0" + String(seconds) : String(seconds);
return strMin + ":" + strSec;
}
/**
void showGameStatus()
Displays the current status of the game counters on the screen.
*/
void showGameStatus() {
lcd.clear();
lcd.setCursor(5, 0);
lcd.print(getFormattedTime(gameTime));
lcd.setCursor(0, 0);
lcd.print("RED");
lcd.setCursor(0, 1);
lcd.print(getFormattedTime(timeA));
lcd.setCursor(11, 1);
lcd.print(getFormattedTime(timeB));
lcd.setCursor(12, 0);
lcd.print("BLUE");
}
/**
void showTakenPoint()
Displays a message on the screen indicating that the point has already been taken.
*/
void showTakenPoint() {
lcd.clear();
lcd.setCursor(2, 0);
lcd.print("POINT TAKEN!");
}
/**
int getUserInput()
Waits for the user to press a button and returns which button was pressed:
1 - BtnA
2 - BtnB
3 - Both at the same time
*/
int getUserInput() {
int userInput = 0;
while (true) {
if (digitalRead(btnA) == LOW) {
tone(buzzer, 5000, 100);
delay(150);
if (digitalRead(btnB) == LOW) {
tone(buzzer, 6000, 100);
userInput = 3;
break;
}
userInput = 1;
break;
}
if (digitalRead(btnB) == LOW) {
tone(buzzer, 5000, 100);
delay(150);
if (digitalRead(btnA) == LOW) {
tone(buzzer, 6000, 100);
userInput = 3;
break;
}
userInput = 2;
break;
}
}
while (digitalRead(btnA) == LOW || digitalRead(btnB) == LOW) {}
return userInput;
}
/**
void errorTone()
Plays a pair of consecutive low tones on the buzzer indicating an error.
*/
void errorTone() {
tone(buzzer, 250, 50);
delay(100);
tone(buzzer, 250, 50);
delay(100);
}
/**
void initialSetup()
Manages the initial setup, establishing the type of game and duration.
*/
void initialSetup() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("R: TIME");
lcd.setCursor(0, 1);
lcd.print("B: DOMINATION");
int userInput = 0;
while (userInput != 1 && userInput != 2) {
userInput = getUserInput();
}
gameType = userInput;
lcd.clear();
lcd.setCursor(0, 0);
String msg = gameType == 1 ? "MAX TIME" : "GOAL TIME";
lcd.print(msg);
bool setupDone = false;
while (!setupDone) {
lcd.setCursor(0, 1);
lcd.print(getFormattedTime(gameTime));
userInput = getUserInput();
switch (userInput) {
case 1:
if (gameTime > 300)
gameTime -= 300;
else
errorTone();
break;
case 2:
if (gameTime < 30000)
gameTime += 300;
else
errorTone();
break;
case 3:
setupDone = true;
break;
default:
break;
}
}
}
/**
bool isGameOver()
Checks the current state of the game to determine if it is finished.
Returns true if the game is over.
*/
bool isGameOver() {
if (gameType == 1) {
if (timeA > gameTime + timeB || timeB > gameTime + timeA)
return true;
} else if (gameType == 2) {
if (timeA >= gameTime || timeB >= gameTime)
return true;
}
return false;
}
/**
void showGameResult()
End of game announcements and presents the winning team on the screen.
*/
void showGameResult() {
String winner = timeA > timeB ? "RED" : "BLUE";
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("END OF GAME");
lcd.setCursor(3, 1);
lcd.print("WINNER: " + winner);
/** Removed sound from playing at end
tone(buzzer, 2000);
delay(500);
noTone(buzzer);
tone(buzzer, 4000);
delay(500);
noTone(buzzer);
*/
}
/**
bool conqer(int teamButton)
Point conquest process. Returns true if the point was conquered.
*/
bool conqer(int teamButton) {
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("CAPTURING");
int progress = 0;
while (digitalRead(teamButton) == LOW) {
lcd.setCursor(progress, 1);
lcd.print("*");
tone(buzzer, 500, 100);
delay(400);
progress++;
if (progress == 16)
return true;
}
return false;
}
/**
void setup()
Program entry point.
*/
void setup() {
pinMode(buzzer, OUTPUT);
pinMode(btnA, INPUT_PULLUP);
pinMode(btnB, INPUT_PULLUP);
pinMode(redled, OUTPUT);
pinMode(blueled, OUTPUT);
lcd.begin(16, 2);
for (int i = 0; i < 3; i++) {
tone(buzzer, 5000, 50);
delay(100);
}
initialSetup();
currentMillis = millis();
}
/**
void loop()
Eternal cycle of execution.
*/
void loop() {
if (digitalRead(btnA) == LOW) {
if (dominationA) {
tone(buzzer, 100);
showTakenPoint();
while (digitalRead(btnA) == LOW) {}
noTone(buzzer);
} else if (conqer(btnA)) {
digitalWrite(redled, HIGH);
digitalWrite(blueled, LOW);
dominationA = true;
dominationB = false;
}
} else if (digitalRead(btnB) == LOW) {
if (dominationB) {
tone(buzzer, 100);
showTakenPoint();
while (digitalRead(btnB) == LOW) {}
noTone(buzzer);
} else if (conqer(btnB)) {
digitalWrite(redled, LOW);
digitalWrite(blueled, HIGH);
dominationA = false;
dominationB = true;
}
}
if (millis() - currentMillis > 1000) {
currentMillis = millis();
if (gameType == 1) gameTime--;
if (dominationA) timeA++;
if (dominationB) timeB++;
showGameStatus();
if (isGameOver()) showGameResult();
}
// Blink LEDs when the team has control
if (dominationA) {
if (millis() - blinkMillisA >= 500) { // 500 ms interval
blinkMillisA = millis();
ledStateA = !ledStateA;
digitalWrite(redled, ledStateA);
}
} else {
digitalWrite(redled, LOW);
}
if (dominationB) {
if (millis() - blinkMillisB >= 500) { // 500 ms interval
blinkMillisB = millis();
ledStateB = !ledStateB;
digitalWrite(blueled, ledStateB);
}
}
}