Simon Game

Hey Everyone,

I'm still pretty new to using the Arduino, but I challenged myself to recreate the classic game of Simon with the Arduino. I bet this has been done before, but I didn't manage to find any examples of it in my searches. I have had some programming experience in the past, but it was pretty limited (only a couple of courses), so I hit a few roadblocks with some logic which one of my friends helped me through. Anyways, here's a link to a video of the game. I plan to put this all into a nice project box at some point, but for now it's still on the breadboard. Hope you like it.

1 Like

Great job!

I can imagine the coding must have been very complicated to work out.

Will you be posting the code?

Thanks

For any seasoned programmer or Arduino user, I'm sure the code is fairly basic. It wasn't an overwhelming challenge for me though, as I had a basic understanding of all the elements of the code I used. I would like to eventually integrate a visual turn counter with a 7 segment display, but I have no experience with shift register, and that seems to be the way to go with a 7 segment display. Also, having varying pitches with each light (just like the original Simon) would be nice.

/Simon Says game by Robert Spann/

int switch1 = 11; //The four button input pins
int switch2 = 10;
int switch3 = 9;
int switch4 = 8;
int led1 = 5; //LED pins
int led2 = 4;
int led3 = 3;
int led4 = 2;
int turn = 0;
int input1 = LOW;
int input2 = LOW;
int input3 = LOW;
int input4 = LOW;

int randomArray[100]; //Intentionally long to store up to 100 inputs (doubtful anyone will get this far)
int inputArray[100];

void setup() {

Serial.begin(9600);

pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);
pinMode(led4, OUTPUT);
pinMode(switch1, INPUT);
pinMode(switch2, INPUT);
pinMode(switch3, INPUT);
pinMode(switch4, INPUT);
randomSeed(analogRead(0)); //Added to generate "more randomness" with the randomArray for the output function

for (int y=0; y<=99; y++){ //For statement to loop through the output and input functions
output();
input();
}

}

void output() { //function for generating the array to be matched by the player

for (int y=turn; y <= turn; y++){ //Limited by the turn variable
Serial.println(""); //Some serial output to follow along
Serial.print("Turn: ");
Serial.print(y);
Serial.println("");
randomArray[y] = random(1, 5); //Assigning a random number (1-4) to the randomArray[y], y being the turn count
for (int x=0; x <= turn; x++){

Serial.print(randomArray[x]);

if (randomArray[x] == 1) { //if statements to display the stored values in the array
digitalWrite(led1, HIGH);
delay(500);
digitalWrite(led1, LOW);
delay(100);
}

if (randomArray[x] == 2) {
digitalWrite(led2, HIGH);
delay(500);
digitalWrite(led2, LOW);
delay(100);
}

if (randomArray[x] == 3) {
digitalWrite(led3, HIGH);
delay(500);
digitalWrite(led3, LOW);
delay(100);
}

if (randomArray[x] == 4) {
digitalWrite(led4, HIGH);
delay(500);
digitalWrite(led4, LOW);
delay(100);
}
}
}
}

void input() { //Function for allowing user input and checking input against the generated array

for (int x=0; x <= turn;){ //Statement controlled by turn count
input1 = digitalRead(switch1);
input2 = digitalRead(switch2);
input3 = digitalRead(switch3);
input4 = digitalRead(switch4);

if (input1 == HIGH){ //Checking for button push
digitalWrite(led1, HIGH);
delay(200);
digitalWrite(led1, LOW);
inputArray[x] = 1;
delay(50);
Serial.print(" ");
Serial.print(1);
if (inputArray[x] != randomArray[x]) { //Checks value input by user and checks it against
fail(); //the value in the same spot on the generated array
} //The fail function is called if it does not match
x++;
}

if (input2 == HIGH){
digitalWrite(led2, HIGH);
delay(200);
digitalWrite(led2, LOW);
inputArray[x] = 2;
delay(50);
Serial.print(" ");
Serial.print(2);
if (inputArray[x] != randomArray[x]) {
fail();
}
x++;

}

if (input3 == HIGH){
digitalWrite(led3, HIGH);
delay(200);
digitalWrite(led3, LOW);
inputArray[x] = 3;
delay(50);
Serial.print(" ");
Serial.print(3);
if (inputArray[x] != randomArray[x]) {
fail();
}
x++;

}

if (input4 == HIGH){

digitalWrite(led4, HIGH);
delay(200);
digitalWrite(led4, LOW);
inputArray[x] = 4;
delay(50);
Serial.print(" ");
Serial.print(4);
if (inputArray[x] != randomArray[x]) {
fail();
}
x++;

}
}
delay(500);
turn++; //Increments the turn count, also the last action before starting the output function over again
}

