c语言版贪吃蛇(Pro Max版)附源代码

1 背景

        贪吃蛇是一款经典的电子游戏,最早出现在20世纪70年代的街机游戏中。游戏的核心玩法是玩家控制一条蛇在有限的空间内移动,通过吃食物来增长身体长度,同时避免撞到墙壁、障碍物或自身。随着蛇的长度增加,游戏难度逐渐提升。

                                

本实验通过C语言实现一个增强版的贪吃蛇游戏,加入以下功能:

  1. 多种食物:普通食物和特殊食物,特殊食物具有额外效果。

  2. 障碍物:随机生成的障碍物增加游戏难度。

  3. 加速功能:玩家可以消耗能量加速蛇的移动。

  4. 传送门:蛇可以通过传送门在地图中快速移动。

  5. 统计系统:记录玩家的游戏数据,包括得分、游戏时间和最长蛇长度等


2 实验技术 

2.1开发环境
        编程语言:C语言

        开发工具:Visual Studio 2022

        操作系统:Windows 11

        依赖库:Windows API(用于控制台操作和音效)

2.2 关键技术
控制台操作:

        使用 SetConsoleCursorPosition 控制光标位置。

        使用 SetConsoleTextAttribute 设置文本颜色。

        使用 Beep 函数播放音效。

双缓冲技术:通过清空控制台并重新绘制地图,避免画面闪烁。

随机数生成:使用 rand 函数生成随机位置,确保食物和障碍物的随机性。

数据结构:

        使用结构体管理游戏对象(蛇、食物、传送门等)。

        使用二维数组表示地图。

文件操作:使用 fopen、fwrite 和 fread 实现游戏状态的保存与加载。


3 实现细节

        下面来详细介绍贪吃蛇游戏的实现细节,涵盖了游戏的核心逻辑、数据结构、功能模块以及关键算法。

3.1 游戏核心数据结构

         游戏的核心数据结构包括食物传送门游戏状态和统计信息等。

1.1 蛇 (Snake)
结构体定义:

typedef struct {
    Point body[WIDTH * HEIGHT];  // 蛇的身体坐标
    int length;                  // 蛇的长度
    int direction;               // 当前移动方向
    int speed;                   // 移动速度
    int boost_available;         // 加速能量
    int is_boosting;             // 是否正在加速
} Snake;

说明:

        蛇的身体由一系列坐标点组成,body[0] 是蛇头,body[length-1] 是蛇尾。

        蛇的移动通过更新 body 数组实现。

        加速功能通过 is_boosting 和 boost_available 控制。

1.2 食物 (Food)
结构体定义:

typedef struct {
    Point pos;                   // 食物位置
    int value;                   // 食物分值
    char type;                   // 食物类型(普通/特殊)
    int lifetime;                // 特殊食物的存在时间
    int is_special;              // 是否为特殊食物
} Food;

