Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / IoT / Arduino

Arduino Platform - SIMON Game Implementation

4.80/5 (26 votes)
27 Oct 2009CPOL4 min read 97.1K   669  
Using the Arduino platform for a SIMON game implementation.

Arduino Simon Schematic

Introduction

Having been a CodeProject member for several years, and not having got round to ever publishing an article, left me feeling a bit disappointed in myself. I have thought many a time on what kind of article I can produce. Then after coming across some great articles by jeffb42 here on CodeProject, my problem was solved.

I started playing with the Arduino hardware platform about two months ago, after looking for something suitable for a couple of projects I had in mind for use in the house. In order to get to the stage of being able to make use of the device, I had to first get to know its capabilities.

This article will be looking at how to overcame the problem of running a SIMON game clone using the Arduino platform, as this demonstrates methods of dealing with the main application Loop constraint and code reuse on this hardware platform.

For those of you not familiar with SIMON, this was an early electronics game from the 70's, where the user basically had to repeat back a sequence to the console to progress to the next level. In my implementation of the game, the user can play the Progressive Mode, where the game re-uses the previous level as the start of the next level before adding a random step at the end, or Random Mode, where every level of the game produces a new random sequence, each step longer than the previous.

jeffb42's Introduction to Arduino and Interfacing with LCD articles provide more details on the Arduino platform specifics, and on my website, I have various examples of some of the IO basics, so there is no need to repeat this here.

Background

The challenge to building this game on the Arduino is the way in which the platform works. Within the source code, there are three areas in which to place code: the initialisation area, the setup method, and the loop method. These are executed in that order.

C++
//initialisation section
// Library references and variable/constant declarations contained here

void setup()
{
    //This method runs once
    //Hardware allocation done here e.g. input/output pin directions
}

void loop()
{
    //This method will run until power is removed or a new program is 
    //uploaded to the platform
}

The challenge is being able to make the code operate in such a way that a game can be played over and over again, in either of the two modes, without ever leaving a never ending loop.

Using the Code

The schematic of the hardware requirements is included in the download file, as well as the source code. If you own the necessary components, you can build the game and upload the code to the Arduino to make it work. Alternatively, if you are just starting out with the platform or something similar, the code may provide you with ideas on how to achieve similar goals in your own projects.

The Game Structure

We need to be able to keep the game code running within an endless loop, and one method to achieve this is by using flags. Boolean variables which are either True or False is one of the easiest ways to achieve this. Looking at how the game works, there are a few basic flags that are required. They hold the state of the game, i.e., has it started, has it been played, and if the game is now over. A couple of other variables are also required to keep track of what the sequence of steps generated is and what level the user is currently on. These requirements as well as the hardware pin allocations are identified in the initialisation section of the code:

C++
#include <LiquidCrystal.h>


//initialise the library with the numbers of the interface pins
LiquidCrystal lcd(13,12,11,10,9,8);

int userInput = 0;      //Analog pin for user input from buttons
int led1 = 2;           //LED 1
int led2 = 3;           //LED 2
int led3 = 4;           //LED 3
int led4 = 5;           //LED 4
int speaker = 6;        //Speaker

//Game Stats
boolean started = false;    //Has the game started yet
boolean gameover = false;   //Has the game ended
int level = 0;              //What level is the user on (Score at end = level -1)

int gameMode = 0;           //Which game mode is being used
                            // 1 = Progressive
                            // 2 = Random
                            
boolean soundEnabled = true;  //Is the sound enabled or not
                            
int lastLevelSeq[50];        //The sequence for the steps used
                             //in progressive mode previous level
                             //Also used by game over to replay correct sequence back
                             //Nobody can get passed 50, surely!

The next section of the code is the setup() method. This is where the hardware pins are initialised.

C++
void setup()
{
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(led4, OUTPUT);
  pinMode(speaker, OUTPUT);
  
  //Set up the LCD Col and Row count
  lcd.begin(16,2);
  delay(100);
  lcd.clear();
  lcd.print("Welcome to");
  lcd.setCursor(0,1);
  lcd.print("Arduino SIMON");
  
  //...........rest of setup code snipped. see the download.

From here, the next thing that is executed is the loop() method, which is run endlessly, hence the requirement to keep track of the game status. Also, to keep the code shorter and more efficient, a number of helper methods are used to meet the reuse requirements mentioned at the start of the article.

C++
//used to determine which button the user is pressing
getButtonPressed()
//Play a given sound
playTone(tone)
//This is the actual game level, it returns boolean true
//is user success or false if user failed
doLevel(level)
//Turn on a given led, or 0 to turn them all off
lightLed(led)
//This will play a sound and light the appropriate 
//led using the other helper methods
playStep(step)

The main loop() structure looks like the following (all the details have been stripped to leave the structure):

C++
void loop()
{        
    while (started == false)
    {
      if (getButtonPressed() > 0)
      {
        //This part waits for the user to press a button to start the game
      }
    }
     
    while (gameMode == 0)
    {     
      switch (getButtonPressed())
      {
      case 1:
            //The user pressed button 1 for Progressive Mode
        break;
       
      case 2:
            //The user pressed button 2 for Random Mode
        break;
      
      case 4:
        soundEnabled = (!soundEnabled);
        //The user user is pressing Button 4 toggling the sound on and off
        break;  
      }
    }    
     
    while (gameover == false)
    {
      if (doLevel(level)==true)
        {
            //The user played a level and got it correct
        } 
       else
        {
            //Level Wrong, set game over
        }  
    }
    
    if (gameover == true)
    {
      //The game is now over, playback the correct sequence
    }
      
    //Wait for user
    while (gameover == true)
    {
       if (getButtonPressed() > 0)
        {
            //Wait for the user to press a button to go back to the start menu
        }        
    }     
}

The easiest way of coming up with a structure is to play the game in your head and write down in blocks each step that is required; from this, you can build a flow diagram and then the code structure.

Points of Interest

Given the limited number of digital IO pins available, the four buttons were actually linked through a resistor network onto an analog input pin. Each button pressed will change the value of the analog input; from this value, it is then possible to determine which button is pressed, using the getButtonPressed() method. Also, some variance may occur through fluctuations of the analog signal, and suitable resistor sizes must be used to give sufficient spacing of the input values:

C++
/*
Read the analog input and determine which button is pressed
*/  
int getButtonPressed()
{
    // What is the pushbutton resistor matrix value
    int userValue = 0;
    userValue = analogRead(userInput);
    
    int buttonPressed = 0;
      
    if (userValue > 850)
    {
      buttonPressed = 0;
      //No Button Pressed
    }
    if (userValue < 850)
    { 
      buttonPressed = 4;
      // Maybe Button 4 still to check others
    }
    if (userValue < 800)
    {
      buttonPressed = 3;
      // Maybe Button 3 still to check others
    }
    if (userValue < 700)
    {
      buttonPressed = 2;
      // Maybe Button 2 still to check last one
    }
    if (userValue < 600)
    {
      buttonPressed = 1;
      // Done Checking buttons
    }
    return buttonPressed;  
}

Overall, as a first project on the Arduino for myself, this gave me a good challenge into coming up with a suitably structured code that met the game requirements.

History

  • 25th October 2009- First version of the article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)