#include "effect_snake.h" #include "functions.h" SnakeEffect::SnakeEffect() { window = new Window(0, 0, LED_WIDTH, LED_HEIGHT-6); _pixels = window->width * window->height; _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() { 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.xwidth && np.y>=0 && np.yheight && _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) { //window->fadeToBlackBy(2); //CRGB color(CHSV(hue, 200, 255)); //window->setPixel(this->coords.x, this->coords.y, &color); //hue++; if (millis() < _last_apple_at || millis() - _last_apple_at > 30000) { _dying = 150; } if (_dying==0) { _decide(); } _move(); _draw(); } boolean SnakeEffect::can_be_shown_with_clock() { return true; }