From 497179818b0d94919a74412bff805f6c09ea68e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Nut=CC=A6iu?= Date: Fri, 23 Sep 2016 20:06:07 +0300 Subject: [PATCH] Initial Commit --- simon_says.ino | 318 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 simon_says.ino diff --git a/simon_says.ino b/simon_says.ino new file mode 100644 index 0000000..58aaf1d --- /dev/null +++ b/simon_says.ino @@ -0,0 +1,318 @@ +/* + * Author: Denis Cosmin + * Date: 19.09.2016 + * Name: Simon Says + * + * To add a reset button connect: reset -> button <- pulldown resistor ground. + * The buttons have 1k pulldown resitors. + * The leds have a 220 ohm resistor. + * + * Will use the following numbers for colors, pins and notes + * 0 - Yellow + * 1 - Green + * 2 - Red + * 3 - Blue + * + */ + +/* + * The game class, handles everything. + */ +class Game { + private: + int debounce(int last, int buttonPin); + void playNote(int note, int noteSpeed) const; + void flashLed(int led, int flashSpeed) const; + public: + static const int RED_PIN; + static const int BLUE_PIN; + static const int GREEN_PIN; + static const int YELLOW_PIN; + static const int MICROPHONE_PIN; + static const int RED_BUTTON_PIN; + static const int BLUE_BUTTON_PIN; + static const int GREEN_BUTTON_PIN; + static const int YELLOW_BUTTON_PIN; + static const int RED_TONE; + static const int BLUE_TONE; + static const int GREEN_TONE; + static const int YELLOW_TONE; + static const int GAMEOVER_TONE; + int gameLevel[200]; + int gameSpeed; + int lastButtonValue; + int currentLevel; + int gameIsOver; + double gameDifficulty; + enum color { YELLOW, GREEN, RED, BLUE }; + public: + Game(); + Game(int); + void playLevel(); + int userInput(); + int gameOver(); + int getNote(int note) const; + int pinToColorCode(int); + int colorCodeToPin(int); + int readButton(int buttonPin); +}; + +// Settings +/* Pin settings */ +// Button pins must be in consecutive descending order! Eg: blue 12, red 11, green 10, yellow 9 +static const int Game::MICROPHONE_PIN = 13; +static const int Game::BLUE_PIN = 12; +static const int Game::RED_PIN = 11; +static const int Game::GREEN_PIN = 10; +static const int Game::YELLOW_PIN = 9; +static const int Game::BLUE_BUTTON_PIN = 8; +static const int Game::RED_BUTTON_PIN = 7; +static const int Game::GREEN_BUTTON_PIN = 6; +static const int Game::YELLOW_BUTTON_PIN = 5; +/* Tone frequencies */ +static const int Game::RED_TONE = 200; +static const int Game::BLUE_TONE = 400; +static const int Game::YELLOW_TONE = 600; +static const int Game::GREEN_TONE = 800; +static const int Game::GAMEOVER_TONE = 1000; + +// Construct and initialize the Game object. +Game::Game(int difficulty) : gameSpeed(1000), lastButtonValue(-1), currentLevel(0), gameDifficulty(difficulty), gameIsOver(0) { + Serial.print("Constructing game object with difficulty: "); + Serial.println(difficulty); + pinMode(Game::MICROPHONE_PIN, OUTPUT); + pinMode(Game::BLUE_PIN, OUTPUT); + pinMode(Game::RED_PIN, OUTPUT); + pinMode(Game::GREEN_PIN, OUTPUT); + pinMode(Game::YELLOW_PIN, OUTPUT); +} + +Game::Game() : gameSpeed(1000), lastButtonValue(-1), currentLevel(0), gameDifficulty(10), gameIsOver(0) { + Serial.println("Constructing game object"); + pinMode(Game::MICROPHONE_PIN, OUTPUT); + pinMode(Game::BLUE_PIN, OUTPUT); + pinMode(Game::RED_PIN, OUTPUT); + pinMode(Game::GREEN_PIN, OUTPUT); + pinMode(Game::YELLOW_PIN, OUTPUT); +} + +/* + * Makes sure the button is pressed only once. + */ +int Game::debounce(int last, int buttonPin) { + int current = digitalRead(buttonPin); + if (last != current) + { + delay(5); + current = digitalRead(buttonPin); + } + return current; +} + +/* + * Plays a note. + * Receives the button number and plays the corresponding note. + */ +void Game::playNote(int note, int noteSpeed) const { + Serial.print("playNote: Playing note: "); + Serial.print(note); + Serial.print(" with speed: "); + Serial.println(noteSpeed); + + note = Game::getNote(note); + + tone(Game::MICROPHONE_PIN, note, noteSpeed); +} + +/* + * Returns the corresponding color code based on pin. + */ +int Game::colorCodeToPin(int value) { + int ret_val = -1; + + switch(value) { + case RED: + ret_val = Game::RED_PIN; + break; + case GREEN: + ret_val = Game::GREEN_PIN; + break; + case BLUE: + ret_val = Game::BLUE_PIN; + break; + case YELLOW: + ret_val = Game::YELLOW_PIN; + break; + default: + Serial.println("colorCodeToPin: Invalid value!"); + delay(1000); + exit(0); + } + + return ret_val; +} + +/* + * Converts the button pin to a color code. + */ +int Game::pinToColorCode(int value) { + int ret_val = -1; + switch(value) { + case Game::RED_BUTTON_PIN: + ret_val = RED; + break; + case Game::GREEN_BUTTON_PIN: + ret_val = GREEN; + break; + case Game::BLUE_BUTTON_PIN: + ret_val = BLUE; + break; + case Game::YELLOW_BUTTON_PIN: + ret_val = YELLOW; + break; + default: + Serial.println("pinToColorCode: Invalid value!"); + delay(1000); + exit(0); + } + + return ret_val; +} + +/* + * The the corresponding note based on the color code it receives. + */ +int Game::getNote(int note) const { + int return_value = -1; + switch(note) { + case YELLOW: + return_value = Game::YELLOW_TONE; + break; + case GREEN: + return_value = Game::GREEN_TONE; + break; + case RED: + return_value = Game::RED_TONE; + break; + case BLUE: + return_value = Game::BLUE_TONE; + break; + case 4: + return_value = Game::GAMEOVER_TONE; + break; + default: + Serial.println("playNote: Error! Invalid note!"); + delay(1000); + exit(0); + } + return return_value; +} + +/* + * Flashes a led. Receives the led code and sets it to the corresponding pin. + */ +void Game::flashLed(int led, int flashSpeed) const { + Serial.print("flashLed: Flashing LED: "); + Serial.print(led); + Serial.print(" with speed: "); + Serial.println(flashSpeed); + + led = Game::colorCodeToPin(led); + + digitalWrite(led, HIGH); + delay(flashSpeed); + digitalWrite(led, LOW); +} + +/* + * Plays the next level. + */ +void Game::playLevel() { + Serial.print("playLevel: Playing on level: "); + Serial.println(Game::currentLevel); + Game::gameLevel[Game::currentLevel] = random(0, 4); // Create a random move every time. 0 to 4 exclusive. + ++Game::currentLevel; + int nextDificulty = Game::gameDifficulty * Game::currentLevel; + if (Game::gameSpeed - nextDificulty >= 10) { + Game::gameSpeed -= nextDificulty; // decrease the speed; + } + + // Play all the moves + for (int i = 0; i < Game::currentLevel; ++i) { + Game::playNote(Game::gameLevel[i], Game::gameSpeed); + Game::flashLed(Game::gameLevel[i], Game::gameSpeed); + } +} + +/* + * Reads the button value and returns the following codes: + * 0 - Yellow 1 - Green 2 - Red 3 - Blue + */ +int Game::readButton(int buttonPin) { + int currentButtonValue = Game::debounce(Game::lastButtonValue, buttonPin); + int return_value = -1; + if (lastButtonValue == LOW && currentButtonValue > LOW) { + return_value = Game::pinToColorCode(buttonPin); + } + Game::lastButtonValue = currentButtonValue; + if (return_value >= 0) { + Serial.print("readButton: Received signal from button number: "); + Serial.println(return_value); + } + return return_value; +} + +int Game::gameOver() { + Serial.println("game_is_over: Checking if game is over!"); + if (Game::gameIsOver) { + Serial.println("game_is_over: Game is over!"); + } + return Game::gameIsOver; +} + +/* + * Gets the user button presses and checks them to see if they're good. + */ +int Game::userInput() { + for (int i = 0; i < Game::currentLevel; ++i) { + Serial.println("userInput: User is pressing."); + int buttonPressed = -1; + while(true) { + buttonPressed = readButton(Game::RED_BUTTON_PIN); + if (buttonPressed != -1) { break; } + buttonPressed = readButton(Game::GREEN_BUTTON_PIN); + if (buttonPressed != -1) { break; } + buttonPressed = readButton(Game::YELLOW_BUTTON_PIN); + if (buttonPressed != -1) { break; } + buttonPressed = readButton(Game::BLUE_BUTTON_PIN); + if (buttonPressed != -1) { break; } + } + + if (buttonPressed != gameLevel[i]) { + Game::playNote(4, 100); // game over note, and game over note speed. + Game::flashLed(buttonPressed, 1000); + return 0; + } + Game::playNote(buttonPressed, Game::gameSpeed); + Game::flashLed(buttonPressed, Game::gameSpeed); + } + delay(500); + return 1; +} + +Game g(50); // Constructs the game object. +void setup() { + Serial.begin(9600); + randomSeed(0); +} + +void loop() { + if (g.gameOver()) { + delay(1000); // Wait for serial to finish printing. + exit(0); + } + g.playLevel(); + if (g.userInput() == 0) { + g.gameIsOver = 1; + } +}