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.
void setup()
{
}
void loop()
{
}
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:
#include <LiquidCrystal.h>
LiquidCrystal lcd(13,12,11,10,9,8);
int userInput = 0; int led1 = 2; int led2 = 3; int led3 = 4; int led4 = 5; int speaker = 6;
boolean started = false; boolean gameover = false; int level = 0;
int gameMode = 0;
boolean soundEnabled = true;
int lastLevelSeq[50];
The next section of the code is the setup()
method. This is where the hardware pins are initialised.
void setup()
{
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);
pinMode(led4, OUTPUT);
pinMode(speaker, OUTPUT);
lcd.begin(16,2);
delay(100);
lcd.clear();
lcd.print("Welcome to");
lcd.setCursor(0,1);
lcd.print("Arduino SIMON");
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.
getButtonPressed()
playTone(tone)
doLevel(level)
lightLed(led)
playStep(step)
The main loop()
structure looks like the following (all the details have been stripped to leave the structure):
void loop()
{
while (started == false)
{
if (getButtonPressed() > 0)
{
}
}
while (gameMode == 0)
{
switch (getButtonPressed())
{
case 1:
break;
case 2:
break;
case 4:
soundEnabled = (!soundEnabled);
break;
}
}
while (gameover == false)
{
if (doLevel(level)==true)
{
}
else
{
}
}
if (gameover == true)
{
}
while (gameover == true)
{
if (getButtonPressed() > 0)
{
}
}
}
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:
int getButtonPressed()
{
int userValue = 0;
userValue = analogRead(userInput);
int buttonPressed = 0;
if (userValue > 850)
{
buttonPressed = 0;
}
if (userValue < 850)
{
buttonPressed = 4;
}
if (userValue < 800)
{
buttonPressed = 3;
}
if (userValue < 700)
{
buttonPressed = 2;
}
if (userValue < 600)
{
buttonPressed = 1;
}
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.