How to use the start button

Friends, this game starts automatically.

What I want is to add a button (so that the game starts when the button is pressed).

Button (A0)

Where and how should I add the code?

https://wokwi.com/projects/454143470040826881

/*Arduino Whack-A-Mole Game 
by mircemk, June 2025
*/

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

// Pin Definitions
const int buttonPins[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; // Button pins
const int ledPins[] = {14, 15, 16, 17, 18, 19, 20, 21, 22, 23};      // LED pins
const int buzzerPin = 13;                   // Buzzer pin (digital 13)
const int numMoles = 10;                     // Number of moles/buttons/LEDs

// Game variables
int currentMole = -1;         // Current mole (LED) to be lit
int score = 0;                // Player's score
unsigned long reactionTime = 1000;  // Initial reaction time (milliseconds)
unsigned long lastMoleTime = 0;     // Time when the last mole was lit
unsigned long gameStartTime = 0;    // Start time of the game
unsigned long gameDuration = 30000; // Total game duration (30 seconds)

// Reaction time adjustment
const unsigned long reactionTimeDecrement = 0; // Time to reduce reaction by (milliseconds)
const unsigned long minReactionTime = 0;       // Minimum reaction time (milliseconds)

void setup() {
  lcd.backlight();
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(2, 0);
  lcd.print("Whack-a-Mole");
  lcd.setCursor(3, 1);
  lcd.print("by mircemk");
  delay(2000);
  lcd.clear();

  // Initialize button pins and LED pins
  for (int i = 0; i < numMoles; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);  // Set button pins as input with pull-up resistors
    pinMode(ledPins[i], OUTPUT);           // Set LED pins as output
    digitalWrite(ledPins[i], LOW);         // Turn off all LEDs initially
  }

  pinMode(buzzerPin, OUTPUT); // Set buzzer pin as output

  Serial.begin(9600); // For debugging and displaying the score
  randomSeed(analogRead(0)); // Initialize random seed from an unused analog pin
  Serial.println("Whack-a-Mole Game Started!");

  lcd.setCursor(2, 0);
  lcd.print("GAME STARTED!");
  delay(500);
  lcd.clear();

  gameStartTime = millis(); // Record game start time
}

void loop() {
  unsigned long currentMillis = millis();  // Get the current time

  // Update the progress bar
  unsigned long elapsedTime = currentMillis - gameStartTime;
  if (elapsedTime <= gameDuration) {
    int barLength = map(gameDuration - elapsedTime, 0, gameDuration, 0, 16);
    lcd.setCursor(0, 1);
    for (int i = 0; i < 16; i++) {
      lcd.print(i < barLength ? '-' : ' '); // Print '-' for remaining time, ' ' for elapsed
    }
  }

  // Light up a mole after a certain amount of time (based on reactionTime)
  if (currentMillis - lastMoleTime >= reactionTime) {
    if (currentMole != -1) {
      digitalWrite(ledPins[currentMole], LOW);  // Turn off the previous mole
    }
    currentMole = random(0, numMoles);  // Randomly pick a mole (LED)
    digitalWrite(ledPins[currentMole], HIGH); // Light up the chosen LED

    lastMoleTime = currentMillis;  // Update the time when the mole was lit
  }

  // Check if the player pressed the correct button for the lit mole
  for (int i = 0; i < numMoles; i++) {
    if (digitalRead(buttonPins[i]) == LOW) {  // Button pressed (LOW due to INPUT_PULLUP)
      if (i == currentMole) {
        score++;  // Correct mole hit
 lcd.setCursor(2, 0);
lcd.print(" Score:      "); // Clear the score field with extra spaces
lcd.setCursor(12, 0);
lcd.print(score); // Update the score

        tone(buzzerPin, 1000, 200);  // High-pitched sound (1000Hz) for 200ms

        if (reactionTime > minReactionTime) {
          reactionTime -= reactionTimeDecrement;
        }
      } else {
        score--;  // Wrong mole hit
 lcd.setCursor(2, 0);
lcd.print(" Score:      "); // Clear the score field with extra spaces
lcd.setCursor(12, 0);
lcd.print(score); // Update the score

        tone(buzzerPin, 400, 200);  // Low-pitched sound (400Hz) for 200ms
      }

      digitalWrite(ledPins[currentMole], LOW);  // Turn off the current mole
      currentMole = -1;  // Reset the mole to indicate no active mole
      delay(500);  // Short delay to debounce button press
    }
  }

  // End the game after the set duration
  if (elapsedTime >= gameDuration) {
lcd.setCursor(3, 0);
lcd.print("Game Over!   ");
lcd.setCursor(0, 1);
lcd.print("Final Score: ");
lcd.setCursor(13, 1);
lcd.print("   ");           // Clear any leftover characters
lcd.setCursor(13, 1);
lcd.print(score);           // Print the final score

// Flash all LEDs and play a sound three times
for (int i = 0; i < 3; i++) {
  for (int j = 0; j < numMoles; j++) {
    digitalWrite(ledPins[j], HIGH);
  }
  tone(buzzerPin, 1000, 300);  // Play sound
  delay(300);                  // Keep LEDs on
  for (int j = 0; j < numMoles; j++) {
    digitalWrite(ledPins[j], LOW);
  }
  delay(300);                  // Keep LEDs off
}

delay(2000);                   // Pause before resetting the game
lcd.clear();
score = 0;
currentMole = -1;
for (int i = 0; i < numMoles; i++) {
  digitalWrite(ledPins[i], LOW);
}
lcd.setCursor(0, 0);
lcd.print(" Start New Game");
delay(5000);
lcd.clear();
gameStartTime = millis();
reactionTime = 1000;
  }
}

