A simple Simon Says game to run on Arduino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Author: Elbow-Room | |
* Purpose: To run the classic game "Simon" on arduino using random sequences and a maximum of 100 turns | |
* | |
* HARDWARE SETUP: | |
* Connect lights to digital ports 10 through 13 | |
* Connect buttons to digital ports 2 through 5 | |
* Connect Piezo to digital port 7 and switch to digital port 9 | |
*/ | |
/* Game related constants */ | |
#define BUTTON_0 2 | |
#define BUTTON_1 3 | |
#define BUTTON_2 4 | |
#define BUTTON_3 5 | |
#define GREEN_LED 10 | |
#define RED_LED 11 | |
#define YELLOW_LED 12 | |
#define BLUE_LED 13 | |
#define PIEZO 7 | |
#define PIEZO_SWITCH 9 | |
static int pitches [] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 262, 294, 330, 349}; | |
/* General constants */ | |
#define TRUE 1 | |
#define FALSE 0 | |
#define CORRECT 1 | |
#define INCORRECT 0 | |
/* Time constants */ | |
#define ONE_SEC 1000 | |
#define HALF_SEC 500 | |
#define QUART_SEC 250 | |
/* Generates a random number then flashes the 4 lights in an order dictated by the array of random numbers | |
* Parameter - sequence: The array which stores the sequence of lights to be flashed | |
* Parameter - roundnum: The round number which is also the number of lights to read from the array | |
*/ | |
void flash_lights (int sequence [], int roundnum); | |
/* Reads the order of buttons pressed and stores them in an array | |
* Parameter - input: the array which stores the order of the buttons pressed | |
* Parameter - roundnum: The round number which is also the number of buttons to read and store in the array | |
*/ | |
void get_input (int input [], int roundnum); | |
/* Compares the light sequence with the buttons pressed and returns the state of "Correct" or "Incorrect" | |
* Parameter - sequence: The sequence of lights | |
* Parameter - input: The sequence of button presses | |
* Parameter - roundnum: The round number which is also the number of entries to be compared in each array | |
* Return: Whether the user entered a correct or incorrect sequence of button pushes | |
*/ | |
int check_input (int sequence [], int input [], int roundnum); | |
/* Determines what to do in the next round based on the Correct or Incorrect state of the user's input. Whether to add a light to the | |
* sequence, award a win and restart, or give a lose signal and restart | |
* Parameter - status: The "Correct" or "Incorrect" status of the user's entered button sequence | |
* Parameter - roundnum: The current round number | |
* Return: The new round number | |
*/ | |
int next_round (int status, int roundnum); | |
void setup () | |
{ | |
pinMode (2, INPUT); | |
pinMode (3, INPUT); | |
pinMode (4, INPUT); | |
pinMode (5, INPUT); | |
pinMode (7, OUTPUT); | |
pinMode (9, INPUT); | |
pinMode (10, OUTPUT); | |
pinMode (11, OUTPUT); | |
pinMode (12, OUTPUT); | |
pinMode (13, OUTPUT); | |
randomSeed (analogRead(0)); | |
} | |
int roundnum = 1; /* The current round number, number of lights to flash, number of buttons to read */ | |
int sequence [100]; /* The sequence of lights to flash in each round */ | |
int input [100]; /* The sequence of buttons that the user presses */ | |
int state; /* Whether the user's button entries are correct or incorrect */ | |
/* Run one round of outputs and inputs then determine how many outputs and inputs to use in the next round */ | |
void loop() | |
{ | |
flash_lights(sequence, roundnum); | |
get_input(input, roundnum); | |
state = check_input(sequence, input, roundnum); | |
roundnum = next_round(state, roundnum); | |
} | |
/* End of main program, start of functions */ | |
void flash_lights (int sequence [], int roundnum) | |
{ | |
int count; | |
/* Generates a random number and assigns it to the round's position in the sequence array */ | |
sequence [roundnum-1] = random(10, 14); | |
/* Flashes the lights as dictated by the array and the round number */ | |
for (count = 0; count < roundnum; count++) | |
{ | |
delay (QUART_SEC); | |
digitalWrite (sequence [count], HIGH); | |
tone (PIEZO, pitches [sequence [count]], QUART_SEC); | |
delay (QUART_SEC); | |
digitalWrite (sequence [count], LOW); | |
} | |
} | |
void get_input (int input [], int roundnum) | |
{ | |
int count; | |
int i0; | |
int i1; | |
int i2; | |
int i3; | |
/* Loops until the number of buttons pressed matches the round number */ | |
for (count = 0; count < roundnum; count++) | |
{ | |
/* Read from buttons and stores their statuses in variables until a button is pressed */ | |
do | |
{ | |
i0 = digitalRead (BUTTON_0); | |
i1 = digitalRead (BUTTON_1); | |
i2 = digitalRead (BUTTON_2); | |
i3 = digitalRead (BUTTON_3); | |
}while (i0 == LOW && i1 == LOW && i2 == LOW && i3 == LOW); | |
/* Assigns the value of the button pressed to the round number's psoition in the input array */ | |
if (i0 == HIGH) | |
input [count] = 10; | |
else if (i1 == HIGH) | |
input [count] = 11; | |
else if (i2 == HIGH) | |
input [count] = 12; | |
else if (i3 == HIGH) | |
input [count] = 13; | |
/* Turns on the light corresponding to the button being pressed */ | |
digitalWrite (input[count], HIGH); | |
if (digitalRead (PIEZO_SWITCH) == HIGH) | |
tone (PIEZO, pitches [input [count]]); | |
/* delay to avoid multiple reads from button bouncing */ | |
delay (200); | |
/* Ensures that the pressed button is released before carrying on (avoids reading multiple times if the button is held) */ | |
do | |
{ | |
i0 = digitalRead (BUTTON_0); | |
i1 = digitalRead (BUTTON_1); | |
i2 = digitalRead (BUTTON_2); | |
i3 = digitalRead (BUTTON_3); | |
}while (i0 == HIGH || i1 == HIGH || i2 == HIGH || i3 == HIGH); | |
/* Turns off the light of the button that was just released */ | |
digitalWrite (input[count], LOW); | |
noTone(PIEZO); | |
} | |
} | |
int check_input (int sequence [], int input [], int roundnum) | |
{ | |
int count = 0; | |
int test = CORRECT; | |
/* Compares the individual entries in the sequence and input arrays and assigns the value of INCORRECT to the test variable if the values | |
* in the arrays do not match | |
* Loop breaks when all values relevant to the round have been read or when the entries in the arrays do not match | |
*/ | |
while (count < roundnum && test == CORRECT) | |
{ | |
if (sequence[count] != input[count]) | |
test = INCORRECT; | |
count++; | |
} | |
/* Returns whether or not the input array matches the output array up the round numbe's position */ | |
return test; | |
} | |
int next_round (int state, int roundnum) | |
{ | |
int newround; | |
int i; | |
/* If user has entered correct buttons but has not yet completed the entire game, adds one output/input to the next round of play */ | |
if (state == CORRECT && roundnum < 100) | |
{ | |
newround = roundnum + 1; | |
tone (PIEZO, 440); | |
delay (QUART_SEC); | |
tone (PIEZO, 880, 250); | |
delay (QUART_SEC); | |
} | |
/* If user has successfully responded up to the maximum number of rounds, flashes the green light three times and assigns | |
* a value to newround in order to start a new game | |
*/ | |
else if (state == CORRECT && roundnum == 100) | |
{ | |
delay (HALF_SEC); | |
for (i = 0; i < 3; i++) | |
{ | |
digitalWrite (GREEN_LED, HIGH); | |
delay (HALF_SEC); | |
digitalWrite(GREEN_LED, LOW); | |
delay (QUART_SEC); | |
} | |
newround = 1; | |
} | |
/* If input buttons are wrong, flashes red light three times and assigns a value to newround in order to restart the game */ | |
else if (state == INCORRECT) | |
{ | |
delay (HALF_SEC); | |
for (i = 0; i < 3; i++) | |
{ | |
digitalWrite (RED_LED, HIGH); | |
tone (PIEZO, 200); | |
delay (HALF_SEC); | |
digitalWrite (RED_LED, LOW); | |
noTone(PIEZO); | |
delay (HALF_SEC); | |
} | |
newround = 1; | |
} | |
/* Pauses momentarily and returns the number of inputs/outputs to use in the next round of play */ | |
delay (HALF_SEC); | |
return newround; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment