📄 snake.c
字号:
/*
** snake.c
**
** Written by Peter Sutton - October 2004
**
** Details of the snake
*/
#include "snake.h"
#include "board.h"
#define MAX_SNAKE_ELEMENTS 16
/* A snake is made up of some number of elements.
** An element consists of a start position, a direction and
** the number of blocks in that element (i.e. element length).
** (If the element length is 1, then only the element at
** the start position is filled in.) No snake element
** should have a length of 0.
*/
typedef struct {
posn_type start;
int8_t dirn;
int8_t len;
} element_type;
/* Global variables */
/* Position of all elements of the snake - we can't
** have more than the maximum. We also keep track
** of the position of the head of the snake.
*/
element_type snake_elements[MAX_SNAKE_ELEMENTS];
posn_type snake_head_position;
/*
** Variable to keep track of the number of
** elements in the snake - should always be at
** least 1.
*/
int8_t num_snake_elements;
/*
** Variable to keep track of the current direction
** of the snake and the next direction of the
** snake. (The current direction will become the
** next direction when we move the snake.) The
** directions must be one of LEFT, RIGHT,
** UP or DOWN. (We keep track of both of these
** because (1) we allow directions to be changed
** multiple times between moves (and only the last
** one will count) and (2) we can never allow the
** snake to go back on itself, it's only possible
** to turn 90degrees.
*/
int8_t cur_snake_dirn;
int8_t next_snake_dirn;
/* FUNCTIONS */
/********** init_snake() **********
**
** Resets out snake to the initial configuration
*/
void init_snake(void) {
int8_t x;
int8_t y;
/* We have only one element */
num_snake_elements = 1;
/* The initial position of the snake is the centre
** of the board, length of 2, moving right
*/
x = BOARD_WIDTH / 2 - 1;
y = BOARD_ROWS / 2;
snake_elements[0].start.x = x;
snake_elements[0].start.y = y;
snake_elements[0].dirn = RIGHT;
snake_elements[0].len = 2;
cur_snake_dirn = RIGHT;
next_snake_dirn = RIGHT;
snake_head_position.x = x+1;
snake_head_position.y = y;
/* Make sure the element is represented on the board.
** The board must have been initialised before calling
** this function.
*/
update_snake_block(x, y, 1);
update_snake_block(x+1, y, 1);
}
/*
** get_snake_head_position()
**
** Returns the position of the head of the snake.
** We look at the last element in the snake and
** work out its end position based on its start
** position and length.
*/
posn_type get_snake_head_position(void) {
return snake_head_position;
}
/*
** move_snake()
**
** Attempt to move the snake by one in the current direction.
** Returns -1 if the snake has run into the edge or itself,
** 0 if the move is successful, 1 if the snake has eaten
** some food (and grown). If the snake has too many bends
** (i.e. the move would create an extra element beyond
** our element array then any attempt to turn is rejected.
*/
int8_t move_snake(void) {
int8_t food_at_head;
element_type* last_elmnt;
posn_type new_head_posn;
last_elmnt = &snake_elements[num_snake_elements - 1];
/* Work out where the new head position should be - we
** move 1 position in our NEXT direction of movement.
*/
new_head_posn = snake_head_position;
switch (next_snake_dirn) {
case UP:
new_head_posn.y -= 1;
break;
case DOWN:
new_head_posn.y += 1;
break;
case LEFT:
new_head_posn.x -= 1;
break;
case RIGHT:
new_head_posn.x += 1;
break;
}
if(is_off_board(new_head_posn.x, new_head_posn.y)) {
/* Snake would run off board */
return OUT_OF_BOUNDS;
}
if(is_snake_at(new_head_posn.x, new_head_posn.y)) {
/* Snake would run into itself */
return COLLISION;
}
/* Check if there is food at the head position
** Value will be -1 if no food, otherwise value will
** be the food ID
*/
food_at_head = food_at(new_head_posn.x, new_head_posn.y);
/*
** If we get here, the move should be possible.
** Advance head by 1.
*/
if(next_snake_dirn == cur_snake_dirn) {
/* Last element is going in the right direction - just
** extend it
*/
last_elmnt->len++;
} else {
/* Last element is going in a different direction - need
** to add an element (if possible)
*/
if(num_snake_elements == MAX_SNAKE_ELEMENTS) {
/* Can't change direction since we've run out of space
** to store snake elements - restore directon to original
** and try again (recursively, but recursion depth will
** never be more than 1).
*/
next_snake_dirn = cur_snake_dirn;
return move_snake();
} else {
/* Add an element to our list of elements */
last_elmnt++; /* Advance list_elmnt pointer */
num_snake_elements++;
last_elmnt->start.x = new_head_posn.x;
last_elmnt->start.y = new_head_posn.y;
last_elmnt->dirn = next_snake_dirn;
last_elmnt->len = 1;
cur_snake_dirn = next_snake_dirn;
}
}
update_snake_block(new_head_posn.x, new_head_posn.y, 1);
snake_head_position = new_head_posn;
if(food_at_head == -1) {
/* No food at head, we need to move the tail along by 1
** (and possibly reclaim an element from our array if
** that element is now finished
*/
update_snake_block(snake_elements[0].start.x,
snake_elements[0].start.y, 0);
if(snake_elements[0].len == 1) {
/* First element is only 1 long, time to
** remove it. We shuffle all snake elements
** along.
*/
int8_t i;
for(i=1; i< num_snake_elements; i++) {
snake_elements[i-1] = snake_elements[i];
}
num_snake_elements--;
} else {
/* Just decrease the length of the first element
** (We need to advance the start position also,
** based on the directon of travel of the
** first element.)
*/
snake_elements[0].len--;
switch(snake_elements[0].dirn) {
case UP:
snake_elements[0].start.y -= 1;
break;
case DOWN:
snake_elements[0].start.y += 1;
break;
case LEFT:
snake_elements[0].start.x -= 1;
break;
case RIGHT:
snake_elements[0].start.x += 1;
break;
}
}
return MOVE_OK;
} else {
/* Food at head - snake has grown (we haven't moved
** the tail).
*/
consume_food(food_at_head);
return ATE_FOOD;
}
}
/* set_snake_dirn
** Attempt to set the next snake direction to one of
** UP, DOWN, LEFT or RIGHT. Returns 1 if successful,
** 0 otherwise.
** (Will fail if try and reverse snake from its current
** direction.)
** It's OK to continue in same direction or turn 90degrees.
*/
int8_t set_snake_dirn(int8_t dirn) {
/*
** Snake directon is opposite if snake_dirn and dirn
** are 2 different
*/
if(cur_snake_dirn - dirn == 2 ||
cur_snake_dirn - dirn == -2) {
/* Can't reverse snake instantaneously */
return 0;
} else {
next_snake_dirn = dirn;
return 1;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -