Week 9: Reaction-Time Game

Concept

I got the idea for this assignment after watching a campus cat swiftly pounce upon a tiny lizard on the wall in front of the arts center. It got me thinking about reflexes and reaction times and how I can create a mini-game out of this using Arduino. The game basically works like this:
There are two LEDs, one red and one green, one button, and one potentiometer. When the green LED turns on, the player must press the button as fast as they can. If they press it in time, the green LED flashes thrice, indicating a win, otherwise the red LED flashes, indicating the loss. If the green LED flashes, they can see their reaction time in milliseconds on the screen as well. The potentiometer controls the difficulty of the game in two ways. Firstly, it controls the random waiting period (i.e. how long the Arduino waits before turning on the green LED). A decrease in the delay between instances would need the player to be on higher alert. Secondly, it controls the reaction time threshold (i.e. how fast the player must press the button to win). At the easiest setting, the player has 400ms to react, and at the hardest, only 100ms.

Image & Video Documentation

The code

// potentiometer (A0), button (2), red LED (9), green LED (8)

const int potPin = A0;
const int buttonPin = 2;
const int greenLED = 8;
const int redLED = 9;

void setup() {
  pinMode(greenLED, OUTPUT);
  pinMode(redLED, OUTPUT);
  // use a resistor in the microcontroller instead of on the breadboard
  // causes inverted logic: not pressed - HIGH, pressed - LOW
  pinMode(buttonPin, INPUT_PULLUP); // Internal pull-up resistor
  Serial.begin(9600);
  randomSeed(analogRead(A5)); // Add some randomness
}

void loop() {
  Serial.println("Get ready");
  digitalWrite(redLED, LOW);
  digitalWrite(greenLED, LOW);
  delay(2000); // brief pause before start

  // Read difficulty from potentiometer
  int potValue = analogRead(potPin);
  int waitTime = map(potValue, 0, 1023, 1000, 3000); // 1s to 3s random wait range
  // potValue = 0 then threshold = 400 ms; 
  // potValue = 1023 then threshold = 100 ms (hard)
  int threshold = map(potValue, 0, 1023, 400, 100);  

  // Random gap time before LED turns on
  int randomDelay = random(1000, waitTime);
  delay(randomDelay);

  // Start the test
  digitalWrite(greenLED, HIGH);
  unsigned long startTime = millis();

  // Wait for button to be pressed or timeout
  bool pressed = false;
  unsigned long reactionTime = 0;

  while (millis() - startTime < 2000) {       // 2 seconds max to press button
    if (digitalRead(buttonPin) == LOW) {
      pressed = true;   // player successfully pressed the button
      reactionTime = millis() - startTime;    // calculate the player's reaction time
      break;
    }
  }

  digitalWrite(greenLED, LOW);    // turn off green LED

  if (pressed && reactionTime < threshold) {
    // Player wins
    // Display reaction time
    Serial.print("Your reaction time: ");
    Serial.println(reactionTime);

    // Flash green LED thrice to indicate win
    for (int i = 0; i < 3; i++) {
      digitalWrite(greenLED, HIGH);
      delay(150);
      digitalWrite(greenLED, LOW);
      delay(150);
    }

  } else {
    // Player loses
    Serial.println("Too slow!");
    // Flash red LED thrice to indicate loss
    for (int i = 0; i < 3; i++) {
      digitalWrite(redLED, HIGH);
      delay(200);
      digitalWrite(redLED, LOW);
      delay(200);
    }
  }

  delay(1000); // small 1s pause between game rounds
}

Reflection & Future Improvements

I had a lot of fun making this project. I think the physical setup was not too complicated, and still gave an effective output through the implemented code. In future versions, I think it would be nice to have a buzzer that gives different sounds on win/loss conditions, and maybe also implement a score counter that keeps track of how many times the player won throughout multiple rounds. I believe it would also be effective to add another LED (probably yellow) that blinks during the “get ready” phase of each round.

Leave a Reply