#include "pitches.h"
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
#include <MD_MAX72xx.h>
const byte ledPins[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 1
#define SPEAKER_PIN 15
#define CLK_PIN 13
#define DATA_PIN 11
#define CS_PIN 10
#define MAX_GAME_LENGTH 100
MD_MAX72XX mx = MD_MAX72XX(MD_MAX72XX::PAROLA_HW, CS_PIN, MAX_DEVICES);
const int gameTones[] = { NOTE_A1, NOTE_A2, NOTE_A3, NOTE_A4, NOTE_B1, NOTE_B2, NOTE_B3, NOTE_B4, NOTE_C1, NOTE_C2, NOTE_C3, NOTE_C4,NOTE_D1, NOTE_D2, NOTE_D3, NOTE_D4};
int speed = 300;
int gameSequence[MAX_GAME_LENGTH] = {0};
byte gameIndex = 0;
int score = 0;
int maxscore = 0;
const uint8_t ROWS = 4;
const uint8_t COLS = 4;
uint8_t rowPins[ROWS] = { 5, 4, 3, 2 };
uint8_t colPins[COLS] = { 9, 8, 7, 6 };
char keys[ROWS][COLS] = {
{ 'A', 'B', 'C', 'D' },
{ 'E', 'F', 'G', 'H' },
{ 'I', 'J', 'K', 'L' },
{ 'M', 'O', 'P', 'Q' }
};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
LiquidCrystal_I2C lcd(0x27, 20, 4);
char key = NO_KEY;
void LightAll() {
mx.setPoint(0, 0, true);
mx.setPoint(0, 7, true);
mx.setPoint(7, 0, true);
mx.setPoint(7, 7, true);
mx.setPoint(1, 1, true);
mx.setPoint(1, 6, true);
mx.setPoint(6, 1, true);
mx.setPoint(6, 6, true);
mx.setPoint(2, 2, true);
mx.setPoint(2, 5, true);
mx.setPoint(5, 2, true);
mx.setPoint(5, 5, true);
mx.setPoint(3, 3, true);
mx.setPoint(3, 4, true);
mx.setPoint(4, 3, true);
mx.setPoint(4, 4, true);
mx.update();
}
void setup() {
mx.begin();
mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY / 2);
mx.clear();
lcd.init();
lcd.backlight();
lcd.setCursor(1, 0);
lcd.print("GOOD LUCK!");
lcd.setCursor(1, 1);
lcd.print("HAVE FUN!");
delay(1000);
lcd.clear();
Serial.begin(9600);
for (byte i = 0; i < 15; i++) {
pinMode(ledPins[i], OUTPUT);
}
pinMode(SPEAKER_PIN, OUTPUT);
randomSeed(analogRead(A7));
}
void lightLedAndPlayTone(byte ledIndex) {
if (ledIndex == 'A') {
mx.setPoint(1, 6, true);
mx.setPoint(1, 7, true);
mx.setPoint(0, 6, true);
mx.setPoint(0, 7, true);
mx.update();
}
if (ledIndex == 'B') {
mx.setPoint(3, 6, true);
mx.setPoint(2, 6, true);
mx.setPoint(3, 7, true);
mx.setPoint(2, 7, true);
mx.update();
}
if (ledIndex == 2) {
mx.setPoint(5, 6, true);
mx.setPoint(4, 6, true);
mx.setPoint(5, 7, true);
mx.setPoint(4, 7, true);
mx.update();
}
if (ledIndex - 65 == 3) {
mx.setPoint(7, 6, true);
mx.setPoint(6, 6, true);
mx.setPoint(7, 7, true);
mx.setPoint(6, 7, true);
mx.update();
}
if (ledIndex - 65 == 4) {
mx.setPoint(1, 4, true);
mx.setPoint(0, 4, true);
mx.setPoint(1, 5, true);
mx.setPoint(0, 5, true);
mx.update();
}
if (ledIndex - 65 == 5) {
mx.setPoint(3, 4, true);
mx.setPoint(2, 4, true);
mx.setPoint(3, 5, true);
mx.setPoint(2, 5, true);
mx.update();
}
if (ledIndex - 65 == 6) {
mx.setPoint(5, 4, true);
mx.setPoint(4, 4, true);
mx.setPoint(5, 5, true);
mx.setPoint(4, 5, true);
mx.update();
}
if (ledIndex - 65 == 7) {
mx.setPoint(7, 4, true);
mx.setPoint(6, 4, true);
mx.setPoint(7, 5, true);
mx.setPoint(6, 5, true);
mx.update();
}
if (ledIndex - 65 == 8) {
mx.setPoint(1, 2, true);
mx.setPoint(0, 2, true);
mx.setPoint(1, 3, true);
mx.setPoint(0, 3, true);
mx.update();
}
if (ledIndex - 65 == 9) {
mx.setPoint(3, 2, true);
mx.setPoint(2, 2, true);
mx.setPoint(3, 3, true);
mx.setPoint(2, 3, true);
mx.update();
}
if (ledIndex - 65 == 10) {
mx.setPoint(5, 2, true);
mx.setPoint(4, 2, true);
mx.setPoint(5, 3, true);
mx.setPoint(4, 3, true);
mx.update();
}
if (ledIndex - 65 == 11) {
mx.setPoint(7, 2, true);
mx.setPoint(6, 2, true);
mx.setPoint(7, 3, true);
mx.setPoint(6, 3, true);
mx.update();
}
if (ledIndex - 65 == 12) {
mx.setPoint(1, 0, true);
mx.setPoint(0, 0, true);
mx.setPoint(1, 1, true);
mx.setPoint(0, 1, true);
mx.update();
}
if (ledIndex - 65 == 14) {
mx.setPoint(3, 0, true);
mx.setPoint(2, 0, true);
mx.setPoint(3, 1, true);
mx.setPoint(2, 1, true);
mx.update();
}
if (ledIndex - 65 == 15) {
mx.setPoint(5, 0, true);
mx.setPoint(5, 1, true);
mx.setPoint(4, 0, true);
mx.setPoint(4, 1, true);
mx.update();
}
if (ledIndex - 65 == 16) {
mx.setPoint(7, 0, true);
mx.setPoint(6, 0, true);
mx.setPoint(7, 1, true);
mx.setPoint(6, 1, true);
mx.update();
}
digitalWrite(ledPins[ledIndex - 65], HIGH);
tone(SPEAKER_PIN, gameTones[ledIndex - 65]);
delay(speed);
mx.clear();
noTone(SPEAKER_PIN);
}
void playSequence() {
for (int i = 0; i < gameIndex; i++) {
byte currentLed = gameSequence[i];
lightLedAndPlayTone(currentLed);
delay(100);
}
}
byte readButtons() {
while(key == NO_KEY) {
key = keypad.getKey();
if (key != NO_KEY) {
return key;
}
delay(100);
}
delay(1000);
}
void gameOver() {
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("GAME OVER :(");
delay(1000);
lcd.setCursor(1, 0);
lcd.print("Your score : ");
lcd.setCursor(14, 0);
lcd.print(score);
lcd.setCursor(1, 1);
lcd.print("High score : ");
lcd.setCursor(14, 1);
lcd.print(maxscore);
speed = 300;
gameIndex = 0;
delay(1000);
lcd.clear();
score = 0;
noTone(SPEAKER_PIN);
delay(500);
}
bool checkUserSequence() {
for (int i = 0; i < gameIndex; i++) {
byte expectedButton = gameSequence[i];
byte actualButton = readButtons();
key = NO_KEY;
lightLedAndPlayTone(actualButton);
if (expectedButton != actualButton) {
return false;
}
}
return true;
}
void playLevelUpSound() {
LightAll();
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);
delay(1000);
mx.clear();
}
void loop() {
lcd.setCursor(1, 0);
lcd.print("Your score : ");
lcd.setCursor(14, 0);
lcd.print(score);
lcd.setCursor(1, 1);
lcd.print("High score : ");
lcd.setCursor(14, 1);
lcd.print(maxscore);
gameSequence[gameIndex] = random(65, 81);
gameIndex++;
if (gameIndex >= MAX_GAME_LENGTH) {
gameIndex = MAX_GAME_LENGTH - 1;
}
playSequence();
if (!checkUserSequence()) {
gameOver();
} else {
score = score + 1;
if (score == maxscore || score > maxscore)
maxscore = score;
if (speed >= 50)
speed = speed - 20;
}
delay(300);
if (gameIndex > 0) {
playLevelUpSound();
delay(300);
}
}