RepeatMe! game for Arduino

This is example code for a game I developed based loosely on Simon Says and similar electronic games.  It uses an Arduino, four buttons, four LEDs, and a speaker, and is essentially a sequence memorization game.  It will play a note and light an LED, after which the user presses the button associated with that note and LED in order to repeat the game’s sequence.  The game adds another step so the sequence is two notes/LEDs long, and the user repeats that two step sequence.  This continues, the game adding another step to the sequence, the user repeating the sequence, until either the user makes a mistake, or the user successfully plays the game to the point where the sequence is 30 steps long.

Simply cut and paste into your Arduino IDE to use.

/*
  RepeatMe!
  
  Author:     Adam Davis 
  Contact:    adavis@ubasics.com
  Date:       2 June 2011
  
  SETUP
  
  This project requires one Arduino, four buttons, four LEDs, and one 
  speaker.
  
  The LEDs are connected to pins 3, 9, 10, 11 and VCC (with a resistor)
  The buttons are connected to pins 5, 6, 7, 8 and ground
  The speaker is connected to pin 4 and ground
  
  PLAY
  
  When started, the game blinks and sings randomly.  Any button press will 
  enter game mode.
  
  In game mode the game simultaneously lights an LED and plays a note.
  The player presses the button that is associated with that light and
  note, then the game plays the note and lights the LED again, and then 
  another light and note in a two note/light sequence.  The player then 
  copies the sequence by pressing the two buttons associated with the 
  lights and notes, and then the game adds another light/note to the 
  sequence which the player must again copy.
  
  Game play continues with the game adding new steps to the sequence until
  either the sequence is 30 steps long, or the player makes a mistake in 
  copying the sequence.
  
  If the player succeeds in completing the full 30 step sequence, all LEDs
  are lit briefly, then the game resets.
  
  If the player makes a mistake, the game plays a low note, then resets.
  
  When connected to the computer with a terminal at 9600bps game information
  is displayed as the game is played.
  
  IMPROVEMENTS

   - Make a winning song for the game to play on winning
   - Make losing more interesting - perhaps it gives you a second and third chance
   - Make it explicitly four player - each player gets one button, they 
     have to play them in proper sequence, and when one person gets it 
     wrong they are out, however the game plays their part so the others
     can continue play to find the winner - the last one remaining
   - Add more game modes
   - Make the sequence playback variable speed - as the sequence gets longer,
     each step is played for a shorter time
   - Remove the 30 sequence limit and see how high people can get.  Keep a
     maximum score to encourage people to beat the highest successful sequence
   - Add some achievements or badges (Use serial port and computer software, or
     LCD support to view and post about achievements on social networks)
   - The LEDs are on PWM capable pins - use PWM to pulse them in a more pleasing
     manner than the existing hard on and off
   - The attraction mode the game starts up in could play more interesting
     melodies and show more interesting LED patterns
   - Could be used as a 4 key piano, or even record and play back the user's song
   - Complex audio generation using a wavetable or sinewaves could produce
     fun synthesizer or more interesting sounds.  Add a microphone and play
     the game with a recorded sound
  
  LICENSE
  
  This code is copyright 2011 Adam Davis, and is provided to the public as
  a public domain work.  You may use it in any way or for any purpose you
  desire.  If it makes things easier for you, feel free to consider this
  work licensed under the BSD, Apache, MIT, or GNU license of your choice. 
  See http://opensource.org/licenses/category for more information on these
  licenses.
  
  This code is provided AS IS without warranties or conditions of any kind.
  You are solely responsible for determining the appropriateness of use or
  redistribution of this code or any derivative, and assume any risks.
 */

// Pin definitions
const static int led[4] = {3, 9, 10, 11};
const static int button[4] = {5, 6, 7, 8};
const static int spk = 4;
const static int pentatonic[5] = {262, 294, 330, 392, 440}; // C, D, E, A, G

int buttonpress;

// Game states
enum GameStates{START, ADD, REPEAT, QUIZ, WIN, LOSE};
int state;
int memory[31];
int count;