void fail() { //Function used if the player fails to match the sequence

for (int y=0; y<=5; y++){ //Flashes lights for failure
digitalWrite(led1, HIGH);
digitalWrite(led2, HIGH);
digitalWrite(led3, HIGH);
digitalWrite(led4, HIGH);
delay(200);
digitalWrite(led1, LOW);
digitalWrite(led2, LOW);
digitalWrite(led3, LOW);
digitalWrite(led4, LOW);
delay(200);
}
delay(500);
turn = -1; //Resets turn value so the game starts over without need for a reset button
}

void loop() { //Unused void loop(), though for some reason it doesn't compile without this /shrug
}

Thanks for posting your code jackal858.

I'm sure I'll learn a lot from it.

No problem. I threw in all the commenting before posting it as a learning tool for others. If you have any questions about it let me know.

Thanks

I've just had a good look at your code and thanks to your comments, I can see exactly what's going on. Looking forward to building the circuit.

Thanks again for sharing. seeing other peoples examples is a great way to learn.

I figured out how to generate tones through a small speaker last night after finding some example code. I'll probably be adding that into the code later today, and I'll be sure to post that as well.

Looking forward to that.

While I've got you, I've just built the circuit BUT I'm getting very strange behaviour.

The game starts by flashing only two leds then immediately goes into the "fail" state and there is no time to try and repeat the sequence on the input buttons. Input buttons are connected via Pull Down resistors and leds are connected like this - Anodes to Arduino output pins and Cathodes to GND. Any thoughts?

OK. My mistake. I had one of the switches the wrong way around.

Now works perfectly.

Glad to hear you figured it out. I just finished adding sound to this game, which helps a lot (for me at least being a musician), plus it's more like the original now. Here's the code:

/*Simon Says game by Robert Spann*/

int switch1 = 11; //The four button input pins
int switch2 = 10;
int switch3 = 9;
int switch4 = 8;
int led1 = 5; //LED pins
int led2 = 4;
int led3 = 3;
int led4 = 2;
int turn = 0;
int speakerPin = 6;
int input1 = LOW;
int input2 = LOW;
int input3 = LOW;
int input4 = LOW;

int randomArray[100]; //Intentionally long to store up to 100 inputs (doubtful anyone will get this far)
int inputArray[100];


void setup() {

  Serial.begin(9600); 

  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(led4, OUTPUT);
  pinMode(switch1, INPUT);
  pinMode(switch2, INPUT);
  pinMode(switch3, INPUT);
  pinMode(switch4, INPUT);
  pinMode(speakerPin, OUTPUT);
  randomSeed(analogRead(0)); //Added to generate "more randomness" with the randomArray for the output function
 
 for (int y=0; y<=1000; y++){ //For statement to loop through the output and input functions
   output();
   input();
 }
 
   }
   
void output() { //function for generating the array to be matched by the player
    
   for (int y=turn; y <= turn; y++){ //Limited by the turn variable
    Serial.println(""); //Some serial output to follow along
    Serial.print("Turn: ");
    Serial.print(y);
    Serial.println("");
    randomArray[y] = random(1, 5); //Assigning a random number (1-4) to the randomArray[y], y being the turn count
    for (int x=0; x <= turn; x++){ 

      Serial.print(randomArray[x]);

      if (randomArray[x] == 1) {  //if statements to display the stored values in the array
        digitalWrite(led1, HIGH);
        playTone(1915, 200); //Passes tone value and duration of the tone to the playTone function
        delay(200);
        digitalWrite(led1, LOW);
        delay(100);
      }

      if (randomArray[x] == 2) {
        digitalWrite(led2, HIGH);
        playTone(1519, 200);//Passes tone value and duration of the tone to the playTone function
        delay(200);
        digitalWrite(led2, LOW);
        delay(100);
      }

      if (randomArray[x] == 3) {
        digitalWrite(led3, HIGH);
        playTone(1275, 200);//Passes tone value and duration of the tone to the playTone function
        delay(200);
        digitalWrite(led3, LOW);
        delay(100);
      }

      if (randomArray[x] == 4) {
        digitalWrite(led4, HIGH);
        playTone(956, 200);//Passes tone value and duration of the tone to the playTone function
        delay(200);
        digitalWrite(led4, LOW);
        delay(100);
      }
     }
    }
   }
  
  
  
