#include <EEPROM.h>
//#include "arduino.h"
#include "PinChangeInterrupt.h"
enum GameMode {
MENU,
GAME,
STARTED,
GAMEOVER
};
#define BTN_0 2
#define BTN_1 3
#define BTN_2 4
#define BTN_3 5
#define RST_BTN 6
#define DATA 7 //pinnit D7-D12
#define LATCH 8
#define CLOCK 9
#define BUZZER 13
#define DEBOUNCE 150
#define INTERVAL_DEF 1000 // (oikeasti 1 sec)
#define SPEED 2
int messageCounter=0;
int score = 0;
int highscore = 0;
int state = MENU;
byte ledNumber = 0;
int ledCount=0;
int ledArray[100];
int buttonArray[100];
int btn_x = 0;
int led_x = 0;
//int turn = 0; // pelikierros
int correct_press = 0;
//byte pressed = 1;
int data [] = {1, 79, 18, 6, 76, 36, 32, 15, 0, 4,}; // taulukkoon 0-9 arvot XOR käännettynä binääristä desimaaliin muutettuna.
int data2 [] = {1, 79, 18, 6, 76, 36, 32, 15, 0, 4,}; //samat arvot highscore näytölle
int nuottimaara = 14; //melodian nuottimäärä
int NUOTIT[] = {330, 392, 370, 294, 330, 247, 330, 392, 370, 247, 330, 392, 494, 659}; //nuottien taajuus
int nuottimaara2 = 64; //melodian nuottimäärä
int NUOTIT2[] = {
370, 277, 370, 370,
415, 440, 370, 370,
440, 415, 330, 330,
415, 440, 370, 370,
370, 277, 370, 370,
415, 440, 370, 370,
440, 554, 554, 494,
440, 415, 440, 370,
370, 554, 554, 494,
440, 415, 330, 330,
330, 415, 494, 494,
440, 415, 440, 370,
370, 554, 554, 494,
440, 415, 330, 330,
330, 415, 494, 494,
440, 415, 440, 370
}; //nuottien taajuus
int pelinuotit=0;
int NUOTITPELIALKU[] = {370, 277, 370, 277}; //nuottien taajuus
// time vars:
int interval; // alkuarvo (1 sec = 1 Hz)
unsigned long mainTime = 0;
unsigned long menuTimer = 0;
unsigned long previousMillis = 0;
unsigned long current_Time = 0;
unsigned long elapsed_Time = mainTime - current_Time;
// -----------
void initializeLeds();
void initializeGame();
void readHighscore();
void writeHighscore();
void resetHighScore();
void startTheGame();
void gameOver();
void gameMenu();
void PlaySound(void); //funktion proto
void PlaySound2(void); //funktion proto
void displayNumber(int n); //funktion proto
void initializeDisplay(void); //funktion proto
void initButtonsAndButtonInterrupts(void);
extern void initializeDisplay(void);
void setLed(byte ledNumber);
void clearLed(byte ledNumber);
void clearAllLeds(void);
void setAllLeds(void);
void game_Started_LED(void);
void game_Ended_LED(void);
void newHighScore_LED(void);
void menuLEDS(void);
void i_RST_BTN(void);
void i_BTN_0(void);
void i_BTN_1(void);
void i_BTN_2(void);
void i_BTN_3(void);
void setup() {
Serial.begin(9600);
initButtonsAndButtonInterrupts();
initializeDisplay();
readHighscore();
}
void loop() {
if(state == MENU)
gameMenu();
else if(state == GAME){
initializeGame();
state = STARTED;
game_Started_LED();
}
else if(state == STARTED)
runGame();
else {
gameOver();
game_Ended_LED();
state = MENU;
}
}
// *** FUNKTIOT ***
void initializeGame(){
score = 0;
pelinuotit = 0;
displayNumber(score);
correct_press = 0;
randomSeed(millis());
for(int x = 0; x <= 99 ; x++){
ledNumber = random(16,20); // taulukko luodaan
ledArray[x] = ledNumber;
}
interval = INTERVAL_DEF;
led_x = 0;
btn_x = 0;
}
void runGame()
{
mainTime = millis();
if (mainTime - previousMillis >= interval)
{
previousMillis = mainTime;
//for(int x = turn; x <= turn; x++){
setLed(ledArray[led_x]); // intervalin välein sytytetään LED
tone(BUZZER, NUOTIT2[pelinuotit]);
Serial.print(led_x); Serial.print(". debug LED: "); Serial.println(ledArray[led_x]);
//if (ledArray[x] != buttonArray[btn_x]) state = GAMEOVER;
led_x++;
pelinuotit++;
if(pelinuotit>=nuottimaara2){pelinuotit=0;}
if (ledCount >= SPEED && ledCount % SPEED == 0 && interval >= 300) // SPEED = 10
{
interval *= 0.95; // oikeasti 0.9
}
if (led_x==99)
{
led_x=0;
}
if(score==999)
{
gameOver();
}
}
}
void gameMenu()
{
clearAllLeds();
menuLEDS();
mainTime = millis();
if (mainTime - previousMillis >= 3000)
{
previousMillis = mainTime;
if (messageCounter % 2 == 0) {
Serial.println("Displaying highscore");
displayNumber(highscore);
} else {
Serial.println("Displaying last score");
displayNumber(score);
}
messageCounter++;
}
}
void gameOver()
{
if(score > highscore) { // tarkistetaan, onko uusi suurin pistemäärä saatu, ja kirjoitetaan se muistiin
highscore = score;
writeHighscore();
PlaySound2();
newHighScore_LED();
}
else PlaySound();
state = MENU;
ledNumber = 0; // estetään pisteiden kasvu pelin ulkopuolella
/* debug:
Serial.println("GAME OVER");
Serial.print("Score: "); Serial.println(score);
delay(1000);
*/
}
void readHighscore() {
highscore = (EEPROM.read(0) << 8) + EEPROM.read(1);
if(highscore == 0xffff)
highscore = 0;
}
void writeHighscore() {
EEPROM.write(0, highscore >> 8);
EEPROM.write(1, highscore & 0xff);
}
void resetHighScore(){
highscore = 0;
writeHighscore();
}
void initButtonsAndButtonInterrupts(void)
{
pinMode(RST_BTN, INPUT_PULLUP);
pinMode(BTN_0, INPUT_PULLUP);
pinMode(BTN_1, INPUT_PULLUP);
pinMode(BTN_2, INPUT_PULLUP);
pinMode(BTN_3, INPUT_PULLUP);
//attachInterrupt(digitalPinToInterrupt(6), i_RST_BTN, FALLING);
attachPCINT(digitalPinToPCINT(RST_BTN), i_RST_BTN, FALLING); // use PCINT because it supports more pins
attachPCINT(digitalPinToPCINT(BTN_0), i_BTN_0, FALLING);
attachPCINT(digitalPinToPCINT(BTN_1), i_BTN_1, FALLING);
attachPCINT(digitalPinToPCINT(BTN_2), i_BTN_2, FALLING);
attachPCINT(digitalPinToPCINT(BTN_3), i_BTN_3, FALLING);
}
void i_RST_BTN(void)
{
static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > DEBOUNCE) // If interrupts come faster than DEBOUNCE, assume it's a bounce and ignore
{
Serial.println("\n*** RESETTED ***\n"); // keskeytyksessä tehtävät asiat
state = GAME;
current_Time = millis();
}
last_interrupt_time = interrupt_time;
}
void i_BTN_0(void) // press in MENU will reset highscore
{
static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > DEBOUNCE) // If interrupts come faster than DEBOUNCE, assume it's a bounce and ignore
{
if(state == MENU) resetHighScore();
else {
Serial.println("BTN_0");
if(ledArray[btn_x] == 16) {
btn_x++;
score++;
displayNumber(score);
correct_press++;
noTone(BUZZER);
clearLed(16);
pelinuotit++;
if(btn_x == 99){
btn_x=0;
}
}
else state = GAMEOVER;
}
}
last_interrupt_time = interrupt_time;
}
void i_BTN_1(void)
{
static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > DEBOUNCE)
{
if(state == STARTED) {
Serial.println("BTN_1");
if(ledArray[btn_x] == 17) {
btn_x++;
score++;
displayNumber(score);
correct_press++;
//pressed = 1;
noTone(BUZZER);
clearLed(17);
if(btn_x == 99){
btn_x=0;
}
}
else state = GAMEOVER;
}
}
last_interrupt_time = interrupt_time;
}
void i_BTN_2(void)
{
static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > DEBOUNCE)
{
if(state == STARTED) {
Serial.println("BTN_2");
if(ledArray[btn_x] == 18) {
btn_x++;
score++;
displayNumber(score);
correct_press++;
//pressed = 1;
noTone(BUZZER);
clearLed(18);
if(btn_x == 99){
btn_x=0;
}
}
else state = GAMEOVER;
}
}
last_interrupt_time = interrupt_time;
}
void i_BTN_3(void)
{
static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > DEBOUNCE)
{
if(state == STARTED) {
Serial.println("BTN_3");
if(ledArray[btn_x] == 19) {
btn_x++;
score++;
displayNumber(score);
correct_press++;
//pressed = 1;
noTone(BUZZER);
clearLed(19);
if(btn_x == 99){
btn_x=0;
}
}
else state = GAMEOVER;
}
}
last_interrupt_time = interrupt_time;
}
void PlaySound(void)
{
for (int i = 0; i < nuottimaara; i++) //soittaa arrayhyn tallenetut taajuudet läpi, soittaa jokaista taajuutta 200ms, lopettaa kun array päättyy
{
tone(BUZZER, NUOTIT[i]);
delay(200);
}
noTone(BUZZER);
}
void PlaySound2()
{
for (int i = 0; i < nuottimaara2; i++) //soittaa arrayhyn tallenetut taajuudet läpi, soittaa jokaista taajuutta 200ms, lopettaa kun array päättyy
{
tone(BUZZER, NUOTIT2[i]);
delay(200);
}
noTone(BUZZER);
}
void initializeDisplay(void)
{
int score; //score globaali muuttuja
int highscore; //highscore globaali muuttuja
pinMode(LATCH, OUTPUT); //3x D-pinniä per 2x näyttöä, serial in data, kello, ja latch asetetaan outputeiksi
pinMode(CLOCK, OUTPUT);
pinMode(DATA, OUTPUT);
displayNumber(highscore);
}
void displayNumber(int n) { //score näytön funktio, näyttää numeroita int muodossa funktiota kutsuttaessa
int ones = n % 10;//yköset modulo
n = n /10;// jaetaan se kymmenellä
int tens = n % 10;//kympit tästä vielä modulo
n = n /10;// jaetaan se kymmenellä
int hund = n % 10;//satkut tästä vielä modulo
digitalWrite(LATCH, LOW); //latch low kun kirjoitetaan
shiftOut(DATA, CLOCK, LSBFIRST, data [ones]); //kirjoitetaan data kahdelle näytölle, tallenetaan käytännössä kolmeen arrayhyn
shiftOut(DATA, CLOCK, LSBFIRST, data [tens]);
shiftOut(DATA, CLOCK, LSBFIRST, data [hund]);
digitalWrite(LATCH, HIGH); //latch high, kun lopetetaan kirjoitus
}
void initializeLeds()
{
// intializes ANALOG pins A2,A3,A4,A5 to be used as outputs. LEDs are connected to those pins.
pinMode(A2, OUTPUT);
pinMode(A3, OUTPUT);
pinMode(A4, OUTPUT);
pinMode(A5, OUTPUT);
}
void setLed(byte ledNumber)
{
clearAllLeds();
noTone(BUZZER);
ledCount++;
delay(100);
analogWrite(ledNumber, 128);
/*
setLed(byte) sets correct led given as A2, A3, A4 or A5
Arduino pin A2 = 16
Arduino pin A3 = 17
Arduino pin A4 = 18
Arduino pin A5 = 19
*/
}
void clearAllLeds(void)
{
// clearAllLeds(void) subroutine clears all leds
analogWrite(A2, 0);
analogWrite(A3, 0);
analogWrite(A4, 0);
analogWrite(A5, 0);
}
void clearLed(byte ledNumber){
analogWrite(ledNumber, 0);
}
void setAllLeds(void)
{
// setAllLeds subroutine sets all leds ON
analogWrite(A2, 128);
analogWrite(A3, 128);
analogWrite(A4, 128);
analogWrite(A5, 128);
}
void game_Started_LED(void)
{
clearAllLeds();
delay(500);
setAllLeds();
tone(BUZZER, NUOTIT2[0]);
delay(200);
noTone(BUZZER);
clearAllLeds();
tone(BUZZER, NUOTIT2[1]);
delay(200);
noTone(BUZZER);
setAllLeds();
tone(BUZZER, NUOTIT2[2]);
delay(200);
noTone(BUZZER);
clearAllLeds();
tone(BUZZER, NUOTIT2[3]);
delay(200);
noTone(BUZZER);
delay(200);
}
void game_Ended_LED(void)
{
clearAllLeds();
delay(300);
setAllLeds();
delay(300);
clearAllLeds();
delay(300);
setAllLeds();
delay(700);
}
void newHighScore_LED(void)
{
setLed(19);
delay(150);
setLed(18);
delay(100);
setLed(17);
delay(100);
setLed(16);
delay(300);
setLed(16);
delay(100);
setLed(17);
delay(100);
setLed(18);
delay(100);
setLed(19);
delay(300);
/*
clearAllLeds();
delay(300);
setAllLeds();
delay(300);
clearAllLeds();
delay(300);
setAllLeds();
delay(700);
*/
}
void menuLEDS(void)
{
analogWrite(17, 128);
analogWrite(18, 128);
delay(150);
analogWrite(17, 0);
analogWrite(18, 0);
analogWrite(16, 128);
analogWrite(19, 128);
delay(130);
analogWrite(17, 0);
analogWrite(18, 0);
delay(250);
clearAllLeds();
delay(600);
}