123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- #include <string.h>
- #include <stdlib.h>
- #include <rtthread.h>
- #include "snake.h"
- #define ASSERT_RET(x, ret) \
- do{ \
- if (x) \
- return ret; \
- }while(0)
- rt_list_t snake_head;
- SNAKE_DIR prevdir, newdir;
- static SNAKE_DIR dir_adjust(SNAKE_DIR dir)
- {
- if ((SNAKE_DIR_UP == prevdir && SNAKE_DIR_DOWN != dir)
- || (SNAKE_DIR_DOWN == prevdir && SNAKE_DIR_UP != dir)
- || (SNAKE_DIR_LEFT == prevdir && SNAKE_DIR_RIGHT != dir)
- || (SNAKE_DIR_RIGHT == prevdir && SNAKE_DIR_LEFT != dir)
- )
- {
- newdir = dir;
- }
- else
- {
- rt_kprintf("dirction change error\n\r");
- }
- return newdir;
- }
- static void across_XY(point_t *node, const map_t *map)
- {
- RT_ASSERT(node != RT_NULL && map != RT_NULL);
- // 如果长度超出当前边框则可以穿越墙到对面
- node->x = (node->x + map->width) % map->width;
- node->y = (node->y + map->height) % map->height;
- }
- static SYS_STE node_update(snake_t *tail, const point_t *node, map_t *map)
- {
- SYS_STE ret;
- point_t *pos;
- RT_ASSERT(tail != RT_NULL && node != RT_NULL && map != RT_NULL);
- pos = map->snake_flush;
- pos[0].x = pos[0].y = -1;
- pos[1].x = pos[1].y = -1;
- ret = (SYS_STE)map->range[node->y * map->width + node->x];
- if (FOOD == map->range[node->y * map->width + node->x])
- {
- // 吃一个食物增加一个节点
- snake_t *new = (snake_t *)rt_malloc(sizeof(snake_t));
- if (!new)
- return NORMAL;
- pos[0] = *node;
- new->body = *node;
- rt_list_insert_after(&snake_head, &new->list);
- }
- else if (NORMAL == map->range[node->y * map->width + node->x])
- {
- // 将尾巴修改后拿到头部,其他不变
- rt_list_remove(&tail->list);
- map->range[tail->body.y * map->width + tail->body.x] = NORMAL;
- pos[0] = *node;
- pos[1] = tail->body;
- tail->body = *node;
- rt_list_insert_after(&snake_head, &tail->list);
- }
- map->range[node->y * map->width + node->x] = OVER;
- if (ret != OVER)
- prevdir = newdir;
- return ret;
- }
- map_t *map_init(rt_uint32_t width, rt_uint32_t heigth)
- {
- map_t *map = rt_malloc(sizeof(map_t));
- if (map != RT_NULL)
- {
- map->range = rt_malloc(heigth * width);
- if (!map->range)
- {
- rt_free(map);
- map = RT_NULL;
- }
- else
- {
- map->width = width;
- map->height = heigth;
- memset(map->range, NORMAL, heigth * width);
- }
- }
- return map;
- }
- // 构造一条指定长度的蛇在指定点
- rt_bool_t snake_init(const point_t *start, const int length, const SNAKE_DIR dir, map_t *map)
- {
- rt_int32_t i;
- rt_int32_t inc_x, inc_y;
- point_t old = *start;
- ASSERT_RET(!map || !start, RT_FALSE);
- rt_list_init(&snake_head);
- if (dir == SNAKE_DIR_UP || dir == SNAKE_DIR_DOWN)
- {
- if (map->height <= length)
- return RT_FALSE;
- inc_x = 0;
- inc_y = dir == SNAKE_DIR_DOWN ? 1 : -1; // 反向延长身子,头部在指定位置
- old.y -= inc_y;
- }
- else
- {
- if (map->width <= length)
- return RT_FALSE;
- inc_y = 0;
- inc_x = dir == SNAKE_DIR_RIGHT ? -1 : 1;
- old.x -= inc_x;
- }
- for (i = 0; i < length; i++)
- {
- snake_t *new = (snake_t *)rt_malloc(sizeof(snake_t));
- if (!new)
- return RT_FALSE;
- new->body.y = inc_y + old.y;
- new->body.x = inc_x + old.x;
- // 如果长度超出当前边框则可以穿越墙到对面
- across_XY(&new->body, map);
- map->range[new->body.y * map->width + new->body.x] = OVER;
- old = new->body;
- rt_list_insert_before(&snake_head, &new->list);
- }
- prevdir = dir;
- return RT_TRUE;
- }
- // 构造出食物
- rt_bool_t food_init(map_t *map, rt_uint32_t max_num)
- {
- point_t food;
- #ifndef FOOD_TIMEOUT
- #define FOOD_TIMEOUT 10
- #endif
- rt_uint32_t timeout, num;
- ASSERT_RET(!map, RT_FALSE);
- num = 0;
- timeout = rt_tick_get();
- srand(rand());
- map->food_flush[0].x = map->food_flush[0].y = -1;
- do
- {
- food.x = rand() % map->width;
- food.y = rand() % map->height;
- if (map->range[food.y * map->width + food.x] == NORMAL)
- {
- map->food_flush[0] = food;
- map->range[food.y * map->width + food.x] = FOOD;
- num++;
- }
- }
- while (num < max_num && rt_tick_get() - timeout < FOOD_TIMEOUT);
- return num;
- }
- void map_deinit(map_t *map)
- {
- if (map)
- {
- if (map->range)
- {
- rt_free(map->range);
- map->range = RT_NULL;
- }
- rt_free(map);
- }
- }
- void snake_deinit(void)
- {
- snake_t *node;
- while (!rt_list_isempty(&snake_head))
- {
- node = rt_list_entry(snake_head.prev, snake_t, list);
- rt_list_remove(&node->list);
- rt_free(node);
- }
- }
- void food_deinit(void)
- {
- }
- SYS_STE snake_step(SNAKE_DIR dir, map_t *map)
- {
- snake_t *tail, *head;
- point_t node;
- ASSERT_RET(!map, RT_FALSE);
- dir = dir_adjust(dir);
- // 取出头尾两个节点,其他节点不需要改变
- tail = rt_list_entry(snake_head.prev, snake_t, list);
- head = rt_list_entry(snake_head.next, snake_t, list);
- node = head->body;
- // 构造一个新的蛇头坐标
- switch (dir)
- {
- case SNAKE_DIR_UP:
- case SNAKE_DIR_DOWN:
- node.y = head->body.y + (dir == SNAKE_DIR_DOWN ? -1 : 1);
- break;
- case SNAKE_DIR_LEFT:
- case SNAKE_DIR_RIGHT:
- node.x = head->body.x + (dir == SNAKE_DIR_RIGHT ? 1 : -1);
- break;
- }
- across_XY(&node, map);
- return node_update(tail, &node, map);
- }
- rt_bool_t snake_restart(const point_t *start, const int length, const SNAKE_DIR dir, map_t *map)
- {
- ASSERT_RET(!map || !start, RT_FALSE);
- snake_deinit();
- memset(map->range, NORMAL, map->width * map->height);
- return snake_init(start, length, dir, map);
- }
|