说明:

        普通食物 (*) 分值为 10,特殊食物 (#) 分值为 20。

        特殊食物有倒计时 (lifetime),超时后消失。

1.3 传送门 (Portal)
结构体定义:

typedef struct {
    Point pos1;                  // 传送门入口
    Point pos2;                  // 传送门出口
    int active;                  // 是否激活
} Portal;

说明:蛇头进入传送门后,从另一个传送门出口出现。

1.4 游戏状态 (GameState)
结构体定义:

typedef struct {
    int score;                   // 当前得分
    int high_score;              // 最高得分
    int level;                   // 当前等级
    int is_running;              // 游戏是否运行
    int is_paused;               // 游戏是否暂停
    time_t start_time;           // 游戏开始时间
    Difficulty difficulty;       // 游戏难度
    int obstacles_count;         // 障碍物数量
    int power_ups;               // 特殊道具数量
    int portal_active;           // 传送门是否激活
} GameState;

说明:管理游戏的运行状态、得分、等级、难度等信息。

1.5 统计信息 (Statistics)
结构体定义:

typedef struct {
    int games_played;            // 总游戏次数
    int total_score;             // 总得分
    int longest_snake;           // 最长蛇长度
    time_t total_play_time;      // 总游戏时间
    float average_score;         // 平均得分
    int highest_level;           // 最高等级
    int total_food_eaten;        // 总食物数量
} Statistics;

说明:记录玩家的游戏数据,用于统计和展示。

3.2游戏整体框架 

贪吃蛇游戏整体框架图

3.3模块划分

(1)游戏核心逻辑模块

组件

功能描述

重要性

Snake

蛇的属性与行为管理

核心

Food

食物生成与状态管理

核心

GameState

游戏状态控制

重要

Score

得分系统管理

次要

主要功能:

维护游戏核心数据结构

处理游戏逻辑

管理游戏状态转换

控制得分计算

(2)显示控制模块

组件

功能描述

重要性

width/height

显示区域尺寸控制

基础

buffer

显示缓冲区管理

核心

colors

颜色方案控制

优化

主要功能:

管理显示区域大小

控制显示缓冲

处理颜色渲染

优化显示效果

(3)输入控制模块

组件

功能描述

重要性

device

输入设备管理

核心

state

输入状态维护

重要

callback

输入响应处理

核心

主要功能:

处理用户输入

维护输入状态

执行回调函数

管理输入设备

3.4核心算法

(1)   蛇身移动算法

算法具体步骤如下:

1.保存尾部:

获取蛇身体最后一个元素(即尾部)的坐标,并将其存储在变量tail中。

2.身体移动:

从蛇的尾部开始,即数组body的最后一个元素,向前遍历至头部(即数组的第一个元素)。

在遍历过程中,每个元素的坐标被更新为前一个元素的坐标。这样,蛇的身体就向前移动了一个单位。

3.头部移动:

根据蛇当前的方向(dir),更新蛇头的坐标:

如果方向是UP,则蛇头的y坐标减1(向上移动)。

如果方向是DOWN,则蛇头的y坐标加1(向下移动)。

如果方向是LEFT,则蛇头的x坐标减1(向左移动)。

如果方向是RIGHT,则蛇头的x坐标加1(向右移动)。

(2)碰撞检测算法

算法具体步骤如下:

1.获取蛇头位置:从snake结构体中取出数组的第一个元素,这个元素表示蛇头的位置,并将其存储在变量head中。

2.检查边界碰撞:

判断蛇头的x坐标是否小于0或者大于等于游戏区域的宽度WIDTH。

判断蛇头的y坐标是否小于0或者大于等于游戏区域的高度HEIGHT。

如果以上任一条件成立,说明蛇头已经碰撞到边界,函数返回true表示发生碰撞。

3.检查自身碰撞:

从数组的第二个元素开始遍历(索引为1,因为第一个元素是蛇头,不需要与自己比较),直到蛇的长度snake->length。

在循环中,判断当前蛇身的x坐标和y坐标是否与蛇头的坐标相同。

如果找到任何一个蛇身部分的坐标与蛇头坐标相同,说明蛇头碰撞到了自己的身体,函数返回true表示发生碰撞。

4.如果以上两种碰撞情况都没有发生,则函数返回false,表示没有发生碰撞。

(3)双缓冲池技术

  • 使用双缓冲技术避免画面闪烁。

  • 通过 SetConsoleCursorPosition 和 SetConsoleTextAttribute 控制控制台光标和颜色。

优化方法

实现要点

预期效果

增量更新

仅更新变化部分

提升刷新率

双缓冲

防止画面闪烁

平滑显示

局部刷新

减少刷新区域

降低开销

3.5游戏总体实现步骤

  4 游戏展示           

(1) 游戏主页面

(2)开始新游戏

(3)保存游戏状态

(4)加载之前保存的游戏状态

(5)选择游戏难度

(6)游戏说明

5 源代码

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <string.h>
#include <ctype.h>  // 为tolower函数
//@author:小梁不秃捏
// link:https://blog.csdn.net/m0_73804764?spm=1000.2115.3001.5343
// 替代 usleep 函数
void my_sleep(unsigned long microseconds) {
    Sleep(microseconds / 1000);
}

// 游戏配置
#define WIDTH 50
#define HEIGHT 25
#define STUDENT_ID "2022212396"
#define MAX_SPEED 50
#define MIN_SPEED 200

// 游戏元素
#define SNAKE_HEAD 'O'
#define SNAKE_BODY 'o'
#define NORMAL_FOOD '*'
#define SPECIAL_FOOD '#'
#define WALL '#'
#define OBSTACLE 'X'
#define EMPTY ' '
#define PORTAL '@'

// 方向枚举
enum Direction {
    UP,
    DOWN,
    LEFT,
    RIGHT
};

// 控制键
#define KEY_UP 'w'
#define KEY_DOWN 's'
#define KEY_LEFT 'a'
#define KEY_RIGHT 'd'
#define KEY_QUIT 'q'
#define KEY_PAUSE 'p'
#define KEY_SAVE 'v'
#define KEY_BOOST 'b'

// 颜色定义
#define COLOR_RED     FOREGROUND_RED | FOREGROUND_INTENSITY
#define COLOR_GREEN   FOREGROUND_GREEN | FOREGROUND_INTENSITY
#define COLOR_BLUE    FOREGROUND_BLUE | FOREGROUND_INTENSITY
#define COLOR_YELLOW  FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY
#define COLOR_PURPLE  FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY
#define COLOR_CYAN    FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
#define COLOR_WHITE   FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY

// 游戏难度
typedef enum {
    EASY = 1,
    MEDIUM = 2,
    HARD = 3
} Difficulty;

// 基础结构体
typedef struct {
    int x, y;
} Point;

typedef struct {
    Point body[WIDTH * HEIGHT];
    int length;
    int direction;
    int speed;
    int boost_available;
    int is_boosting;
} Snake;

typedef struct {
    Point pos;
    int value;
    char type;
    int lifetime;
    int is_special;
} Food;

typedef struct {
    Point pos1;
    Point pos2;
    int active;
} Portal;

typedef struct {
    int score;
    int high_score;
    int level;
    int is_running;
    int is_paused;
    time_t start_time;
    Difficulty difficulty;
    int obstacles_count;
    int power_ups;
    int portal_active;
} GameState;

typedef struct {
    int games_played;
    int total_score;
    int longest_snake;
    time_t total_play_time;
    float average_score;
    int highest_level;
    int total_food_eaten;
} Statistics;

// 全局变量
Snake snake;
Food food;
Portal portal;
GameState game;
Statistics stats;
char map[HEIGHT][WIDTH];
HANDLE hConsole;
char obstacle_map[HEIGHT][WIDTH] = { 0 };  // 用于保存障碍物位置

// 初始化双缓冲
void init_double_buffer() {
    // 获取标准输出句柄
    hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    // 设置控制台窗口和缓冲区大小
    COORD coord = { WIDTH * 2 + 30, HEIGHT + 15 };
    SMALL_RECT rect = { 0, 0, WIDTH * 2 + 29, HEIGHT + 14 };

    SetConsoleScreenBufferSize(hConsole, coord);
    SetConsoleWindowInfo(hConsole, TRUE, &rect);

    // 隐藏光标
    CONSOLE_CURSOR_INFO info = { 100, FALSE };
    SetConsoleCursorInfo(hConsole, &info);
}

// 颜色控制函数
void set_color(int color) {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}
// 终端控制函数
void init_terminal(void) {
    // 设置控制台窗口大小
    char cmd[100];
    sprintf_s(cmd, "mode con cols=%d lines=%d", WIDTH * 2 + 30, HEIGHT + 15);
    system(cmd);

    // 隐藏光标
    HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO info;
    info.dwSize = 100;
    info.bVisible = FALSE;
    SetConsoleCursorInfo(consoleHandle, &info);
}

void reset_terminal(void) {
    system("cls");
}

void clear_screen(void) {
    system("cls");
}

// 声音效果
void play_effect(int type) {
    switch (type) {
    case 1: // 吃到普通食物
        Beep(800, 50);
        break;
    case 2: // 吃到特殊食物
        Beep(1000, 50);
        Beep(1200, 50);
        Beep(1500, 50);
        Beep(2000, 50);
        break;
    case 3: // 游戏结束
        Beep(200, 200);
        Beep(150, 200);
        break;
    }
}

// 动画效果
void show_animation(const char* text) {
    clear_screen();
    printf("\n\n\n");
    set_color(COLOR_YELLOW);
    for (int i = 0; text[i] != '\0'; i++) {
        printf("%c", text[i]);
        Sleep(50);
        fflush(stdout);
    }
    set_color(COLOR_WHITE);
    Sleep(1000);
}

// 改进的随机位置生成
Point get_random_position() {
    Point pos;
    int attempts = 0;
    const int MAX_ATTEMPTS = 100;

    do {
        pos.x = rand() % (WIDTH - 2) + 1;
        pos.y = rand() % (HEIGHT - 2) + 1;
        attempts++;

        if (attempts >= MAX_ATTEMPTS) {
            for (int i = 1; i < HEIGHT - 1; i++) {
                for (int j = 1; j < WIDTH - 1; j++) {
                    if (map[i][j] == EMPTY) {
                        pos.x = j;
                        pos.y = i;
                        return pos;
                    }
                }
            }
        }
    } while (map[pos.y][pos.x] != EMPTY);

    return pos;
}

// 生成传送门
void generate_portal() {
    if (!game.portal_active) {
        portal.pos1 = get_random_position();
        portal.pos2 = get_random_position();
        map[portal.pos1.y][portal.pos1.x] = PORTAL;
        map[portal.pos2.y][portal.pos2.x] = PORTAL;
        portal.active = 1;
        game.portal_active = 1;
    }
}

// 保存游戏状态
void save_game_state() {
    FILE* file;
    if (fopen_s(&file, "snake_save.dat", "wb") == 0) {
        fwrite(&snake, sizeof(Snake), 1, file);
        fwrite(&food, sizeof(Food), 1, file);
        fwrite(&portal, sizeof(Portal), 1, file);
        fwrite(&game, sizeof(GameState), 1, file);
        fwrite(map, sizeof(map), 1, file);
        fclose(file);
        show_animation("游戏已保存!");
    }
}

// 加载游戏状态
void load_game_state() {
    FILE* file;
    if (fopen_s(&file, "snake_save.dat", "rb") == 0) {
        fread(&snake, sizeof(Snake), 1, file);
        fread(&food, sizeof(Food), 1, file);
        fread(&portal, sizeof(Portal), 1, file);
        fread(&game, sizeof(GameState), 1, file);
        fread(map, sizeof(map), 1, file);
        fclose(file);
        show_animation("游戏已加载!");
    }
    else {
        show_animation("没有找到存档!");
    }
}
// 设置游戏难度
void set_difficulty(int level) {
    switch (level) {
    case EASY:
        snake.speed = 200;  // 较慢
        game.obstacles_count = 5;
        break;
    case MEDIUM:
        snake.speed = 150;  // 中等
        game.obstacles_count = 10;
        break;
    case HARD:
        snake.speed = 100;  // 较快
        game.obstacles_count = 15;
        break;
    default:
        snake.speed = 200;  // 默认较慢
        game.obstacles_count = 5;
    }
    game.difficulty = (Difficulty)level;
}

// 修改generate_food函数
void generate_food() {
    food.pos = get_random_position();

    // 确保食物不会生成在蛇身上或障碍物上
    int valid_position = 0;
    while (!valid_position) {
        valid_position = 1;

        // 检查是否在蛇身上
        for (int i = 0; i < snake.length; i++) {
            if (food.pos.x == snake.body[i].x && food.pos.y == snake.body[i].y) {
                food.pos = get_random_position();
                valid_position = 0;
                break;
            }
        }

        // 检查是否在障碍物上
        if (map[food.pos.y][food.pos.x] == OBSTACLE) {
            food.pos = get_random_position();
            valid_position = 0;
            continue;
        }
    }

    // 设置食物类型和属性
    food.is_special = (rand() % 10 == 0);  // 10%的概率生成特殊食物
    if (food.is_special) {
        food.type = SPECIAL_FOOD;
        food.value = 20;
        food.lifetime = 50;
    }
    else {
        food.type = NORMAL_FOOD;
        food.value = 10;
        food.lifetime = -1;
    }

    // 在地图上放置食物
    map[food.pos.y][food.pos.x] = food.type;
}

// 生成障碍物
void generate_obstacles() {
    for (int i = 0; i < game.obstacles_count; i++) {
        Point pos = get_random_position();
        map[pos.y][pos.x] = OBSTACLE;
    }
}

// 初始化游戏
void init_game() {
    // 清空地图和障碍物地图
    memset(map, EMPTY, sizeof(map));
    memset(obstacle_map, 0, sizeof(obstacle_map));

    // 设置默认速度(如果没有设置难度)
    if (snake.speed == 0) {
        snake.speed = MIN_SPEED;
    }

    // 初始化边界
    for (int i = 0; i < WIDTH; i++) {
        map[0][i] = WALL;
        map[HEIGHT - 1][i] = WALL;
    }
    for (int i = 0; i < HEIGHT; i++) {
        map[i][0] = WALL;
        map[i][WIDTH - 1] = WALL;
    }

    // 初始化蛇
    snake.length = 3;
    snake.body[0].x = WIDTH / 2;
    snake.body[0].y = HEIGHT / 2;
    snake.body[1].x = snake.body[0].x - 1;
    snake.body[1].y = snake.body[0].y;
    snake.body[2].x = snake.body[1].x - 1;
    snake.body[2].y = snake.body[1].y;
    snake.direction = RIGHT;
    snake.boost_available = 100;
    snake.is_boosting = 0;

    // 在地图上放置蛇
    map[snake.body[0].y][snake.body[0].x] = SNAKE_HEAD;
    for (int i = 1; i < snake.length; i++) {
        map[snake.body[i].y][snake.body[i].x] = SNAKE_BODY;
    }

    // 初始化游戏状态
    game.score = 0;
    game.level = 1;
    game.is_running = 1;
    game.is_paused = 0;
    game.power_ups = 3;
    game.portal_active = 0;
    game.start_time = time(NULL);

    // 生成初始食物和障碍物
     // 生成障碍物时同时更新 obstacle_map
    for (int i = 0; i < game.obstacles_count; i++) {
        Point pos = get_random_position();
        map[pos.y][pos.x] = OBSTACLE;
        obstacle_map[pos.y][pos.x] = 1;
    }
    generate_food();  // 只生成一个食物

    // 初始化传送门
    portal.active = 0;
    game.portal_active = 0;  // 确保初始状态无传送门
}

// 更新分数
void update_score() {
    game.score += food.value;
    if (game.score > game.high_score) {
        game.high_score = game.score;
    }

    // 每100分升一级
    int new_level = game.score / 100 + 1;
    if (new_level != game.level) {
        game.level = new_level;
        snake.speed = snake.speed > MAX_SPEED ? snake.speed - 10 : snake.speed;
        show_animation("升级!");
    }
}

// 更新统计信息
void update_statistics() {
    stats.games_played++;
    stats.total_score += game.score;
    stats.average_score = (float)stats.total_score / stats.games_played;
    if (snake.length > stats.longest_snake) {
        stats.longest_snake = snake.length;
    }
    if (game.level > stats.highest_level) {
        stats.highest_level = game.level;
    }
    stats.total_play_time += time(NULL) - game.start_time;
}

// 保存统计信息
void save_statistics() {
    FILE* file;
    if (fopen_s(&file, "snake_stats.dat", "wb") == 0) {
        fwrite(&stats, sizeof(Statistics), 1, file);
        fclose(file);
    }
}
// 检查碰撞
int check_collision(int x, int y) {
    // 检查是否撞墙
    if (map[y][x] == WALL) return 1;

    // 检查是否撞到障碍物
    if (map[y][x] == OBSTACLE) return 1;

    // 检查是否撞到自己(除了尾巴,因为尾巴会移动)
    for (int i = 0; i < snake.length - 1; i++) {
        if (snake.body[i].x == x && snake.body[i].y == y) {
            return 1;
        }
    }

    return 0;
}

// 在move_snake函数
void move_snake() {
    int new_x = snake.body[0].x;
    int new_y = snake.body[0].y;

    switch (snake.direction) {
    case UP:    new_y--; break;
    case DOWN:  new_y++; break;
    case LEFT:  new_x--; break;
    case RIGHT: new_x++; break;
    }

    // 处理加速能量衰减
    if (snake.is_boosting && snake.boost_available > 0) {
        snake.boost_available--;
        if (snake.boost_available <= 0) {
            snake.is_boosting = 0;
        }
    }

    // 检查碰撞
    if (check_collision(new_x, new_y)) {
        game.is_running = 0;
        play_effect(3);
        return;
    }

    // 检查是否吃到食物
    if (new_x == food.pos.x && new_y == food.pos.y) {
        // 增加蛇的长度
        snake.length++;

        // 更新分数
        update_score();

        // 播放音效
        play_effect(food.is_special ? 2 : 1);

        // 如果是特殊食物,增加加速能量
        if (food.is_special) {
            snake.boost_available += 50;
        }

        // 先移动蛇身
        for (int i = snake.length - 1; i > 0; i--) {
            snake.body[i] = snake.body[i - 1];
        }

        // 更新蛇头位置
        snake.body[0].x = new_x;
        snake.body[0].y = new_y;

        // 生成新的食物
        generate_food();
    }
    else {
        // 如果没有吃到食物,正常移动
        // 移动蛇身
        for (int i = snake.length - 1; i > 0; i--) {
            snake.body[i] = snake.body[i - 1];
        }

        // 更新蛇头位置
        snake.body[0].x = new_x;
        snake.body[0].y = new_y;
    }

    // 更新地图
    memset(map, EMPTY, sizeof(map));

    // 重绘边界
    for (int i = 0; i < WIDTH; i++) {
        map[0][i] = WALL;
        map[HEIGHT - 1][i] = WALL;
    }
    for (int i = 0; i < HEIGHT; i++) {
        map[i][0] = WALL;
        map[i][WIDTH - 1] = WALL;
    }

    // 重绘障碍物
    for (int i = 0; i < HEIGHT; i++) {
        for (int j = 0; j < WIDTH; j++) {
            if (obstacle_map[i][j]) {
                map[i][j] = OBSTACLE;
            }
        }
    }

    // 重绘蛇
    map[snake.body[0].y][snake.body[0].x] = SNAKE_HEAD;
    for (int i = 1; i < snake.length; i++) {
        map[snake.body[i].y][snake.body[i].x] = SNAKE_BODY;
    }

    // 重绘食物
    map[food.pos.y][food.pos.x] = food.type;
}

// 修改draw_game函数
void draw_game() {
    // 移动光标到起始位置
    COORD pos = { 0, 0 };
    SetConsoleCursorPosition(hConsole, pos);

    // 绘制游戏信息
    SetConsoleTextAttribute(hConsole, COLOR_YELLOW);
    printf("\n  得分: %d  最高分: %d  等级: %d  加速能量: %d%%\n",
        game.score, game.high_score, game.level, snake.boost_available);
    printf("  难度: ");
    switch (game.difficulty) {
    case EASY:   printf("简单"); break;
    case MEDIUM: printf("中等"); break;
    case HARD:   printf("困难"); break;
    }
    printf("  游戏时间: %d秒\n\n", (int)(time(NULL) - game.start_time));

    // 绘制地图
    for (int i = 0; i < HEIGHT; i++) {
        printf("  ");
        for (int j = 0; j < WIDTH; j++) {
            switch (map[i][j]) {
            case SNAKE_HEAD:
                SetConsoleTextAttribute(hConsole, COLOR_GREEN);
                printf("O ");
                break;
            case SNAKE_BODY:
                SetConsoleTextAttribute(hConsole, COLOR_GREEN);
                printf("o ");
                break;
            case NORMAL_FOOD:
                SetConsoleTextAttribute(hConsole, COLOR_RED);
                printf("* ");
                break;
            case SPECIAL_FOOD:
                SetConsoleTextAttribute(hConsole, COLOR_PURPLE);
                printf("# ");
                break;

            case OBSTACLE:
                SetConsoleTextAttribute(hConsole, COLOR_RED);
                printf("X ");
                break;
            case PORTAL:
                SetConsoleTextAttribute(hConsole, COLOR_CYAN);
                printf("@ ");
                break;
            default:
                SetConsoleTextAttribute(hConsole, COLOR_WHITE);
                printf("  ");
            }
        }
        printf("\n");
    }

    // 绘制控制说明
    SetConsoleTextAttribute(hConsole, COLOR_WHITE);
    printf("\n  控制: WASD移动 P暂停 Q退出 V保存 B加速\n");
}

// 显示菜单
int show_menu() {
    clear_screen();
    set_color(COLOR_YELLOW);
    printf("\n");
    printf("   SSSSS  N   N    AAA   K   K  EEEEE\n");
    printf("   S      NN  N   A   A  K  K   E    \n");
    printf("   SSSSS  N N N   AAAAA  KK     EEEE \n");
    printf("       S  N  NN   A   A  K  K   E    \n");
    printf("   SSSSS  N   N   A   A  K   K  EEEEE\n");
    printf("\n\n");
    printf("    ----------\n\n");
    printf("    小梁贪吃蛇(pro max版)\n");
    printf("    1. 新游戏\n");
    printf("    2. 加载游戏\n");
    printf("    3. 查看统计\n");
    printf("    4. 选择难度\n");
    printf("    5. 游戏说明\n");
    printf("    6. 退出\n\n");
    printf("    请选择: ");

    set_color(COLOR_WHITE);
    int choice;
    scanf_s("%d", &choice);
    return choice;
}

// 显示统计信息
void show_statistics() {
    clear_screen();
    set_color(COLOR_CYAN);
    printf("\n\n");
    printf("    游戏统计\n");
    printf("    --------\n\n");
    printf("    总游戏次数: %d\n", stats.games_played);
    printf("    总得分: %d\n", stats.total_score);
    printf("    平均得分: %.2f\n", stats.average_score);
    printf("    最长蛇长度: %d\n", stats.longest_snake);
    printf("    最高等级: %d\n", stats.highest_level);
    printf("    总游戏时间: %d分钟\n\n", (int)(stats.total_play_time / 60));
    printf("    按任意键返回...");

    set_color(COLOR_WHITE);
    _getch();
}
// 显示游戏说明
void show_instructions() {
    clear_screen();
    set_color(COLOR_CYAN);
    printf("\n\n");
    printf("    游戏说明\n");
    printf("    --------\n\n");
    printf("    控制方式:\n");
    printf("    W - 向上移动\n");
    printf("    S - 向下移动\n");
    printf("    A - 向左移动\n");
    printf("    D - 向右移动\n");
    printf("    P - 暂停游戏\n");
    printf("    Q - 退出游戏\n");
    printf("    V - 保存游戏\n");
    printf("    B - 开启/关闭加速\n\n");
    printf("    游戏规则:\n");
    printf("    * - 普通食物,得分+10\n");
    printf("    # - 特殊食物,得分+20,有特殊效果\n");
    printf("    @ - 传送门,可传送到另一端\n");
    printf("    X - 障碍物,碰到即死亡\n\n");
    printf("    特殊食物效果:\n");
    printf("    1. 增加加速能量\n");
    printf("    2. 生成传送门\n");
    printf("    3. 清除障碍物\n\n");
    printf("    按任意键返回...");

    set_color(COLOR_WHITE);
    _getch();
}

// 主函数
int main() {
    srand((unsigned)time(NULL));
    init_terminal();
    init_double_buffer();  // 添加这行
    while (1) {
        int choice = show_menu();

        switch (choice) {
        case 1: // 新游戏
            init_game();
            while (game.is_running) {
                if (!game.is_paused) {
                    move_snake();
                    draw_game();

                    // 特殊食物倒计时
                    if (food.is_special && food.lifetime > 0) {
                        food.lifetime--;
                        if (food.lifetime <= 0) {
                            generate_food();
                        }
                    }

                    // 控制游戏速度
                    int delay = snake.is_boosting ? snake.speed / 2 : snake.speed;
                    Sleep(delay);
                }

                // 处理输入
                if (_kbhit()) {
                    char input = _getch();
                    switch (tolower(input)) {  // 转换为小写以支持大小写
                    case 'w':
                        if (snake.direction != DOWN) snake.direction = UP;
                        break;
                    case 's':
                        if (snake.direction != UP) snake.direction = DOWN;
                        break;
                    case 'a':
                        if (snake.direction != RIGHT) snake.direction = LEFT;
                        break;
                    case 'd':
                        if (snake.direction != LEFT) snake.direction = RIGHT;
                        break;
                    case 'p':
                        game.is_paused = !game.is_paused;
                        break;
                    case 'q':
                        game.is_running = 0;
                        break;
                    case 'v':
                        save_game_state();
                        break;
                    case 'b':
                        if (snake.boost_available > 0) {
                            snake.is_boosting = !snake.is_boosting;
                        }
                        break;
                    }
                }
            }
            update_statistics();
            save_statistics();
            break;

        case 2: // 加载游戏
            load_game_state();
            break;

        case 3: // 查看统计
            show_statistics();
            break;

        case 4: // 选择难度
            clear_screen();
            printf("\n\n    选择难度(1-简单 2-中等 3-困难): ");
            int level;
            scanf_s("%d", &level);
            set_difficulty(level);
            break;

        case 5: // 游戏说明
            show_instructions();
            break;

        case 6: // 退出
            CloseHandle(hConsole);
            reset_terminal();
            return 0;
        }
    }

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/960370.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AI软件外包需要注意什么 外包开发AI软件的关键因素是什么 如何选择AI外包开发语言

1. 定义目标与需求 首先&#xff0c;要明确你希望AI智能体做什么。是自动化任务、数据分析、自然语言处理&#xff0c;还是其他功能&#xff1f;明确目标可以帮助你选择合适的技术和方法。 2. 选择开发平台与工具 开发AI智能体的软件时&#xff0c;你需要选择适合的编程语言、…

分布式理解

分布式 如何理解分布式 狭义的分布是指&#xff0c;指多台PC在地理位置上分布在不同的地方。 分布式系统 分布式系**统&#xff1a;**多个能独立运行的计算机&#xff08;称为结点&#xff09;组成。各个结点利用计算机网络进行信息传递&#xff0c;从而实现共同的“目标或者任…

python学opencv|读取图像(四十七)使用cv2.bitwise_not()函数实现图像按位取反运算

【0】基础定义 按位与运算&#xff1a;两个等长度二进制数上下对齐&#xff0c;全1取1&#xff0c;其余取0。按位或运算&#xff1a;两个等长度二进制数上下对齐&#xff0c;有1取1&#xff0c;其余取0。 按位取反运算&#xff1a;一个二进制数&#xff0c;0变1,1变0。 【1】…

CVE-2023-38831 漏洞复现:win10 压缩包挂马攻击剖析

目录 前言 漏洞介绍 漏洞原理 产生条件 影响范围 防御措施 复现步骤 环境准备 具体操作 前言 在网络安全这片没有硝烟的战场上&#xff0c;新型漏洞如同隐匿的暗箭&#xff0c;时刻威胁着我们的数字生活。其中&#xff0c;CVE - 2023 - 38831 这个关联 Win10 压缩包挂…

链表排序--(奇数位是升序,偶数位是降序)

题目描述 对一个单链表进行排序&#xff0c;但这个链表有一个特殊的结构&#xff1a; 奇数位是升序&#xff1a;链表中位于奇数位置的节点是按升序排列的。例如&#xff0c;如果链表的第1个节点的值是1&#xff0c;第3个节点的值是3&#xff0c;第5个节点的值是5&#xff0c;那…

在无sudo权限Linux上安装 Ollama 并使用 DeepSeek-R1 模型

本教程将指导你如何在 Linux 系统上安装 Ollama&#xff08;一个本地运行大型语言模型的工具&#xff09;&#xff0c;并加载 DeepSeek-R1 模型。DeepSeek-R1 是一个高性能的开源语言模型&#xff0c;适用于多种自然语言处理任务。 DeepSeek-R1 简介 DeepSeek-R1 是 DeepSeek …

arduino学习

一、log日志 只看自己 看指定 看错误日志 二、布局 重要&#xff1a;新建activity时需要的配置 若一个工程中有多个activity&#xff0c;需要修改开启activity属性、总容器标签、debug启动activity。下面流程内截图activity不一致&#xff0c;根据自己新建的activity配置&am…

obsidian插件——Metadata Hider

原本是要找导出图片时显示属性的插件&#xff0c;奈何还没找到&#xff0c;反而找到了可以隐藏属性的插件。唉&#xff0c;人生不如意&#xff0c;十之八九。 说一下功能&#xff1a; 这个插件可以把obsidian的文档属性放在右侧显示&#xff0c;或者决定只显示具体几项属性&a…

SimpleFOC STM32教程10|基于STM32F103+CubeMX,速度闭环控制(有电流环)

导言 SimpleFOC STM32教程09&#xff5c;基于STM32F103CubeMX&#xff0c;ADC采样相电流 如上图所示, 增加了电流环. 效果如下&#xff1a; 20250123-200906 RTT 如上图所示&#xff0c;三相占空比依然是马鞍波。当我用手去给电机施加阻力时&#xff0c;PID要维持目标转速&am…

Qt 5.14.2 学习记录 —— 이십일 Qt网络和音频

文章目录 1、UDP带有界面的Udp服务器&#xff08;回显服务器&#xff09; 2、TCP回显服务器 3、HTTP客户端4、音频 和Linux的网络一样&#xff0c;Qt封装了Linux的网络API&#xff0c;即Socket API。网络编程是在应用层写&#xff0c;需要传输层支持&#xff0c;传输层有UDP和T…

【C语言基础】编译并运行第一个C程序

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 博客内容主要围绕&#xff1a; 5G/6G协议讲解 高级C语言讲解 Rust语言讲解 文章目录 编译并运行第一个C程序一、编译上面的程序二、运行上面的程序…

TikTok 推出了一款 IDE,用于快速构建 AI 应用

字节跳动(TikTok 的母公司)刚刚推出了一款名为 Trae 的新集成开发环境(IDE)。 Trae 基于 Visual Studio Code(VS Code)构建,继承了这个熟悉的平台,并加入了 AI 工具,帮助开发者更快、更轻松地构建应用——有时甚至无需编写任何代码。 如果你之前使用过 Cursor AI,T…

HarmonyOS简介:HarmonyOS核心技术理念

核心理念 一次开发、多端部署可分可合、自由流转统一生态、原生智能 一次开发、多端部署 可分可合 自由流转 自由流转可分为跨端迁移和多端协同两种情况 统一生态 支持业界主流跨平台开发框架&#xff0c;通过多层次的开放能力提供统一接入标准&#xff0c;实现三方框架快速…

STM32 按键密码系统的实现

本次基于STM32F407开发板&#xff0c;来实现密码系统&#xff0c;输入四位密码&#xff0c;密码正确时LED1亮&#xff0c;密码错误时四个LED灯双闪。 LED双闪代码 简单的逻辑&#xff0c;让四个LED灯先亮然后再延时一会LED灯灭&#xff0c;循环4此实现双闪的效果。 按键密码的…

【C++ 动态规划】1024. 视频拼接|1746

本文涉及知识点 C动态规划 LeetCode1024. 视频拼接 你将会获得一系列视频片段&#xff0c;这些片段来自于一项持续时长为 time 秒的体育赛事。这些片段可能有所重叠&#xff0c;也可能长度不一。 使用数组 clips 描述所有的视频片段&#xff0c;其中 clips[i] [starti, end…

A7. Jenkins Pipeline自动化构建过程,可灵活配置多项目、多模块服务实战

服务容器化构建的环境配置构建前需要解决什么下面我们带着问题分析构建的过程:1. 如何解决jenkins执行环境与shell脚本执行环境不一致问题?2. 构建之前动态修改项目的环境变量3. 在通过容器打包时避免不了会产生比较多的不可用的镜像资源,这些资源要是不及时删除掉时会导致服…

Oracle-Java JDBC 连接超时之后的认知纠正

背景 偶然读到熊老师的文章《老熊的三分地-JDBC中语句超时与事务》了解到&#xff1a;JAVA代码的最后正常断开数据库连接&#xff0c;在默认情况下&#xff0c;正常断开的数据库连接会自动提交没有提交的事务。   通过文章的测试JAVA程序&#xff0c;可以表明&#xff0c;JDB…

redis的分片集群模式

redis的分片集群模式 1 主从哨兵集群的问题和分片集群特点 主从哨兵集群可应对高并发写和高可用性&#xff0c;但是还有2个问题没有解决&#xff1a; &#xff08;1&#xff09;海量数据存储 &#xff08;2&#xff09;高并发写的问题 使用分片集群可解决&#xff0c;分片集群…

【Linux】 冯诺依曼体系与计算机系统架构全解

Linux相关知识点可以通过点击以下链接进行学习一起加油&#xff01;初识指令指令进阶权限管理yum包管理与vim编辑器GCC/G编译器make与Makefile自动化构建GDB调试器与Git版本控制工具Linux下进度条 冯诺依曼体系是现代计算机设计的基石&#xff0c;其统一存储和顺序执行理念推动…

【论文复现】基于维度狩猎学习的改进秃鹰搜索算法用于自动驾驶问题

目录 1.摘要2.秃鹰搜索算法BES原理3.改进策略4.结果展示5.参考文献6.代码获取 1.摘要 由于道路曲率穿透和参数不确定性带来的侧向偏差&#xff0c;自动驾驶车辆控制器面临提供准确、快速响应及小幅超调等性能挑战。本文提出了一种基于维度狩猎学习&#xff08;DLH&#xff09;…