Snake game for IMP class.

Dependencies:   mbed Terminal SerialTerminal TSI MMA8451Q

Committer:
lpiwowar
Date:
Fri Dec 13 10:14:54 2019 +0000
Revision:
0:ca75772f63a0
Initial commit;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
lpiwowar 0:ca75772f63a0 1 #include <stdlib.h>
lpiwowar 0:ca75772f63a0 2 #include "mbed.h"
lpiwowar 0:ca75772f63a0 3 #include "TSISensor.h"
lpiwowar 0:ca75772f63a0 4 #include "SerialTerminal.h"
lpiwowar 0:ca75772f63a0 5 #include "MMA8451Q.h"
lpiwowar 0:ca75772f63a0 6
lpiwowar 0:ca75772f63a0 7 #define MMA8451_I2C_ADDRESS (0x1d<<1)
lpiwowar 0:ca75772f63a0 8
lpiwowar 0:ca75772f63a0 9 PwmOut rled(LED_RED);
lpiwowar 0:ca75772f63a0 10 PwmOut gled(LED_GREEN);
lpiwowar 0:ca75772f63a0 11 Timeout timeout;
lpiwowar 0:ca75772f63a0 12
lpiwowar 0:ca75772f63a0 13 PinName const SDA = PTE25; /** < I2C serial data */
lpiwowar 0:ca75772f63a0 14 PinName const SCL = PTE24; /** < I2C serial clock */
lpiwowar 0:ca75772f63a0 15
lpiwowar 0:ca75772f63a0 16 /** Accelerometer */
lpiwowar 0:ca75772f63a0 17 MMA8451Q acc(SDA, SCL, MMA8451_I2C_ADDRESS);
lpiwowar 0:ca75772f63a0 18
lpiwowar 0:ca75772f63a0 19 //Baud rate values: 57600, 115200, 460800
lpiwowar 0:ca75772f63a0 20 /** Access terminal via USB */
lpiwowar 0:ca75772f63a0 21 SerialTerminal term(USBTX, USBRX, 460800);
lpiwowar 0:ca75772f63a0 22
lpiwowar 0:ca75772f63a0 23 const int FIELD_WIDTH = 60; /** < Width of game field */
lpiwowar 0:ca75772f63a0 24 const int FIELD_HEIGHT = 20; /** < Height of game field */
lpiwowar 0:ca75772f63a0 25 const int INIT_SNAKE_X = 30; /** < Snake initial x coordinates */
lpiwowar 0:ca75772f63a0 26 const int INIT_SNAKE_Y = 10; /** < Snake initial y coordinates */
lpiwowar 0:ca75772f63a0 27
lpiwowar 0:ca75772f63a0 28 /** @brief Stores the game field. ('#' = Snake + walls) */
lpiwowar 0:ca75772f63a0 29 char field[FIELD_HEIGHT][FIELD_WIDTH] = {};
lpiwowar 0:ca75772f63a0 30
lpiwowar 0:ca75772f63a0 31 ////////////////////////////////////////////////////////////////////////////////
lpiwowar 0:ca75772f63a0 32 /// SNAKE - start ///
lpiwowar 0:ca75772f63a0 33 ////////////////////////////////////////////////////////////////////////////////
lpiwowar 0:ca75772f63a0 34
lpiwowar 0:ca75772f63a0 35 /** Values for direction of snake */
lpiwowar 0:ca75772f63a0 36 enum snake_move {SNAKE_UP, SNAKE_DOWN, SNAKE_LEFT, SNAKE_RIGHT, SNAKE_NONE};
lpiwowar 0:ca75772f63a0 37 typedef enum snake_move snake_move_T;
lpiwowar 0:ca75772f63a0 38
lpiwowar 0:ca75772f63a0 39 /** Stores facts about one cell of snake */
lpiwowar 0:ca75772f63a0 40 typedef struct snake_cell_struct snake_cell_T;
lpiwowar 0:ca75772f63a0 41 struct snake_cell_struct {
lpiwowar 0:ca75772f63a0 42 short x; /** < X coordinates within @var field */
lpiwowar 0:ca75772f63a0 43 short y; /** < Y coordinates within @var field */
lpiwowar 0:ca75772f63a0 44 bool head; /** < True if cell is head (first cell) */
lpiwowar 0:ca75772f63a0 45 snake_cell_T *next_cell; /** < Pointer to next cell of snake */
lpiwowar 0:ca75772f63a0 46 };
lpiwowar 0:ca75772f63a0 47
lpiwowar 0:ca75772f63a0 48 /**
lpiwowar 0:ca75772f63a0 49 * @brif Creates first cell of snake and returns pointer to it. Atribute
lpiwowar 0:ca75772f63a0 50 * head is set to true.
lpiwowar 0:ca75772f63a0 51 * @param x X coordinates of location where the snake should be spawned.
lpiwowar 0:ca75772f63a0 52 * @param y Y coordinates of location where the snake should be spawned.
lpiwowar 0:ca75772f63a0 53 * @return pointer to the first cell of snake
lpiwowar 0:ca75772f63a0 54 */
lpiwowar 0:ca75772f63a0 55 snake_cell_T *init_snake(int x, int y) {
lpiwowar 0:ca75772f63a0 56 snake_cell_T *new_snake = (snake_cell_T *)malloc(sizeof(snake_cell_T));
lpiwowar 0:ca75772f63a0 57 if(new_snake == NULL) {
lpiwowar 0:ca75772f63a0 58 term.printf("Error: malloc()\r\n");
lpiwowar 0:ca75772f63a0 59 exit(1);
lpiwowar 0:ca75772f63a0 60 }
lpiwowar 0:ca75772f63a0 61
lpiwowar 0:ca75772f63a0 62 new_snake->x = x;
lpiwowar 0:ca75772f63a0 63 new_snake->y = y;
lpiwowar 0:ca75772f63a0 64 new_snake->next_cell = NULL;
lpiwowar 0:ca75772f63a0 65 new_snake->head = true;
lpiwowar 0:ca75772f63a0 66
lpiwowar 0:ca75772f63a0 67 return new_snake;
lpiwowar 0:ca75772f63a0 68 }
lpiwowar 0:ca75772f63a0 69
lpiwowar 0:ca75772f63a0 70 /**
lpiwowar 0:ca75772f63a0 71 * @brief Frees all memory allocated for Snake.
lpiwowar 0:ca75772f63a0 72 * @param snake Pointer to first cell of Snake
lpiwowar 0:ca75772f63a0 73 */
lpiwowar 0:ca75772f63a0 74 void destroy_snake(snake_cell_T *snake) {
lpiwowar 0:ca75772f63a0 75 snake_cell_T *snake_cell_tmp = NULL;
lpiwowar 0:ca75772f63a0 76 while(snake != NULL) {
lpiwowar 0:ca75772f63a0 77 snake_cell_tmp = snake;
lpiwowar 0:ca75772f63a0 78 snake = snake->next_cell;
lpiwowar 0:ca75772f63a0 79 free(snake_cell_tmp);
lpiwowar 0:ca75772f63a0 80 }
lpiwowar 0:ca75772f63a0 81 }
lpiwowar 0:ca75772f63a0 82
lpiwowar 0:ca75772f63a0 83 /**
lpiwowar 0:ca75772f63a0 84 * @brief Appends cell to the end of Snake.
lpiwowar 0:ca75772f63a0 85 * @param snake Snake which should contain the new cell.
lpiwowar 0:ca75772f63a0 86 * @param snake_cell Cell which should be appended to the Snake.
lpiwowar 0:ca75772f63a0 87 */
lpiwowar 0:ca75772f63a0 88 void append_cell_to_snake(snake_cell_T *snake, snake_cell_T *snake_cell) {
lpiwowar 0:ca75772f63a0 89
lpiwowar 0:ca75772f63a0 90 while(snake != NULL) {
lpiwowar 0:ca75772f63a0 91 if(snake->next_cell == NULL) {
lpiwowar 0:ca75772f63a0 92 snake->next_cell = snake_cell;
lpiwowar 0:ca75772f63a0 93 break;
lpiwowar 0:ca75772f63a0 94 }
lpiwowar 0:ca75772f63a0 95 snake = snake->next_cell;
lpiwowar 0:ca75772f63a0 96 }
lpiwowar 0:ca75772f63a0 97
lpiwowar 0:ca75772f63a0 98 }
lpiwowar 0:ca75772f63a0 99
lpiwowar 0:ca75772f63a0 100 const int WALL = -1; /** < Return value if Snake hit the wall */
lpiwowar 0:ca75772f63a0 101 const int FOOD_FOUND = 1; /** < Return value if Snake ate the food */
lpiwowar 0:ca75772f63a0 102 /**
lpiwowar 0:ca75772f63a0 103 * @brief Updates the position of Snake. If the position where the snake
lpiwowar 0:ca75772f63a0 104 * wants to move contains food ('*') it returns @var FOOD_FOUND and
lpiwowar 0:ca75772f63a0 105 * creates new snake cell and appends it to the snake. If the position
lpiwowar 0:ca75772f63a0 106 * where the snake wants to move contains wall ('#') it returns
lpiwowar 0:ca75772f63a0 107 * WALL. Also updates coordinates coordinates of snake based on
lpiwowar 0:ca75772f63a0 108 * direction in which the snake is moving.
lpiwowar 0:ca75772f63a0 109 * @param snake Snake whose coordinates should be updated.
lpiwowar 0:ca75772f63a0 110 * @param move_direction In which direction is the snake moving.
lpiwowar 0:ca75772f63a0 111 * @return 0 if success. WALL if snake hit the wall. FOOD_FOUND if snake ate
lpiwowar 0:ca75772f63a0 112 * the food.
lpiwowar 0:ca75772f63a0 113 */
lpiwowar 0:ca75772f63a0 114 int update_snake_pos(snake_cell_T *snake, snake_move_T move_direction) {
lpiwowar 0:ca75772f63a0 115
lpiwowar 0:ca75772f63a0 116 bool food_found = false;
lpiwowar 0:ca75772f63a0 117
lpiwowar 0:ca75772f63a0 118 switch(move_direction) {
lpiwowar 0:ca75772f63a0 119 case SNAKE_UP: if(field[snake->y-1][snake->x] == '#')
lpiwowar 0:ca75772f63a0 120 return WALL;
lpiwowar 0:ca75772f63a0 121 else if(field[snake->y-1][snake->x] == '*')
lpiwowar 0:ca75772f63a0 122 food_found = true;
lpiwowar 0:ca75772f63a0 123 break;
lpiwowar 0:ca75772f63a0 124
lpiwowar 0:ca75772f63a0 125 case SNAKE_DOWN: if(field[snake->y+1][snake->x] == '#')
lpiwowar 0:ca75772f63a0 126 return WALL;
lpiwowar 0:ca75772f63a0 127 else if(field[snake->y+1][snake->x] == '*')
lpiwowar 0:ca75772f63a0 128 food_found = true;
lpiwowar 0:ca75772f63a0 129 break;
lpiwowar 0:ca75772f63a0 130
lpiwowar 0:ca75772f63a0 131 case SNAKE_RIGHT: if(field[snake->y][snake->x+1] == '#')
lpiwowar 0:ca75772f63a0 132 return WALL;
lpiwowar 0:ca75772f63a0 133 else if(field[snake->y][snake->x+1] == '*')
lpiwowar 0:ca75772f63a0 134 food_found = true;
lpiwowar 0:ca75772f63a0 135 break;
lpiwowar 0:ca75772f63a0 136
lpiwowar 0:ca75772f63a0 137 case SNAKE_LEFT: if(field[snake->y][snake->x-1] == '#')
lpiwowar 0:ca75772f63a0 138 return WALL;
lpiwowar 0:ca75772f63a0 139 else if(field[snake->y][snake->x-1] == '*')
lpiwowar 0:ca75772f63a0 140 food_found = true;
lpiwowar 0:ca75772f63a0 141 break;
lpiwowar 0:ca75772f63a0 142 }
lpiwowar 0:ca75772f63a0 143
lpiwowar 0:ca75772f63a0 144 snake_cell_T *new_cell = NULL;
lpiwowar 0:ca75772f63a0 145 snake_cell_T *save_snake = snake;
lpiwowar 0:ca75772f63a0 146 int prev_x = 0;
lpiwowar 0:ca75772f63a0 147 int prev_y = 0;
lpiwowar 0:ca75772f63a0 148 int tmp = 0;
lpiwowar 0:ca75772f63a0 149
lpiwowar 0:ca75772f63a0 150 while(snake != NULL) {
lpiwowar 0:ca75772f63a0 151
lpiwowar 0:ca75772f63a0 152 if(food_found && snake->next_cell == NULL) {
lpiwowar 0:ca75772f63a0 153 new_cell = init_snake(snake->x, snake->y);
lpiwowar 0:ca75772f63a0 154 new_cell->head = false;
lpiwowar 0:ca75772f63a0 155 }
lpiwowar 0:ca75772f63a0 156
lpiwowar 0:ca75772f63a0 157 if(snake->head) {
lpiwowar 0:ca75772f63a0 158 switch(move_direction) {
lpiwowar 0:ca75772f63a0 159 case SNAKE_UP:
lpiwowar 0:ca75772f63a0 160 prev_x = snake->x; prev_y = snake->y;
lpiwowar 0:ca75772f63a0 161 field[snake->y][snake->x] = ' ';
lpiwowar 0:ca75772f63a0 162 snake->y -= 1;
lpiwowar 0:ca75772f63a0 163 field[snake->y][snake->x] = '#';
lpiwowar 0:ca75772f63a0 164 break;
lpiwowar 0:ca75772f63a0 165 case SNAKE_DOWN:
lpiwowar 0:ca75772f63a0 166 prev_x = snake->x; prev_y = snake->y;
lpiwowar 0:ca75772f63a0 167 field[snake->y][snake->x] = ' ';
lpiwowar 0:ca75772f63a0 168 snake->y += 1;
lpiwowar 0:ca75772f63a0 169 field[snake->y][snake->x] = '#';
lpiwowar 0:ca75772f63a0 170 break;
lpiwowar 0:ca75772f63a0 171 case SNAKE_RIGHT:
lpiwowar 0:ca75772f63a0 172 prev_x = snake->x; prev_y = snake->y;
lpiwowar 0:ca75772f63a0 173 field[snake->y][snake->x] = ' ';
lpiwowar 0:ca75772f63a0 174 snake->x += 1;
lpiwowar 0:ca75772f63a0 175 field[snake->y][snake->x] = '#';
lpiwowar 0:ca75772f63a0 176 break;
lpiwowar 0:ca75772f63a0 177 case SNAKE_LEFT:
lpiwowar 0:ca75772f63a0 178 prev_x = snake->x; prev_y = snake->y;
lpiwowar 0:ca75772f63a0 179 field[snake->y][snake->x] = ' ';
lpiwowar 0:ca75772f63a0 180 snake->x -= 1;
lpiwowar 0:ca75772f63a0 181 field[snake->y][snake->x] = '#';
lpiwowar 0:ca75772f63a0 182 break;
lpiwowar 0:ca75772f63a0 183 }
lpiwowar 0:ca75772f63a0 184 } else {
lpiwowar 0:ca75772f63a0 185 field[snake->y][snake->x] = ' ';
lpiwowar 0:ca75772f63a0 186 field[prev_y][prev_x] = '#';
lpiwowar 0:ca75772f63a0 187 tmp = snake->x; snake->x = prev_x; prev_x = tmp;
lpiwowar 0:ca75772f63a0 188 tmp = snake->y; snake->y = prev_y; prev_y = tmp;
lpiwowar 0:ca75772f63a0 189 }
lpiwowar 0:ca75772f63a0 190
lpiwowar 0:ca75772f63a0 191 snake = snake->next_cell;
lpiwowar 0:ca75772f63a0 192 }
lpiwowar 0:ca75772f63a0 193
lpiwowar 0:ca75772f63a0 194 if(food_found) {
lpiwowar 0:ca75772f63a0 195 append_cell_to_snake(save_snake, new_cell);
lpiwowar 0:ca75772f63a0 196 return FOOD_FOUND;
lpiwowar 0:ca75772f63a0 197 }
lpiwowar 0:ca75772f63a0 198 else {
lpiwowar 0:ca75772f63a0 199 return 0;
lpiwowar 0:ca75772f63a0 200 }
lpiwowar 0:ca75772f63a0 201 }
lpiwowar 0:ca75772f63a0 202
lpiwowar 0:ca75772f63a0 203 ////////////////////////////////////////////////////////////////////////////////
lpiwowar 0:ca75772f63a0 204 /// SNAKE - end ///
lpiwowar 0:ca75772f63a0 205 ////////////////////////////////////////////////////////////////////////////////
lpiwowar 0:ca75772f63a0 206
lpiwowar 0:ca75772f63a0 207 ////////////////////////////////////////////////////////////////////////////////
lpiwowar 0:ca75772f63a0 208 /// MENU - start ///
lpiwowar 0:ca75772f63a0 209 ////////////////////////////////////////////////////////////////////////////////
lpiwowar 0:ca75772f63a0 210
lpiwowar 0:ca75772f63a0 211 typedef enum {EASY, DIFFICULT, SUPER_DIFFICULT} difficulty_T;
lpiwowar 0:ca75772f63a0 212 TSISensor tsi;
lpiwowar 0:ca75772f63a0 213
lpiwowar 0:ca75772f63a0 214 void print_menu(difficulty_T difficulty, float time_left) {
lpiwowar 0:ca75772f63a0 215 term.cls();
lpiwowar 0:ca75772f63a0 216 term.move_cursor_up(FIELD_HEIGHT + 3);
lpiwowar 0:ca75772f63a0 217
lpiwowar 0:ca75772f63a0 218 for(int i = 0; i != FIELD_HEIGHT/3; i++)
lpiwowar 0:ca75772f63a0 219 term.printf("\r\n");
lpiwowar 0:ca75772f63a0 220
lpiwowar 0:ca75772f63a0 221 for(int i = 0; i != (FIELD_WIDTH - strlen("Please select dificulty)"))/2; i++)
lpiwowar 0:ca75772f63a0 222 term.printf(" ");
lpiwowar 0:ca75772f63a0 223
lpiwowar 0:ca75772f63a0 224 term.printf("Please selectt dificulty (%1.1f)", time_left);
lpiwowar 0:ca75772f63a0 225 term.printf("\r\n");
lpiwowar 0:ca75772f63a0 226
lpiwowar 0:ca75772f63a0 227 for(int i = 0; i != (FIELD_WIDTH - strlen("Please select dificulty)"))/2; i++)
lpiwowar 0:ca75772f63a0 228 term.printf(" ");
lpiwowar 0:ca75772f63a0 229
lpiwowar 0:ca75772f63a0 230 switch(difficulty) {
lpiwowar 0:ca75772f63a0 231 case EASY:
lpiwowar 0:ca75772f63a0 232 term.printf("[*]Eeasy [ ]Difficult [ ]Super Difficult\r\n");
lpiwowar 0:ca75772f63a0 233 break;
lpiwowar 0:ca75772f63a0 234 case DIFFICULT:
lpiwowar 0:ca75772f63a0 235 term.printf("[ ]Eeasy [*]Difficult [ ]Super Difficult\r\n");
lpiwowar 0:ca75772f63a0 236 break;
lpiwowar 0:ca75772f63a0 237 case SUPER_DIFFICULT:
lpiwowar 0:ca75772f63a0 238 term.printf("[ ]Eeasy [ ]Difficult [*]Super Difficult\r\n");
lpiwowar 0:ca75772f63a0 239 break;
lpiwowar 0:ca75772f63a0 240 }
lpiwowar 0:ca75772f63a0 241 }
lpiwowar 0:ca75772f63a0 242
lpiwowar 0:ca75772f63a0 243 difficulty_T get_difficulty() {
lpiwowar 0:ca75772f63a0 244 difficulty_T save_state = EASY;
lpiwowar 0:ca75772f63a0 245 float total_time = 10.0;
lpiwowar 0:ca75772f63a0 246 float elapsed_time = 0.0;
lpiwowar 0:ca75772f63a0 247 while(1) {
lpiwowar 0:ca75772f63a0 248
lpiwowar 0:ca75772f63a0 249 float percentage = tsi.readPercentage();
lpiwowar 0:ca75772f63a0 250
lpiwowar 0:ca75772f63a0 251 if(percentage <= 0.3 && percentage >= 0.05) {
lpiwowar 0:ca75772f63a0 252 print_menu(EASY, total_time - elapsed_time);
lpiwowar 0:ca75772f63a0 253 save_state = EASY;
lpiwowar 0:ca75772f63a0 254 } else if(percentage > 0.3 && percentage <= 0.6) {
lpiwowar 0:ca75772f63a0 255 print_menu(DIFFICULT, total_time - elapsed_time);
lpiwowar 0:ca75772f63a0 256 save_state = DIFFICULT;
lpiwowar 0:ca75772f63a0 257 } else if(percentage > 0.6) {
lpiwowar 0:ca75772f63a0 258 print_menu(SUPER_DIFFICULT, total_time - elapsed_time);
lpiwowar 0:ca75772f63a0 259 save_state = SUPER_DIFFICULT;
lpiwowar 0:ca75772f63a0 260 } else {
lpiwowar 0:ca75772f63a0 261 print_menu(save_state, total_time - elapsed_time);
lpiwowar 0:ca75772f63a0 262 }
lpiwowar 0:ca75772f63a0 263
lpiwowar 0:ca75772f63a0 264 wait(0.1);
lpiwowar 0:ca75772f63a0 265 elapsed_time += 0.1;
lpiwowar 0:ca75772f63a0 266 if(elapsed_time > 10.0)
lpiwowar 0:ca75772f63a0 267 break;
lpiwowar 0:ca75772f63a0 268 }
lpiwowar 0:ca75772f63a0 269
lpiwowar 0:ca75772f63a0 270 return save_state;
lpiwowar 0:ca75772f63a0 271 }
lpiwowar 0:ca75772f63a0 272
lpiwowar 0:ca75772f63a0 273 ////////////////////////////////////////////////////////////////////////////////
lpiwowar 0:ca75772f63a0 274 /// MENU - end ///
lpiwowar 0:ca75772f63a0 275 ////////////////////////////////////////////////////////////////////////////////
lpiwowar 0:ca75772f63a0 276
lpiwowar 0:ca75772f63a0 277 /**
lpiwowar 0:ca75772f63a0 278 * @brief Initializes the game field with walls and snake.
lpiwowar 0:ca75772f63a0 279 */
lpiwowar 0:ca75772f63a0 280 void init_field() {
lpiwowar 0:ca75772f63a0 281 for(int i = 0; i < FIELD_WIDTH; i++)
lpiwowar 0:ca75772f63a0 282 field[0][i] = '#';
lpiwowar 0:ca75772f63a0 283
lpiwowar 0:ca75772f63a0 284 for(int y = 1; y < FIELD_HEIGHT - 1; y++) {
lpiwowar 0:ca75772f63a0 285 field[y][0] = '#';
lpiwowar 0:ca75772f63a0 286 field[y][FIELD_WIDTH - 1] = '#';
lpiwowar 0:ca75772f63a0 287
lpiwowar 0:ca75772f63a0 288 if(y == INIT_SNAKE_Y)
lpiwowar 0:ca75772f63a0 289 field[INIT_SNAKE_Y][INIT_SNAKE_X] = '#';
lpiwowar 0:ca75772f63a0 290
lpiwowar 0:ca75772f63a0 291 for(int x = 1; x < FIELD_WIDTH - 1; x++) {
lpiwowar 0:ca75772f63a0 292 field[y][x] = ' ';
lpiwowar 0:ca75772f63a0 293 }
lpiwowar 0:ca75772f63a0 294 }
lpiwowar 0:ca75772f63a0 295
lpiwowar 0:ca75772f63a0 296 for(int i = 0; i < FIELD_WIDTH; i++)
lpiwowar 0:ca75772f63a0 297 field[FIELD_HEIGHT - 1][i] = '#';
lpiwowar 0:ca75772f63a0 298 }
lpiwowar 0:ca75772f63a0 299
lpiwowar 0:ca75772f63a0 300 /**
lpiwowar 0:ca75772f63a0 301 * @brief Prints the game field.
lpiwowar 0:ca75772f63a0 302 */
lpiwowar 0:ca75772f63a0 303 void print_field(SerialTerminal &term) {
lpiwowar 0:ca75772f63a0 304 for(int y = 0; y < FIELD_HEIGHT; y++) {
lpiwowar 0:ca75772f63a0 305
lpiwowar 0:ca75772f63a0 306 for(int x = 0; x < FIELD_WIDTH; x++)
lpiwowar 0:ca75772f63a0 307 term.printf("%c", field[y][x]);
lpiwowar 0:ca75772f63a0 308
lpiwowar 0:ca75772f63a0 309 term.printf("\r\n");
lpiwowar 0:ca75772f63a0 310 }
lpiwowar 0:ca75772f63a0 311 }
lpiwowar 0:ca75772f63a0 312
lpiwowar 0:ca75772f63a0 313 /**
lpiwowar 0:ca75772f63a0 314 * @brief Clears the terminal.
lpiwowar 0:ca75772f63a0 315 */
lpiwowar 0:ca75772f63a0 316 void clear_field(SerialTerminal &term) {
lpiwowar 0:ca75772f63a0 317 term.cls();
lpiwowar 0:ca75772f63a0 318 term.move_cursor_up(FIELD_HEIGHT + 3);
lpiwowar 0:ca75772f63a0 319 }
lpiwowar 0:ca75772f63a0 320
lpiwowar 0:ca75772f63a0 321 /**
lpiwowar 0:ca75772f63a0 322 * @brief Generates food and puts it to the game field.
lpiwowar 0:ca75772f63a0 323 */
lpiwowar 0:ca75772f63a0 324 void generate_food() {
lpiwowar 0:ca75772f63a0 325 bool not_found = true;
lpiwowar 0:ca75772f63a0 326
lpiwowar 0:ca75772f63a0 327 while(not_found) {
lpiwowar 0:ca75772f63a0 328 int food_x = (rand() % (FIELD_WIDTH - 6)) + 3;
lpiwowar 0:ca75772f63a0 329 int food_y = (rand() % (FIELD_HEIGHT - 6)) + 3;
lpiwowar 0:ca75772f63a0 330
lpiwowar 0:ca75772f63a0 331 if(field[food_y][food_x] == ' ') {
lpiwowar 0:ca75772f63a0 332 field[food_y][food_x] = '*';
lpiwowar 0:ca75772f63a0 333 not_found = false;
lpiwowar 0:ca75772f63a0 334 }
lpiwowar 0:ca75772f63a0 335 }
lpiwowar 0:ca75772f63a0 336 }
lpiwowar 0:ca75772f63a0 337
lpiwowar 0:ca75772f63a0 338 /**
lpiwowar 0:ca75772f63a0 339 * @brief Gets the direction of required direction of snake based on values
lpiwowar 0:ca75772f63a0 340 * from accelerometer.
lpiwowar 0:ca75772f63a0 341 */
lpiwowar 0:ca75772f63a0 342 snake_move_T get_direction(int score_counter) {
lpiwowar 0:ca75772f63a0 343 float up_down = acc.getAccX(); /* - = UP, + = DOWN */
lpiwowar 0:ca75772f63a0 344 float left_right = acc.getAccY(); /* - = LEFT, + = RIGHT */
lpiwowar 0:ca75772f63a0 345
lpiwowar 0:ca75772f63a0 346 static snake_move_T remember_last_dir = SNAKE_NONE;
lpiwowar 0:ca75772f63a0 347
lpiwowar 0:ca75772f63a0 348 if(abs(up_down) > abs(left_right)) {
lpiwowar 0:ca75772f63a0 349 if(up_down <= -0.25) {
lpiwowar 0:ca75772f63a0 350 if(score_counter != 0 && remember_last_dir == SNAKE_DOWN)
lpiwowar 0:ca75772f63a0 351 return remember_last_dir;
lpiwowar 0:ca75772f63a0 352 remember_last_dir = SNAKE_UP;
lpiwowar 0:ca75772f63a0 353 return SNAKE_UP;
lpiwowar 0:ca75772f63a0 354 }
lpiwowar 0:ca75772f63a0 355
lpiwowar 0:ca75772f63a0 356 if(up_down >= 0.25) {
lpiwowar 0:ca75772f63a0 357 if(score_counter != 0 && remember_last_dir == SNAKE_UP)
lpiwowar 0:ca75772f63a0 358 return remember_last_dir;
lpiwowar 0:ca75772f63a0 359 remember_last_dir = SNAKE_DOWN;
lpiwowar 0:ca75772f63a0 360 return SNAKE_DOWN;
lpiwowar 0:ca75772f63a0 361 }
lpiwowar 0:ca75772f63a0 362
lpiwowar 0:ca75772f63a0 363 } else {
lpiwowar 0:ca75772f63a0 364 if (left_right <= -0.25) {
lpiwowar 0:ca75772f63a0 365 if(score_counter != 0 && remember_last_dir == SNAKE_RIGHT)
lpiwowar 0:ca75772f63a0 366 return remember_last_dir;
lpiwowar 0:ca75772f63a0 367 remember_last_dir = SNAKE_LEFT;
lpiwowar 0:ca75772f63a0 368 return SNAKE_LEFT;
lpiwowar 0:ca75772f63a0 369 }
lpiwowar 0:ca75772f63a0 370
lpiwowar 0:ca75772f63a0 371 if (left_right >= 0.25) {
lpiwowar 0:ca75772f63a0 372 if(score_counter != 0 && remember_last_dir == SNAKE_LEFT)
lpiwowar 0:ca75772f63a0 373 return remember_last_dir;
lpiwowar 0:ca75772f63a0 374 remember_last_dir = SNAKE_RIGHT;
lpiwowar 0:ca75772f63a0 375 return SNAKE_RIGHT;
lpiwowar 0:ca75772f63a0 376 }
lpiwowar 0:ca75772f63a0 377 }
lpiwowar 0:ca75772f63a0 378
lpiwowar 0:ca75772f63a0 379 if(remember_last_dir != SNAKE_NONE)
lpiwowar 0:ca75772f63a0 380 return remember_last_dir;
lpiwowar 0:ca75772f63a0 381 else
lpiwowar 0:ca75772f63a0 382 return SNAKE_RIGHT;
lpiwowar 0:ca75772f63a0 383 }
lpiwowar 0:ca75772f63a0 384
lpiwowar 0:ca75772f63a0 385 /**
lpiwowar 0:ca75772f63a0 386 * @brief The higher the score the shorter time this function waits. If the
lpiwowar 0:ca75772f63a0 387 * snake is moving horizontally the function waits shorter period of
lpiwowar 0:ca75772f63a0 388 * time to compensate that letter's height is bigger than width;
lpiwowar 0:ca75772f63a0 389 */
lpiwowar 0:ca75772f63a0 390 void score_wait(int score_counter,
lpiwowar 0:ca75772f63a0 391 snake_move_T snake_direction,
lpiwowar 0:ca75772f63a0 392 difficulty_T difficulty) {
lpiwowar 0:ca75772f63a0 393
lpiwowar 0:ca75772f63a0 394 float time = 1;
lpiwowar 0:ca75772f63a0 395
lpiwowar 0:ca75772f63a0 396 if (difficulty == EASY) time = 1;
lpiwowar 0:ca75772f63a0 397 else if (difficulty == DIFFICULT) time = 0.6;
lpiwowar 0:ca75772f63a0 398 else if(difficulty == SUPER_DIFFICULT) time = 0.4;
lpiwowar 0:ca75772f63a0 399
lpiwowar 0:ca75772f63a0 400 if (score_counter > 5) time = time / 3;
lpiwowar 0:ca75772f63a0 401 else if (score_counter > 10) time = time / 5;
lpiwowar 0:ca75772f63a0 402 else if (score_counter > 15) time = time / 6;
lpiwowar 0:ca75772f63a0 403
lpiwowar 0:ca75772f63a0 404 if(snake_direction == SNAKE_RIGHT || snake_direction == SNAKE_LEFT)
lpiwowar 0:ca75772f63a0 405 wait(time/2);
lpiwowar 0:ca75772f63a0 406 else
lpiwowar 0:ca75772f63a0 407 wait(time);
lpiwowar 0:ca75772f63a0 408
lpiwowar 0:ca75772f63a0 409 }
lpiwowar 0:ca75772f63a0 410
lpiwowar 0:ca75772f63a0 411 //void blick_red_diode() {
lpiwowar 0:ca75772f63a0 412 //}
lpiwowar 0:ca75772f63a0 413
lpiwowar 0:ca75772f63a0 414 /**
lpiwowar 0:ca75772f63a0 415 * @brief Lights up diode with collor corresponding to actual speed of the
lpiwowar 0:ca75772f63a0 416 * snake. (e.g.: snake moves slowly => green, snakes moves fast => red)
lpiwowar 0:ca75772f63a0 417 */
lpiwowar 0:ca75772f63a0 418 void light_up_diode(int score_counter, difficulty_T difficulty) {
lpiwowar 0:ca75772f63a0 419 static bool lock = false;
lpiwowar 0:ca75772f63a0 420 if(lock) return;
lpiwowar 0:ca75772f63a0 421
lpiwowar 0:ca75772f63a0 422 float new_red = 1.0 - (1.0/2.0 * (float)score_counter);
lpiwowar 0:ca75772f63a0 423 float new_green = 0.0 + (1.0/2.0 * (float)score_counter);
lpiwowar 0:ca75772f63a0 424 rled = new_red;
lpiwowar 0:ca75772f63a0 425 gled = new_green;
lpiwowar 0:ca75772f63a0 426
lpiwowar 0:ca75772f63a0 427 if(new_green >= 0.99) {
lpiwowar 0:ca75772f63a0 428 lock = true;
lpiwowar 0:ca75772f63a0 429 //timeout.attach(&blick_red_diode, 10000);
lpiwowar 0:ca75772f63a0 430 }
lpiwowar 0:ca75772f63a0 431 }
lpiwowar 0:ca75772f63a0 432
lpiwowar 0:ca75772f63a0 433 int main(void) {
lpiwowar 0:ca75772f63a0 434 rled = 1; gled = 1;
lpiwowar 0:ca75772f63a0 435
lpiwowar 0:ca75772f63a0 436 term.hide_cursor();
lpiwowar 0:ca75772f63a0 437 init_field();
lpiwowar 0:ca75772f63a0 438 generate_food();
lpiwowar 0:ca75772f63a0 439
lpiwowar 0:ca75772f63a0 440 difficulty_T difficulty = get_difficulty();
lpiwowar 0:ca75772f63a0 441 snake_cell_T *snake = init_snake(INIT_SNAKE_X, INIT_SNAKE_Y);
lpiwowar 0:ca75772f63a0 442 int ret_update_snake = update_snake_pos(snake, SNAKE_RIGHT);
lpiwowar 0:ca75772f63a0 443
lpiwowar 0:ca75772f63a0 444 int score_counter = 0;
lpiwowar 0:ca75772f63a0 445 while(42) {
lpiwowar 0:ca75772f63a0 446 clear_field(term);
lpiwowar 0:ca75772f63a0 447
lpiwowar 0:ca75772f63a0 448 snake_move_T snake_direction = get_direction(score_counter);
lpiwowar 0:ca75772f63a0 449 ret_update_snake = update_snake_pos(snake, snake_direction);
lpiwowar 0:ca75772f63a0 450
lpiwowar 0:ca75772f63a0 451 if(ret_update_snake == WALL)
lpiwowar 0:ca75772f63a0 452 break;
lpiwowar 0:ca75772f63a0 453 else if(ret_update_snake == FOOD_FOUND) {
lpiwowar 0:ca75772f63a0 454 generate_food();
lpiwowar 0:ca75772f63a0 455 score_counter++;
lpiwowar 0:ca75772f63a0 456 }
lpiwowar 0:ca75772f63a0 457
lpiwowar 0:ca75772f63a0 458
lpiwowar 0:ca75772f63a0 459 term.printf("Score:%d\r\n", score_counter);
lpiwowar 0:ca75772f63a0 460 print_field(term);
lpiwowar 0:ca75772f63a0 461
lpiwowar 0:ca75772f63a0 462 score_wait(score_counter, snake_direction, difficulty);
lpiwowar 0:ca75772f63a0 463 light_up_diode(score_counter, difficulty);
lpiwowar 0:ca75772f63a0 464 }
lpiwowar 0:ca75772f63a0 465
lpiwowar 0:ca75772f63a0 466 clear_field(term);
lpiwowar 0:ca75772f63a0 467 destroy_snake(snake);
lpiwowar 0:ca75772f63a0 468 term.printf("GAME OVER! (You score: %d)", score_counter);
lpiwowar 0:ca75772f63a0 469 destroy_snake(snake);
lpiwowar 0:ca75772f63a0 470 }