用了链表添头去尾的方法,添加了历史排行榜用文件统计,分数 等级 难度,暂停
#ifndef _SNAKE_H_ #define _SNAKE_H_ #include <stdbool.h> //食物 typedef struct food { int x; int y; int count; } Food; //蛇身 typedef struct item { int x; int y; } Item; typedef struct snake { Item item; struct snake *last; struct snake *next; } Snake; typedef struct list { int hp; Snake *head; Snake *end; } List; static int PauseGame = 0; //排行榜 typedef struct score { int one; int two; int three; } Score; //绘制地图 void Map(); //初始化蛇 void InitializeSnake(List *pts); //添加蛇 bool AddSnake(Item *snake, List *pts); //显示蛇 void ShowSnake(List *pts); //移动蛇 void MoveSnake(Food *tfood, List *pts); //初始化食物 void InitializeFood(Food *temp); //生成食物 void Foods(Food *temp, List *pts); //判断食物是否与蛇身重叠 bool FoodSnake(Food *temp, List *pts); //设置光标位置 void gotoxy(int x, int y); //判断蛇碰到地图边界 bool MapSnake(List *pts); //判断蛇碰到自己 bool MeSnake(List *pts); //游戏统计 void ShowScore(Score *pt, List *pts); //游戏速度控制 int Speed(List *pts); //清除蛇 void DeleteSnake(List *pts); //得分写入结构 void WriteData(Score *pt, List *pts); #endif
#include <Windows.h> #include <stdio.h> #include "snake.h" enum Key { U, D, L, R }; //设置光标位置 void gotoxy(int x, int y) { COORD pos = { x,y }; HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);// 获取标准输出设备句柄 SetConsoleCursorPosition(hOut, pos);//两个参数分别是指定哪个窗体,具体位置 } //初始化蛇 void InitializeSnake(List *pts) { pts->head = pts->end = NULL; pts->hp = 0; } //添加蛇 bool AddSnake(Item *snake, List *pts) { Snake *temp; temp = (Snake *)malloc(sizeof(Snake)); if (temp == NULL) { fputs("错误: 添加蛇身失败", stderr); return false; } temp->item = *snake; temp->last = NULL; temp->next = NULL; pts->hp++; if (pts->end != NULL) { temp->last = pts->end; pts->end->next = temp; } if (pts->head == NULL) { pts->head = temp; pts->end = temp; } else pts->end = temp; ShowSnake(pts); return true; } //显示蛇 void ShowSnake(List *pts) { Snake *temp; temp = pts->head; while (temp != NULL) { gotoxy(temp->item.x, temp->item.y); printf("■"); temp = temp->next; } } //移动蛇 void MoveSnake(Food *tfood, List *pts) { Snake *temp; //添加新蛇头节点 Snake *Temp; //保存蛇尾上一个节点 Item item; //保存蛇尾坐标 static char ch = D; //获取键值 int Hp; Hp = pts->hp; temp = (Snake *)malloc(sizeof(Snake)); temp->item = pts->head->item; temp->next = pts->head; temp->last = NULL; pts->head->last = temp; pts->head = temp; if (temp->item.x == tfood->x&&temp->item.y == tfood->y) { item = pts->end->item; pts->hp++; tfood->count--; } else { Temp = pts->end->last; Temp->next = NULL; item = pts->end->item; free(pts->end); pts->end = Temp; } if (GetAsyncKeyState(VK_UP) && ch != D) { ch = U; } else if (GetAsyncKeyState(VK_DOWN) && ch != U) { ch = D; } else if (GetAsyncKeyState(VK_LEFT) && ch != R) { ch = L; } else if (GetAsyncKeyState(VK_RIGHT) && ch != L) { ch = R; } else if (GetAsyncKeyState(VK_SPACE) && PauseGame == 1) { PauseGame = 2; } switch (ch) { case U: temp->item.y--; break; case D: temp->item.y++; break; case L: temp->item.x -= 2; break; case R: temp->item.x += 2; break; default: break; } gotoxy(temp->item.x, temp->item.y); printf("■"); if (pts->hp == Hp) { if (item.x == temp->item.x&&item.y == temp->item.y); //防止追尾时清除蛇头 else { gotoxy(item.x, item.y); printf(" "); } } //重置光标到底部 gotoxy(0, 27); } //初始化食物 void InitializeFood(Food *temp) { temp->x = temp->y = temp->count = 0; } //判断食物是否与蛇身重叠 bool FoodSnake(Food *temp, List *pts) { Snake *Temp; Temp = pts->head; while (Temp != NULL) { if (temp->x == Temp->item.x&&temp->y == Temp->item.y) return false; Temp = Temp->next; } return true; } //生成食物 void Foods(Food *temp, List *pts) { if (temp->count == 0) { temp->x = (rand() % 25 + 1) * 2; temp->y = rand() % 24 + 1; while (!FoodSnake(temp, pts)) { temp->x = (rand() % 25 + 1) * 2; temp->y = rand() % 24 + 1; } temp->count++; gotoxy(temp->x, temp->y); printf("■"); } } //判断蛇碰到地图边界 bool MapSnake(List *pts) { if (pts->head->item.x < 2 || pts->head->item.x > 50) return false; if (pts->head->item.y < 1 || pts->head->item.y > 25) return false; return true; } //判断蛇碰到自己 bool MeSnake(List *pts) { Snake *temp; temp = pts->head->next; while (temp != NULL) { if (pts->head->item.x == temp->item.x&&pts->head->item.y == temp->item.y) return false; temp = temp->next; } return true; } //游戏统计 void ShowScore(Score *pt, List *pts) { gotoxy(58, 1); printf("历史排行榜:"); gotoxy(62, 3); printf("第1名: %d", pt->one); gotoxy(62, 5); printf("第2名: %d", pt->two); gotoxy(62, 7); printf("第3名: %d", pt->three); gotoxy(58, 14); printf("游戏统计:"); gotoxy(62, 16); printf("得分: %d", (pts->hp - 3) * 10); gotoxy(62, 18); printf("等级: %d", (pts->hp - 3) / 10 + 1); gotoxy(62, 20); printf("难度: %d", (pts->hp - 3) / 15 + 1); gotoxy(58, 24); printf("游戏状态: "); if (PauseGame == 0) { gotoxy(69, 24); printf("请按任意键开始"); gotoxy(0, 27); system("pause"); gotoxy(0, 27); printf(" "); PauseGame = 1; } else if (PauseGame == 1) { gotoxy(69, 24); printf("游戏运行中 "); gotoxy(69, 26); printf("空格键暂停游戏"); gotoxy(0, 27); } else if (PauseGame == 2) { gotoxy(69, 24); printf("游戏暂停中 "); gotoxy(69, 26); printf("任意键开始游戏"); gotoxy(0, 27); system("pause"); gotoxy(0, 27); printf(" "); PauseGame = 1; } } //游戏速度控制 int Speed(List *pts) { int speed = 300; speed -= (pts->hp - 3) / 15 * 30; return speed; } //绘制地图 void Map() { int i; for (i = 0; i < 54; i += 2) { gotoxy(i, 0); printf("■"); gotoxy(i, 26); printf("■"); } for (i = 1; i < 26; i++) { gotoxy(0, i); printf("■"); gotoxy(52, i); printf("■"); } gotoxy(58, 9); printf("游戏说明:"); gotoxy(62, 11); printf("控制: ↑ ↓ ← →"); gotoxy(0, 27); } //清除蛇 void DeleteSnake(List *pts) { Snake *temp; temp = pts->head; while (temp != NULL) { pts->head = pts->head->next; free(temp); temp = pts->head; } } //得分写入结构 void WriteData(Score *pt, List *pts) { int temp; temp = (pts->hp - 3) * 10; if (temp > pt->one&&temp > pt->two&&temp > pt->three) { pt->three = pt->two; pt->two = pt->one; pt->one = temp; } else if (temp <= pt->one&&temp > pt->two&&temp > pt->three) { pt->three = pt->two; pt->two = temp; } else if (temp <= pt->one&&temp <= pt->two&&temp > pt->three) pt->three = temp; }
#include <stdio.h> #include <Windows.h> #include <time.h> #include <stdlib.h> #include "snake.h" int main() { List snake; Item temp; int i; Food F_food; Score t_list; errno_t err; FILE *fp; while ((err = fopen_s(&fp, "data.dat", "rb")) != 0) { //如果没有数据文件创建新文件并把初始化结构写入文件 if ((err = fopen_s(&fp, "data.dat", "wb")) != 0) { fputs("错误: 创建数据文件失败", stderr); exit(EXIT_FAILURE); } t_list.one = t_list.two = t_list.three = 0; fwrite(&t_list, sizeof(Score), 1, fp); fclose(fp); } rewind(fp);//打开文件回到开始 fread(&t_list, sizeof(Score), 1, fp); //读取文件记录 //初始化蛇 InitializeSnake(&snake); for (i = 0; i < 3; i++) { temp.x = 16; temp.y = 8 - i; if (!AddSnake(&temp, &snake)) { fputs("错误: 初始化蛇身失败\n", stderr); exit(EXIT_FAILURE); } } //初始化地图 Map(); srand((unsigned int)time(0)); //随机种子 //初始化食物 InitializeFood(&F_food); while (1) { ShowScore(&t_list, &snake); //生成食物 Foods(&F_food, &snake); MoveSnake(&F_food, &snake); if (!MapSnake(&snake)) //判断蛇碰到边界 { gotoxy(69, 24); printf("碰到地图边界, 游戏结束."); gotoxy(69, 26); printf(" "); WriteData(&t_list, &snake); //重置光标到底部 gotoxy(0, 27); break; } if (!MeSnake(&snake)) //判断蛇碰到自己 { gotoxy(69, 24); printf("碰到自己, 游戏结束."); gotoxy(69, 26); printf(" "); WriteData(&t_list, &snake); //重置光标到底部 gotoxy(0, 27); break; } Sleep(Speed(&snake)); } fclose(fp); if ((err = fopen_s(&fp, "data.dat", "wb")) != 0) { fputs("错误: 创建数据文件失败", stderr); exit(EXIT_FAILURE); } fwrite(&t_list, sizeof(Score), 1, fp); DeleteSnake(&snake); fclose(fp); system("pause"); return 0; }