您的位置:

C语言贪吃蛇详解

一、数据结构和算法

C语言贪吃蛇主要运用了以下数据结构和算法:

1. 链表

typedef struct body {
    int x;
    int y;
    struct body *next;
} body;

贪吃蛇身体使用链表来储存,每个节点包括x,y坐标和下一个节点的指针。新的节点插入在头部,旧的节点从尾部删除。

2. 随机数

#include 
srand(time(NULL));
int rand_num = rand() % 4;

  

每次移动时,贪吃蛇会随机生成一个随机数,决定下一步往上、下、左、右哪个方向移动。

3. 碰撞检测

for (body *ptr = snake->next; ptr != NULL; ptr = ptr->next) {
    if (snake->x == ptr->x && snake->y == ptr->y) {
        return true;
    }
}

贪吃蛇在移动时需要检测是否与自己相撞,通过遍历链表来检查贪吃蛇的头部与身体的坐标是否重复。

二、游戏逻辑实现

贪吃蛇的整个游戏逻辑包括游戏的启动、渲染、输入接收和移动。

1. 启动

游戏启动时需要生成初始的贪吃蛇身体节点和食物坐标,以及初始化游戏地图。

body *snake = malloc(sizeof(body)); // 初始化蛇的头部节点
snake->x = 10;
snake->y = 10;
snake->next = NULL;

int food_x = rand() % map_width;
int food_y = rand() % map_height;

2. 渲染

游戏需要在终端上进行渲染,包括游戏地图、贪吃蛇身体和食物。

printf("Score: %d\n", score);
for (int i = 0; i < map_height; i++) {
    for (int j = 0; j < map_width; j++) {
        if (i == food_y && j == food_x) {
            printf("o");
        } else {
            bool body_flag = false;
            for (body *ptr = snake->next; ptr != NULL; ptr = ptr->next) {
                if (ptr->x == j && ptr->y == i) {
                    printf("#");
                    body_flag = true;
                    break;
                }
            }
            if (!body_flag) {
                printf(".");
            }
        }
    }
    printf("\n");
}

3. 输入接收

游戏需要接收玩家的键盘输入,来控制贪吃蛇的方向。

char input = getch();
switch (input) {
    case 'w':
        if (direction != 2) direction = 0;
        break;
    case 's':
        if (direction != 0) direction = 2;
        break;
    case 'a':
        if (direction != 1) direction = 3;
        break;
    case 'd':
        if (direction != 3) direction = 1;
        break;
}

4. 移动

贪吃蛇每隔一段时间就会向前移动一格,玩家需要控制方向来移动贪吃蛇。

int next_x = snake->x;
int next_y = snake->y;
switch (direction) {
    case 0: // 上
        next_y--;
        break;
    case 1: // 右
        next_x++;
        break;
    case 2: // 下
        next_y++;
        break;
    case 3: // 左
        next_x--;
        break;
}

三、代码示例

以下是完整的C语言贪吃蛇代码示例:

#include 
#include 
   
#include 
    
#include 
     
#include 
      

#define map_width 20
#define map_height 20

typedef struct body {
    int x;
    int y;
    struct body *next;
} body;

int score = 0;
int direction = 1;

body *snake;

void generate_food(int *food_x, int *food_y)
{
    do {
        *food_x = rand() % map_width;
        *food_y = rand() % map_height;
    } while (*food_x == snake->x && *food_y == snake->y);

}

bool check_collision(int x, int y)
{
    if (x < 0 || x >= map_width || y < 0 || y >= map_height) { // 超出边界
        return true;
    }

    for (body *ptr = snake->next; ptr != NULL; ptr = ptr->next) { // 撞到自己
        if (x == ptr->x && y == ptr->y) {
            return true;
        }
    }

    return false;
}

void game_over()
{
    printf("\nGame over!\nYour Score: %d\n", score);
    exit(0);
}

void game_loop()
{
    int food_x, food_y;
    generate_food(&food_x, &food_y);

    while (true) {
        system("cls");
        printf("Score: %d\n", score);
        for (int i = 0; i < map_height; i++) {
            for (int j = 0; j < map_width; j++) {
                if (i == food_y && j == food_x) { // 食物
                    printf("o");
                } else {
                    bool body_flag = false;
                    for (body *ptr = snake->next; ptr != NULL; ptr = ptr->next) { // 蛇身体
                        if (ptr->x == j && ptr->y == i) {
                            printf("#");
                            body_flag = true;
                            break;
                        }
                    }
                    if (!body_flag) { // 空格
                        printf(".");
                    }
                }
            }
            printf("\n");
        }

        // 移动
        int next_x = snake->x;
        int next_y = snake->y;
        switch (direction) {
            case 0: // 上
                next_y--;
                break;
            case 1: // 右
                next_x++;
                break;
            case 2: // 下
                next_y++;
                break;
            case 3: // 左
                next_x--;
                break;
        }

        if (check_collision(next_x, next_y)) { // 检测碰撞
            game_over();
        }

        // 头部移动
        body *new_head = malloc(sizeof(body));
        new_head->x = next_x;
        new_head->y = next_y;

        new_head->next = snake;
        snake = new_head;

        // 检查是否吃到食物
        if (next_x == food_x && next_y == food_y) {
            score++;
            generate_food(&food_x, &food_y);
        } else {
            // 尾部删除
            body *prev_tail = snake;
            body *tail = snake->next;
            while (tail->next != NULL) {
                prev_tail = tail;
                tail = tail->next;
            }
            prev_tail->next = NULL;
            free(tail);
        }

        // 等待一段时间
        Sleep(100);
    }
}

int main()
{
    snake = malloc(sizeof(body)); // 初始化蛇的头部节点
    snake->x = 10;
    snake->y = 10;
    snake->next = NULL;

    srand(time(NULL));

    game_loop();

    return 0;
}