Загрузка данных



#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Adafruit_NeoPixel.h>

// LCD
LiquidCrystal_I2C lcd(0x27, 16, 2);

// RGB-кольцо
#define LED_PIN 6
#define LED_COUNT 16

Adafruit_NeoPixel ring(
  LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800
);

// Пины
#define JOY_X A0
#define JOY_SW 2
#define BUZZER 3

#define RED_PIN 9
#define GREEN_PIN 10
#define BLUE_PIN 11

// Настройки
const unsigned long GAME_TIME = 50000;
const unsigned long HOLD_TIME = 3000;

const int TOTAL_ROUNDS = 5;

int selected = 0;
int target = 0;
int roundNumber = 0;

unsigned long gameStart = 0;
unsigned long holdStart = 0;
unsigned long lastMove = 0;
unsigned long lastMusic = 0;
unsigned long stateStart = 0;
unsigned long lastLCD = 0;

bool holding = false;
int musicNote = 0;

int melody[] = {
  523, 587, 659, 784,
  659, 587, 523, 440
};

enum GameState {
  WAITING,
  COUNTDOWN,
  PLAYING,
  FEEDBACK,
  WIN,
  LOSE
};

GameState state = WAITING;

// Преобразование оттенка в RGB
uint32_t hueColor(int hue) {
  int h = hue * 6;
  int sector = h / 256;
  int f = h % 256;

  int q = 255 - f;

  int r = 0, g = 0, b = 0;

  switch (sector) {
    case 0: r = 255; g = f; break;
    case 1: r = q; g = 255; break;
    case 2: g = 255; b = f; break;
    case 3: g = q; b = 255; break;
    case 4: r = f; b = 255; break;
    default: r = 255; b = q; break;
  }

  return ring.Color(r, g, b);
}

// RGB светодиод показывает целевой цвет
void showTarget() {
  uint32_t c = hueColor(target * 16);

  uint8_t r = (c >> 16) & 255;
  uint8_t g = (c >> 8) & 255;
  uint8_t b = c & 255;

  analogWrite(RED_PIN, r);
  analogWrite(GREEN_PIN, g);
  analogWrite(BLUE_PIN, b);
}

// Отображение кольца
void showRing() {
  for (int i = 0; i < LED_COUNT; i++) {
    if (i == selected) {
      ring.setPixelColor(i, ring.Color(255, 255, 255));
    } else {
      ring.setPixelColor(i, hueColor(i * 16));
    }
  }

  ring.show();
}

// Выключение RGB
void clearLights() {
  ring.clear();
  ring.show();

  analogWrite(RED_PIN, 0);
  analogWrite(GREEN_PIN, 0);
  analogWrite(BLUE_PIN, 0);
}

// Музыка
void music() {
  if (millis() - lastMusic >= 250) {
    lastMusic = millis();

    tone(BUZZER, melody[musicNote], 180);

    musicNote++;
    if (musicNote >= 8) {
      musicNote = 0;
    }
  }
}

// Начальный экран
void waitingScreen() {
  noTone(BUZZER);
  clearLights();

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("COLOR CHALLENGE");

  lcd.setCursor(0, 1);
  lcd.print("PRESS TO START");

  state = WAITING;
}

// Начало игры
void startGame() {
  roundNumber = 0;
  selected = 0;
  musicNote = 0;

  lcd.clear();
  lcd.print("GET READY!");

  state = COUNTDOWN;
  stateStart = millis();
}

// Новый раунд
void newRound() {
  // Цель совпадает с одним из 16 цветов кольца
  target = random(0, 16);

  selected = 0;

  showTarget();
  showRing();

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("ROUND ");
  lcd.print(roundNumber + 1);
  lcd.print("/5");

  lcd.setCursor(0, 1);
  lcd.print("FIND COLOR!");

  state = PLAYING;
}

// Победа
void winGame() {
  state = WIN;

  noTone(BUZZER);
  clearLights();

  lcd.clear();
  lcd.print("YOU WIN!");
  lcd.setCursor(0, 1);
  lcd.print("5/5 COMPLETED");

  tone(BUZZER, 1200, 300);
}

// Поражение
void loseGame() {
  state = LOSE;

  clearLights();

  lcd.clear();
  lcd.print("TIME IS OVER!");
  lcd.setCursor(0, 1);
  lcd.print("GAME OVER");

  tone(BUZZER, 1000);
  stateStart = millis();
}

