Improved 'Simon Says' Code

3,876

10

11

About: Professional Software, Hardware, Systems Engineer for more than 40 years. Amateur Radio HAM (KI7NEW)

An updated 'Simple Simon' project.

Specifically, easier to work with software implementation.

Step 1: Getting Started

I started with the instructable at 'Simple-Simon-Says-Game'

Refer to it for general hardware implementation.

As I already had done a project of my own which had 4 buttons, 4 LEDs and a speaker, I used that hardware (seen above). There is an LCD display under a tape, as it is not used by this project.

It uses an Nano 3.0 and I used different pin assignments for the peripherals.

By the way, you may also be interested in a hardware simplified version I did Instructables.com/id/Fast-Easy-Simon

Step 2: Adapting to New Hardware

The Simon_Says sketch did not work for me as the code relied on fix pin assignments. Further the code was hard to follow and had some bugs.

So I created this updated version.

  • Fixed the miss use of type 'boolean' for pin numbers
  • Modified the code so that it will work for any LED & button pin assignments.
  • The logic flow was overly complicated and in spots too repetitive, causing it to be hard to understand and debug. So I simplified it for the most part.
  • Along with other improvements like the fact that I changed the 'Tone' class object's name from 'speakerpin' to 'speaker' and created a byte variable 'speakerpin' for its pin # assignment.
  • Oct 2015: allowed for fast button input sequences

A download link for my updated sketch is included here. You should find it easy to get going with your own hardware by simply changing pin assignments near the beginning of the code. Download and have fun with it.

Step 3: By Popular Demand

As there has been queries about how to use the software with a servo to operate a latch when a successful set of Simon pattern matching is done. I am including here versions of 'Simon_Says' as well as the similar 'Simon_Sings' which I adapted to be suitable for further modification with appropriate servo code. I have placed '@TODO' comments in the code of each showing where to put one's servo code.

The exact coding will be dependent on the hardware implementation and the servo library one uses. I do not have answers for servo particular issues. For that, I recommend reviewing the likes of the following:
video: How to control servos
instructables.com/id/Arduino-Servo-Motors/
instructables.com/id/Access-control-with-Arduino-Keypad-4x4-Servo/
For those needing further servo related help, I recommend a post to the servo related instructable with the most similarities to their servo implementation.

