/*
https://www.waitingforfriday.com/?p=586
The tones for the lights are as follows (on Pocket Simon):
Blue – 415 Hz – G#4 (true pitch 415.305 Hz)
Yellow – 310 Hz – D#4 (true pitch 311.127 Hz)
Red – 252 Hz ‐ B3 (true pitch 247.942 Hz)
Green – 209 Hz – G#3 (true pitch 207.652 Hz)
On the full‐size version of Simon the lights are in the opposite order:
Green – 415 Hz – G#4 (true pitch 415.305 Hz)
Red – 310 Hz – D#4 (true pitch 311.127 Hz)
Yellow – 252 Hz ‐ B3 (true pitch 247.942 Hz)
Blue – 209 Hz – G#3 (true pitch 207.652 Hz)
*/
#include <Button.h>
#include <Tone.h>
const int DEBUG = 0;
const int MAX_NOTE_SEQ_LEN = 150;
const int TIME_OUT = 2000;
const int NONE = -1;
const int BLUE = 0;
const int YELLOW = 1;
const int RED = 2;
const int GREEN = 3;
const int BIG_DELAY = 1200;
const int SMALL_DELAY = 600;
const int TIMEOUT = 3000;
const int NOTE[] = {209, 252, 310, 415};
const int BUTTON_PIN[] = {3, 8, 2, 9};
const int LED_PIN[] = {5, 6, 4, 7};
const int SPEAKER_PIN = 10;
const int RND_SEED_PIN = A1;
Button button[] = {
Button(BUTTON_PIN[BLUE]),
Button(BUTTON_PIN[YELLOW]),
Button(BUTTON_PIN[RED]),
Button(BUTTON_PIN[GREEN]),
};
Tone audio;
int note_sequence[MAX_NOTE_SEQ_LEN];
int note_sequence_length;
int current_note;
int note_duration;
int pause_between_notes;
int level;
unsigned long int level_started_at;
int level_ongoing;
void setup() {
for (int i = 0; i < 4; i++) {
pinMode(LED_PIN[i], OUTPUT);
button[i].begin();
}
audio.begin(SPEAKER_PIN);
Serial.begin(9600);
reset_game();
}
void led(int led, int status = 1) {
digitalWrite(LED_PIN[led], status);
}
void reset_game() {
level = 0;
level_ongoing = 0;
}
void loop() {
// start next level if there is no current level ongoing
if (!level_ongoing) {
start_next_level();
set_timeout();
level_ongoing = 1;
current_note = 0;
}
// if timed out
if (timeout()) {
delay(SMALL_DELAY);
notify("timeout");
delay(BIG_DELAY);
reset_game();
return;
}
// if player gives an input
int player_input = get_player_input();
if (player_input != NONE) {
if (note_sequence[current_note] == player_input) {
// Input matched. Now check next note.
current_note += 1;
set_timeout();
} else {
delay(SMALL_DELAY);
notify("failed");
delay(BIG_DELAY);
reset_game();
return;
}
};
// if level completed
if (current_note == note_sequence_length) {
delay(SMALL_DELAY);
notify("passed");
delay(BIG_DELAY);
level_ongoing = 0;
}
return;
}
void set_timeout() {
level_started_at = millis();
if (DEBUG) Serial.println(level_started_at);
}
int timeout() {
return (millis() - level_started_at) > TIMEOUT;
}
int get_player_input() {
for (int i = 0; i < 4; i++) {
if (button[i].pressed()) {
audio.play(NOTE[i]);
digitalWrite(LED_PIN[i], HIGH);
delay(note_duration);
audio.stop();
digitalWrite(LED_PIN[i], LOW);
return i;
}
}
return -1;
}
void start_next_level() {
level += 1;
level_ongoing = 1;
note_duration = 600;
pause_between_notes = 150;
note_sequence_length = level;
randomSeed(analogRead(RND_SEED_PIN));
for (int i = 0; i < note_sequence_length; i++) {
note_sequence[i] = random(4);
audio.play(NOTE[note_sequence[i]]);
led(note_sequence[i], HIGH);
delay(note_duration);
audio.stop();
led(note_sequence[i], LOW);
delay(pause_between_notes);
if (DEBUG) Serial.print(note_sequence[i]);
if (DEBUG) Serial.print(" | ");
}
if (DEBUG) Serial.println("");
}
void notify(String notif_type) {
if (notif_type == "passed") {
if (DEBUG) Serial.println("Passed");
int notif_note_sequence[] = {RED, YELLOW, BLUE, GREEN};
int notif_note_duration[] = {100, 100, 100, 100};
play_note_sequence(4, notif_note_sequence, notif_note_duration);
}
if (notif_type == "failed" || notif_type == "timeout") {
if (DEBUG) Serial.println("Failed");
int notif_note_sequence[] = {BLUE, GREEN, NONE, RED, YELLOW, BLUE, GREEN, NONE, RED, YELLOW};
int notif_note_duration[] = {100, 100, 100, 100, 100, 100, 100, 100, 100, 100};
play_note_sequence(10, notif_note_sequence, notif_note_duration);
}
}
void play_note_sequence(int notif_note_sequence_length, int notif_note_sequence[], int notif_note_duration[]) {
for (int i = 0; i < notif_note_sequence_length; i++) {
if (notif_note_sequence[i] != NONE) {
audio.play(NOTE[notif_note_sequence[i]]);
led(notif_note_sequence[i], 1);
}
delay(notif_note_duration[i]);
if (notif_note_sequence[i] != NONE) {
audio.stop();
led(notif_note_sequence[i], 0);
}
}
}