SWUST 2021 —— 数据结构课程设计 贪吃蛇

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
const int Width = 50;
const int Height = 25;
int Speed = 200;//全局-记录速度 
int Point;//全局-记录分数 
int Level = 1;
int Count = 1;
int Number = 1;
typedef struct Snake {
    int x, y;
    Snake* prev;
    Snake* next;
}Snake, * Snakee;
typedef struct Food {
    int x, y;
    bool isEat;
}Food;
//获取蛇坐标 
void gotoxySnake(Snakee snake) {
    COORD position = { snake->x,snake->y };
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), position);
}
//获取实体坐标
void gotoxyEntity(int x, int y) {
    COORD position = { x,y };
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), position);
}
Snakee snake_move(Snakee snake, int dir, Food& food);
void snake_grow(Snakee snake, int x, int y);
void free_snake(Snakee snake);
bool snake_die_itself(Snakee snake);
bool snake_die_edge(int x, int y);
bool snake_eat(int s_x, int s_y, int f_x, int f_y);
int snake_get_dir(int old_dir);
Snakee init_snake();
void generate_food(Food& food, Snakee* snake);
bool food_is_eat(Food& food, Snakee* snake);
void level_add();
void speed_add();
void init_game(Snakee snake, Food& food);
int main() {
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO CursorInfo;
    GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息
    CursorInfo.bVisible = false; //隐藏控制台光标
    SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标状态
    Snakee snake;
    Food food;
    snake = init_snake();
    int new_dir = 75;//向左
    init_game(snake, food);
    while (true) {
        if (_kbhit()) {
            new_dir = snake_get_dir(new_dir);
        }
        if (snake) {
            snake = snake_move(snake, new_dir, food);
        }
        if (food.isEat == true) {
            generate_food(food, &snake);
        }
    }
}
void init_game(Snakee snake, Food& food) {

    Snakee p = snake;
    do {
        gotoxySnake(p), printf("O");
        p = p->next;
    } while (p != snake);
    gotoxyEntity(Width, Height / 4), printf("  Point:  %d", Point);
    gotoxyEntity(Width, Height / 4 + Height / 8), printf("  Speed:  %d", Speed);
    gotoxyEntity(Width, (Height / 4) - Height / 8), printf("  Level:  %d", Level);
    gotoxyEntity(Width + 20, Height), printf("By 5121095644 周麟志");
    gotoxyEntity(Width + 20, Height/3), printf(" 本人博客园  ");
    gotoxyEntity(Width + 20, (Height/2)), printf("https://www.cnblogs.com/lightWh1te/");
    for (int i = Width; i < Width + Width / 3; i++) {
        gotoxyEntity(i, Height / 2), printf("*");
        gotoxyEntity(i, 1), printf("*");
        gotoxyEntity(i, Height), printf("*");
    }
    for (int i = 1; i <= Width; i++) {
        gotoxyEntity(i, 1), printf("*");
        gotoxyEntity(i, Height), printf("*");
    }
    for (int i = 1; i <= Height; i++) {
        gotoxyEntity(1, i), printf("*");
        gotoxyEntity(Width, i), printf("*");
        gotoxyEntity(Width + Width / 3, i), printf("*");
    }
    food.isEat = false;
    food.x = 10;
    food.y = 10;
    gotoxyEntity(food.x, food.y), printf("#");
}
void generate_food(Food& food, Snakee* snake) {
    srand(time(NULL));
    bool generate = true;
    if (generate == true) {
        generate = false;
        food.x = (rand() % (Width - 2 - 5 + 1)) + 5;
        food.y = (rand() % (Height - 2 - 5 + 1)) + 5;
        if (food_is_eat(food, snake)) {
            generate = true;
        }
    }
    food.isEat = false;
    gotoxyEntity(food.x, food.y);
    printf("#");
}
bool food_is_eat(Food& food, Snakee* snake) {
    Snakee p = *snake;//这里获得了一级指针
    food.isEat = true;
    if (food.x == p->x && food.y == p->y) {
        return true;
    }
    else
        return false;
}
void snake_grow(Snakee snake, int x, int y) {
    Snakee head = (Snakee)malloc(sizeof(Snake));
    head->prev = snake->prev;
    head->next = snake;
    head->x = x;
    head->y = y;
    snake->prev->next = head;
    snake->prev = head;
}
Snakee init_snake() {
    Snakee head = (Snakee)malloc(sizeof(Snake));
    head->x = 36;
    head->y = 5;
    head->next = head;//双向循环链表初始化 
    head->prev = head;
    for (int i = 36; i < 40; i++) {
        snake_grow(head, i, 5);
    }
    return head;
}
int snake_get_dir(int old_dir) {
    int new_dir = old_dir;
    if (_kbhit()) {
        _getch();
        new_dir = _getch();//第二次getch才是实际字符
        if (abs(new_dir - old_dir == 2) || abs(new_dir - old_dir) == 8) {
            new_dir = old_dir;
        }
    }
    return new_dir;
}
Snakee snake_move(Snakee snake, int dir, Food& food) {
    Snakee head;
    head = (Snakee)malloc(sizeof(Snake));
    head->prev = snake->prev;
    head->next = snake;
    head->x = snake->x;
    head->y = snake->y;
    snake->prev->next = head;
    snake->prev = head;
    Snakee p = head->prev;
    int tail_x = p->x;
    int tail_y = p->y;
    gotoxySnake(p);
    printf(" ");
    p->prev->next = p->next;
    p->next->prev = p->prev;
    free(p);
    int new_dir = snake_get_dir(dir);
    if (dir) {
        switch (new_dir)
        {
        case 72://
            head->y--;
            break;
        case 77://
            head->x++;
            break;
        case 75://
            head->x--;
            break;
        case 80://
            head->y++;
            break;
        default:
            break;
        }
    }

    if (snake_die_edge(head->x, head->y) == true || snake_die_itself(snake) == true) {
        system("cls");
        gotoxyEntity((Width + 10) / 2, (Height) / 2);
        printf("Game Over
");
        free_snake(snake);
        return 0;
    }
    if (snake_eat(head->x, head->y, food.x, food.y) == true) {
        food.isEat = true;
        Snakee tail = (Snakee)malloc(sizeof(Snake));
        tail->prev = head->prev;
        tail->next = head;
        tail->x = tail_x;
        tail->y = tail_y;
        head->prev->next = tail;
        head->prev = tail;
    }
    gotoxySnake(head), printf("O");
    Sleep(Speed);
    return head;
}
bool snake_die_edge(int x, int y) {
    if (x == 1 || x == Width || y == 1 || y == Height) {
        return true;
    }
    else
        return false;
}
bool snake_die_itself(Snakee snake) {
    Snakee t;
    t = snake->next->next;
    do {
        if (snake->x == t->x && snake->y == t->y) {
            return true;
        }
        t = t->next;
    } while (t != snake);
    return false;
}
bool snake_eat(int s_x, int s_y, int f_x, int f_y) {

    if (Number % 3 == 0) {
        Level++;
        Number = 1;
        gotoxyEntity(Width, (Height / 4) - Height / 8), printf("  Level:  %d", Level);
        speed_add();
    }
    if (s_x == f_x && s_y == f_y) {
        Count++;
        Number++;
        Point += 10;
        gotoxyEntity(Width, Height / 4), printf("  Point:  %d", Point);
        return true;
    }
    else
        return false;
}
void free_snake(Snakee snake) 
{
    Snakee p = snake;
    do {
        Snakee t = p;
        p = p->next;
        free(t);
    } while (p != snake);
}
void speed_add() 
{//速度逻辑
    Speed -= 20;
    gotoxyEntity(Width, Height / 4 + Height / 8), printf("  Speed:  %d", Speed);
}
View Code

V1.0 

  • 建模:程序界面是一个二维平面图

  • 蛇:蛇的身体可以看作是链表的节点,当蛇吃到食物时,就增加一节链表长度++;

  • 食物:随机生成

  • 蛇的移动:取得上下左右键的ASCII码的键值,通过switch语句响应相应的键值对,实现蛇的方向获取

  • 闪烁问题:通过局部打印空格与蛇身节点的移动,来实现局部更新可避免全局绘制造成的闪烁问题,也能提高性能

  • 获取实体:获取游戏一个实体的坐标需要得到当前窗口的句柄,并重写gotoxy()函数,在绘制时也要注意绘制重合的问题

  • 结构:把相应的功能模块化,结构化,封装成一个个函数,像蛇逻辑有自噬死亡,撞墙死亡,吃食,变长等

  • 交互:在相应的自定义逻辑函数中调用各自的函数,主函数则主要写下简短的循环框架,直到游戏结束

  • Windows窗口
原文地址:https://www.cnblogs.com/lightWh1te/p/14743819.html