snake.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. #include <string.h>
  2. #include <stdlib.h>
  3. #include <rtthread.h>
  4. #include "snake.h"
  5. rt_list_t snake_head;
  6. SNAKE_DIR prevdir;
  7. static SNAKE_DIR dir_adjust(SNAKE_DIR dir)
  8. {
  9. if ( (SNAKE_DIR_UP == prevdir && SNAKE_DIR_DOWN != dir)
  10. || (SNAKE_DIR_DOWN == prevdir && SNAKE_DIR_UP != dir)
  11. || (SNAKE_DIR_LEFT == prevdir && SNAKE_DIR_RIGHT != dir)
  12. || (SNAKE_DIR_RIGHT == prevdir && SNAKE_DIR_LEFT != dir)
  13. )
  14. {
  15. prevdir = dir;
  16. }
  17. else
  18. {
  19. rt_kprintf("dirction change error\n\r");
  20. }
  21. return prevdir;
  22. }
  23. static void across_XY(point_t *node, const map_t *map)
  24. {
  25. RT_ASSERT(node != RT_NULL && map != RT_NULL);
  26. // 如果长度超出当前边框则可以穿越墙到对面
  27. node->x = (node->x + map->width) % map->width;
  28. node->y = (node->y + map->height) % map->height;
  29. }
  30. static SYS_STE node_update(snake_t *tail, const point_t *node, map_t *map)
  31. {
  32. SYS_STE ret;
  33. point_t *pos;
  34. RT_ASSERT(tail != RT_NULL && node != RT_NULL && map != RT_NULL);
  35. pos = map->snake_flush;
  36. pos[0].x = pos[0].y = -1;
  37. pos[1].x = pos[1].y = -1;
  38. ret = (SYS_STE)map->range[node->y * map->width + node->x];
  39. if (FOOD == map->range[node->y * map->width + node->x])
  40. {
  41. // 吃一个食物增加一个节点
  42. snake_t *new = (snake_t*)rt_malloc(sizeof(snake_t));
  43. if (!new)
  44. return NORMAL;
  45. pos[0] = *node;
  46. new->body = *node;
  47. rt_list_insert_after(&snake_head, &new->list);
  48. }
  49. else if (NORMAL == map->range[node->y * map->width + node->x])
  50. {
  51. // 将尾巴修改后拿到头部,其他不变
  52. rt_list_remove(&tail->list);
  53. map->range[tail->body.y * map->width + tail->body.x] = NORMAL;
  54. pos[0] = *node;
  55. pos[1] = tail->body;
  56. tail->body = *node;
  57. rt_list_insert_after(&snake_head, &tail->list);
  58. }
  59. map->range[node->y * map->width + node->x] = OVER;
  60. return ret;
  61. }
  62. map_t* map_init(rt_uint32_t width, rt_uint32_t heigth)
  63. {
  64. map_t *map = rt_malloc(sizeof(map_t));
  65. if (map != RT_NULL)
  66. {
  67. map->range = rt_malloc(heigth * width);
  68. if (!map->range)
  69. {
  70. rt_free(map);
  71. map = RT_NULL;
  72. }
  73. else
  74. {
  75. map->width = width;
  76. map->height = heigth;
  77. memset(map->range, NORMAL, heigth * width);
  78. }
  79. }
  80. return map;
  81. }
  82. // 构造一条指定长度的蛇在指定点
  83. rt_bool_t snake_init(const point_t *start, const int length, const SNAKE_DIR dir, map_t *map)
  84. {
  85. rt_int32_t i;
  86. rt_int32_t inc_x, inc_y;
  87. point_t old = *start;
  88. rt_list_init(&snake_head);
  89. if (dir == SNAKE_DIR_UP || dir == SNAKE_DIR_DOWN)
  90. {
  91. if (map->height <= length)
  92. return RT_FALSE;
  93. inc_x = 0;
  94. inc_y = dir == SNAKE_DIR_DOWN ? 1 : -1; // 反向延长身子,头部在指定位置
  95. old.y -= inc_y;
  96. }
  97. else
  98. {
  99. if (map->width <= length)
  100. return RT_FALSE;
  101. inc_y = 0;
  102. inc_x = dir == SNAKE_DIR_RIGHT ? -1 : 1;
  103. old.x -= inc_x;
  104. }
  105. for (i=0; i<length; i++)
  106. {
  107. snake_t *new = (snake_t*)rt_malloc(sizeof(snake_t));
  108. if (!new)
  109. return RT_FALSE;
  110. new->body.y = inc_y + old.y;
  111. new->body.x = inc_x + old.x;
  112. // 如果长度超出当前边框则可以穿越墙到对面
  113. across_XY(&new->body, map);
  114. map->range[new->body.y * map->width + new->body.x] = OVER;
  115. old = new->body;
  116. rt_list_insert_before(&snake_head, &new->list);
  117. }
  118. prevdir = dir;
  119. return RT_TRUE;
  120. }
  121. // 构造出食物
  122. rt_bool_t food_init(map_t *map, rt_uint32_t max_num)
  123. {
  124. point_t food;
  125. #ifndef FOOD_TIMEOUT
  126. #define FOOD_TIMEOUT 10
  127. #endif
  128. rt_uint32_t timeout, num;
  129. num = 0;
  130. timeout = rt_tick_get();
  131. srand(rand());
  132. map->food_flush[0].x = map->food_flush[0].y = -1;
  133. do
  134. {
  135. food.x = rand() % map->width;
  136. food.y = rand() % map->height;
  137. if (map->range[food.y * map->width + food.x] == NORMAL)
  138. {
  139. map->food_flush[0] = food;
  140. map->range[food.y * map->width + food.x] = FOOD;
  141. num++;
  142. }
  143. }
  144. while (num < max_num && rt_tick_get() - timeout < FOOD_TIMEOUT);
  145. return num;
  146. }
  147. void map_deinit(map_t *map)
  148. {
  149. if (map)
  150. {
  151. if (map->range)
  152. {
  153. rt_free(map->range);
  154. map->range = RT_NULL;
  155. }
  156. rt_free(map);
  157. }
  158. }
  159. void snake_deinit(void)
  160. {
  161. snake_t *node;
  162. while (!rt_list_isempty(&snake_head))
  163. {
  164. node = rt_list_entry(snake_head.prev, snake_t, list);
  165. rt_list_remove(&node->list);
  166. rt_free(node);
  167. }
  168. }
  169. void food_deinit(void)
  170. {
  171. }
  172. SYS_STE snake_step(SNAKE_DIR dir, map_t *map)
  173. {
  174. snake_t *tail, *head;
  175. point_t node;
  176. dir = dir_adjust(dir);
  177. // 取出头尾两个节点,其他节点不需要改变
  178. tail = rt_list_entry(snake_head.prev, snake_t, list);
  179. head = rt_list_entry(snake_head.next, snake_t, list);
  180. node = head->body;
  181. // 构造一个新的蛇头坐标
  182. switch (dir)
  183. {
  184. case SNAKE_DIR_UP:
  185. case SNAKE_DIR_DOWN:
  186. node.y = head->body.y + (dir == SNAKE_DIR_DOWN ? -1 : 1);
  187. break;
  188. case SNAKE_DIR_LEFT:
  189. case SNAKE_DIR_RIGHT:
  190. node.x = head->body.x + (dir == SNAKE_DIR_RIGHT ? 1 : -1);
  191. break;
  192. }
  193. across_XY(&node, map);
  194. return node_update(tail, &node, map);
  195. }
  196. rt_bool_t snake_restart(const point_t *start, const int length, const SNAKE_DIR dir, map_t *map)
  197. {
  198. snake_deinit();
  199. memset(map->range, NORMAL, map->width * map->height);
  200. return snake_init(start, length, dir, map);
  201. }