// Button and LED macros
#define btn(x) (!(digitalRead((button[(x)]))))
//#define ledpwm(x,y) (analogWrite((led[(x)]),(255-(y))))
#define led(x,y) (digitalWrite((led[(x)]),(!(y))))

int debounce(void);
int leds(int ledvalue);

void setup() {                
  // initialize the digital pin as an output.
  // Pin 13 has an LED connected on most Arduino boards:
  Serial.begin(9600);
  pinMode(13, OUTPUT);     
  for(int index=0; index<4; index++)
  {
    pinMode(led[index], OUTPUT);
    digitalWrite(led[index], HIGH);
    pinMode(button[index], INPUT);
    digitalWrite(button[index], HIGH); // Turn on the pull up resistors
  }
  pinMode(spk, OUTPUT);
  randomSeed(analogRead(0));
  state = START;
  Serial.print("hi");
}

void loop() {
  switch(state)
  {
    case START: // Attract mode
      leds(random(16));
      tone(spk, pentatonic[random(5)]);
      delay(100);
      if(debounce() > -1)
      {
        noTone(spk);
        leds(0);
        Serial.print(" Waiting for you to let go of button\n");
        while(debounce() >= 0);
        delay(500);
        count = 0;
        state = ADD;
      }
      break;
    case ADD: // Add a new step to the existing sequence
      Serial.print("Add\n");
      memory[count] = random(4);
      count++;
      state = REPEAT;
      break;
    case REPEAT: // Play the current sequence
      Serial.print("Repeat\n");
      for(int index=0; index < count; index++)
      {
        tone(spk, pentatonic[memory[index]], 400);
        leds(1<<memory[index]);
        delay(400);
        leds(0);
        delay(100);
      }
      state = QUIZ;
      break;
    case QUIZ: // Quiz the user on the current sequence
      Serial.print("Start quiz\n");
      int answer;
      state = ADD; // Default go to ADD
      for(int index=0; index < count; index++)
      {
        Serial.print(" Wait for button\n");
        while((answer = debounce()) < 0); // Wait for a button press
        // Light the LED
        led(answer, 1);
        Serial.print(" Got button\n");
        // If it's the right button play the tone, if not go to lose
        if(answer == memory[index])
        {
          // Correct
          Serial.print(" Correct\n");
          tone(spk, pentatonic[answer]);
          if(count >=31)
          {
            state = WIN;
          }
        }
        else
        {
          // Incorrect
          Serial.print(" Incorrect\n");
          state = LOSE;
          tone(spk, 60);
          leds(15);
          Serial.print(" Waiting for you to let go of button\n");
          while(debounce() >= 0);
          break; // Stop the for loop before it finishes
        }
        // wait for button to stop, then go to next tone
        Serial.print(" Waiting for you to let go of button.\n"); 
        while(debounce() >= 0);
        leds(0);
        noTone(spk);
      }
      delay(500);
      break;
    case WIN: // User won
      Serial.print("Win\n");
      leds(15);
      delay(250);
      leds(0);
      delay(250);
      break;
    case LOSE: // User lost
      Serial.print("Lose\n");
      Serial.print(" Waiting for a new button press\n");
      if(debounce() >= 0)
      {
        state = START;
      }
      break;
    default: // Uh oh, something bad happened, reset game
      Serial.print("Default\n");
      state = START;
      break;
  }
}

// Check all four buttons. If a button is pressed, wait 30 mS then check again.
// If it's still pressed, return that button number as a successful button press.
int debounce(void)
{
  int index;
  for(index=0; index<4; index++)
  {
    if(btn(index))
    {
      delay(30);
      if(btn(index))
      {
        return index;
      }
    }
  }
  return -1;
}

// Light the LEDs according to the first four bits in ledvalue.
int leds(int ledvalue)
{
  
  led(0, ledvalue & 1);
  led(1, ledvalue & 2);
  led(2, ledvalue & 4);
  led(3, ledvalue & 8);
}
  1. Simon Springs | Semiaxis - pingback on 30Aug2012 at 11:50 am

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackbacks and Pingbacks: