simon.pde
/*
This is a the classic "copy the sequence of coloured lights".
Originally called Simon.
There are coloured lights, each with its own button.
The computer picks a random colour, which the player then has to copy (by pressing that colour's button).
The computer then picks another colour, and adds it to the original. Now the player has to copy both colours.
This continues, with the sequence getting longer and longer until the player gets it wrong, at which point
the game is over.
*/
int COLOURS = 4;
int ledPins[ 4 ]= {6,7,8,9};
int buttonPins[ 4 ] = {2,3,4,5};
int speakerPin = 10;
int speedPin = 0;
int NONE = -1;
int colour = NONE; // The currently lit LED. 0 to 3, or NONE when no colour is lit.
int tones[4] = {700,800,900,1000}; // Each colour has a different tone
/*
"state" determines what is to happen next, and the following are the vaues that
"state" can have. The numbers don't mean anything (as long as they are all different).
*/
int STATE_NONE = -1;
int STATE_RESTART = 1; // Press any key to start a new game.
int STATE_LISTEN = 2; // The program plays the sequence that the player will soon repeat.
int STATE_REPEAT = 3; // The player is trying to repeat the sequence.
int state = STATE_RESTART;
const int MAX_SEQUENCE = 100;
int sequence[ MAX_SEQUENCE ]; // The list of random colours (0..3) in the sequence so far.
int sequenceSize = 0; // The number of items in the sequence so far
int repeatIndex = 0; // The number of colours the player has repeated.
int delayDuration = 500;
int awaitState = HIGH;
void setup()
{
Serial.begin( 9600 );
for ( int i = 0; i < COLOURS; i ++ ) {
pinMode( ledPins[ i ], OUTPUT );
pinMode( buttonPins[ i ], INPUT );
digitalWrite( ledPins[ i ], LOW ); // All lights off at the beginning
}
pinMode( speakerPin, OUTPUT );
}
void loop()
{
if ( state == STATE_RESTART ) {
awaitRestart();
} else if ( state == STATE_LISTEN ) {
computersTurn();
} else if ( state == STATE_REPEAT ) {
playersTurn();
}
}
void awaitRestart()
{
colour ++;
if ( (colour >= COLOURS) || (colour < 0) ) {
colour = 0;
awaitState = (awaitState == HIGH) ? LOW : HIGH;
}
Serial.print( awaitState ); Serial.println( colour );
digitalWrite( ledPins[ colour ], awaitState );
delayDuration = analogRead( speedPin );
delay( delayDuration );
for ( int i = 0; i < COLOURS; i ++ ) {
if ( ! digitalRead( buttonPins[ i ] ) ) {
randomSeed( millis() );
changeState( STATE_LISTEN );
break;
}
}
}
void changeState( int newState )
{
colour = NONE;
repeatIndex = 0;
state = newState;
for ( int i = 0; i < COLOURS; i ++ ) {
digitalWrite( ledPins[ i ], LOW );
}
}
void computersTurn()
{
if ( sequenceSize >= MAX_SEQUENCE ) {
// The player has remembered the maximum size sequence - they win!
} else {
// Add a ramdon colour to the sequence, and then play it back.
int newColour = random( 4 );
sequence[ sequenceSize ] = newColour;
sequenceSize ++;
playSequence( delayDuration );
changeState( STATE_REPEAT );
}
}
void playSequence( int duration )
{
delay( duration * 2 );
for ( int i = 0; i < sequenceSize; i ++ ) {
int colour = sequence[ i ];
digitalWrite( ledPins[ colour ], HIGH ); // Turn the LED ON
playTone( tones[ colour ], duration ); // Play the note
digitalWrite( ledPins[ colour ], LOW ); // Turn the LED OFF
delay( duration / 4 );
}
}
void playersTurn()
{
if ( colour == NONE ) {
for ( int i = 0; i < COLOURS; i ++ ) {
boolean value = digitalRead( buttonPins[ i ] );
// Serial.print( "button down? : " ); Serial.print( i ); Serial.print( " = " ); Serial.println( value );
if ( ! value ) {
colour = i;
digitalWrite( ledPins[ colour ], HIGH ); // Turn the LED ON
break;
}
}
} else {
boolean value = digitalRead( buttonPins[ colour ] );
if ( ! value ) {
// Button is still pressed
playTone( tones[ colour ], 10 );
} else {
// Button has been released
digitalWrite( ledPins[ colour ], LOW ); // Turn the LED OFF
checkColour();
}
}
}
/*
Checks that the correct colour has been chosen.
If it isn't then the game is over, and the buzzer will sound.
Press any key to start a new game.
*/
boolean checkColour()
{
Serial.print( repeatIndex ); Serial.print( " = " ); Serial.print( sequence[ repeatIndex ] ); Serial.print( " vs " );Serial.println( colour );
int requiredColour = sequence[ repeatIndex ];
if ( requiredColour == colour ) {
// Yes they have chosen the correct color
repeatIndex ++;
colour = NONE;
if ( repeatIndex == sequenceSize ) {
// They have repeated the whole index, so now its the computers turn
changeState( STATE_LISTEN );
}
} else {
// No that's wrong!
playTone( 1200, 600 ); // Error sound
playTone( 1400, 700 ); // Error sound
playTone( 1800, 1000 ); // Error sound
changeState( STATE_RESTART );
}
}
/*
Plays a note.
The pitch is different for each colour. See the array "tones".z
*/
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 );
}
}