⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 snake.c

📁 snake game in avr snake game in avr
💻 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 + -