Compare commits
No commits in common. "a3caaa1fefd25cee692f80ad8eb70ae782038e13" and "8568436fc16ba299768014413ec4631e5f8fc19b" have entirely different histories.
a3caaa1fef
...
8568436fc1
@ -3,42 +3,23 @@
|
|||||||
#include "Effect.h"
|
#include "Effect.h"
|
||||||
#include "prototypes.h"
|
#include "prototypes.h"
|
||||||
|
|
||||||
#define SNAKE_DIR_NORTH 0
|
|
||||||
#define SNAKE_DIR_EAST 1
|
|
||||||
#define SNAKE_DIR_SOUTH 2
|
|
||||||
#define SNAKE_DIR_WEST 3
|
|
||||||
|
|
||||||
class SnakeEffect : public Effect {
|
class SnakeEffect : public Effect {
|
||||||
private:
|
private:
|
||||||
Coords _pos;
|
Coords coords;
|
||||||
Coords _apple;
|
uint8_t direction = 1;
|
||||||
int8_t _dir = SNAKE_DIR_NORTH;
|
uint8_t hue = 0;
|
||||||
uint8_t* _map;
|
uint8_t run = 0;
|
||||||
uint16_t _pixels;
|
bool is_turn_needed();
|
||||||
uint8_t _length;
|
void turn_random();
|
||||||
unsigned long _last_apple_at;
|
bool turn_right();
|
||||||
unsigned long _last_move_at;
|
bool turn_left();
|
||||||
// The following code is a handwritten "ai". Useful for testing and stuff.
|
bool is_direction_okay(uint8_t direction);
|
||||||
//int8_t _decisions[64] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,-1,1,-1,-1,-1,-1,0,0,0,0,-1,-1,0,0,0,1,0,0,-1,-1,0,0};
|
|
||||||
int8_t _decisions[64] = {0, 1, 1, -1, 0, 1, 1, -1, 0, -1, 1, -1, -1, 0, 1, -1, -1, 0, 0, 1, -1, -1, 0, 0, -1, 0, 0, -1, 0, -1, 0, -1, -1, 0, 0, -1, -1, 0, 1, -1, -1, 1, 1, -1, -1, 1, -1, 0, 0, 1, 0, 1, -1, -1, 0, 0, 0, -1, 0, 1, 0, -1, 0, -1};
|
|
||||||
//int8_t _decisions[64] = {1, 1, 0, 0, 1, 1, -1, -1, 0, -1, 0, -1, -1, 0, -1, 1, 1, -1, 0, 0, 1, -1, 0, 1, 0, -1, 0, -1, 0, 1, 1, 1, -1, 0, 0, 0, -1, -1, -1, 1, -1, -1, 1, 1, -1, 0, 1, 1, 1, 0, 0, -1, -1, 0, -1, 1, 0, 0, 0, -1, 0, -1, 1, 1};
|
|
||||||
uint16_t _xy2i(uint8_t x, uint8_t y);
|
|
||||||
uint16_t _xy2i(Coords c);
|
|
||||||
Coords _i2xy(uint16_t i);
|
|
||||||
Coords _new_pos(uint8_t dir);
|
|
||||||
uint8_t _dying = 0;
|
|
||||||
bool _is_free(uint8_t dir);
|
|
||||||
bool _to_apple(uint8_t dir);
|
|
||||||
void _place_apple();
|
|
||||||
void _init();
|
|
||||||
void _decide();
|
|
||||||
int8_t _manual_decision();
|
|
||||||
void _move();
|
|
||||||
void _draw();
|
|
||||||
public:
|
public:
|
||||||
SnakeEffect();
|
SnakeEffect();
|
||||||
~SnakeEffect();
|
~SnakeEffect();
|
||||||
void loop(uint16_t ms);
|
void loop(uint16_t ms);
|
||||||
|
boolean valid_position(Coords c);
|
||||||
|
Coords update_position(Coords c, uint8_t direction);
|
||||||
boolean can_be_shown_with_clock();
|
boolean can_be_shown_with_clock();
|
||||||
String get_name() override { return "snake"; }
|
String get_name() override { return "snake"; }
|
||||||
};
|
};
|
||||||
|
@ -2,184 +2,63 @@
|
|||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
|
|
||||||
SnakeEffect::SnakeEffect() {
|
SnakeEffect::SnakeEffect() {
|
||||||
window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
|
this->coords = {0, 0};
|
||||||
_pixels = window->width * window->height;
|
this->window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6);
|
||||||
_map = new uint8_t[_pixels];
|
|
||||||
_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SnakeEffect::_init() {
|
|
||||||
_dying = 0;
|
|
||||||
_last_apple_at = millis();
|
|
||||||
_last_move_at = millis();
|
|
||||||
_dir = SNAKE_DIR_NORTH;
|
|
||||||
_length = 4;
|
|
||||||
_pos = {(uint8_t)(window->width/2), (uint8_t)(window->height/2)};
|
|
||||||
for (int i=0; i<_pixels; i++) _map[i]=0;
|
|
||||||
_map[_xy2i(_pos)]=1;
|
|
||||||
_place_apple();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SnakeEffect::~SnakeEffect() {
|
SnakeEffect::~SnakeEffect() {
|
||||||
delete window;
|
delete window;
|
||||||
delete _map;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SnakeEffect::_place_apple() {
|
|
||||||
if (_length < _pixels) {
|
|
||||||
uint8_t start = random8(_pixels);
|
|
||||||
for (int i=0; i<_pixels; i++) {
|
|
||||||
if (_map[start + i]==0) {
|
|
||||||
_apple = _i2xy(start + i);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SnakeEffect::_decide() {
|
|
||||||
uint8_t input = 0;
|
|
||||||
if (_is_free(_dir - 1)) input |= 1<<5;
|
|
||||||
if (_is_free(_dir)) input |= 1<<4;
|
|
||||||
if (_is_free(_dir + 1)) input |= 1<<3;
|
|
||||||
if (_to_apple(_dir - 1)) input |= 1<<2;
|
|
||||||
if (_to_apple(_dir)) input |= 1<<1;
|
|
||||||
if (_to_apple(_dir + 1)) input |= 1;
|
|
||||||
|
|
||||||
_dir += _decisions[input];
|
|
||||||
if (_dir < 0) _dir += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is old (and hence disabled) code, showing
|
|
||||||
* a simple, hand-crafted "AI" for plaing snake.
|
|
||||||
**
|
|
||||||
int8_t SnakeEffect::_manual_decision() {
|
|
||||||
bool free_l = _is_free(_dir - 1);
|
|
||||||
bool free_s = _is_free(_dir);
|
|
||||||
bool free_r = _is_free(_dir + 1);
|
|
||||||
bool apple_l = _to_apple(_dir - 1);
|
|
||||||
bool apple_s = _to_apple(_dir);
|
|
||||||
bool apple_r = _to_apple(_dir + 1);
|
|
||||||
|
|
||||||
if (!free_s) {
|
|
||||||
if (apple_l && free_l) return -1;
|
|
||||||
if (apple_r && free_r) return 1;
|
|
||||||
if (free_l) return -1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (apple_s) return 0;
|
|
||||||
if (apple_l && free_l) return -1;
|
|
||||||
if (apple_r && free_r) return 1;
|
|
||||||
return 0;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
bool SnakeEffect::_is_free(uint8_t dir) {
|
|
||||||
Coords np = _new_pos(dir);
|
|
||||||
return np.x>=0 && np.x<window->width && np.y>=0 && np.y<window->height && _map[_xy2i(np)]==0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SnakeEffect::_to_apple(uint8_t dir) {
|
|
||||||
uint8_t d = dir % 4;
|
|
||||||
switch(d) {
|
|
||||||
case SNAKE_DIR_NORTH: return _apple.y<_pos.y;
|
|
||||||
case SNAKE_DIR_EAST: return _apple.x>_pos.x;
|
|
||||||
case SNAKE_DIR_SOUTH: return _apple.y>_pos.y;
|
|
||||||
case SNAKE_DIR_WEST: return _apple.x<_pos.x;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Coords SnakeEffect::_new_pos(uint8_t dir) {
|
|
||||||
uint8_t d = dir % 4;
|
|
||||||
Coords p(_pos);
|
|
||||||
switch(d) {
|
|
||||||
case SNAKE_DIR_NORTH: p.y--; break;
|
|
||||||
case SNAKE_DIR_EAST: p.x++; break;
|
|
||||||
case SNAKE_DIR_SOUTH: p.y++; break;
|
|
||||||
case SNAKE_DIR_WEST: p.x--; break;
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t SnakeEffect::_xy2i(Coords c) {
|
|
||||||
return _xy2i(c.x, c.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t SnakeEffect::_xy2i(uint8_t x, uint8_t y) {
|
|
||||||
return y*window->width + x;
|
|
||||||
}
|
|
||||||
|
|
||||||
Coords SnakeEffect::_i2xy(uint16_t i) {
|
|
||||||
return {(uint16_t)(i%window->width), (uint16_t)(i/window->width)};
|
|
||||||
}
|
|
||||||
|
|
||||||
void SnakeEffect::_move() {
|
|
||||||
if (_dying==0 && !_is_free(_dir)) {
|
|
||||||
_dying = 150;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_dying > 0) {
|
|
||||||
_dying--;
|
|
||||||
|
|
||||||
if (_dying==0) {
|
|
||||||
_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long now = millis();
|
|
||||||
if (_last_move_at < now && now - _last_move_at < 100) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_last_move_at = now;
|
|
||||||
_pos = _new_pos(_dir);
|
|
||||||
if (_pos.x==_apple.x && _pos.y==_apple.y) {
|
|
||||||
_last_apple_at = millis();
|
|
||||||
_length++;
|
|
||||||
}
|
|
||||||
for (int i=0; i<_pixels; i++) {
|
|
||||||
if (_map[i]>0 && _map[i]<_length-1) _map[i]++;
|
|
||||||
else _map[i]=0;
|
|
||||||
}
|
|
||||||
_map[_xy2i(_pos)] = 1;
|
|
||||||
if (_pos.x==_apple.x && _pos.y==_apple.y) {
|
|
||||||
_place_apple();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SnakeEffect::_draw() {
|
|
||||||
if (_dying) {
|
|
||||||
window->fadeToBlackBy(4);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
window->clear();
|
|
||||||
CRGB red(0xBB0000);
|
|
||||||
for (int i=0; i<_pixels; i++) {
|
|
||||||
if (_map[i]>0) window->setPixelByIndex(i, &red);
|
|
||||||
}
|
|
||||||
CRGB white(0xFFFFFF);
|
|
||||||
window->setPixel(_pos.x, _pos.y, &white);
|
|
||||||
CRGB green(0xFFFF00);
|
|
||||||
window->setPixel(_apple.x, _apple.y, &green);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SnakeEffect::loop(uint16_t ms) {
|
void SnakeEffect::loop(uint16_t ms) {
|
||||||
//window->fadeToBlackBy(2);
|
if (run++ % settings.effects.snake.slowdown == 0) { // Change the coordinates only on every n-th run.
|
||||||
//CRGB color(CHSV(hue, 200, 255));
|
if (random8(settings.effects.snake.direction_change)==0 || is_turn_needed()) turn_random();
|
||||||
//window->setPixel(this->coords.x, this->coords.y, &color);
|
|
||||||
//hue++;
|
this->coords = update_position(this->coords, this->direction);
|
||||||
if (millis() < _last_apple_at || millis() - _last_apple_at > 30000) {
|
|
||||||
_dying = 150;
|
|
||||||
}
|
}
|
||||||
if (_dying==0) {
|
|
||||||
_decide();
|
window->fadeToBlackBy(2);
|
||||||
|
CRGB color(CHSV(hue, 200, 255));
|
||||||
|
window->setPixel(this->coords.x, this->coords.y, &color);
|
||||||
|
hue++;
|
||||||
}
|
}
|
||||||
_move();
|
|
||||||
_draw();
|
void SnakeEffect::turn_random() {
|
||||||
|
if ((random8() & 1) == 0) {
|
||||||
|
turn_right() || turn_left();
|
||||||
|
} else {
|
||||||
|
turn_left() || turn_right();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SnakeEffect::turn_left() {
|
||||||
|
if (!is_direction_okay(this->direction - 1)) return false;
|
||||||
|
this->direction--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SnakeEffect::turn_right() {
|
||||||
|
if (!is_direction_okay(this->direction + 1)) return false;
|
||||||
|
this->direction++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SnakeEffect::is_turn_needed() {
|
||||||
|
return !is_direction_okay(this->direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SnakeEffect::is_direction_okay(uint8_t dir) {
|
||||||
|
Coords c = update_position(this->coords, dir);
|
||||||
|
return c.x<window->width && c.y<window->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
Coords SnakeEffect::update_position(Coords original, uint8_t direction) {
|
||||||
|
direction = direction % 4;
|
||||||
|
if (direction == 0) original.y--;
|
||||||
|
else if (direction == 1) original.x++;
|
||||||
|
else if (direction == 2) original.y++;
|
||||||
|
else if (direction == 3) original.x--;
|
||||||
|
return original;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean SnakeEffect::can_be_shown_with_clock() { return true; }
|
boolean SnakeEffect::can_be_shown_with_clock() { return true; }
|
||||||
|
Loading…
Reference in New Issue
Block a user