void input() { //Function for allowing user input and checking input against the generated array

  for (int x=0; x <= turn;){ //Statement controlled by turn count
    input1 = digitalRead(switch1);
    input2 = digitalRead(switch2);
    input3 = digitalRead(switch3);
    input4 = digitalRead(switch4);

    if (input1 == HIGH){ //Checking for button push
      digitalWrite(led1, HIGH);
      playTone(1915, 200);//Passes tone value and duration of the tone to the playTone function
      delay(200);
      digitalWrite(led1, LOW);
      inputArray[x] = 1;
      delay(50);
      Serial.print(" ");
      Serial.print(1);
      if (inputArray[x] != randomArray[x]) { //Checks value input by user and checks it against
        fail();                              //the value in the same spot on the generated array
      }                                      //The fail function is called if it does not match
      x++;
    }

    if (input2 == HIGH){
      digitalWrite(led2, HIGH);
      playTone(1519, 200);//Passes tone value and duration of the tone to the playTone function
      delay(200);
      digitalWrite(led2, LOW);
      inputArray[x] = 2;
      delay(50);
      Serial.print(" ");
      Serial.print(2);
      if (inputArray[x] != randomArray[x]) {
        fail();
      }
      x++;

    }

    if (input3 == HIGH){
      digitalWrite(led3, HIGH);
      playTone(1275, 200);//Passes tone value and duration of the tone to the playTone function
      delay(200);
      digitalWrite(led3, LOW);
      inputArray[x] = 3;
      delay(50);
      Serial.print(" ");
      Serial.print(3);
      if (inputArray[x] != randomArray[x]) {
        fail();
      }
      x++;

    }

    if (input4 == HIGH){

      digitalWrite(led4, HIGH);
      playTone(956, 200);//Passes tone value and duration of the tone to the playTone function
      delay(200);
      digitalWrite(led4, LOW);
      inputArray[x] = 4;
      delay(50);
      Serial.print(" ");
      Serial.print(4);
      if (inputArray[x] != randomArray[x]) {
        fail();
      }
      x++;

    }
   }
  delay(500);
  turn++; //Increments the turn count, also the last action before starting the output function over again
}

void fail() { //Function used if the player fails to match the sequence
  playTone(1432, 200); //Tune playing when fail, there is a more elegant way to do this, but this works for short tunes
  playTone(1, 5);
  playTone(1432, 200);
  playTone(1700, 200);
  playTone(1275, 200);
  playTone(1432, 200);
  playTone(1, 5);
  playTone(1432, 200);
  playTone(1700, 400);
  for (int y=0; y<=5; y++){ //Flashes lights for failure
   digitalWrite(led1, HIGH);
   digitalWrite(led2, HIGH);
   digitalWrite(led3, HIGH);
   digitalWrite(led4, HIGH);
   delay(200);
   digitalWrite(led1, LOW);
   digitalWrite(led2, LOW);
   digitalWrite(led3, LOW);
   digitalWrite(led4, LOW);
   delay(200);
  }
  delay(500);
  turn = -1; //Resets turn value so the game starts over without need for a reset button
}

void playTone(int tone, int duration) {
  for (long i = 0; i < duration * 1000L; i += tone * 2) {
    digitalWrite(speakerPin, HIGH);
    delayMicroseconds(tone);
    digitalWrite(speakerPin, LOW);
    delayMicroseconds(tone);
  }
}