In void setup()

  int Button = A0;
  pinMode(Button, INPUT_PULLUP);

Penultimate line at the end of void setup()

  while (digitalRead(Button) == HIGH) {}; // wait for Button (A0) press to create LOW when pressed
  gameStartTime = millis(); // Record game start time

may be with a digitalRead() ? :innocent:

1 Like

Eek... yes... correcting now... sorry...
/* time passes */
Corrected.

2 Likes

as you are making the correction, use HIGH instead of 1 - that's the best practice....

3 Likes

Yes... I have been reading that... but I do not (yet) fully understand why... so I will go off and read more about "why." Thank you.

Friends, there are 10 lights in the game.
8 of them light up correctly and progress correctly when the button is pressed.
2 of them (the light and dark purple ones) light up and go out very quickly.
Is there a bug in the code?

can you post the current code you use and a picture of the circuit / power ?

Hey guys, I want to add a time display (RGB LED) to this game ( https://www.youtube.com/watch?v=GjmTD4byFTk


like in the video link I provided).
Is this possible?
If so, could you teach me how to do it?

I've only done the application work for the project so far.
I haven't actually started the project yet.
I'm trying to figure out the logic behind it.
Right now everything revolves around this.

your code includes an LCD with

LiquidCrystal_I2C lcd(0x27, 16, 2);

On your MEGA, SDA is pin 20 and SCL is pin 21 and it seems you are using them for your leds

const int ledPins[] = {14, 15, 16, 17, 18, 19, 20, 21, 22, 23};      // LED pins

➜ don't

(you can add the LCD in wokwi)

thanks very much my friend

I understand now and I've corrected it. Thank you very much.

It seems the game "progresses" very soon, to the point where no human can react quickly enough.

By documents, digitalRead() returns HIGH or LOW. ← period.

Without looking under the hood, it is not strictly correct to expect any other value.

Same as digitalWrite(), which can only take HIGH or LOW as its second argument.

Yes it is stupid. Yes everyone breaks the rulz around it.

But

  digitalWrite(digitalRead(somePin) == HIGH ? LOW : HIGH);

is what you gotta do to pass with an A+.

So

# define PRESST LOW

or

const auto PRESST = LOW;

and

  bool isPressed = digitalRead(somePin) == PRESST;

is how to escape the stupidity as quickly as you can.

a7

A convention makes sense for understanding other code, and is not stupid. I am late to the coding convention by way of "learnt it on the streets" so I never defined "HIGH" as "1" or "LOW" as "0"... so I am dragging my old, bad, habits into this... and hopefully thisoldog can learn "new" (relative to sliced bread) tricks.

  • Or, PRESSED when you live in the cold north.

:cold_face:

Pressed snow.

Not gonna say where I've been. :wink:

a7

1 Like

:scream:

1 Like

2 Likes