#define BUTTON_L 12
#define BUTTON_R 2
#define BUZZER 13
byte leds[] = {11, 10, 9, 8, 7, 6, 5, 4, 3}; // All LEDs in order from left to right
// for now, LEDs quantity should be ODD number
byte leds_qtty;
byte leds_mid;
void setup() {
Serial.begin(9600);
leds_qtty = sizeof(leds) / sizeof(leds[0]);
leds_mid = (byte)leds_qtty / 2;
Serial.println(leds_mid);
for (int i = 0; i < leds_qtty; i++) {
pinMode(leds[i], OUTPUT);
}
pinMode(BUTTON_L, INPUT_PULLUP);
pinMode(BUTTON_R, INPUT_PULLUP);
pinMode(BUZZER, OUTPUT);
Serial.println("^_^");
}
//-------------------------
// ↓↓↓ Global variables ↓↓↓
//-------------------------
unsigned long timer[3] = {0, 0, 0};
// timer[0] - arduino time, getting in every loop() iteration
// timer[1] - time when counter[0] increases - game mode
// timer[2] - time when counter[1] increases - idle
unsigned long counter[] = {0, 0, 0, 0};
// counter[0] - increases after game_counter_time time range
// counter[1] - controlling LEDs switching
// counter[2] - idle counter
// counter[3] - controlling idle LEDs switching
bool is_pressed[] = {0, 0}; // Buttons state
unsigned long release_time[] = {0, 0}; // When buttons were released
unsigned long toggle_time[] = {0, 0}; // When buttons were pressed
int pressed_time[] = {0, 0}; // How long are/were buttons pressed
bool game_state[] = {0, 0};
// game_state[0] - idle / game mode
// game_state[1] - difficulty settings
int game_counter_time = 60; // game "timer" time/step
int idle_time = 400; // idle "timer" time/step
byte game_points[] = {0, 0};
bool led_state = true; // LED state HIGH / LOW
byte pos = 0; // current led position
byte prev_pos = pos; // previous led position, to check correct button press
int dir = 1; // blinking direction
byte difficulty_lvl = 5; // difficulty level, 1-9 | how fast LEDs are switching
//=========================
// ↑↑↑ Global variables ↑↑↑
//=========================
//------------------------------
// ↓↓↓ LEDs control functions ↓↓↓
//------------------------------
void blinking_in_a_row(int counter0, int counter1) {
if (counter[counter1] < counter[counter0]) {
counter[counter1] = counter[counter0];
digitalWrite(leds[pos], led_state);
led_state = !led_state;
if (led_state) {
pos += dir;
prev_pos = pos - dir;
if (pos >= leds_qtty) {
dir = -1;
pos = leds_qtty - 2;
prev_pos = leds_qtty - 1;
} else if (pos <= 0) {
dir = 1;
pos = 0;
prev_pos = 1;
}
}
}
}
void all_leds_on() {
for (int i = 0; i < leds_qtty; i++) {
digitalWrite(leds[i], 1);
}
}
void all_leds_off() {
for (int i = 0; i < leds_qtty; i++) {
digitalWrite(leds[i], 0);
}
}
void blink_all_leds(int times, int pause, bool buzz) {
all_leds_off();
for (int i = 0; i < times; i++) {
if (buzz) {
tone(BUZZER, 2000);
}
all_leds_on();
delay(pause);
all_leds_off();
noTone(BUZZER);
delay(pause);
}
}
void blink_points(bool player, int points, int pause, byte type) { // type 0 is default, as required
all_leds_off();
switch (type) {
case 0:
if (!player) {
for (int i = 0; i < points; i++) {
digitalWrite(leds[0], 1);
delay(pause);
digitalWrite(leds[0], 0);
delay(pause);
}
} else {
for (int i = 0; i < points; i++) {
digitalWrite(leds[leds_qtty - 1], 1);
delay(pause);
digitalWrite(leds[leds_qtty - 1], 0);
delay(pause);
}
}
break;
case 1:
int p0 = 0;
int p0p = game_points[0];
int p1 = leds_qtty - 1;
int p1p = game_points[1];
for (int t = 0; t < 3; t++) {
for (int i = p0; i <= p0 + p0p - 1; i++) {
digitalWrite(leds[i], 1);
}
for (int i = p1; i >= p1 - p1p + 1; i--) {
digitalWrite(leds[i], 1);
}
delay(pause);
all_leds_off();
delay(pause);
}
break;
default:
break;
}
all_leds_off();
}
void winning_animation(byte player, int pause, byte type) {
all_leds_off();
for (int i = 0; i <= leds_mid; i++) {
digitalWrite(leds[leds_mid + i], 1);
digitalWrite(leds[leds_mid - i], 1);
delay(pause);
}
byte switch_case;
if (player == 0 && type == 1) {
switch_case = 1; // player1 win, first animation
} else if (player == 1 && type == 1) {
switch_case = 2; // player2 win, first animation
} else if (player == 0 && type == 2) {
switch_case = 3; // player1 win, second animation
} else if (player == 1 && type == 2) {
switch_case = 4; // player2 win, second animation
}
switch (switch_case) {
case 1: // p1 - a1
for (int i = leds_qtty - 1; i > 0; i--) {
digitalWrite(leds[i], 0);
delay(pause);
}
break;
case 2: // p2 - a1
for (int i = 0; i < leds_qtty - 1; i++) {
digitalWrite(leds[i], 0);
delay(pause);
}
break;
case 3: // p1 - a2
// for (int i = 0; i <= 8; i++) {
// digitalWrite(leds[i], 1);
// delay(pause);
// }
break;
case 4: // p2 - a2
// for (int i = 8; i >= 0; i--) {
// digitalWrite(leds[i], 1);
// delay(pause);
// }
break;
default:
break;
}
delay(500);
blink_all_leds(1, 200, false);
blink_all_leds(1, 2000, false);
reset_all();
}
//==============================
// ↑↑↑ LED control functions ↑↑↑
//==============================
//-----------------------------
// ↓↓↓ Game logic functions ↓↓↓
//-----------------------------
// TODO chimes on game finish
// TODO difficulty level is based on number of lights, fastest would be 5 milliseconds
// TODO after miss, LED position changes to middle, and direction sets randomly?
void difficulty() {
if (!is_pressed[1] && pressed_time[1] >= 10) {
difficulty_lvl++;
if (difficulty_lvl > 9) {
difficulty_lvl = 9;
}
pressed_time[1] = 0;
}
if (!is_pressed[0] && pressed_time[0] >= 10) {
difficulty_lvl--;
if (difficulty_lvl < 1) {
difficulty_lvl = 1;
}
pressed_time[0] = 0;
all_leds_off();
}
for (int i = 0; i < difficulty_lvl; i++) {
digitalWrite(leds[i], 1);
}
switch (difficulty_lvl) {
case 1:
game_counter_time = 200;
break;
case 2:
game_counter_time = 150;
break;
case 3:
game_counter_time = 100;
break;
case 4:
game_counter_time = 80;
break;
case 5:
game_counter_time = 60;
break;
case 6:
game_counter_time = 50;
break;
case 7:
game_counter_time = 40;
break;
case 8:
game_counter_time = 30;
break;
case 9:
game_counter_time = 10;
break;
default:
break;
}
}
void game_logic() {
if (game_state[0]) {
if (is_pressed[0] && pressed_time[0] < game_counter_time * 2) {
if (digitalRead(leds[leds_qtty - 1])) {
game_points[0] += 1;
delay(200);
Serial.print(game_points[0]); Serial.print("\t"); Serial.println(game_points[1]);
blink_points(0, game_points[0], 500, 1);
} else {
blink_all_leds(2, 200, true);
}
}
if (is_pressed[1] && pressed_time[1] < game_counter_time * 2) {
if (digitalRead(leds[0])) {
game_points[1] += 1;
delay(200);
Serial.print(game_points[0]); Serial.print("\t"); Serial.println(game_points[1]);
blink_points(1, game_points[1], 500, 1);
} else {
blink_all_leds(2, 200, true);
}
}
}
if (game_points[0] >= 5) {
winning_animation(0, 300, 1);
}
if (game_points[1] >= 5) {
winning_animation(1, 300, 1);
}
}
void reset_all() {
game_points[0] = 0;
game_points[1] = 0;
game_state[0] = false;
game_state[1] = false;
}
//=============================
// ↑↑↑ Game logic functions ↑↑↑
//=============================
// /-------------------------\
// | ↓↓↓ MAIN Arduino LOOP ↓↓↓ |
// \-------------------------/
void loop() {
timer[0] = millis();
// Reading button state and hold time
if (!digitalRead(BUTTON_L)) {
if (!is_pressed[0]) {
toggle_time[0] = timer[0];
}
is_pressed[0] = true;
release_time[0] = timer[0];
pressed_time[0] = release_time[0] - toggle_time[0];
} else {
is_pressed[0] = false;
}
if (!digitalRead(BUTTON_R)) {
if (!is_pressed[1]) {
toggle_time[1] = timer[0];
}
is_pressed[1] = true;
release_time[1] = timer[0];
pressed_time[1] = release_time[1] - toggle_time[1];
} else {
is_pressed[1] = false;
}
// Switching from idle to game mode, by holding both buttons for 3 sec.
if (pressed_time[0] >= 2000 &&
pressed_time[1] >= 2000 &&
is_pressed[0] &&
is_pressed[1] )
{
blink_all_leds(3, 400, false);
game_state[0] = !game_state[0];
if (!game_state[0]) {
reset_all();
}
}
// Switching to difficulty menu
if (pressed_time[0] >= 5000 && is_pressed[0]) {
blink_all_leds(2, 200, false);
pressed_time[0] = 0;
pressed_time[1] = 0;
game_state[1] = true;
}
// Saving difficulty menu settings
if (pressed_time[1] >= 5000 && is_pressed[1] && game_state[1]) {
blink_all_leds(2, 200, false);
blink_all_leds(1, 300, true);
reset_all();
}
// Game and Idle counters increase
if (timer[0] - timer[1] >= game_counter_time) {
counter[0] += 1;
timer[1] = timer[0];
}
if (timer[0] - timer[2] >= idle_time) {
counter[2] += 1;
timer[2] = timer[0];
}
// Blinking speed depending on game mode
if (!game_state[0] && !game_state[1]) // idle and not in difficulty menu
{
blinking_in_a_row(2, 3);
}
else if (game_state[0] && !game_state[1]) // game mode (not in difficulty menu)
{
blinking_in_a_row(0, 1);
}
else // difficulty menu
{
difficulty();
}
// In-game logic
game_logic();
}