void setup() {
  pinMode(JOY_SW, INPUT_PULLUP);
  pinMode(BUZZER, OUTPUT);

  pinMode(RED_PIN, OUTPUT);
  pinMode(GREEN_PIN, OUTPUT);
  pinMode(BLUE_PIN, OUTPUT);

  lcd.init();
  lcd.backlight();

  ring.begin();
  ring.setBrightness(60);
  ring.show();

  randomSeed(analogRead(A2));

  waitingScreen();
}

void loop() {
  unsigned long now = millis();

  // ОЖИДАНИЕ
  if (state == WAITING) {

    if (digitalRead(JOY_SW) == LOW) {
      delay(30);

      if (digitalRead(JOY_SW) == LOW) {
        startGame();

        while (digitalRead(JOY_SW) == LOW) {}
      }
    }
  }

  // ОБРАТНЫЙ ОТСЧЁТ
  else if (state == COUNTDOWN) {

    int count = 3 - (now - stateStart) / 1000;

    if (count >= 1) {
      lcd.setCursor(0, 0);
      lcd.print("STARTING...");

      lcd.setCursor(0, 1);
      lcd.print("       ");
      lcd.setCursor(7, 1);
      lcd.print(count);

      static int lastCount = 0;

      if (count != lastCount) {
        tone(BUZZER, 1000, 180);
        lastCount = count;
      }
    }

    if (now - stateStart >= 3000) {
      noTone(BUZZER);

      gameStart = millis();
      lastMusic = millis();

      // Сбрасываем отсчёт для следующего запуска
      stateStart = 0;

      newRound();
    }
  }

  // ИГРА
  else if (state == PLAYING) {

    // Проверка времени
    if (now - gameStart >= GAME_TIME) {
      loseGame();
      return;
    }

    music();

    // Движение джойстика
    int x = analogRead(JOY_X);

    if (now - lastMove >= 180) {

      if (x < 400) {
        selected--;

        if (selected < 0) {
          selected = 15;
        }

        lastMove = now;
        showRing();
      }

      else if (x > 620) {
        selected++;

        if (selected > 15) {
          selected = 0;
        }

        lastMove = now;
        showRing();
      }
    }

    // LCD таймер
    if (now - lastLCD >= 200) {
      lastLCD = now;

      int seconds = (GAME_TIME - (now - gameStart)) / 1000;

      lcd.setCursor(0, 0);
      lcd.print("TIME: ");
      lcd.print(seconds);
      lcd.print("s R:");
      lcd.print(roundNumber + 1);
      lcd.print("   ");

      lcd.setCursor(0, 1);

      if (holding) {
        int left = 3 - (now - holdStart) / 1000;

        lcd.print("HOLD: ");
        lcd.print(left);
        lcd.print(" SEC       ");
      } else {
        lcd.print("HOLD SEL 3 SEC ");
      }
    }

    // Кнопка SEL
    if (digitalRead(JOY_SW) == LOW) {

      if (!holding) {
        holding = true;
        holdStart = now;
      }

      if (now - holdStart >= HOLD_TIME) {

        holding = false;

        noTone(BUZZER);

        if (selected == target) {

          roundNumber++;

          lcd.clear();
          lcd.print("CORRECT!");
          lcd.setCursor(0, 1);
          lcd.print("SCORE: ");
          lcd.print(roundNumber);
          lcd.print("/5");

          tone(BUZZER, 1400, 200);

          if (roundNumber >= TOTAL_ROUNDS) {
            winGame();
          } else {
            state = FEEDBACK;
            stateStart = now;
          }

        } else {

          lcd.clear();
          lcd.print("WRONG COLOR!");
          lcd.setCursor(0, 1);
          lcd.print("TRY AGAIN");

          tone(BUZZER, 250, 200);

          state = FEEDBACK;
          stateStart = now;
        }
      }

    } else {
      holding = false;
    }
  }

  // ПЕРЕХОД К СЛЕДУЮЩЕМУ РАУНДУ
  else if (state == FEEDBACK) {

    if (now - gameStart >= GAME_TIME) {
      loseGame();
    }

    else if (now - stateStart >= 700) {
      noTone(BUZZER);
      newRound();
      lastMusic = now;
    }
  }

  // ПОБЕДА
  else if (state == WIN) {

    if (digitalRead(JOY_SW) == LOW) {
      while (digitalRead(JOY_SW) == LOW) {}
      waitingScreen();
    }
  }

  // ПОРАЖЕНИЕ
  else if (state == LOSE) {

    if (now - stateStart >= 3000) {
      noTone(BUZZER);

      lcd.clear();
      lcd.print("GAME OVER");
      lcd.setCursor(0, 1);
      lcd.print("PRESS TO RETRY");

      state = WAITING;
    }
  }
}