void loop() { //Unused void loop(), though for some reason it doesn't compile without this /shrug
}

The main thing that was added was the playTone function after the fail function. Don't ask me how it works, as I barely know. I found the following code, and just tried to find the source to give credit but can't seem to figure out exactly where I found it last night.

int speakerPin = 9;

int length = 15; // the number of notes
char notes[] = "cdefgabC "; // a space represents a rest
int beats[] = { 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 4 };
int tempo = 300;

void playTone(int tone, int duration) {
  for (long i = 0; i < duration * 1000L; i += tone * 2) {
    digitalWrite(speakerPin, HIGH);
    delayMicroseconds(tone);
    digitalWrite(speakerPin, LOW);
    delayMicroseconds(tone);
  }
}

void playNote(char note, int duration) {
  char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };
  int tones[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 956, };

  // play the tone corresponding to the note name
  for (int i = 0; i < 8; i++) {
    if (names[i] == note) {
      playTone(tones[i], duration);
    }
  }
}

void setup() {
  pinMode(speakerPin, OUTPUT);
}

void loop() {
  for (int i = 0; i < length; i++) {
    if (notes[i] == ' ') {
      delay(beats[i] * tempo); // rest
    } else {
      playNote(notes[i], beats[i] * tempo);
    }

    // pause between notes
    delay(tempo / 2); 
  }
}

This code also shows the values for a C scale (scale with all whole steps between notes). The values are stored in the tones array, and called with the names array. This should give you a starting place for creating custom tunes though using the values, as a quick reference:

Low C = 1915
D = 1700
E = 1519
F = 1432
G = 1275
A = 1136
B = 1014
High C = 956

I assume any half steps (such as A#) would be the number in the middle of the two full steps (G and B, (1275+1136)/2 = 1206).

The tune I added into the fail part of the game is the classic "nanny nanny boo boo" type tune. :stuck_out_tongue: I am using a speaker I salvaged from an old computer from my work, but you can buy a small speaker at radio shack that should work just as well, maybe not quite as loud though.

Here's the link for a video with the sound in place:

Brilliant Work. I love what you've done with the sound.

Thanks again for sharing the code.

Very thanks for the code, but for me it don't works.
However, it works, but blinks just the LED1, and if I push some of others buttons, the corrispective led blinks and the game give me error...
The connections are all ok, and I can't understand... :frowning:

I had a similar experience BUT the problem was my connections. I had one of the buttons wired wrongly. I'm sure the code is fine.

Check your wiring again and again. Good luck.

The mistake isn't the wiring work, but my brain... :stuck_out_tongue:
I've modified the code in order to use an old shield, and I've changed this:

int switch1 = 5; //The four button input pins
int switch2 = 4;
int switch3 = 3;
int switch4 = 2;
int led1 = 12; //LED pins
int led2 = 11;
int led3 = 10;
int led4 = 9;

pheraps this pin can't work fine?

NetWorm,

With my limited knowledge kept in mind, I am unsure why simply changing the pins for the buttons and LEDs would result in the game not working properly. As mentioned in the first video of the project, I had problems understanding the use of pull down resistors to eliminate random inputs from buttons. Do you have a resistor connected in line with the wire running to the input pin(~10k ohm), as well as a resistor in line running to ground(~1k ohm)? Basically, there should be two resistors in line with each button.

simple and cool!!

jackal858, I have simple 1 Kohm pull-down resistor for each button, and it work properly with a simple test code (when I press the button the corrispective led turn ON).
The game works, but only with LED1, I explain:
-the led1 flash 1 time, I press switch11 time, then the led1 flash 2 times, so I press the switch 1 2 times, and more to the infinite... :smiley:
The game works properly buth with just une led, if i press another button the corrispective led turn it on and the game give me error end retes him.
This makes me crazy, this evening I'll try to add some pull-down resistor. Thanks all for now and excuse me for my scary english :wink:

Oh, so the game is only outputting to LED 1 when creating the randomArray? That seems pretty odd. The code I posted is the exact code I am using in the videos I posted. I am unsure as to why it would be doing that.

Yes, my mistakes are all pretty cool mistakes :smiley: