/**************************************************
* Author: Danilo Gallo *
* Datum: 12.06.2022 *
* Klasse: INS2A *
* Titel: Simon Says - Senso *
*************************************************/
/**************************************************
Diese Datei definiert Konstanten mit der Frequenz
der verschiedenen Musiknoten.
Quelle: https://www.arduino.cc/en/Tutorial/BuiltInExamples/toneMelody
*************************************************/
#include "pitches.h"
/**************************************************
Konstants:
Pin-Nummern für LEDs, Tasten und Lautsprecher
sowie Spieltöne werden definiert:
*************************************************/
const byte ledPins[] = {10, 11, 12, 13}; //Pin 10-13 für LEDs
const byte buttonPins[] = {4, 5, 6, 7}; //Pin 2-5 für Buttons
#define SPEAKER_PIN 2
#define MAX_GAME_LENGTH 50 //Kombination max. 50 Elemente
const int gameTones[] = { NOTE_G3, NOTE_C4, NOTE_E4, NOTE_G5}; //Definition der Töne für jede Farbe
/**************************************************
Globale Variablen
*************************************************/
byte gameSequence[MAX_GAME_LENGTH] = {0}; //Enthält die Kombination der Tasten
byte gameIndex = 0; //Enthält die erreichte Stufe/Niveau
int delaytime; //Variable für Delay
bool LEDs; // true oder false Variable zum Einschalten der LEDs
bool music; // true oder false Variable zum Einschalten der Musik
bool picked; // true oder false Variable zur Überprüfung, ob man sich im Menü befindet
int RandomLED; // Zufallsvariable zur Auswahl eines Led
/**************************************************
Variablen zum Speichern der LEDS-Zustände für
zufälliges Blinken und Abspielen
*************************************************/
bool led1;
bool led2;
bool led3;
bool led4;
/**************************************************
Einrichten des Arduino-Boards und Initialisierung
der seriellen Kommunikation
*************************************************/
void setup() {
Serial.begin(9600);
for (byte i = 0; i < 4; i++) {
pinMode(ledPins[i], OUTPUT);
pinMode(buttonPins[i], INPUT_PULLUP);
}
/**************************************************
Display the main menu
*************************************************/
Serial.println("1 (rot) button - Start normal game.");
Serial.println("2 (gruen) button - Start game ohne Ton.");
Serial.println("3 (blau) button - Start game ohne LEDs.");
Serial.println();
Serial.println("Bitte wählen Sie den gewünschten Game-Modus :-)");
pinMode(SPEAKER_PIN, OUTPUT);
// Die folgende Zeile setzt den Zufallszahlengenerator in Gang.
// Sie geht davon aus, dass Pin A0 potentialfrei ist (nicht angeschlossen):
randomSeed(analogRead(A0));
//Erklärung: Der Startpunkt für die Erzeugung von Zufallszahlen wird als Seed bezeichnet.
//In diesem Fall liest der Code den Wert eines nicht angeschlossenen Analogeingangs und verwendet ihn als Startwert.
//Dies ist eher zufällig, denn die nicht angeschlossenen Stifte verhalten sich im Grunde wie Antennen
//und nehmen elektromagnetische Felder aus der Umgebung auf.
}
/**************************************************
Leuchtet die LED und spielt einen passenden Ton
*************************************************/
void lightLedAndPlayTone(byte ledIndex) {
if (LEDs) digitalWrite(ledPins[ledIndex], HIGH);
if (music) tone(SPEAKER_PIN, gameTones[ledIndex]);
delaytime = map(gameIndex, 0, 50, 500, 10); // Legt den Delay nach Stufe fest, von Stufe 0 bis 50, Delay 500ms bis 10ms
Serial.print("Delay in ms is: "); // Anzeige der aktuellen Dely im seriellen Monitor
Serial.println(delaytime);
delay(delaytime);
if (LEDs) digitalWrite(ledPins[ledIndex], LOW);
if (music) noTone(SPEAKER_PIN);
}
/**************************************************
Spielt die Notenfolge ab, die der Benutzer
wiederholen muss
*************************************************/
void playSequence() {
for (int i = 0; i < gameIndex; i++) {
byte currentLed = gameSequence[i];
lightLedAndPlayTone(currentLed);
delay(50);
}
}
/**************************************************
Wartet, bis der Benutzer eine der Tasten gedrückt hat,
und gibt den Index dieser Taste zurück
*************************************************/
byte readButtons() {
while (true) {
for (byte i = 0; i < 4; i++) {
byte buttonPin = buttonPins[i];
if (digitalRead(buttonPin) == LOW) {
return i;
}
}
delay(1);
}
}
/**************************************************
"Game over sequence" abspielen und game score
auf dem Serial Monitor zeigen
*************************************************/
void gameOver() {
Serial.print("Game over! your score: ");
Serial.println(gameIndex - 1);
gameIndex = 0;
delay(200);
// Wah-Wah-Wah-Wah sound abspielen
tone(SPEAKER_PIN, NOTE_DS5);
delay(300);
tone(SPEAKER_PIN, NOTE_D5);
delay(300);
tone(SPEAKER_PIN, NOTE_CS5);
delay(300);
for (byte i = 0; i < 10; i++) {
for (int pitch = -10; pitch <= 10; pitch++) {
tone(SPEAKER_PIN, NOTE_C5 + pitch);
delay(5);
}
}
noTone(SPEAKER_PIN);
delay(500);
// Am Ende des Spiels wird das Menü aktiviert und auf dem seriellen Monitor angezeigt.
Serial.println("1 (rot) button - Start normal game.");
Serial.println("2 (gruen) button - Start game ohne Ton.");
Serial.println("3 (blau) button - Start game ohne LEDs.");
Serial.println();
Serial.println("Bitte wählen Sie den gewünschten Game-Modus :-)");
picked = 0;
}
/**************************************************
Abfrage der Benutzereingaben und Vergleich
mit der erwarteten Reihenfolge.
*************************************************/
bool checkUserSequence() {
for (int i = 0; i < gameIndex; i++) {
byte expectedButton = gameSequence[i];
byte actualButton = readButtons();
lightLedAndPlayTone(actualButton);
if (expectedButton != actualButton) {
return false;
}
}
return true;
}
/**************************************************
Spielt einen Hurra!-Sound, wenn der Benutzer
ein Level beendet
*************************************************/
void playLevelUpSound() {
tone(SPEAKER_PIN, NOTE_E4);
delay(150);
tone(SPEAKER_PIN, NOTE_G4);
delay(150);
tone(SPEAKER_PIN, NOTE_E5);
delay(150);
tone(SPEAKER_PIN, NOTE_C5);
delay(150);
tone(SPEAKER_PIN, NOTE_D5);
delay(150);
tone(SPEAKER_PIN, NOTE_G5);
delay(150);
noTone(SPEAKER_PIN);
}
/**************************************************
The main game loop (Attract Modus)
*************************************************/
void loop() {
if (!picked) { // Wenn man sich im Menü befindet
RandomLED = random(0, 4); // Wähle eine zufällige Zahl für den Betrieb mit LED
if (RandomLED == 0) led1 = !led1; // Zustand der ausgewählten LED ändern
if (RandomLED == 1) led2 = !led2;
if (RandomLED == 2) led3 = !led3;
if (RandomLED == 3) led4 = !led4;
delay(150);
RandomLED = random(0, 4); // Zufallszahl wird generiert, um den Ton abzuspielen
if (RandomLED == 0) { // Ton abspiele und shuffle die LEDs.
led1 = !led1;
tone(SPEAKER_PIN, NOTE_G3);
delay(100);
noTone(SPEAKER_PIN);
}
if (RandomLED == 1) {
led2 = !led2;
tone(SPEAKER_PIN, NOTE_C4);
delay(100);
noTone(SPEAKER_PIN);
}
if (RandomLED == 2) {
led3 = !led3;
tone(SPEAKER_PIN, NOTE_E4);
delay(100);
noTone(SPEAKER_PIN);
}
if (RandomLED == 3) {
led4 = !led4;
tone(SPEAKER_PIN, NOTE_G5);
delay(100);
noTone(SPEAKER_PIN);
}
digitalWrite(ledPins[0], led1); // Die aktuellen Zustände werden in die LEDs geschrieben
digitalWrite(ledPins[1], led2);
digitalWrite(ledPins[2], led3);
digitalWrite(ledPins[3], led4);
if (digitalRead(buttonPins[3]) == LOW) { // Wenn einer Taste gerückt wird
picked = HIGH; // Menu abschalten, Piezo und LED-Variablen ein- oder ausschalten und die LEDs ausschalten.
LEDs = true;
music = true;
digitalWrite(ledPins[0], LOW);
digitalWrite(ledPins[1], LOW);
digitalWrite(ledPins[2], LOW);
digitalWrite(ledPins[3], LOW);
delay(1000);
}
if (digitalRead(buttonPins[2]) == LOW) {
picked = HIGH;
LEDs = true;
music = false;
digitalWrite(ledPins[0], LOW);
digitalWrite(ledPins[1], LOW);
digitalWrite(ledPins[2], LOW);
digitalWrite(ledPins[3], LOW);
delay(1000);
}
if (digitalRead(buttonPins[1]) == LOW) {
picked = HIGH;
LEDs = false;
music = true;
digitalWrite(ledPins[0], LOW);
digitalWrite(ledPins[1], LOW);
digitalWrite(ledPins[2], LOW);
digitalWrite(ledPins[3], LOW);
delay(1000);
}
}
else { //Wenn man spielt (also wenn man sich nicht im Menu befindet)
// einer zufälligen Farbe am Ende der Sequenz hinzufügen
gameSequence[gameIndex] = random(0, 4);
gameIndex++;
if (gameIndex >= MAX_GAME_LENGTH) {
gameIndex = MAX_GAME_LENGTH - 1;
}
playSequence(); //wenn die beiden Sequenzen nicht stimment
if (!checkUserSequence()) {
gameOver(); //wird die Funktion gameOver aufgerufen
}
delay(300);
//gameIndex wird in Fall von Gameover auf 0 gesetzt.
//Also wird nach jedem korrekten Spielrunde di funktion fürs Spielen
//des Hurra!Sound aufgerufen
if (gameIndex > 0) {
playLevelUpSound();
delay(500);
}
}
}