A simple two button snake.

Dependencies:   microbit

A Snake Game with animation, score and continuous play

Steps:

  • Switch On.
  • Snake animation plays.
  • Game starts.
  • Press buttons to move the snake left, right, up and down.
  • Food appears as a dot on the display.
  • Try eating the food by manoeuvring Snake to run over it.
  • Snake grows as it eats food.
  • As it grows it becomes hard to avoid snake biting itself.
  • Game Over.
  • Snake is flashed and then score is scrolled.
  • Game restarts after replaying animation.

Controls:

  • Left Button (A)
    • If snake moving UP/DOWN moves snake to LEFT.
    • If snake moving LEFT moves snake to DOWN.
    • If snake moving RIGHT moves snake to UP.
  • Right Button (B)
    • If snake moving UP/DOWN moves snake to RIGHT.
    • If snake moving LEFT moves snake to UP.
    • If snake moving RIGHT moves snake to DOWN.

How it looks:

https://www.youtube.com/watch?v=unEs3NOvIKA

Binary to play with

/media/uploads/mazimkhan/microbit_snake_nrf51_microbit.hex

Committer:
mazimkhan
Date:
Wed Apr 13 15:03:44 2016 +0000
Revision:
5:9328487a0a46
Parent:
4:9fd9402eca3d
Changed random max to 5 to allow value between 0-4 for x,y coordinates. Otherwise we are stuck in an endless loop trying find good snake food!

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mazimkhan 0:af1bb8b895c7 1 /*
mazimkhan 0:af1bb8b895c7 2 The MIT License (MIT)
mazimkhan 0:af1bb8b895c7 3 Copyright (c) 2016 British Broadcasting Corporation.
mazimkhan 0:af1bb8b895c7 4 This software is provided by Lancaster University by arrangement with the BBC.
mazimkhan 0:af1bb8b895c7 5 Permission is hereby granted, free of charge, to any person obtaining a
mazimkhan 0:af1bb8b895c7 6 copy of this software and associated documentation files (the "Software"),
mazimkhan 0:af1bb8b895c7 7 to deal in the Software without restriction, including without limitation
mazimkhan 0:af1bb8b895c7 8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
mazimkhan 0:af1bb8b895c7 9 and/or sell copies of the Software, and to permit persons to whom the
mazimkhan 0:af1bb8b895c7 10 Software is furnished to do so, subject to the following conditions:
mazimkhan 0:af1bb8b895c7 11 The above copyright notice and this permission notice shall be included in
mazimkhan 0:af1bb8b895c7 12 all copies or substantial portions of the Software.
mazimkhan 0:af1bb8b895c7 13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
mazimkhan 0:af1bb8b895c7 14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
mazimkhan 0:af1bb8b895c7 15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
mazimkhan 0:af1bb8b895c7 16 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
mazimkhan 0:af1bb8b895c7 17 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
mazimkhan 0:af1bb8b895c7 18 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
mazimkhan 0:af1bb8b895c7 19 DEALINGS IN THE SOFTWARE.
mazimkhan 0:af1bb8b895c7 20 */
mazimkhan 0:af1bb8b895c7 21
mazimkhan 0:af1bb8b895c7 22 #include "MicroBit.h"
mazimkhan 0:af1bb8b895c7 23 #include "DigitalOut.h"
mazimkhan 0:af1bb8b895c7 24
mazimkhan 3:a0200bceae4b 25 #define SNAKE_HEAD_PIXEL_BRIGHTNESS 150
mazimkhan 3:a0200bceae4b 26 #define SNAKE_BONE_PIXEL_BRIGHTNESS 15
mazimkhan 0:af1bb8b895c7 27 #define SNAKE_FOOD_PIXEL_BRIGHTNESS 255
mazimkhan 0:af1bb8b895c7 28
mazimkhan 0:af1bb8b895c7 29 template <class T> class Node{
mazimkhan 0:af1bb8b895c7 30 public:
mazimkhan 0:af1bb8b895c7 31 Node(T data): d(data), next(NULL), prev(NULL) {}
mazimkhan 0:af1bb8b895c7 32
mazimkhan 0:af1bb8b895c7 33 Node * getNext(){
mazimkhan 0:af1bb8b895c7 34 return next;
mazimkhan 0:af1bb8b895c7 35 }
mazimkhan 0:af1bb8b895c7 36 Node * getPrev(){
mazimkhan 0:af1bb8b895c7 37 return prev;
mazimkhan 0:af1bb8b895c7 38 }
mazimkhan 0:af1bb8b895c7 39 void detach () {
mazimkhan 0:af1bb8b895c7 40 if (prev){
mazimkhan 0:af1bb8b895c7 41 prev->next = next;
mazimkhan 0:af1bb8b895c7 42 }
mazimkhan 0:af1bb8b895c7 43 if (next){
mazimkhan 0:af1bb8b895c7 44 next->prev = prev;
mazimkhan 0:af1bb8b895c7 45 }
mazimkhan 0:af1bb8b895c7 46
mazimkhan 0:af1bb8b895c7 47 next = NULL;
mazimkhan 0:af1bb8b895c7 48 prev = NULL;
mazimkhan 0:af1bb8b895c7 49 }
mazimkhan 0:af1bb8b895c7 50 void append(Node * node) {
mazimkhan 0:af1bb8b895c7 51 Node * n = this;
mazimkhan 0:af1bb8b895c7 52 while (n->getNext()){
mazimkhan 0:af1bb8b895c7 53 n = n->getNext();
mazimkhan 0:af1bb8b895c7 54 }
mazimkhan 0:af1bb8b895c7 55 n->next = node;
mazimkhan 0:af1bb8b895c7 56 if (node){
mazimkhan 0:af1bb8b895c7 57 node->prev = n;
mazimkhan 0:af1bb8b895c7 58 }
mazimkhan 0:af1bb8b895c7 59 }
mazimkhan 0:af1bb8b895c7 60 public:
mazimkhan 0:af1bb8b895c7 61 T d;
mazimkhan 0:af1bb8b895c7 62 private:
mazimkhan 0:af1bb8b895c7 63 Node * next;
mazimkhan 0:af1bb8b895c7 64 Node * prev;
mazimkhan 0:af1bb8b895c7 65 };
mazimkhan 0:af1bb8b895c7 66
mazimkhan 0:af1bb8b895c7 67 template <class T> class List {
mazimkhan 0:af1bb8b895c7 68 public:
mazimkhan 0:af1bb8b895c7 69 List(): head(NULL), tail(NULL){
mazimkhan 0:af1bb8b895c7 70 }
mazimkhan 0:af1bb8b895c7 71 void prepend(Node<T> * node){
mazimkhan 0:af1bb8b895c7 72 if (node){
mazimkhan 0:af1bb8b895c7 73 if (head == NULL && tail == NULL) {
mazimkhan 0:af1bb8b895c7 74 head = tail = node;
mazimkhan 0:af1bb8b895c7 75 } else {
mazimkhan 0:af1bb8b895c7 76 node->append(head);
mazimkhan 0:af1bb8b895c7 77 head = node;
mazimkhan 0:af1bb8b895c7 78 }
mazimkhan 0:af1bb8b895c7 79 }
mazimkhan 0:af1bb8b895c7 80 }
mazimkhan 0:af1bb8b895c7 81 Node<T> * removeTail(){
mazimkhan 0:af1bb8b895c7 82 Node<T> * node = tail;
mazimkhan 0:af1bb8b895c7 83 if (tail) {
mazimkhan 0:af1bb8b895c7 84 tail = tail->getPrev();
mazimkhan 0:af1bb8b895c7 85 node->detach();
mazimkhan 3:a0200bceae4b 86 if (tail == NULL){
mazimkhan 3:a0200bceae4b 87 head = NULL;
mazimkhan 3:a0200bceae4b 88 }
mazimkhan 0:af1bb8b895c7 89 }
mazimkhan 0:af1bb8b895c7 90 return node;
mazimkhan 0:af1bb8b895c7 91 }
mazimkhan 0:af1bb8b895c7 92 Node<T> * getHead(){
mazimkhan 0:af1bb8b895c7 93 return head;
mazimkhan 0:af1bb8b895c7 94 }
mazimkhan 0:af1bb8b895c7 95 Node<T> * getTail(){
mazimkhan 0:af1bb8b895c7 96 return tail;
mazimkhan 0:af1bb8b895c7 97 }
mazimkhan 0:af1bb8b895c7 98 void cleanup(){
mazimkhan 0:af1bb8b895c7 99 Node<T> * node = tail;
mazimkhan 0:af1bb8b895c7 100 while(node){
mazimkhan 0:af1bb8b895c7 101 Node<T> * temp = node;
mazimkhan 0:af1bb8b895c7 102 node = node->getPrev();
mazimkhan 0:af1bb8b895c7 103
mazimkhan 0:af1bb8b895c7 104 temp->detach();
mazimkhan 0:af1bb8b895c7 105 delete temp;
mazimkhan 0:af1bb8b895c7 106 }
mazimkhan 0:af1bb8b895c7 107 head = tail = NULL;
mazimkhan 0:af1bb8b895c7 108 }
mazimkhan 0:af1bb8b895c7 109 private:
mazimkhan 0:af1bb8b895c7 110 Node<T> * head;
mazimkhan 0:af1bb8b895c7 111 Node<T> * tail;
mazimkhan 0:af1bb8b895c7 112 };
mazimkhan 0:af1bb8b895c7 113
mazimkhan 0:af1bb8b895c7 114 class Dimension
mazimkhan 0:af1bb8b895c7 115 {
mazimkhan 0:af1bb8b895c7 116 public:
mazimkhan 0:af1bb8b895c7 117 Dimension (int start, int end) {
mazimkhan 0:af1bb8b895c7 118 this->start = start;
mazimkhan 0:af1bb8b895c7 119 this->end = end;
mazimkhan 0:af1bb8b895c7 120 this->cur = start;
mazimkhan 0:af1bb8b895c7 121 }
mazimkhan 0:af1bb8b895c7 122
mazimkhan 0:af1bb8b895c7 123 Dimension (int start, int end, int cur) {
mazimkhan 0:af1bb8b895c7 124 this->start = start;
mazimkhan 0:af1bb8b895c7 125 this->end = end;
mazimkhan 0:af1bb8b895c7 126 this->cur = cur;
mazimkhan 0:af1bb8b895c7 127 }
mazimkhan 0:af1bb8b895c7 128
mazimkhan 0:af1bb8b895c7 129 void operator ++(int){
mazimkhan 0:af1bb8b895c7 130 cur++;
mazimkhan 0:af1bb8b895c7 131 if (cur > end){
mazimkhan 0:af1bb8b895c7 132 cur = start;
mazimkhan 0:af1bb8b895c7 133 }
mazimkhan 0:af1bb8b895c7 134 }
mazimkhan 0:af1bb8b895c7 135
mazimkhan 0:af1bb8b895c7 136 void operator --(int){
mazimkhan 0:af1bb8b895c7 137 cur--;
mazimkhan 0:af1bb8b895c7 138 if (cur < start){
mazimkhan 0:af1bb8b895c7 139 cur = end;
mazimkhan 0:af1bb8b895c7 140 }
mazimkhan 0:af1bb8b895c7 141 }
mazimkhan 0:af1bb8b895c7 142
mazimkhan 0:af1bb8b895c7 143 int operator -(int i){
mazimkhan 0:af1bb8b895c7 144 int r = cur - i;
mazimkhan 0:af1bb8b895c7 145 if (r < start){
mazimkhan 0:af1bb8b895c7 146 r = end;
mazimkhan 0:af1bb8b895c7 147 }
mazimkhan 0:af1bb8b895c7 148 return r;
mazimkhan 0:af1bb8b895c7 149 }
mazimkhan 0:af1bb8b895c7 150
mazimkhan 0:af1bb8b895c7 151 operator int(){
mazimkhan 0:af1bb8b895c7 152 return cur;
mazimkhan 0:af1bb8b895c7 153 }
mazimkhan 0:af1bb8b895c7 154 private:
mazimkhan 0:af1bb8b895c7 155 int start;
mazimkhan 0:af1bb8b895c7 156 int end;
mazimkhan 0:af1bb8b895c7 157 int cur;
mazimkhan 0:af1bb8b895c7 158 };
mazimkhan 0:af1bb8b895c7 159
mazimkhan 0:af1bb8b895c7 160
mazimkhan 0:af1bb8b895c7 161 class SnakeBone {
mazimkhan 0:af1bb8b895c7 162 public:
mazimkhan 0:af1bb8b895c7 163 SnakeBone(int startx, int endx, int curx, int starty, int endy, int cury):
mazimkhan 0:af1bb8b895c7 164 x(startx, endx, curx), y(starty, endy, cury)
mazimkhan 0:af1bb8b895c7 165 {
mazimkhan 0:af1bb8b895c7 166 }
mazimkhan 0:af1bb8b895c7 167
mazimkhan 0:af1bb8b895c7 168 Dimension getX(){
mazimkhan 0:af1bb8b895c7 169 return x;
mazimkhan 0:af1bb8b895c7 170 }
mazimkhan 0:af1bb8b895c7 171
mazimkhan 0:af1bb8b895c7 172 Dimension getY(){
mazimkhan 0:af1bb8b895c7 173 return y;
mazimkhan 0:af1bb8b895c7 174 }
mazimkhan 0:af1bb8b895c7 175
mazimkhan 0:af1bb8b895c7 176 private:
mazimkhan 0:af1bb8b895c7 177 Dimension x;
mazimkhan 0:af1bb8b895c7 178 Dimension y;
mazimkhan 0:af1bb8b895c7 179 };
mazimkhan 0:af1bb8b895c7 180
mazimkhan 0:af1bb8b895c7 181
mazimkhan 0:af1bb8b895c7 182 class Snake {
mazimkhan 0:af1bb8b895c7 183 public:
mazimkhan 0:af1bb8b895c7 184 enum Direction {
mazimkhan 0:af1bb8b895c7 185 UP,
mazimkhan 0:af1bb8b895c7 186 DOWN,
mazimkhan 0:af1bb8b895c7 187 LEFT,
mazimkhan 0:af1bb8b895c7 188 RIGHT
mazimkhan 0:af1bb8b895c7 189 };
mazimkhan 0:af1bb8b895c7 190
mazimkhan 0:af1bb8b895c7 191 Snake (): d(UP){
mazimkhan 0:af1bb8b895c7 192 bones.prepend(new Node<SnakeBone>(SnakeBone(0, 4, 2, 0, 4, 2)));
mazimkhan 0:af1bb8b895c7 193 }
mazimkhan 0:af1bb8b895c7 194
mazimkhan 0:af1bb8b895c7 195 Node<SnakeBone> * getHead(){
mazimkhan 0:af1bb8b895c7 196 return bones.getHead();
mazimkhan 0:af1bb8b895c7 197 }
mazimkhan 0:af1bb8b895c7 198 Dimension getHeadX(){
mazimkhan 0:af1bb8b895c7 199 return _getNodeX(bones.getHead());
mazimkhan 0:af1bb8b895c7 200 }
mazimkhan 0:af1bb8b895c7 201 Dimension getHeadY(){
mazimkhan 0:af1bb8b895c7 202 return _getNodeY(bones.getHead());
mazimkhan 0:af1bb8b895c7 203 }
mazimkhan 0:af1bb8b895c7 204 Dimension getTailX(){
mazimkhan 0:af1bb8b895c7 205 return _getNodeX(bones.getTail());
mazimkhan 0:af1bb8b895c7 206 }
mazimkhan 0:af1bb8b895c7 207 Dimension getTailY(){
mazimkhan 0:af1bb8b895c7 208 return _getNodeY(bones.getTail());
mazimkhan 0:af1bb8b895c7 209 }
mazimkhan 0:af1bb8b895c7 210
mazimkhan 0:af1bb8b895c7 211 void grow(){
mazimkhan 0:af1bb8b895c7 212 // Find next position to place new head
mazimkhan 0:af1bb8b895c7 213 Dimension nextX = getHeadX();
mazimkhan 0:af1bb8b895c7 214 Dimension nextY = getHeadY();
mazimkhan 0:af1bb8b895c7 215
mazimkhan 0:af1bb8b895c7 216 switch (d){
mazimkhan 0:af1bb8b895c7 217 case UP: {
mazimkhan 0:af1bb8b895c7 218 nextY--;
mazimkhan 0:af1bb8b895c7 219 }
mazimkhan 0:af1bb8b895c7 220 break;
mazimkhan 0:af1bb8b895c7 221 case DOWN: {
mazimkhan 0:af1bb8b895c7 222 nextY++;
mazimkhan 0:af1bb8b895c7 223 }
mazimkhan 0:af1bb8b895c7 224 break;
mazimkhan 0:af1bb8b895c7 225 case LEFT: {
mazimkhan 0:af1bb8b895c7 226 nextX--;
mazimkhan 0:af1bb8b895c7 227 }
mazimkhan 0:af1bb8b895c7 228 break;
mazimkhan 0:af1bb8b895c7 229 case RIGHT: {
mazimkhan 0:af1bb8b895c7 230 nextX++;
mazimkhan 0:af1bb8b895c7 231 }
mazimkhan 0:af1bb8b895c7 232 break;
mazimkhan 0:af1bb8b895c7 233 }
mazimkhan 0:af1bb8b895c7 234
mazimkhan 0:af1bb8b895c7 235 // New bone at head
mazimkhan 0:af1bb8b895c7 236 bones.prepend(new Node<SnakeBone>(SnakeBone(0, 4, nextX, 0, 4, nextY)));
mazimkhan 0:af1bb8b895c7 237 }
mazimkhan 0:af1bb8b895c7 238
mazimkhan 0:af1bb8b895c7 239 void reduce(){
mazimkhan 0:af1bb8b895c7 240 Node<SnakeBone> * tail = bones.removeTail();
mazimkhan 0:af1bb8b895c7 241 if (tail){
mazimkhan 0:af1bb8b895c7 242 delete tail;
mazimkhan 0:af1bb8b895c7 243 }
mazimkhan 0:af1bb8b895c7 244 }
mazimkhan 0:af1bb8b895c7 245
mazimkhan 0:af1bb8b895c7 246 void left(){
mazimkhan 0:af1bb8b895c7 247 switch (d){
mazimkhan 0:af1bb8b895c7 248 case UP:
mazimkhan 0:af1bb8b895c7 249 case DOWN: {
mazimkhan 0:af1bb8b895c7 250 d = LEFT;
mazimkhan 0:af1bb8b895c7 251 }
mazimkhan 0:af1bb8b895c7 252 break;
mazimkhan 0:af1bb8b895c7 253 case LEFT: {
mazimkhan 0:af1bb8b895c7 254 d = DOWN;
mazimkhan 0:af1bb8b895c7 255 }
mazimkhan 0:af1bb8b895c7 256 break;
mazimkhan 0:af1bb8b895c7 257 case RIGHT: {
mazimkhan 0:af1bb8b895c7 258 d = UP;
mazimkhan 0:af1bb8b895c7 259 }
mazimkhan 0:af1bb8b895c7 260 break;
mazimkhan 0:af1bb8b895c7 261 }
mazimkhan 0:af1bb8b895c7 262 }
mazimkhan 0:af1bb8b895c7 263
mazimkhan 0:af1bb8b895c7 264 void right(){
mazimkhan 0:af1bb8b895c7 265 switch (d){
mazimkhan 0:af1bb8b895c7 266 case UP:
mazimkhan 0:af1bb8b895c7 267 case DOWN: {
mazimkhan 0:af1bb8b895c7 268 d = RIGHT;
mazimkhan 0:af1bb8b895c7 269 }
mazimkhan 0:af1bb8b895c7 270 break;
mazimkhan 0:af1bb8b895c7 271 case LEFT: {
mazimkhan 0:af1bb8b895c7 272 d = UP;
mazimkhan 0:af1bb8b895c7 273 }
mazimkhan 0:af1bb8b895c7 274 break;
mazimkhan 0:af1bb8b895c7 275 case RIGHT: {
mazimkhan 0:af1bb8b895c7 276 d = DOWN;
mazimkhan 0:af1bb8b895c7 277 }
mazimkhan 0:af1bb8b895c7 278 break;
mazimkhan 0:af1bb8b895c7 279 }
mazimkhan 0:af1bb8b895c7 280 }
mazimkhan 0:af1bb8b895c7 281
mazimkhan 0:af1bb8b895c7 282 void reset(){
mazimkhan 0:af1bb8b895c7 283 bones.cleanup();
mazimkhan 0:af1bb8b895c7 284 bones.prepend(new Node<SnakeBone>(SnakeBone(0, 4, 2, 0, 4, 2)));
mazimkhan 0:af1bb8b895c7 285 d = UP;
mazimkhan 0:af1bb8b895c7 286 }
mazimkhan 0:af1bb8b895c7 287
mazimkhan 0:af1bb8b895c7 288 Direction getDirection(){
mazimkhan 0:af1bb8b895c7 289 return d;
mazimkhan 0:af1bb8b895c7 290 }
mazimkhan 0:af1bb8b895c7 291
mazimkhan 0:af1bb8b895c7 292 private:
mazimkhan 0:af1bb8b895c7 293 Dimension _getNodeX(Node<SnakeBone> * node){
mazimkhan 0:af1bb8b895c7 294 if (node){
mazimkhan 0:af1bb8b895c7 295 return node->d.getX();
mazimkhan 0:af1bb8b895c7 296 }
mazimkhan 0:af1bb8b895c7 297 return Dimension(-1, -1, -1);
mazimkhan 0:af1bb8b895c7 298 }
mazimkhan 0:af1bb8b895c7 299
mazimkhan 0:af1bb8b895c7 300 Dimension _getNodeY(Node<SnakeBone> * node){
mazimkhan 0:af1bb8b895c7 301 if (node){
mazimkhan 0:af1bb8b895c7 302 return node->d.getY();
mazimkhan 0:af1bb8b895c7 303 }
mazimkhan 0:af1bb8b895c7 304 return Dimension(-1, -1, -1);
mazimkhan 0:af1bb8b895c7 305 }
mazimkhan 0:af1bb8b895c7 306
mazimkhan 0:af1bb8b895c7 307 List<SnakeBone> bones;
mazimkhan 0:af1bb8b895c7 308 Direction d;
mazimkhan 0:af1bb8b895c7 309 };
mazimkhan 0:af1bb8b895c7 310
mazimkhan 0:af1bb8b895c7 311 class Game {
mazimkhan 0:af1bb8b895c7 312 public:
mazimkhan 3:a0200bceae4b 313 Game(MicroBit & ubit): uBit(ubit), foodx(-1), foody(-1), image(5,5), score(0),
mazimkhan 0:af1bb8b895c7 314 buttonPressed(false) {
mazimkhan 0:af1bb8b895c7 315 uBit.display.setDisplayMode(DISPLAY_MODE_GREYSCALE);
mazimkhan 0:af1bb8b895c7 316 uBit.display.print(image);
mazimkhan 0:af1bb8b895c7 317 }
mazimkhan 0:af1bb8b895c7 318
mazimkhan 0:af1bb8b895c7 319 void left(){
mazimkhan 0:af1bb8b895c7 320 if (!buttonPressed){
mazimkhan 0:af1bb8b895c7 321 buttonPressed = true;
mazimkhan 0:af1bb8b895c7 322 snake.left();
mazimkhan 0:af1bb8b895c7 323 }
mazimkhan 0:af1bb8b895c7 324 }
mazimkhan 0:af1bb8b895c7 325
mazimkhan 0:af1bb8b895c7 326 void right(){
mazimkhan 0:af1bb8b895c7 327 if (!buttonPressed){
mazimkhan 0:af1bb8b895c7 328 buttonPressed = true;
mazimkhan 0:af1bb8b895c7 329 snake.right();
mazimkhan 0:af1bb8b895c7 330 }
mazimkhan 0:af1bb8b895c7 331 }
mazimkhan 0:af1bb8b895c7 332
mazimkhan 0:af1bb8b895c7 333 bool move(){
mazimkhan 3:a0200bceae4b 334 // Dim old head
mazimkhan 3:a0200bceae4b 335 Dimension x = snake.getHeadX();
mazimkhan 3:a0200bceae4b 336 Dimension y = snake.getHeadY();
mazimkhan 3:a0200bceae4b 337 image.setPixelValue(x, y, SNAKE_BONE_PIXEL_BRIGHTNESS);
mazimkhan 0:af1bb8b895c7 338
mazimkhan 0:af1bb8b895c7 339 snake.grow();
mazimkhan 0:af1bb8b895c7 340
mazimkhan 0:af1bb8b895c7 341 Dimension nextX = snake.getHeadX();
mazimkhan 0:af1bb8b895c7 342 Dimension nextY = snake.getHeadY();
mazimkhan 0:af1bb8b895c7 343
mazimkhan 0:af1bb8b895c7 344 // check if we grew by eating.
mazimkhan 0:af1bb8b895c7 345 if (nextX == foodx && nextY == foody){
mazimkhan 0:af1bb8b895c7 346 // food gone
mazimkhan 0:af1bb8b895c7 347 foodx = -1;
mazimkhan 0:af1bb8b895c7 348 foody = -1;
mazimkhan 3:a0200bceae4b 349 score++;
mazimkhan 0:af1bb8b895c7 350
mazimkhan 0:af1bb8b895c7 351 // Since we have grown to the head. no need to delete tail.
mazimkhan 0:af1bb8b895c7 352 } else {
mazimkhan 0:af1bb8b895c7 353 // Switch off end.
mazimkhan 0:af1bb8b895c7 354 int endx = snake.getTailX();
mazimkhan 0:af1bb8b895c7 355 int endy = snake.getTailY();
mazimkhan 0:af1bb8b895c7 356 if (endx != -1 && endy != -1){
mazimkhan 0:af1bb8b895c7 357 image.setPixelValue(endx, endy, 0);
mazimkhan 0:af1bb8b895c7 358 }
mazimkhan 0:af1bb8b895c7 359 snake.reduce();
mazimkhan 0:af1bb8b895c7 360 }
mazimkhan 0:af1bb8b895c7 361
mazimkhan 4:9fd9402eca3d 362 // Check snake bite
mazimkhan 4:9fd9402eca3d 363 if (image.getPixelValue(nextX, nextY) == 15){
mazimkhan 4:9fd9402eca3d 364 // Game Over
mazimkhan 4:9fd9402eca3d 365 return false;
mazimkhan 4:9fd9402eca3d 366 }
mazimkhan 4:9fd9402eca3d 367
mazimkhan 0:af1bb8b895c7 368 // Turn On head.
mazimkhan 3:a0200bceae4b 369 image.setPixelValue(nextX, nextY, SNAKE_HEAD_PIXEL_BRIGHTNESS);
mazimkhan 0:af1bb8b895c7 370 uBit.display.print(image);
mazimkhan 0:af1bb8b895c7 371 buttonPressed = false;
mazimkhan 0:af1bb8b895c7 372 return true;
mazimkhan 0:af1bb8b895c7 373 }
mazimkhan 0:af1bb8b895c7 374
mazimkhan 0:af1bb8b895c7 375 bool isGoodFood(int x, int y){
mazimkhan 0:af1bb8b895c7 376 bool ret = image.getPixelValue(x, y) == 0;
mazimkhan 0:af1bb8b895c7 377
mazimkhan 0:af1bb8b895c7 378 // also don't accept food in the direction of movement
mazimkhan 0:af1bb8b895c7 379 if (ret){
mazimkhan 0:af1bb8b895c7 380 switch(snake.getDirection()){
mazimkhan 0:af1bb8b895c7 381 case Snake::UP:
mazimkhan 0:af1bb8b895c7 382 case Snake::DOWN: {
mazimkhan 0:af1bb8b895c7 383 ret = x != snake.getHeadX();
mazimkhan 0:af1bb8b895c7 384 }
mazimkhan 0:af1bb8b895c7 385 break;
mazimkhan 0:af1bb8b895c7 386 case Snake::LEFT:
mazimkhan 0:af1bb8b895c7 387 case Snake::RIGHT: {
mazimkhan 0:af1bb8b895c7 388 ret = y != snake.getHeadY();
mazimkhan 0:af1bb8b895c7 389 }
mazimkhan 0:af1bb8b895c7 390 break;
mazimkhan 0:af1bb8b895c7 391 }
mazimkhan 0:af1bb8b895c7 392 }
mazimkhan 0:af1bb8b895c7 393 return ret;
mazimkhan 0:af1bb8b895c7 394 }
mazimkhan 0:af1bb8b895c7 395
mazimkhan 0:af1bb8b895c7 396 void play(){
mazimkhan 0:af1bb8b895c7 397 while (true) {
mazimkhan 0:af1bb8b895c7 398 if (!move()){
mazimkhan 0:af1bb8b895c7 399 showGameOver();
mazimkhan 0:af1bb8b895c7 400 break;
mazimkhan 0:af1bb8b895c7 401 }
mazimkhan 0:af1bb8b895c7 402
mazimkhan 0:af1bb8b895c7 403 // Put food
mazimkhan 0:af1bb8b895c7 404 if (foodx == -1 && foody == -1){
mazimkhan 0:af1bb8b895c7 405 while (true){
mazimkhan 5:9328487a0a46 406 int x = uBit.random(5);
mazimkhan 5:9328487a0a46 407 int y = uBit.random(5);
mazimkhan 0:af1bb8b895c7 408
mazimkhan 0:af1bb8b895c7 409 if (isGoodFood(x, y)){
mazimkhan 0:af1bb8b895c7 410 foodx = x;
mazimkhan 0:af1bb8b895c7 411 foody = y;
mazimkhan 3:a0200bceae4b 412 image.setPixelValue(foodx, foody, 255);
mazimkhan 3:a0200bceae4b 413 uBit.display.print(image);
mazimkhan 0:af1bb8b895c7 414 break;
mazimkhan 0:af1bb8b895c7 415 }
mazimkhan 0:af1bb8b895c7 416 }
mazimkhan 0:af1bb8b895c7 417 }
mazimkhan 0:af1bb8b895c7 418 uBit.sleep(500);
mazimkhan 0:af1bb8b895c7 419 }
mazimkhan 0:af1bb8b895c7 420 }
mazimkhan 3:a0200bceae4b 421
mazimkhan 3:a0200bceae4b 422 void animateSnake(){
mazimkhan 3:a0200bceae4b 423 #define ANIMATION_SPEED 50
mazimkhan 3:a0200bceae4b 424 // UP 2
mazimkhan 3:a0200bceae4b 425 foodx = 2;foody = 1;
mazimkhan 3:a0200bceae4b 426 move();
mazimkhan 3:a0200bceae4b 427 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 428
mazimkhan 3:a0200bceae4b 429 foodx = 2;foody = 0;
mazimkhan 3:a0200bceae4b 430 move();
mazimkhan 3:a0200bceae4b 431 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 432
mazimkhan 3:a0200bceae4b 433 // LEFT
mazimkhan 3:a0200bceae4b 434 foodx = 1;foody = 0;
mazimkhan 3:a0200bceae4b 435 left();
mazimkhan 3:a0200bceae4b 436 move();
mazimkhan 3:a0200bceae4b 437 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 438
mazimkhan 3:a0200bceae4b 439 // DOWN
mazimkhan 3:a0200bceae4b 440 foodx = 1;foody = 1;
mazimkhan 3:a0200bceae4b 441 left();
mazimkhan 3:a0200bceae4b 442 move();
mazimkhan 3:a0200bceae4b 443 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 444
mazimkhan 3:a0200bceae4b 445 foodx = 1;foody = 2;
mazimkhan 3:a0200bceae4b 446 move();
mazimkhan 3:a0200bceae4b 447 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 448 move();
mazimkhan 3:a0200bceae4b 449 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 450 move();
mazimkhan 3:a0200bceae4b 451 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 452
mazimkhan 3:a0200bceae4b 453 for (int i = 0; i < 4; i++){
mazimkhan 3:a0200bceae4b 454 // LEFT
mazimkhan 3:a0200bceae4b 455 left();
mazimkhan 3:a0200bceae4b 456 move();
mazimkhan 3:a0200bceae4b 457 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 458
mazimkhan 3:a0200bceae4b 459 // UP
mazimkhan 3:a0200bceae4b 460 right();
mazimkhan 3:a0200bceae4b 461 move();
mazimkhan 3:a0200bceae4b 462 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 463
mazimkhan 3:a0200bceae4b 464 move();
mazimkhan 3:a0200bceae4b 465 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 466 move();
mazimkhan 3:a0200bceae4b 467 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 468 move();
mazimkhan 3:a0200bceae4b 469 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 470
mazimkhan 3:a0200bceae4b 471 // LEFT
mazimkhan 3:a0200bceae4b 472 left();
mazimkhan 3:a0200bceae4b 473 move();
mazimkhan 3:a0200bceae4b 474 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 475
mazimkhan 3:a0200bceae4b 476 // DOWN
mazimkhan 3:a0200bceae4b 477 left();
mazimkhan 3:a0200bceae4b 478 move();
mazimkhan 3:a0200bceae4b 479 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 480
mazimkhan 3:a0200bceae4b 481 move();
mazimkhan 3:a0200bceae4b 482 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 483 move();
mazimkhan 3:a0200bceae4b 484 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 485 move();
mazimkhan 3:a0200bceae4b 486 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 487 }
mazimkhan 3:a0200bceae4b 488
mazimkhan 3:a0200bceae4b 489 // Back to the centre
mazimkhan 3:a0200bceae4b 490 left();
mazimkhan 3:a0200bceae4b 491 move();
mazimkhan 3:a0200bceae4b 492 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 493
mazimkhan 3:a0200bceae4b 494 left();
mazimkhan 3:a0200bceae4b 495 move();
mazimkhan 3:a0200bceae4b 496 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 497
mazimkhan 3:a0200bceae4b 498 move();
mazimkhan 3:a0200bceae4b 499 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 500 move();
mazimkhan 3:a0200bceae4b 501 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 502
mazimkhan 3:a0200bceae4b 503 // eat the tail
mazimkhan 3:a0200bceae4b 504 while(snake.getHead()){
mazimkhan 3:a0200bceae4b 505 image.setPixelValue(snake.getTailX(), snake.getTailY(), 0);
mazimkhan 3:a0200bceae4b 506 uBit.display.print(image);
mazimkhan 3:a0200bceae4b 507 snake.reduce();
mazimkhan 3:a0200bceae4b 508 uBit.sleep(ANIMATION_SPEED);
mazimkhan 3:a0200bceae4b 509 }
mazimkhan 3:a0200bceae4b 510
mazimkhan 3:a0200bceae4b 511 reset();
mazimkhan 3:a0200bceae4b 512 }
mazimkhan 3:a0200bceae4b 513
mazimkhan 0:af1bb8b895c7 514 void showGameOver(){
mazimkhan 0:af1bb8b895c7 515 // switch off food
mazimkhan 0:af1bb8b895c7 516 if (foodx != -1 && foody != -1){
mazimkhan 0:af1bb8b895c7 517 image.setPixelValue(foodx, foody, 0);
mazimkhan 0:af1bb8b895c7 518 uBit.display.print(image);
mazimkhan 0:af1bb8b895c7 519 }
mazimkhan 0:af1bb8b895c7 520
mazimkhan 0:af1bb8b895c7 521 // change brightness to 255 as pixels with custom brightness
mazimkhan 0:af1bb8b895c7 522 // are not affected by display.setBrightness(). Possible Bug!!!
mazimkhan 0:af1bb8b895c7 523 Node<SnakeBone> * bone = snake.getHead();
mazimkhan 0:af1bb8b895c7 524 while (bone){
mazimkhan 3:a0200bceae4b 525 image.setPixelValue(bone->d.getX(), bone->d.getY(), SNAKE_FOOD_PIXEL_BRIGHTNESS);
mazimkhan 0:af1bb8b895c7 526 bone = bone->getNext();
mazimkhan 0:af1bb8b895c7 527 }
mazimkhan 0:af1bb8b895c7 528 // Flash snake
mazimkhan 0:af1bb8b895c7 529 uBit.display.print(image);
mazimkhan 0:af1bb8b895c7 530 bool toggle = false;
mazimkhan 0:af1bb8b895c7 531 for (int i = 0; i < 10; i++, toggle = !toggle){
mazimkhan 0:af1bb8b895c7 532 if (toggle)
mazimkhan 0:af1bb8b895c7 533 uBit.display.setBrightness(255);
mazimkhan 0:af1bb8b895c7 534 else
mazimkhan 3:a0200bceae4b 535 uBit.display.setBrightness(SNAKE_BONE_PIXEL_BRIGHTNESS);
mazimkhan 0:af1bb8b895c7 536 uBit.sleep(500);
mazimkhan 0:af1bb8b895c7 537 }
mazimkhan 3:a0200bceae4b 538 uBit.display.print(MicroBitImage(5,5));
mazimkhan 3:a0200bceae4b 539 uBit.display.setBrightness(255);
mazimkhan 3:a0200bceae4b 540 uBit.display.scroll("SCORE-"); // don't mind spaces in a scrolling display.
mazimkhan 4:9fd9402eca3d 541 uBit.display.scroll(score, 150);
mazimkhan 0:af1bb8b895c7 542 }
mazimkhan 0:af1bb8b895c7 543
mazimkhan 0:af1bb8b895c7 544 void reset(){
mazimkhan 0:af1bb8b895c7 545 // cleanup snake and state
mazimkhan 0:af1bb8b895c7 546 snake.reset();
mazimkhan 0:af1bb8b895c7 547
mazimkhan 0:af1bb8b895c7 548 foodx = -1;
mazimkhan 0:af1bb8b895c7 549 foody = -1;
mazimkhan 3:a0200bceae4b 550 score = 0;
mazimkhan 0:af1bb8b895c7 551 image = MicroBitImage(5, 5);
mazimkhan 0:af1bb8b895c7 552 uBit.display.setDisplayMode(DISPLAY_MODE_GREYSCALE);
mazimkhan 3:a0200bceae4b 553 image.setPixelValue(snake.getHeadX(), snake.getHeadY(), SNAKE_HEAD_PIXEL_BRIGHTNESS);
mazimkhan 0:af1bb8b895c7 554 uBit.display.print(image);
mazimkhan 0:af1bb8b895c7 555 }
mazimkhan 0:af1bb8b895c7 556
mazimkhan 0:af1bb8b895c7 557
mazimkhan 0:af1bb8b895c7 558 private:
mazimkhan 0:af1bb8b895c7 559 MicroBit & uBit;
mazimkhan 0:af1bb8b895c7 560 int foodx;
mazimkhan 0:af1bb8b895c7 561 int foody;
mazimkhan 0:af1bb8b895c7 562 Snake snake;
mazimkhan 0:af1bb8b895c7 563 MicroBitImage image;
mazimkhan 3:a0200bceae4b 564 int score;
mazimkhan 0:af1bb8b895c7 565
mazimkhan 0:af1bb8b895c7 566 // Sync button press and movement. Don't let quick button presses
mazimkhan 0:af1bb8b895c7 567 // change snake direction twice/thrice/... before moving. As a
mazimkhan 0:af1bb8b895c7 568 // double press can reverse the snake on its own and Game Over!!!
mazimkhan 0:af1bb8b895c7 569 bool buttonPressed;
mazimkhan 0:af1bb8b895c7 570 };
mazimkhan 0:af1bb8b895c7 571
mazimkhan 0:af1bb8b895c7 572
mazimkhan 0:af1bb8b895c7 573 MicroBit uBit;
mazimkhan 0:af1bb8b895c7 574 Game game(uBit);
mazimkhan 0:af1bb8b895c7 575
mazimkhan 0:af1bb8b895c7 576
mazimkhan 0:af1bb8b895c7 577 void onButtonA(MicroBitEvent){
mazimkhan 0:af1bb8b895c7 578 game.left();
mazimkhan 0:af1bb8b895c7 579 }
mazimkhan 0:af1bb8b895c7 580
mazimkhan 0:af1bb8b895c7 581 void onButtonB(MicroBitEvent){
mazimkhan 0:af1bb8b895c7 582 game.right();
mazimkhan 0:af1bb8b895c7 583 }
mazimkhan 0:af1bb8b895c7 584
mazimkhan 3:a0200bceae4b 585
mazimkhan 0:af1bb8b895c7 586 int main()
mazimkhan 0:af1bb8b895c7 587 {
mazimkhan 0:af1bb8b895c7 588 // Initialise the micro:bit runtime.
mazimkhan 0:af1bb8b895c7 589 uBit.init();
mazimkhan 0:af1bb8b895c7 590
mazimkhan 0:af1bb8b895c7 591 uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, onButtonA);
mazimkhan 0:af1bb8b895c7 592 uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonB);
mazimkhan 0:af1bb8b895c7 593
mazimkhan 0:af1bb8b895c7 594 // Continous play
mazimkhan 3:a0200bceae4b 595 while (true){
mazimkhan 3:a0200bceae4b 596 game.animateSnake();
mazimkhan 0:af1bb8b895c7 597 game.play();
mazimkhan 0:af1bb8b895c7 598 game.reset();
mazimkhan 0:af1bb8b895c7 599 }
mazimkhan 0:af1bb8b895c7 600 }