#define LED_PIN 7
#define LED_NUM 50
#define ROW_NUM 10
#define M_PI 3.141592654
#include "FastLED.h"
//#include <iostream>
CRGB leds[LED_NUM];
float counter=1;
bool flag = 0;
uint8_t x0 = 0;
uint8_t y0 = 0;
uint8_t xpurp = 0;
uint8_t ypurp = 0;
uint8_t x1 = 0;
uint8_t y1 = 0;
bool flagnosnake = 0;
bool rib [4];
uint8_t numbcrash = 0;
uint8_t direct[4];
int indexx [4];
int indexy [4];
struct mystack {//структура с массивом ходов индексом головы и хвоста змеи
uint8_t a[50];
uint8_t b[50];
int head = 0; //Индекс первого элемента.
int tail = 0; //Индекс элемента, следующего за последним.
int indexdir = 0;//количество шагов от яблочка до яблочка
bool flagcrash = 0; //флаг неудачи(змейка попала в тупик)
void push(uint8_t x,uint8_t y) { //добавляет в массивы шаги и передвигает индексы головыtail и хвостаhead
if (nosnake(x,y)){
tail++;
if (tail==50){tail=0;}
a[tail] = x;
b[tail] = y;
head++;
if (head==50){head=0;}
}
}
bool nosnake(uint8_t x0, uint8_t y0){// проверяет заняты ли ячейки
if (x0>4||x0<0||y0<0||y0>9){return 0;}
if (head<tail||head==tail){
for (int i = head ; i < tail+1 ;i++) {
if (a[i]==x0 && b[i]==y0){return 0;}
}
}else{
for (int i = head ; i < 50 ;i++) {
if (a[i]==x0 && b[i]==y0){return 0;}
}
for (int i = 0 ; i < tail+1 ;i++) {
if (a[i]==x0 && b[i]==y0){return 0;}
}
}
return 1;
}
void shiftrib(uint8_t (&direct55)[4]){ //проверка всех направлений на препядствии и выбор первого из приоритетного списка
indexx [0] = 1;indexx [1] = 0;indexx [2] = -1;indexx [3] = 0;
indexy [0] = 0;indexy [1] = 1;indexy [2] = 0;indexy [3] = -1;
rib [0] = nosnake(a[tail]+1, b[tail]); rib [1] = nosnake(a[tail], b[tail]+1);
rib [3] = nosnake(a[tail], b[tail]-1); rib [2] = nosnake(a[tail]-1, b[tail]);
bool flag = 0;
//Serial.print("<");
//Serial.print(direct55[0]); Serial.print(direct55[1]); Serial.print(direct55[2]); Serial.print(direct55[3]);
//Serial.print(">");
//Serial.print("-");Serial.print(a[tail]); Serial.print(b[tail]);Serial.print("-");
for (uint8_t i: direct55){
// перечисляет матрицу приоритетов проверяет направления, выбирает первое из возможных и выходит
if (rib [i]){push(a[tail]+indexx[i], b[tail]+indexy[i]);flag = 1; break;}
}
//Serial.print("-");Serial.print(a[tail]); Serial.print(b[tail]);Serial.print("-");
// счет шагов
if (!flag){flagcrash = 1;}else{indexdir=indexdir+1;}// если нет возможных направлений выдает сигнал о неудачи
}
};
mystack pri;//экземпляр структуры
uint16_t XY( uint8_t x, uint8_t y)//функция перевода матрицы в линейный индекс светодиодов в ленте
{
uint16_t i;
if(x%2==1) {
// Odd rows run backwards
uint8_t reverseY = (ROW_NUM-1) - y;
i = (x * ROW_NUM) + reverseY;
} else {
// Even rows run forwards
i = (x * ROW_NUM) + y;
}
return i;
}
void setup() {
Serial.begin(9600);
FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, LED_NUM); //Установки ленты
FastLED.setBrightness(255);//яркость
}
void loop() {
FastLED.clear(); //очистка экрана
do { //генерация яблочек
xpurp = random8(5);
ypurp = random8(10);
flagnosnake = pri.nosnake(xpurp,ypurp); // проверка появляется ли яблочко в змейке
} while (!flagnosnake);
leds[XY(xpurp,ypurp)] = CRGB::White; // высвечивает яблочко
snake(); //рисуем змейку из массива
FastLED.show(); //загружает в массив данные о номере и цвете светодиода
// FastLED.delay(1000/pow(10,counter)); //задержка
x0 = xpurp; //переназначения координат яблочка
y0 = ypurp;
//цикл генерации пути змейки пока голова змейки не совпадет с яблочком
//в массивах а и b структуры pri. сохраняются координаты
// tail -индекс голова змейки, head - хвостик
//
while (pri.a[pri.tail]!=x0 || pri.b[pri.tail]!=y0) {
x1 = pri.a[pri.tail];//голова змеи
y1 = pri.b[pri.tail];
// передвижение змейки к яблочку создаем матрицу приоритетных направлений в зависимисти от расположения головы относительно яблочка
if (x0 != x1 ){//direct[0] вправо,direct[1] вниз,direct[2] влево,direct[3] вверх,
//преоритет движения по горизонтале в зависимости от положения относительно яблочка
if (x0 < x1){direct[0]=2;direct[3]=0;}else{direct[0]=0;direct[3]=2;}
//преоритет движения по вертикале в зависимости от положения относительно яблочка
if (y0 < y1 || y0==y1){direct[1]=3;direct[2]=1;} else if(y0 > y1){direct[1]=1;direct[2]=3;}
}else if(y0 != y1){
//преоритет движения по вертикале в зависимости от положения относительно яблочка
if (y0 < y1){direct[0]=3;direct[3]=1;}else{direct[0]=1;direct[3]=3;}
//преоритет движения по горизонтале в зависимости от положения относительно яблочка
if (x0 < x1||x0==x1){direct[1]=2;direct[2]=0;} else if(x0 > x1){direct[1]=0;direct[2]=2;}
}
pri.shiftrib(direct);//передаем матрицу приоритетов генерируем следующий ход змеи
if (pri.flagcrash){// ветвление в случае неудачного хода(если все 4 направления запрещены, стенка и тело змеи)
//генерирует случайным образом яблочко которое не видно, проверяет удачный или неудачный исход
//если удачный, возвращает обратно настоящее яблочко как цель и далее проверяет исход
//если неудачный, генерирует новое псевдо яблочко
//если удачный исход у настоящего яблока выходит и запоминает ходы в массивах
// если неудач более 49 змейка обнуляется
numbcrash = numbcrash + 1;
if ( numbcrash >49){break; }// выход если неудачных попыток более 49
//откат матрицы ходов в лучае неудачи на количество ходов счетчика pri.indexdir
if (pri.indexdir>pri.tail){pri.tail=50+pri.tail-pri.indexdir;}else{pri.tail = pri.tail-pri.indexdir;}//в случае неудачи откатываем все действия
if (pri.indexdir>pri.head){pri.head=50+pri.head-pri.indexdir;}else{pri.head = pri.head-pri.indexdir;}
pri.indexdir = 0;// обнуление счетчика ходов
do { //генерация яблочек
x0 = random8(5);
y0 = random8(10);
flagnosnake = pri.nosnake(x0,y0); // проверка появляется ли яблочко в змейке
if (x0==xpurp && y0==ypurp){flagnosnake=0;}// совпадает с настоящим яблочком
} while (!flagnosnake);
pri.flagcrash=0;
//генерируем промежуточное яблочко
}
if (pri.a[pri.tail]==x0 && pri.b[pri.tail]==y0){// змейка съела яблочко, удачный исход для псевдо яблок и настоящих
if (x0!=xpurp && y0!=ypurp) {
x0=xpurp;y0=ypurp;
}// если она съела промежуточное яблочко, то назначить настоящее яблочко
}
}
//Serial.print(pri.indexdir);Serial.print("*");Serial.print(pri.tail);Serial.print("*");Serial.print(pri.head);
//откат индекса матрицы на pri.indexdir для генерации движения змейки
if (pri.indexdir>pri.tail){pri.tail=50+pri.tail-pri.indexdir;}else{pri.tail = pri.tail-pri.indexdir;}
if (pri.indexdir>pri.head){pri.head=50+pri.head-pri.indexdir;}else{pri.head = pri.head-pri.indexdir;}
//Serial.print("go");
for(int i = 0; i<pri.indexdir;i++){//генерация змейки от яблочка до яблочка
FastLED.clear();
leds[XY(xpurp,ypurp)] = CRGB::White;
snake();
pri.tail++;
if (pri.tail==50){pri.tail=0;}
pri.head++;
if (pri.head==50){pri.head=0;}
FastLED.show();
FastLED.delay(1000/counter);
counter = counter + 1/2;
}
//обнуление кол-неудач в случае выхода
numbcrash = 0;
pri.indexdir = 0;//обнуление количества шагов
if (pri.flagcrash){pri.head=1;pri.tail=1;pri.flagcrash=0;}else{pri.head--;}//сброс змейки в случае неудачи или удлиннение змейки с хвоста
if ((pri.tail-pri.head)>20 && pri.tail>pri.head){pri.head=0;pri.tail=0;}
if ((pri.tail-pri.head)>-30 && pri.tail<pri.head){pri.head=0;pri.tail=0;}// перед ловлей яблочка удлиняем змейку
}
void snake(){//заполнение массива светодиодов по данным из массивов a и b
uint8_t index = 0;
if (pri.head<pri.tail||pri.head==pri.tail){
for (int i = pri.head ; i < pri.tail+1 ;i++) {
index = index + 12;
// Serial.print("+");Serial.print(pri.a[i]); Serial.print(pri.b[i]);Serial.print("+");
leds[XY(pri.a[i],pri.b[i])] = ColorFromPalette(RainbowColors_p, index, 254, NOBLEND);
}
}else{
for (int i = pri.head ; i < 50 ;i++) {
index = index + 12;
leds[XY(pri.a[i],pri.b[i])] = ColorFromPalette(RainbowColors_p, index, 254, NOBLEND);
}
for (int i = 0 ; i < pri.tail+1 ;i++) {
index = index + 12;
leds[XY(pri.a[i],pri.b[i])] = ColorFromPalette(RainbowColors_p, index, 254, NOBLEND);
}
}
}