Share

    Recommendations

    • Optics Contest

      Optics Contest
    • Make it Glow Contest 2018

      Make it Glow Contest 2018
    • Plastics Contest

      Plastics Contest

    11 Discussions

    0
    None
    MerkMan99

    10 months ago

    I did this project but I am getting an error on:

    Tone speaker;

    saying that 'Tone' does not name a type

    Thank You

    1 reply
    0
    None
    RonM9MerkMan99

    Reply 10 months ago

    Hi, I am happy to hear that you have done this project.
    This is apparently not an uncommon problem. For help with this, please see my post of 2016-01-18 below.
    Looking forward to hearing of your further success; Best Ron
    PS: You may find that you're interested in checking out my other projects.

    0
    None
    patrickevelien

    3 years ago

    hello

    i have it working..thanks for that, i want to use this game as a lock..

    so when the player has it 6 times good i want to open a servo motor but i dont know how to do it.. can you please help me? thanks

    6 replies
    0
    None
    RonM9patrickevelien

    Reply 3 years ago

    OK. You would need to add code like that below after the line "Serial.print(turn);"

    For the coded needed to operate your servo find a project which uses that same hardware-electronics to use as an example.

    You may want to use the version 'FastEasy_Simon_Says.ino' of a Simon type game found in https://www.instructables.com/id/Fast-Easy-Simon/ , as among other differences it waits for an input before proceeding and starts off with a pattern of 4 instead of 1.

    if (turn==6) {
    // !! Here place the code needed to operate the servo latch !!
    bool btnPushed = false;
    while (! btnPushed) { // wait for a key-press before starting all over
    for (int y = 0; y < 4; y++)
    { if (digitalRead(button[y]) == LOW) //Checking for button push
    btnPushed = true; }
    }
    turn = -1; //Reset turn value so the game starts over
    exit;
    }

    0
    None
    RonM9RonM9

    Reply 3 years ago

    Referrence above to 'FastEasy_Simon_Says.ino'

    Should be: 'FastEasy_Simon_Sings.ino'

    0
    None
    patrickevelienRonM9

    Reply 3 years ago

    i did try for a full day to put a servo in...

    im a beginner with arduino is it possible that you write it into the arduino code?

    this is the code.. thanks 1000 times.

    i want the servo on pin 7..

    #include <Tone.h>

    /*Simon Says game. Now with sound effects.

    Originaly made by Robert Spann

    Code trimmed and sound effects added by digimike

    Ron Miller (aka RonM9) Jun 2015: Removed fixed pin
    assignment dependences and simplified code

    RRM Oct 2015: allowed for faster button inputs

    Buttons are to be set on there designated pins without pull
    down resistors

    and connected to ground rather then +5.

    */

    #include "Tone.h"

    Tone speaker;

    byte speakerPin = 12; // speaker was on pin 13

    int starttune[] = {NOTE_C4, NOTE_F4, NOTE_C4, NOTE_F4,
    NOTE_C4, NOTE_F4, NOTE_C4, NOTE_F4, NOTE_G4, NOTE_F4, NOTE_E4, NOTE_F4,
    NOTE_G4};

    int duration2[] = {100, 200, 100, 200, 100, 400, 100, 100,
    100, 100, 200, 100, 500};

    int cheer[] = {NOTE_C4, NOTE_C4, NOTE_G4, NOTE_C5, NOTE_G4,
    NOTE_C5};

    int btnNote[] = {NOTE_G3, NOTE_A3, NOTE_B3, NOTE_C4};

    int duration[] = {100, 100, 100, 300, 100, 300};

    //boolean button[] = {2, 3, 4, 5}; //The four button input
    pins

    //boolean ledpin[] = {8, 9, 10, 11}; // LED pins

    int button[] = {8, 9, 10, 11}; //The four button input pins
    oranje draad

    int ledpin[] = {2, 3, 4, 5};
    // LED pins geel draad

    int turn = 0; // turn
    counter

    int buttonstate = 0;
    // button state checker

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

    int inputArray[100];

    // ===================================================

    void setup()

    {

    int note;

    Serial.begin(9600);


    speaker.begin(speakerPin);

    for (int x = 0; x
    < 4; x++) // LED pins are outputs

    {

    pinMode(ledpin[x],
    OUTPUT);

    pinMode(button[x],
    INPUT); // button pins are inputs


    digitalWrite(button[x], HIGH); //
    enable internal pullup; buttons start in high position; logic reversed

    }


    randomSeed(analogRead(0)); //Added to generate "more randomness"
    with the randomArray for the output function

    for (int thisNote =
    0; thisNote < 13; thisNote ++) {

    // play the next
    note:

    note =
    starttune[thisNote];


    speaker.play(note);

    if (note ==
    NOTE_C4) digitalWrite(ledpin[0],
    HIGH);

    else if (note ==
    NOTE_F4) digitalWrite(ledpin[1], HIGH);

    else if (note ==
    NOTE_G4) digitalWrite(ledpin[2], HIGH);

    else if (note ==
    NOTE_E4) digitalWrite(ledpin[3], HIGH);

    // hold the note:


    delay(duration2[thisNote]);

    // stop for the
    next note:

    speaker.stop();

    allLEDs(LOW);

    delay(25);

    }

    delay(1000);

    }

    // ========================================================

    void loop() // This
    'loop' is automatically ran repeatedly

    {

    for (int level = 0;
    level <= 99; level++)

    {

    allLEDs(HIGH);

    for (int thisNote
    = 0; thisNote < 6; thisNote ++) {

    // play the next
    note:


    speaker.play(cheer[thisNote]);

    // hold the
    note:


    delay(duration[thisNote]);

    // stop for the
    next note:

    speaker.stop();

    delay(25);

    }

    allLEDs(LOW);

    delay(1000);


    Serial.print("\n Turn: ");
    // Some serial output to follow along


    Serial.print(turn);

    // fill up the
    array to be matched by the player

    randomArray[turn]
    = random(1, 5); //Assigning a random number (1-4) to the randomArray[turn
    count]


    Serial.print(" Rand#:
    ");


    Serial.println(randomArray[turn]);

    for (int x = 0; x
    <= turn; x++)

    {


    Serial.print(randomArray[x]);

    byte btn =
    randomArray[x]; // logical button/led #
    (1-4)


    digitalWrite(ledpin[btn - 1], HIGH);


    speaker.play(btnNote[btn - 1], 100);

    delay(400);


    digitalWrite(ledpin[btn - 1], LOW);

    delay(100);

    }

    input();

    }

    }

    // ===================================================

    // local
    functions

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

    bool btnPushed;

    for (int x = 0; x
    <= turn; x++)

    { // for each one in
    the current sequence wait for a button to be pushed

    // if it is the
    correct one we keep looping through the sequence

    btnPushed = false;

    while (!
    btnPushed) {

    for (int y = 0;
    y < 4; y++)

    {

    buttonstate =
    digitalRead(button[y]);

    byte btn = y +
    1; // logical button # (1-4)

    if
    (buttonstate == LOW) //Checking for
    button push

    {

    btnPushed =
    true;


    digitalWrite(ledpin[y], HIGH);


    speaker.play(btnNote[btn - 1], 100);


    delay(100); // insures minimum
    LED illumination


    inputArray[x] = btn;


    Serial.print(" btn pushed:
    ");


    Serial.print(btn);

    // was a poor way to allow for button release: delay(250);


    wait_BtnRelease();


    digitalWrite(ledpin[y], LOW);

    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

    exit;

    }

    }

    }

    } // end while

    }

    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
    <= 2; y++)

    { //Flashes lights
    for failure

    allLEDs(HIGH);


    speaker.play(NOTE_G3, 300);

    delay(200);

    allLEDs(LOW);


    speaker.play(NOTE_C3, 300);

    delay(200);

    }

    delay(500);

    turn = -1; //Resets
    turn value so the game starts over without need for a reset button

    }

    // ------------------------------------------------------

    void allLEDs(byte state) {


    digitalWrite(ledpin[0], state);

    digitalWrite(ledpin[1],
    state);


    digitalWrite(ledpin[2], state);


    digitalWrite(ledpin[3], state);

    }

    void wait_BtnRelease() {

    bool
    btnStillDown=true;

    while
    (btnStillDown) {

    btnStillDown =
    false;

    for (int y = 0;
    y < 4; y++)

    {

    buttonstate =
    digitalRead(button[y]);

    if
    (buttonstate == LOW) //Checking for
    button push

    btnStillDown
    = true;

    }

    }

    }

    0
    None
    RonM9patrickevelien

    Reply 2 years ago

    Patrick, did you ever get your project working?

    Since our last communication I have added a section to this instructable, titled 'By popular demand'. You may find this a little more helpful &/or interesting.

    0
    None
    OndřejT4RonM9

    Reply 2 years ago

    Hi...i am trying to add same servo function like patrickevelien. When I put code to servo open/close right behind void setup(), servo operate correctly and after that game starts, But when I put code behind if (turn==6) { nothing happend. When I put here for example allLEDs(HIGH); , this works. Can you give me some advice please?

    /*Simon Says game. Now with sound effects.

    Originaly made by Robert Spann

    Code trimmed and sound effects added by digimike

    Ron Miller (aka RonM9) Jun 2015: Removed fixed pin assignment dependences and simplified code

    RRM Oct 2015: allowed for faster button inputs

    Buttons are to be set on there designated pins without pull down resistors

    and connected to ground rather then +5.

    */

    #include <Tone.h>

    Tone speaker;

    #include <ServoTimer2.h>

    ServoTimer2 a;

    byte speakerPin = 12; // speaker was on pin 13

    int starttune[] = {NOTE_C4, NOTE_F4, NOTE_C4, NOTE_F4, NOTE_C4, NOTE_F4, NOTE_C4, NOTE_F4, NOTE_G4, NOTE_F4, NOTE_E4, NOTE_F4, NOTE_G4};

    int duration2[] = {100, 200, 100, 200, 100, 400, 100, 100, 100, 100, 200, 100, 500};

    int cheer[] = {NOTE_C4, NOTE_C4, NOTE_G4, NOTE_C5, NOTE_G4, NOTE_C5};

    int btnNote[] = {NOTE_G3, NOTE_A3, NOTE_B3, NOTE_C4};

    int duration[] = {100, 100, 100, 300, 100, 300};

    //boolean button[] = {2, 3, 4, 5}; //The four button input pins

    //boolean ledpin[] = {8, 9, 10, 11}; // LED pins

    int button[] = {5, 6, 7, 8}; //The four button input pins

    int ledpin[] = {2, 3, 17, 16}; // LED pins

    int turn = 0; // turn counter

    int buttonstate = 0; // button state checker

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

    int inputArray[100];

    // ===================================================

    void setup()

    {

    a.attach(9);

    a.write(2000);

    delay(2000);

    a.write(1000);

    delay(2000);

    int note;

    Serial.begin(9600);

    speaker.begin(speakerPin);

    for (int x = 0; x < 4; x++) // LED pins are outputs

    {

    pinMode(ledpin[x], OUTPUT);

    pinMode(button[x], INPUT); // button pins are inputs

    digitalWrite(button[x], HIGH); // enable internal pullup; buttons start in high position; logic reversed

    }

    randomSeed(analogRead(0)); //Added to generate "more randomness" with the randomArray for the output function

    for (int thisNote = 0; thisNote < 13; thisNote ++) {

    // play the next note:

    note = starttune[thisNote];

    speaker.play(note);

    if (note == NOTE_C4) digitalWrite(ledpin[0], HIGH);

    else if (note == NOTE_F4) digitalWrite(ledpin[1], HIGH);

    else if (note == NOTE_G4) digitalWrite(ledpin[2], HIGH);

    else if (note == NOTE_E4) digitalWrite(ledpin[3], HIGH);

    // hold the note:

    delay(duration2[thisNote]);

    // stop for the next note:

    speaker.stop();

    allLEDs(LOW);

    delay(25);

    }

    delay(1000);

    }

    // ========================================================

    void loop() // This 'loop' is automatically ran repeatedly

    {

    for (int level = 0; level <= 99; level++)

    {

    allLEDs(HIGH);

    for (int thisNote = 0; thisNote < 6; thisNote ++) {

    // play the next note:

    speaker.play(cheer[thisNote]);

    // hold the note:

    delay(duration[thisNote]);

    // stop for the next note:

    speaker.stop();

    delay(25);

    }

    allLEDs(LOW);

    delay(1000);

    Serial.print("\n Turn: "); // Some serial output to follow along

    Serial.print(turn);

    // fill up the array to be matched by the player

    if (turn==2) {

    // HERE ADD SERVO OPEN/CLOSE

    bool btnPushed = false;

    while (! btnPushed) { // wait for a key-press before starting all over

    for (int y = 0; y < 4; y++)

    { if (digitalRead(button[y]) == LOW) //Checking for button push

    btnPushed = true; }

    }

    turn = -1; //Reset turn value so the game starts over

    exit;

    }

    randomArray[turn] = random(1, 5); //Assigning a random number (1-4) to the randomArray[turn count]

    Serial.print(" Rand#: ");

    Serial.println(randomArray[turn]);

    for (int x = 0; x <= turn; x++)

    {

    Serial.print(randomArray[x]);

    byte btn = randomArray[x]; // logical button/led # (1-4)

    digitalWrite(ledpin[btn - 1], HIGH);

    speaker.play(btnNote[btn - 1], 100);

    delay(400);

    digitalWrite(ledpin[btn - 1], LOW);

    delay(100);

    }

    input();

    }

    }

    // ===================================================

    // local functions

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

    bool btnPushed;

    for (int x = 0; x <= turn; x++)

    { // for each one in the current sequence wait for a button to be pushed

    // if it is the correct one we keep looping through the sequence

    btnPushed = false;

    while (! btnPushed) {

    for (int y = 0; y < 4; y++)

    {

    buttonstate = digitalRead(button[y]);

    byte btn = y + 1; // logical button # (1-4)

    if (buttonstate == LOW) //Checking for button push

    {

    btnPushed = true;

    digitalWrite(ledpin[y], HIGH);

    speaker.play(btnNote[btn - 1], 100);

    delay(100); // insures minimum LED illumination

    inputArray[x] = btn;

    Serial.print(" btn pushed: ");

    Serial.print(btn);

    // was a poor way to allow for button release: delay(250);

    wait_BtnRelease(); // much better this way

    digitalWrite(ledpin[y], LOW);

    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

    exit;

    }

    }

    }

    } // end while

    }

    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 <= 2; y++)

    { //Flashes lights for failure

    allLEDs(HIGH);

    speaker.play(NOTE_G3, 300);

    delay(200);

    allLEDs(LOW);

    speaker.play(NOTE_C3, 300);

    delay(200);

    }

    delay(500);

    turn = -1; //Resets turn value so the game starts over without need for a reset button

    }

    // ------------------------------------------------------

    void allLEDs(byte state) {

    digitalWrite(ledpin[0], state);

    digitalWrite(ledpin[1], state);

    digitalWrite(ledpin[2], state);

    digitalWrite(ledpin[3], state);

    }

    void wait_BtnRelease() {

    bool btnStillDown;

    int debounce=0; // need depends on button used. mine caused some double trips

    while (debounce<2) {

    delay(5);

    btnStillDown = false;

    for (int y = 0; y < 4; y++)

    {

    buttonstate = digitalRead(button[y]);

    if (buttonstate == LOW) //Checking for button push

    btnStillDown = true;

    }

    if (btnStillDown) debounce=0;

    else debounce++;

    }

    }

    0
    None
    RonM9OndřejT4

    Reply 2 years ago

    Thanks for your interest in this instructable.

    It looks like you have not placed the needed servo control code where this line is located: // HERE ADD SERVO ...

    I also noticed you are using a different servo library than what I see others using; and your initialization code in setup() looks odd to me.

    I have added a version of the .ino code with the idea of being modified for use to operate a latch, with better comments regarding placement of servo support code. Please see the added section to this instructable, titled 'By popular demand'. I hope this gets you going in the right direction.

    Looking forward to hearing about your success.

    0
    None
    MiguelD13

    2 years ago

    C:\Users\user\Downloads\Compressed\Simon_Says\Tone\Tone\Simon_Says\Simon_Says.ino:9:18: fatal error: Tone.h: No such file or directory

    #include <Tone.h>

    ^

    compilation terminated.

    exit status 1

    Error compiling.

    This report would have more information with

    "Show verbose output during compilation"

    enabled in File > Preferences.


    Can you help me with this? TIA =)

    1 reply
    0
    None
    RonM9MiguelD13

    Reply 2 years ago

    It is not finding 'Tone.h'. So the compiler is looking in the wrong places, or the file is in the wrong place or it is missing. The Arduino IDE comes with an Examples/Tone/ToneTest sketch which uses Tone.h from Sketchbook/libraries/Tone. You probably need to reinstall the latest IDE to get this sketch as well as the ToneTest sketch to build.