Snake.cpp
 1  // SPDX-FileCopyrightText: 2019 Anne Barela for Adafruit Industries
 2  //
 3  // SPDX-License-Identifier: MIT
 4  
 5  #include "Snake.h"
 6  
 7  void Snake::run() {
 8    if (gameRunning) {
 9      if ((millis()-lastSnakeMoveTime)>((80-snakeLength)*(80-snakeLength)/20)) {
10        if (!moveSnake()) gameOver();
11        else lastSnakeMoveTime=millis();
12      }
13    }
14  }
15  
16  void Snake::init() {
17    for (uint8_t y=0;y<16;y++) {
18      for (uint8_t x=0;x<8;x++) {
19        snakeBoard[y][x]=0;
20      }
21    }
22    snakeLength=3;
23    snakeHeadX=random(4)+2;
24    snakeHeadY=random(12)+2;
25    uint8_t moveDirection=random(4);
26    switch (moveDirection) {
27      case 0:  // up
28        snakeHeadDX=0;  snakeHeadDY=-1; break;
29      case 1:  // down
30        snakeHeadDX=0;  snakeHeadDY=1;  break;
31      case 2:  // left
32        snakeHeadDX=-1; snakeHeadDY=0;  break;
33      case 3:  // right
34        snakeHeadDX=1;  snakeHeadDY=0;
35    }
36    // Draw the snake of length=3
37    snakeBoard[snakeHeadY][snakeHeadX]=3;
38    snakeBoard[snakeHeadY-snakeHeadDY][snakeHeadX-snakeHeadDX]=2;
39    snakeBoard[snakeHeadY-snakeHeadDY*2][snakeHeadX-snakeHeadDX*2]=1;
40    placeFood();
41    gameRunning=true;
42  }
43  
44  void Snake::gameOver() {
45    gameRunning=false;
46    Serial.println("Game Over");
47  }
48  
49  void Snake::placeFood() {
50    foodX = random(8);
51    foodY = random(16);
52    while(snakeBoard[foodY][foodX]!=0) {
53      foodX = random(8);
54      foodY = random(16);
55    }
56    snakeBoard[foodY][foodX]=snakeLength+1;
57  }
58  
59  bool Snake::moveSnake() {
60    snakeHeadX = (snakeHeadX+snakeHeadDX+8) % 8;
61    snakeHeadY = (snakeHeadY+snakeHeadDY+16)%16;
62    uint8_t temp = snakeBoard[snakeHeadY][snakeHeadX];
63    // if the new snakeHead is already occupied by part of the snake body, then return false, game over 
64    if (temp>1 && temp<=snakeLength) return false;
65    if (snakeHeadX == foodX && snakeHeadY == foodY) {
66      snakeLength+=1;
67      placeFood();
68    }
69    else {
70      for (uint8_t y=0; y<16; y++) {
71        for (uint8_t x=0; x<8; x++) {
72          if (snakeBoard[y][x]>0 && snakeBoard[y][x]<=snakeLength) snakeBoard[y][x]-=1;
73        }
74      }
75      snakeBoard[snakeHeadY][snakeHeadX]=snakeLength;
76    }
77    allowToChangeDirection=true;
78    return true;
79  }
80  
81  void Snake::changeDirection(int8_t dx, int8_t dy) {
82    if (!allowToChangeDirection) return;
83    if ((snakeHeadDX+dx==0 && dx!=0) || (snakeHeadDY+dy==0 && dy!=0)) return;
84    snakeHeadDX=dx;
85    snakeHeadDY=dy;
86    allowToChangeDirection=false;
87  }
88  
89  uint8_t* Snake::getActiveBoard(){
90    for (int8_t y=0; y<16; y++) {
91      uint8_t temp=0;
92      for (int8_t x=0; x<8; x++) {
93        if (snakeBoard[y][x]) temp |= _BV(7-x);
94      }
95      activeSnakeBoard[y]=temp;
96    }
97    return activeSnakeBoard;
98  }