For easy copy-paste, the code for the Simon Says game is below. It is also attached as a file to this project.
/**
* Simon Says
*
* This program represents a simple game of Simon Says with two LEDs and two push buttons.
* It is designed to showcase a minimalistic circuit that still does something interesting.
*
* When the circuit is powered on, both LEDs will blink three times. Then, LEDs will light up
* one at a time in a random pattern that the user must duplicate using the push buttons.
* Once the sequence has completed, each button controls an LED. The pattern in which the
* LEDs blink is randomly generated, and has a length measured in blinks. The patterns begin
* with one blink, then increase by one blink each time the player correctly mimics the sequence.
*
* If the user gets the sequence wrong, both LEDs will blink three times, then start a new
* pattern at length 1. The game will continue until the pattern is 50 blinks long. If the
* user correctly mimics all 50 patterns, the game is over and the LEDs will blink in a
* celebratory pattern until the circuit is power cycled.
*
* This code can be run on an Arduino, but is designed for the ATtiny85 microcontroller.
*
* Author: acr
*/
// pin configuration
const int greenLED = 4;
const int redLED = 1;
const int greenButton = 3;
const int redButton = 2;
// debounce
unsigned long lastGreenDebounceTime = 0;
unsigned long lastRedDebounceTime = 0;
unsigned long debounceDelay = 50;
// game data
char pattern[50] = {0};
int curPatternLength = 1;
int greenButtonState = 0;
int redButtonState = 0;
int lastGreenButtonState = 0;
int lastRedButtonState = 0;
void setup() {
// initialize LED pins as digital outputs
pinMode(greenLED, OUTPUT);
pinMode(redLED, OUTPUT);
// initialize button pins as digital inputs
pinMode(greenButton, INPUT);
pinMode(redButton, INPUT);
// seed random number generator
randomSeed(analogRead(0));
}
/**
* Blink both LEDs in the pattern that occurs when
* the player has lost the game.
*/
void blinkLose() {
for(int i = 0; i < 3; i++) {
digitalWrite(greenLED, HIGH);
digitalWrite(redLED, HIGH);
delay(500);
digitalWrite(greenLED, LOW);
digitalWrite(redLED, LOW);
delay(500);
}
}
/**
* Blink both LEDs in the pattern that occurs when
* the player has won the game.
*/
void blinkWin() {
for(int i = 0; i < 2; i++) {
digitalWrite(greenLED, HIGH);
digitalWrite(redLED, LOW);
delay(500);
digitalWrite(greenLED, LOW);
digitalWrite(redLED, HIGH);
delay(500);
digitalWrite(greenLED, LOW);
digitalWrite(redLED, LOW);
}
for(int i = 0; i < 2; i++) {
digitalWrite(greenLED, HIGH);
digitalWrite(redLED, HIGH);
delay(500);
digitalWrite(greenLED, LOW);
digitalWrite(redLED, LOW);
delay(500);
}
}
/**
* Generate a blink pattern that is length blinks long,
* and store that pattern in the pattern array.
*/
void generatePattern(int length) {
for(int i = 0; i < length; i++) {
int rand = random(10);
if(rand < 5) {
pattern[i] = 'r';
}else {
pattern[i] = 'g';
}
}
}
/**
* Turns off all LEDs.
*/
void turnLightsOff() {
digitalWrite(greenLED, LOW);
digitalWrite(redLED, LOW);
}
/**
* Turns on all LEDs.
*/
void turnLightsOn() {
digitalWrite(greenLED, HIGH);
digitalWrite(redLED, HIGH);
}
/**
* Turns both lights on and blocks all other activity.
* For use in case of an error state to indicate that
* the user should check the logs and power cycle.
*/
void error() {
while(1) {
turnLightsOn();
}
}
/**
* Display the current pattern stored in the pattern array
* using the red and green LEDs.
*/
void displayPattern() {
for(int i = 0; i < curPatternLength; i++) {
turnLightsOff();
delay(500);
if(pattern[i] == 'g') {
digitalWrite(greenLED, HIGH);
delay(500);
}else if(pattern[i] == 'r') {
digitalWrite(redLED, HIGH);
delay(500);
}else {
error();
}
}
turnLightsOff();
}
/**
* Check whether the color at position pos in the pattern
* matches the given color. Returns 1 if true, 0 if false.
*/
int checkPatternColor(char color, int pos) {
if(pattern[pos] == color) {
return 1;
}
return 0;
}
/**
* Returns 1 if both buttons are unpressed, 0 otherwise.
*/
int buttonsUnpressed(int redState, int greenState) {
if(redState == LOW && greenState == LOW) {
return 1;
}
return 0;
}
/**
* Reads the pattern as input by the player. Returns 1 if
* the player entered the pattern correctly, 0 otherwise.
*/
int readPlayerPattern() {
int cntr = 0; // counter for current position in the pattern
int correct = 1; // whether the pattern is correct
char playerColor = 0; // store the current color selection by the player
while(cntr < curPatternLength) {
int greenReading = digitalRead(greenButton);
int redReading = digitalRead(redButton);
int buttonsChanged = 0;
if(greenReading != lastGreenButtonState) {
lastGreenDebounceTime = millis();
}
if(redReading != lastRedButtonState) {
lastRedDebounceTime = millis();
}
if((millis() - lastGreenDebounceTime) > debounceDelay) {
if(greenReading != greenButtonState) {
greenButtonState = greenReading;
buttonsChanged = 1;
}
}
if((millis() - lastRedDebounceTime) > debounceDelay) {
if(redReading != redButtonState) {
redButtonState = redReading;
buttonsChanged = 1;
}
}
if(buttonsChanged == 1) { // monitor button state to debounce
if(greenButtonState == HIGH && redButtonState == HIGH) {
// fail - the two lights will never be on at the same time
correct = 0;
break;
}else if(greenButtonState == HIGH && redButtonState == LOW) {
// green button pressed
playerColor = 'g';
}else if(greenButtonState == LOW && redButtonState == HIGH) {
// red button pressed
playerColor = 'r';
}else {
playerColor = 0;
}
/* Note: Nothing is done if both buttons are low so that the player
* has time to input the pattern at their own pace. */
if(playerColor != 0) {
// check if the choice was correct
correct = checkPatternColor(playerColor, cntr);
if(correct == 1) {
// if so, increment the counter and continue
cntr++;
playerColor = 0;
}else {
// if not, break out of the loop
break;
}
}
}
lastGreenButtonState = greenReading;
lastRedButtonState = redReading;
buttonsChanged = 0;
}
return correct;
}
/**
* The main loop of the program, runs repeatedly while the
* power is on.
*/
void loop() {
// Serial.println("Starting program");
blinkLose(); // blink 3 times on power up
// start the game
while(curPatternLength <= 50) { // game is 50 levels long
generatePattern(curPatternLength);
displayPattern();
int playerResult = readPlayerPattern();
if(playerResult == 1) {
// player got the latest pattern correct, continue to the next one
curPatternLength++;
}else {
// player failed the latest pattern, notify player of loss and restart pattern counter
blinkLose();
curPatternLength = 1;
}
delay(2000); // break in between patterns so user can keep up
}
// at this point, the user must have won all levels, so display win pattern
blinkWin();
}
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.