snake.c 5.8 KB

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