/*** Fast & Easy version of Simon Sings, by Ron Miller (RonM9) July 2015
with special hardware consideration to except direct connection of:
LED & Switch modules from:
- 1st pattern is now all 1-4 in sequence, to facilitate testing of hookup & pin assignments
- uses onboard LED as 'Fail' indicator
- along with some other minor code changes
Refer http://Instructables.com/
***/
/* Simon Sings - a memory game for 4 leds, 4 switches and a buzzer.
"Sings" is the sound-enhanced version of "Fairly Simple Simon".
No relation to the Singh family :)
Original Breadboard diagram, video, etc. at http://bit.ly/simonsings
After reset, Simon plays a bar from "Simple Simon says", and starts playing a game at level 4.
Playing a game at level N:
1) Simon picks a random sequence of N LED flashes.
2) Simon waits for you to press any button when ready.
3) Simon "says" the sequence. Memorize it.
4) You should then repeat the sequence on the buttons.
* If you're right, Simon plays the song, and you start a level N+1 game at step 1.
* If you push a wrong button, Simon plays a sad tune, and you go back to step 2.
cc-by-sa by @TheRealDod, Nov 23, 2010
RRM Oct 2015: allowed for faster button inputs
*/
//#include "pitches.h" the following 'NOTE's were in a separate .h file ...
/*************************************************
* Public Constants
*************************************************/
#define NOTE_B0 31
#define NOTE_C1 33
#define NOTE_CS1 35
#define NOTE_D1 37
#define NOTE_DS1 39
#define NOTE_E1 41
#define NOTE_F1 44
#define NOTE_FS1 46
#define NOTE_G1 49
#define NOTE_GS1 52
#define NOTE_A1 55
#define NOTE_AS1 58
#define NOTE_B1 62
#define NOTE_C2 65
#define NOTE_CS2 69
#define NOTE_D2 73
#define NOTE_DS2 78
#define NOTE_E2 82
#define NOTE_F2 87
#define NOTE_FS2 93
#define NOTE_G2 98
#define NOTE_GS2 104
#define NOTE_A2 110
#define NOTE_AS2 117
#define NOTE_B2 123
#define NOTE_C3 131
#define NOTE_CS3 139
#define NOTE_D3 147
#define NOTE_DS3 156
#define NOTE_E3 165
#define NOTE_F3 175
#define NOTE_FS3 185
#define NOTE_G3 196
#define NOTE_GS3 208
#define NOTE_A3 220
#define NOTE_AS3 233
#define NOTE_B3 247
#define NOTE_C4 262
#define NOTE_CS4 277
#define NOTE_D4 294
#define NOTE_DS4 311
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_AS4 466
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_CS5 554
#define NOTE_D5 587
#define NOTE_DS5 622
#define NOTE_E5 659
#define NOTE_F5 698
#define NOTE_FS5 740
#define NOTE_G5 784
#define NOTE_GS5 831
#define NOTE_A5 880
#define NOTE_AS5 932
#define NOTE_B5 988
#define NOTE_C6 1047
#define NOTE_CS6 1109
#define NOTE_D6 1175
#define NOTE_DS6 1245
#define NOTE_E6 1319
#define NOTE_F6 1397
#define NOTE_FS6 1480
#define NOTE_G6 1568
#define NOTE_GS6 1661
#define NOTE_A6 1760
#define NOTE_AS6 1865
#define NOTE_B6 1976
#define NOTE_C7 2093
#define NOTE_CS7 2217
#define NOTE_D7 2349
#define NOTE_DS7 2489
#define NOTE_E7 2637
#define NOTE_F7 2794
#define NOTE_FS7 2960
#define NOTE_G7 3136
#define NOTE_GS7 3322
#define NOTE_A7 3520
#define NOTE_AS7 3729
#define NOTE_B7 3951
#define NOTE_C8 4186
#define NOTE_CS8 4435
#define NOTE_D8 4699
#define NOTE_DS8 4978
const int NLEDS = 4;
// these pin assignments are for Fast & Easy Instructables configuration using modules noted above
const int SPEAKERPIN = 8; //was orig 8 then 9;
const int LEDPINS[NLEDS] = {2,3,4,5}; // Some Fade effect if PWM pins are used
const int SWITCHPINS[NLEDS] = {15,16,17,18}; // A4-A1
const int PSUDOGND = 19; // needed for button module in this Fast&Easy config
const int PSUDOGND2 = 11; //7; // needed for LED module
const int PSUDOGND3 = 7; //11; // used as -neg for buzzer
const int ONBRD_LED = 13;
const int SWITCHPRESSED = 0; // 1 or 0, for normally-open/closed switches
const int NOTES[NLEDS] = {NOTE_C4, NOTE_D4, NOTE_E4, NOTE_F4};
const int FADESTEPS = 8;
const int FADEINDURATION = 200;
const int FADEOUTDURATION = 150;
const int SEQDELAY = 50; // Millis between led flashes.
const int PAUSEB4SEQ = 500; // Millis before starting the sequence.
bool watchBtn=false; // used to keep LED illumination activity from blocking Button activity
const int MINLEVEL = 4;
const int MAXLEVEL = 16;
int gameLevel;
int simonSez[MAXLEVEL]; // sequence of 0..NLEDS-1
// -- song-array note fields --
// Tone
const int NOTETONE = 0;
const int SILENCE = 0;
const int ENDOFSONG = -1;
// Duration
const int NOTEDURATION = 1;
const int SINGLEBEAT = 125; // Note duration (millis) is multiplied by this
const float PAUSEFACTOR=0.2; // relative length of silence after playing a note
// LED
const int NOTELED = 2;
const int ALLLEDS = -1;
int WINSONG[][3] = {
{SILENCE,2,ALLLEDS}
,{NOTE_E4,1,2} ,{NOTE_E4,1,2} ,{NOTE_E4,1,2}
,{NOTE_F4,1,3} ,{NOTE_E4,1,2} ,{NOTE_D4,3,1}
,{NOTE_G4,1,ALLLEDS} ,{NOTE_G4,1,ALLLEDS} ,{NOTE_G4,1,ALLLEDS}
,{NOTE_A4,2,ALLLEDS} ,{NOTE_G4,5,ALLLEDS}
,{ENDOFSONG,ENDOFSONG,ENDOFSONG}
};
int LOSESONG[][3] = {
{NOTE_B5,2,3},{NOTE_A5,2,2},{NOTE_GS5,2,1},{NOTE_G5,8,ALLLEDS}, {ENDOFSONG,ENDOFSONG,ENDOFSONG}
};
// =============================================================
void setup() {
Serial.begin(9600); // use serial
Serial.println("\r\n ---- Simon Sings ----");
// Analog in 0 should *not* be connected.
// It's mama's little PRNG :)
randomSeed(analogRead(0));
pinMode(ONBRD_LED,OUTPUT);
pinMode(SPEAKERPIN,OUTPUT);
noTone(SPEAKERPIN);
gameLevel=MINLEVEL;
for (byte l=0; l<NLEDS; l++) {
pinMode(LEDPINS[l], OUTPUT);
pinMode(SWITCHPINS[l], INPUT);
digitalWrite(SWITCHPINS[l],1 - SWITCHPRESSED);
}
// setup psuedo ground(s)
pinMode(PSUDOGND, OUTPUT);
digitalWrite(PSUDOGND,LOW);
pinMode(PSUDOGND2, OUTPUT);
digitalWrite(PSUDOGND2,LOW);
pinMode(PSUDOGND3, OUTPUT);
digitalWrite(PSUDOGND3,LOW);
// beep(50); beep(50); beep(50);
// delay(200);
// Visual feedback after reset. Also good as a cable check :)
playWinSequence();
// init Game Sequence as 1,2,3,4 suitable for configuration verification
for (int i=0; i<gameLevel; i++) {
simonSez[i]=i;
}
Serial.println("\r\n ---- Simon Sings ----");
}
// ===========================================================
void loop() {
int done=0;
while (!done) {
Serial.println("\r\n Press any button for next pattern.");
getSwitchStroke();
digitalWrite(ONBRD_LED,LOW); // clears the red 'FAILURE indicator' LED
delay(PAUSEB4SEQ);
playGameSequence(gameLevel);
Serial.println("\r\n Repeat the pattern.");
if (playerGuess(gameLevel)) {
playWinSequence();
done = 1;
if (gameLevel<MAXLEVEL) {
gameLevel++;
}
extendSequence();
} else {
playLoseSequence();
gameLevel = MINLEVEL;
initGameSequence(gameLevel);
}
}
}
// ===========================================================
// Local Utilities
void initGameSequence(int gameLevel) {
// assertion: gameLevel<=MAXLEVEL
for (int i=0; i<gameLevel; i++) {
simonSez[i]=random(NLEDS);
}
}
void extendSequence() {
simonSez[gameLevel-1]=random(NLEDS);
}
void playGameSequence(int gameLevel) {
for (int i=0; i<gameLevel; i++) {
playLed(simonSez[i]); // Fade LED and play its note
}
}
void fadeLed(int theLed,int val,int duration) {
int fadeStep=256/FADESTEPS;
int fadeDelay=duration/FADESTEPS;
for (int i=0; i<256; i+=fadeStep) {
if (theLed>=0) {
analogWrite(LEDPINS[theLed],val?i:255-i);
}
else { // ALLLEDS
for (int j=0; j<NLEDS; j++) {
analogWrite(LEDPINS[j],val?i:255-i);
}
}
delay(fadeDelay);
if (watchBtn && btnReased()) break; // to allow fast button input sequences
}
// force val (in case fadeStep doesn't divide 256)
if (theLed>=0) {
digitalWrite(LEDPINS[theLed],val);
}
else {
for (int j=0; j<NLEDS; j++) {
digitalWrite(LEDPINS[j],val);
}
}
}
void playLed(int theLed) { // Fade LED and play its note
// pinMode(SPEAKERPIN,OUTPUT);
tone(SPEAKERPIN,NOTES[theLed]);
fadeLed(theLed,HIGH,FADEINDURATION); // Fade in
noTone(SPEAKERPIN);
fadeLed(theLed,LOW,FADEOUTDURATION); // Fade out
}
int playerGuess(int gameLevel) {
for (int i=0 ; i<gameLevel ; i++) {
int guess=getSwitchStroke();
//Serial.print(guess,DEC);
//Serial.print(",");
//Serial.println(simonSez[i]);
if (guess!=simonSez[i]) {
return 0;
}
else {
watchBtn = true;
playLed(guess); // Fade LED and play its note
watchBtn = false;
}
}
return 1;
}
void playSong(int song[][3]) {
// pinMode(SPEAKERPIN,OUTPUT);
for (int note=0; song[note][NOTETONE]!=ENDOFSONG; note++) {
int theDuration=SINGLEBEAT*song[note][NOTEDURATION];
int theTone=song[note][NOTETONE];
if (theTone) {
tone(SPEAKERPIN,theTone);
}
int theLed=song[note][NOTELED];
fadeLed(theLed,HIGH,theDuration); // Fade in
noTone(SPEAKERPIN);
fadeLed(theLed,LOW,theDuration*PAUSEFACTOR); // Fade out + silence between note
}
}
int playWinSequence() {
Serial.println("\r\n You are a Winner !");
playSong(WINSONG);
}
int playLoseSequence() {
playSong(LOSESONG);
Serial.println("\r\nRasberrys!! You lost it.");
// digitalWrite(ONBRD_LED,HIGH); // turns on the 'FAILURE indicator' LED
}
int getSwitchStroke() {
while (get1stPressedSwitch()>=0) {
// flush everything until no switch is pressed
delay(10);
}
while (get1stPressedSwitch()<0) {
// wait for next press
delay(10);
}
return get1stPressedSwitch();
}
int get1stPressedSwitch() {
for (int i=0; i<NLEDS; i++) {
if (digitalRead(SWITCHPINS[i])==SWITCHPRESSED) {
return i;
}
}
return -1;
}
bool btnReased() {
bool released=true;
for (int i=0; i<NLEDS; i++) {
if (digitalRead(SWITCHPINS[i])==SWITCHPRESSED) {
released=false;
}
}
return(released);
}
void beep(unsigned char delayms){ // works with both buzzers and speakers
byte pinState = 0; // 0 turns it off
for (int i=0; i<delayms; i++) { // wait for a delayms ms
pinState = 1 - pinState;
digitalWrite ( SPEAKERPIN, pinState);
delay(1);
}
delay(delayms); // wait for a delayms ms
}
nano:12
nano:11
nano:10
nano:9
nano:8
nano:7
nano:6
nano:5
nano:4
nano:3
nano:2
nano:GND.2
nano:RESET.2
nano:0
nano:1
nano:13
nano:3.3V
nano:AREF
nano:A0
nano:A1
nano:A2
nano:A3
nano:A4
nano:A5
nano:A6
nano:A7
nano:5V
nano:RESET
nano:GND.1
nano:VIN
nano:12.2
nano:5V.2
nano:13.2
nano:11.2
nano:RESET.3
nano:GND.3
r1:1
r1:2
led1:A
led1:C
r2:1
r2:2
led2:A
led2:C
led3:A
led3:C
led4:A
led4:C
r3:1
r3:2
r4:1
r4:2
r5:1
r5:2
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r
btn3:1.l
btn3:2.l
btn3:1.r
btn3:2.r
btn4:1.l
btn4:2.l
btn4:1.r
btn4:2.r
bz1:1
bz1:2