272 lines
5.8 KiB
C
272 lines
5.8 KiB
C
|
#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);
|
|||
|
|
|||
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȳ<EFBFBD><C8B3><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD>߿<EFBFBD><DFBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD>Խǽ<D4BD><C7BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
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])
|
|||
|
{
|
|||
|
// <20><>һ<EFBFBD><D2BB>ʳ<EFBFBD><CAB3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ڵ<EFBFBD>
|
|||
|
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])
|
|||
|
{
|
|||
|
// <20><>β<EFBFBD><CEB2><EFBFBD>ĺ<DEB8><C4BA>õ<EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
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;
|
|||
|
}
|
|||
|
|
|||
|
// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD>ȵ<EFBFBD><C8B5><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD>
|
|||
|
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; // <20><><EFBFBD><EFBFBD><EFBFBD>ӳ<EFBFBD><D3B3><EFBFBD><EFBFBD>ӣ<EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>λ<EFBFBD><CEBB>
|
|||
|
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;
|
|||
|
|
|||
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȳ<EFBFBD><C8B3><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD>߿<EFBFBD><DFBF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD>Խǽ<D4BD><C7BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
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;
|
|||
|
}
|
|||
|
|
|||
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʳ<EFBFBD><CAB3>
|
|||
|
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);
|
|||
|
|
|||
|
// ȡ<><C8A1>ͷβ<CDB7><CEB2><EFBFBD><EFBFBD><EFBFBD>ڵ㣬<DAB5><E3A3AC><EFBFBD><EFBFBD><EFBFBD>ڵ㲻<DAB5><E3B2BB>Ҫ<EFBFBD>ı<EFBFBD>
|
|||
|
tail = rt_list_entry(snake_head.prev, snake_t, list);
|
|||
|
head = rt_list_entry(snake_head.next, snake_t, list);
|
|||
|
|
|||
|
node = head->body;
|
|||
|
|
|||
|
// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>µ<EFBFBD><C2B5><EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD>
|
|||
|
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);
|
|||
|
}
|