diff --git a/a.exe b/a.exe new file mode 100644 index 0000000..f4a4cbc Binary files /dev/null and b/a.exe differ diff --git a/tanchishe.c b/tanchishe.c new file mode 100644 index 0000000..906de8e --- /dev/null +++ b/tanchishe.c @@ -0,0 +1,393 @@ +#include "tanchishe.h" + +// 所有函数与类型等都在头文件声明,以下为函数实现 + +// 初始化函数 +Head_Tail* initgame(Head_Tail *snake) +{ + hout = GetStdHandle(STD_OUTPUT_HANDLE); // 获得标准输出的句柄 + CONSOLE_CURSOR_INFO cursor_info = {1,0}; // 隐藏光标所需类型 + int x=0, y=0, i=0; + Fraction = 0; // 分数初始化 + Snake_body *temp =NULL, *p1=NULL; + system ("title 贪 吃 蛇"); + system ("cls"); + SetConsoleCursorInfo(hout, &cursor_info); // 隐藏光标 + snake = (Head_Tail*)malloc(sizeof(Head_Tail)); + if (snake == NULL) + { + fprintf (stderr, "内存分配失败,退出游戏。"); + exit(1); + } + snake->head = (Snake_body*)malloc(sizeof(Snake_body)); + if (snake->head == NULL) + { + fprintf (stderr, "内存分配失败,退出游戏。"); + exit(1); + } + snake->head->up = NULL; + temp = snake->head; + for (y=STARTED_Y, x=STARTED_X; x > STARTED_X - INIT_LENGTH; x--) // X改变而Y不改 + { + temp->x = x; // 将坐标赋值 + temp->y = y; + p1 = (Snake_body*)malloc(sizeof(Snake_body)); // 下一节蛇体 + if (p1 == NULL) + { + fprintf (stderr, "内存分配失败,退出游戏。"); + exit(1); + } + p1->up = temp; + p1->next = NULL; + temp->next = p1; + temp = temp->next; + p1 = NULL; + } + temp->x=x,temp->y=y; + snake->tail = temp; // 蛇尾 + snake->direction = (Direction*)malloc(sizeof(Direction)); // 下一节蛇体 + if (snake->head == NULL) + { + fprintf (stderr, "内存分配失败,退出游戏。"); + exit(1); + } + snake->direction->x = 1; // 方向,x为1表示向右,0表示不转 + snake->direction->y = 0; + food = (Coordinate*)malloc(sizeof(Coordinate)); // 为存放食物坐标的结构体分配内存 + + switch (hard) { + case 0: // 简单难度 + bian_x = SIMPLE_MAP_X; // 地图的边界x + bian_y = SIMPLE_MAP_Y; // 地图的边界y + snake->speed = SIMPLE_SPEED; // 速度 + sleep_max = INIT_SIMPLE_SPEED; // 速度的最低限制 + break; + case 2: // 困难 + bian_x = DIFFICULT_MAP_X; // 地图的边界x + bian_y = DIFFICULT_MAP_Y; // 地图的边界y + snake->speed = DIFFICULT_SPEED; // 速度 + sleep_max = INIT_DIFFICULT_SPEED;// 速度的最低限制 + break; + default: // 普通难度(默认) + bian_x = ORDINARY_MAP_X; // 地图的边界x + bian_y = ORDINARY_MAP_Y; // 地图的边界y + snake->speed = ORDINARY_SPEED; // 速度 + sleep_max = INIT_ORDINARY_SPEED; // 速度的最低限制 + }; + huagame(snake); + return snake; +} + +// 自定义光标定位函数 +void Location(int x, int y) +{ + COORD coord; + coord.X=x; + coord.Y=y; + SetConsoleCursorPosition(hout,coord); +} +// 画游戏界面 +void huagame(Head_Tail *snake) +{ + int x, y; + Snake_body *temp =NULL; + Location(0, 0); // 初始化光标位置 + for (y=0; yhead; temp != NULL; temp = temp->next) + { + y=temp->y, x=temp->x; + map[y][x] = SNAKE_BODY; // 蛇体 + Location(x, y); + putchar(SNAKE_BODY_T); // 画蛇体 + } + Location(snake->head->x, snake->head->y); + putchar(SNAKE_HEAD_T); // 画蛇头 + Location(food->x, food->y); // 将光标移动到食物的坐标上 + putchar(produce_food[food->x % FOOD_MAX]); // 画食物 +} + + + +// 蛇移动和移动后的判断函数 参数是头尾结构体指针 +void Mobile(Head_Tail *snake, int i) +{ + int x=0, y=0, mode=0; + x = snake->head->x + snake->direction->x; // 蛇将要移动到的位置坐标 + y = snake->head->y + snake->direction->y; // 蛇当前位置加要移动的距离 + Snake_body *temp = NULL, *p1 = NULL; + unsigned int oldheadx = snake->head->x; + unsigned int oldheady = snake->head->y; + unsigned int oldtailx = snake->tail->x; + unsigned int oldtaily = snake->tail->y; + if (x == snake->head->next->x && y == snake->head->next->y) //如果是向反方向移动就直接返回 + { + snake->direction->x = olddir.x; // 将旧方向恢复 + snake->direction->y = olddir.y; // 将旧方向恢复 + return; + } + if (map[y][x] == WALL || map[y][x] == SNAKE_BODY) { // 如果撞到墙或者吃到蛇身体就结束游戏 + snake = Game_Over(snake); + return; + } else if (i==1) { + Fraction += 10; + } else if (map[y][x] == AIR) { // 如果是空气 + Location(oldtailx, oldtaily); // 将光标定位到旧的蛇尾位置 + putchar(AIR_T); // 画空气 + map[oldtaily][oldtailx] = AIR; // 在地图上清除蛇尾 + p1 = snake->tail; // p1为要释放内存的节点,存放蛇尾 + snake->tail = snake->tail->up; // 将蛇尾赋值为蛇尾的前一个 + snake->tail->next = NULL; // 将当前蛇尾的下一个赋值为空 + free(p1); // 释放蛇尾 + } else if (map[y][x] == FOOD) { // 如果是食物 + Fraction++; // 如果是食物就分数加一 + snake->speed -= FOOD_SPEED; // 同时速度增快 + Produce_food(); // 同时再次生成食物 + } + map[y][x] = SNAKE_BODY; + temp = (Snake_body*)malloc(sizeof(Snake_body)); + if (temp == NULL) + { + fprintf (stderr, "内存分配失败,退出游戏。"); + exit(1); + } + temp->x = x; // 新节点的x坐标 + temp->y = y; // 新节点的y坐标 + temp->up = NULL; // 新节点的上一个为空 + temp->next = snake->head; // 新节点的下一个为当前蛇头 + snake->head->up = temp; // 当前蛇头的上一个指向新节点 + snake->head = temp; // 将新节点代替蛇头 + Location(oldheadx, oldheady); // 将光标定位到旧的蛇头位置 + putchar(SNAKE_BODY_T); // 画蛇身 + // map[old_head_y][old_head_x] = SNAKE_BODY; 将旧蛇头的位置在地图上改变(仅适应蛇头在用数字表示时与蛇身不同时,在这里蛇头和身体用数字表达时相同,所以注释掉) + Location(x, y); // 将光标定位到新的蛇头位置 + putchar(SNAKE_HEAD_T); // 画蛇头 + map[y][x] = SNAKE_BODY; // 在地图上添加蛇身 +} + +// 游戏结束 +Head_Tail* Game_Over(Head_Tail *oldsnake) +{ + Head_Tail *snake = NULL; + t: + system ("cls"); + printf ("+---------------------------+\n" + "| |\n" + "| 游 戏 结 束 |\n" + "| |\n" + "| 分数:%-6d |\n" + "| 蛇身总长:%-6d |\n" + "| |\n" + "| 按r重来,任意键退出 |\n" + "| 按z回主菜单 |\n" + "+---------------------------+\n", Fraction, Fraction + 5); + memset(map, 0, sizeof(map)); // 将地图初始化 + switch (getch()) + { + case 'z' : Interface(oldsnake); + case 'r' : fre_game(oldsnake, 0); + snake = initgame(snake); + Produce_food(); // 生成食物 + return snake; + default : printf ("\n是否退出游戏?\ny.退出\t其它键返回"); + if (getchar() == 'y') + exit(1); + else goto t; + } +} + +// 生成食物 +void Produce_food(void) +{ + int x=0, y=0; + srand((unsigned)time(NULL)); + while (1) + { + x = rand() % bian_x; + y = rand() % bian_y; + if (map[y][x] == WALL || map[y][x] == SNAKE_BODY); + else + { + map[y][x] = FOOD; // 在地图上赋值食物 + Location(x, y); + food->x = x; + food->y = y; // 保存食物的坐标 + putchar(produce_food[x % FOOD_MAX]); // 画食物 + return; + } + } +} + +// 释放所有分配了的内存 +void fre_game(Head_Tail *snake, int i) +{ + system("cls"); + printf ("正在释放内存..."); + free(snake->direction); + Snake_body *temp = snake->head, *p1; + while (temp != NULL) + { + p1 = temp; + temp = temp->next; + free(p1); + } + snake->head = NULL; + snake->tail = NULL; + free(snake); + snake = NULL; + free(food); + if (i != 0) // 检查是否要退出 + exit(1); +} + +// 游戏开始界面 +void Interface(Head_Tail *snake) +{ + while (1) + { + system("cls"); + printf ("+----------------------------+\n" + "| |\n" + "| 贪 吃 蛇 |\n" + "| |\n" + "| 1.开始游戏 |\n" + "| 2.帮 助 |\n" + "| 3.设 置 |\n" + "| 4.关 于 |\n" + "| q.退 出 |\n" + "+----------------------------+\n"); + switch(getch()) { + case '1': return; + case '2': banzhu(); break; + case '3': set(); break; + case '4': guanyu(); break; + case 'q': + if (snake == NULL) exit(1); + else fre_game(snake, 1); + } + } +} + +// 帮助界面 +void banzhu(void) +{ + system("cls"); + printf ("+----------------------------+\n" + "| |\n" + "| 游 戏 帮 助 |\n" + "| w |\n" + "| a s d 为方向键 |\n" + "|p键为暂停,暂停后任意键继续 |\n" + "|q键退出(请不要强制退出,程序|\n" + "|将释放游戏分配后的内存) |\n" + "| 任意键返回 |\n" + "+----------------------------+\n"); + getch(); +} + +// 关于界面 +void guanyu(void) +{ + system("cls"); + printf ("+----------------------------+\n" + "| |\n" + "| 关 于 |\n" + "| |\n" + "| 作者:筱傑 |\n" + "| 制作时间:5小时 |\n" + "| 版本:第一代 |\n" + "| 作者QQ:840465812 |\n" + "| 任意键返回 |\n" + "+----------------------------+\n"); + getch(); +} + +// 设置 +void set(void) +{ + char haedstr[3][5] = {"简单\0", "普通\0", "困难\0"}; + while (1) + { + system("cls"); + printf ("+----------------------------+\n" + "| |\n" + "| 设 置 |\n" + "| |\n" + "| 难度:%4s |\n" + "| 1.简单 |\n" + "| 2.普通 |\n" + "| 3.困难 |\n" + "| 其它键返回 |\n" + "+----------------------------+\n", haedstr[hard]); + switch (getch()) + { + case '1': hard = 0; break; + case '2': hard = 1; break; + case '3': hard = 2; break; + default : return; + } + } +} + +int main(void) +{ + Head_Tail *snake = NULL; + int i=0; + Interface(snake); + snake = initgame(snake); + Produce_food(); // 生成食物 + while(1) + { + olddir.x = snake->direction->x; // 保存现在的方向到旧方向 + olddir.y = snake->direction->y; + if (kbhit()) + { + switch(getch()) + { + case 'w': snake->direction->y = -1, snake->direction->x = 0; break; + case 's': snake->direction->y = 1, snake->direction->x = 0; break; + case 'a': snake->direction->y = 0, snake->direction->x = -1; break; + case 'd': snake->direction->y = 0, snake->direction->x = 1; break; + case 'q': snake = Game_Over(snake); break; + case 'p': zantin(snake); break; + case 'b': i=1; break; + } + } + Mobile(snake, i); + i=0; + if (snake->speed > sleep_max) + Sleep(snake->speed -= SPEED_JIAN); + else Sleep(snake->speed); + } + return 0; +} + +// 暂停界面 +void zantin(Head_Tail *snake) +{ + system ("cls"); + printf ("+----------------------------+\n" + "| |\n" + "| 游戏正在暂停中 |\n" + "| |\n" + "| 当前分数:%-6d |\n" + "| 当前蛇长:%-6d |\n" + "| |\n" + "| |\n" + "| 任意键键返回 |\n" + "+----------------------------+\n", Fraction, Fraction+5); + getch(); + system("cls"); + huagame(snake); +} \ No newline at end of file diff --git a/tanchishe.h b/tanchishe.h new file mode 100644 index 0000000..c8e741b --- /dev/null +++ b/tanchishe.h @@ -0,0 +1,113 @@ +// 该头文件内容为贪吃蛇的宏定义以及类型声明和函数声明 + +#ifndef _tanchishe_h_ +#define _tanchishe_h_ + +#include +#include +#include +#include +#include +#include + +#define SIMPLE_MAP_X 50 // 简单难度的地图X长度 +#define SIMPLE_MAP_Y 24 // 简单难度的地图Y长度 +#define ORDINARY_MAP_X 30 // 普通难度的地图X长度 +#define ORDINARY_MAP_Y 15 // 普通难度的地图Y长度 +#define DIFFICULT_MAP_X 22 // 困难难度的地图X长度 +#define DIFFICULT_MAP_Y 12 // 困难难度的地图Y长度 +#define STARTED_X 11 // 蛇头的初始化X位置 +#define STARTED_Y 6 // 蛇头的初始化y位置 +#define INIT_LENGTH 5 // 蛇的初始化长度 +#define INIT_SIMPLE_SPEED 250 // 简单难度的蛇最终速度 +#define INIT_ORDINARY_SPEED 200 // 普通难度的蛇最终速度 +#define INIT_DIFFICULT_SPEED 150// 困难难度的蛇最终速度 +#define SIMPLE_SPEED 500 // 简单难度的蛇初始化速度 +#define ORDINARY_SPEED 400 // 普通难度的蛇初始化速度 +#define DIFFICULT_SPEED 300 // 困难难度的蛇初始化速度 +#define FOOD_SPEED 2 // 每吃一个食物就加速(无限制) +#define SPEED_JIAN 2 // 每移动一步就加速(有限制) +#define AIR 0 // 空气 +#define WALL 2 // 墙 +#define SNAKE_BODY 1 // 蛇体 +#define FOOD 3 // 食物 +#define FOOD_MAX 8 // 食物的种类个数 +#define SNAKE_HEAD_T 1 // 蛇头的图案 +#define SNAKE_BODY_T 4 // 蛇身的图案 +#define WALL_T 22 // 墙的图案 +#define AIR_T ' ' // 空气的图案 + + +// 蛇体类型 +typedef struct snake_body { + int x; + int y; + struct snake_body *up; + struct snake_body *next; +} Snake_body; + +// 坐标类型 +typedef struct { + int x; + int y; +} Coordinate; + +// 方向类型 +typedef Coordinate Direction; + +// 包含蛇头蛇尾和方向的指针和速度 +typedef struct head_tail { + Snake_body *head; + Snake_body *tail; + Direction *direction; + unsigned int speed; +} Head_Tail; + +// 全局变量 +HANDLE hout; // 获得标准输出的句柄 +int map[SIMPLE_MAP_Y][SIMPLE_MAP_X] = {0}; // 地图 +int bian_x=0, bian_y=0; // 地图边界(随难度变化而变化) +char produce_food[FOOD_MAX] = {3, 5, 6, 35, 36, 37, 38, 15}; // 食物的图案(ASCII表中的图案) +unsigned int Fraction = 0; // 分数 +int hard = 1; // 难度(默认为普通) +Direction olddir = {0,0}; // 旧的方向(在按错时可以恢复) +Coordinate *food; // 食物的坐标 +unsigned int sleep_max = 0; // 最快的速度 + +// 初始化函数 +Head_Tail* initgame(Head_Tail*); + +// 自定义光标定位函数 +void Location(int x, int y); + +// 蛇移动和移动后的判断函数 参数是头尾结构体指针 +void Mobile(Head_Tail*, int);// 参数二是是否作弊 + +// 游戏结束 +Head_Tail* Game_Over(Head_Tail*); + +// 生成食物 +void Produce_food(void); + +// 释放游戏中分配的内存 +void fre_game(Head_Tail*, int); + +// 游戏开始界面 +void Interface(Head_Tail*); + +// 帮助界面 +void banzhu(void); + +// 关于界面 +void guanyu(void); + +// 设置 +void set(void); + +// 暂停界面 +void zantin(Head_Tail*); + +// 画游戏界面 +void huagame(Head_Tail*); + +#endif \ No newline at end of file diff --git a/璐悆铔囪璁℃枃妗.doc b/璐悆铔囪璁℃枃妗.doc new file mode 100644 index 0000000..ba4ffdb Binary files /dev/null and b/璐悆铔囪璁℃枃妗.doc differ