一、数据结构和算法
C语言贪吃蛇主要运用了以下数据结构和算法:
1. 链表
typedef struct body { int x; int y; struct body *next; } body;
贪吃蛇身体使用链表来储存,每个节点包括x,y坐标和下一个节点的指针。新的节点插入在头部,旧的节点从尾部删除。
2. 随机数
#includesrand(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; }