#include <stdio.h>

#include <windows.h>
#include <conio.h>
#include <string.h>
 
#define UP 0
#define DOWN 1
#define LEFT 2
#define RIGHT 3//宏定义,定义四个方向--0 1 2 3分别代表上下左右
 
#define TURN_NUM 1000//可以保存的最多转弯次数,一条蛇同时最多只能有1000次的弯曲
#define INIT_LENGTH 8
 
#define UP_EDGE 0
#define DOWN_EDGE 24
#define LEFT_EDGE 0
#define RIGHT_EDGE 79//定义上下左右四个边界
 
#define X 0//初始状态下蛇的身体坐标(LEFT_EDGE+X,UP_EDGE+Y)
#define Y 0//决定初始状态下蛇的身体相对于游戏界面原点(LEFT_EDGE,UP_EDGE)的位置
 
/*定义全局变量*/
char buf[1000]="@*******";//决定初始的snake_length的值:必须与INIT_LENGTH保持同步
char *snake=buf;//蛇的身体,最长有1000个环节
char FOOD='$';//记录食物的形状
int food_num=0;//记录已经吃下的食物数量
int score=0;//记录当前的得分,由food_num决定
int snake_length=INIT_LENGTH;//initializer is not a constant:strlen(snake);
int cursor[2]={LEFT_EDGE+20+INIT_LENGTH,UP_EDGE+10};//记录当前光标所指位置
int head[2]={LEFT_EDGE+20+INIT_LENGTH-1,UP_EDGE+10};//记录头部的坐标
int tail[2]={0,0};//记录尾巴的坐标
int old_tail[2];//记录上一步尾巴所在位置
int food[2]={0,0};//记录食物的坐标
int init_position[2]={LEFT_EDGE+X,UP_EDGE+Y};//蛇的初始位置
int direction=RIGHT;//记录当前蛇的头部的运动方向
int turn_point[TURN_NUM][2];
int head_turn_num=0;//记录头部的转弯次数
int tail_turn_num=0;//记录尾巴的转弯次数
int game_over=0;//判断游戏是否结束
 
/*主方法*/
void main(){
//函数声名
void gotoxy(int x,int y);//移动光标的位置
void cur_state();//测试游戏的当前状态参数
void print_introduction();//打印游戏规则
void init();//初始化游戏
void control();//接收键盘控制命令
void move();//控制身体的运动
void move_up();//向上运动
void move_down();//向下运动
void move_left();//向左运动
void move_right();//向右运动
void update_tail_position();//更新尾巴的坐标
void generate_food();//随机产生食物
void eat_food();//吃下食物
 
char ch;
 
while(!game_over){
print_introduction();
printf("\t\t按任意键开始游戏");
getch();
system("cls");
//cur_state();
init();
control();
system("cls");
gotoxy(0,10);
printf("\t\t您的当前得分是%d\n",score);
printf("\t\t这条蛇共转了%d次弯,它的身体长度是%d\n",head_turn_num,strlen(snake));
printf("\t\t游戏结束,您要再玩一局吗?(y/n)");
scanf("%c",&ch);
getchar();
if(ch=='y'||ch=='Y'){
continue;
}else{
system("cls");
printf("\n\n\n\t\t\t谢谢您的使用,再见!");
_sleep(3000);
game_over=1;
}
}
}
 
/*打印游戏规则*/
void print_introduction(){
int i=0;
int rule_num;
char *rule[4];
rule[i++]="\n\n\t\t\t欢迎您来玩贪食蛇游戏\n";
rule[i++]="\t\t游戏规则如下:\n";
rule[i++]="\t\t1.按上下左右键控制蛇的运动方向\n";
rule[i++]="\t\t2.按Ctrl+C结束当前游戏\n";
rule_num=i;
system("cls");
for(i=0;i<rule_num;i++){
puts(rule[i]);
}
}
 
/*移动光标的位置*/
void gotoxy(int x,int y){
COORD coord={x,y};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);
}
 
/*测试游戏的当前状态参数*/
void cur_state(){
printf("游戏的当前状态参数如下:\n");
printf("snake=%s\n",snake);
printf("snake_body_length=%d\n",strlen(snake));
printf("head=(%d,%d)\n",head[0],head[1]);
printf("tail=(%d,%d)\n",tail[0],tail[1]);
printf("direction=%d\n",direction);
printf("game_over=%d\n",game_over);
}
 
/*游戏进入初始状态*/
void init(){
int i;
 
/*初始化游戏参数*/
food_num=0;//记录已经吃下的食物数量
score=0;//记录当前的得分,由food_num决定
snake_length=INIT_LENGTH;
cursor[0]=init_position[0]+INIT_LENGTH;
cursor[1]=init_position[1];//记录当前光标所指位置
head[0]=init_position[0]+INIT_LENGTH-1;
head[1]=init_position[1];//记录头部的坐标
tail[0]=init_position[0];
tail[1]=init_position[1];//记录尾巴的坐标
direction=RIGHT;//记录当前蛇的头部的运动方向
head_turn_num=0;//记录头部的转弯次数
tail_turn_num=0;//记录尾巴的转弯次数
game_over=0;//判断游戏是否结束
turn_point[0][0]=RIGHT_EDGE;
turn_point[0][1]=0;
/*游戏参数初始化完毕*/
 
generate_food();//投下第一粒食物
gotoxy(init_position[0],init_position[1]);//将光标移动到到初始化位置
for(i=snake_length;i>0;i--){
putchar(snake[i-1]);
}
}
 
/*接收键盘控制命令*/
void control(){
char command;//存放接收到命令
while(1){
command=getch();
if(command==-32){
//F11,F12:-123,-122
command=getch();
if(command=='H' && (direction==LEFT || direction==RIGHT)){//光标上移
direction=UP;
turn_point[head_turn_num%TURN_NUM][0]=head[0];
turn_point[head_turn_num%TURN_NUM][1]=head[1];
head_turn_num++;
}else if(command=='P' && (direction==LEFT || direction==RIGHT)){//光标下移
direction=DOWN;
turn_point[head_turn_num%TURN_NUM][0]=head[0];
turn_point[head_turn_num%TURN_NUM][1]=head[1];
head_turn_num++;
}else if(command=='K' && (direction==UP || direction==DOWN)){//光标左移
direction=LEFT;
turn_point[head_turn_num%TURN_NUM][0]=head[0];
turn_point[head_turn_num%TURN_NUM][1]=head[1];
head_turn_num++;
}else if(command=='M' && (direction==UP || direction==DOWN)){//光标右移
direction=RIGHT;
turn_point[head_turn_num%TURN_NUM][0]=head[0];
turn_point[head_turn_num%TURN_NUM][1]=head[1];
head_turn_num++;
}else if(command==-122 || command==-123);
}else if(command==0){
command=getch();//接收Fn的下一个字符
//F1~F10:59~68
}else if(command>=1&&command<=26){
//Ctrl+a~z:1~26
if(command==3){
break;
}
}else{
//do nothing!
}
move();
if(head[0]==food[0] && head[1]==food[1]){
eat_food();//吃掉一粒事物
generate_food();//投下新食物
}
}
}
 
/*蛇的身体运动*/
void move(){
if(direction==UP){
//printf("Moving up!\n");
move_up();
}else if(direction==DOWN){
//printf("Moving down!\n");
move_down();
}else if(direction==LEFT){
//printf("Moving left!\n");
move_left();
}else if(direction==RIGHT){
//printf("Moving right!\n");
move_right();
}
}
 
/*向上运动*/
void move_up(){
if(cursor[1]>=UP_EDGE){
gotoxy(head[0],head[1]);
putchar('*');
gotoxy(head[0],head[1]-1);
putchar(snake[0]);
gotoxy(tail[0],tail[1]);
//_sleep(1000);//查看尾部光标
putchar(0);
update_tail_position();
head[1]-=1;
cursor[0]=head[0];
cursor[1]=head[1]-1;
gotoxy(cursor[0],cursor[1]);
}else{
gotoxy(head[0],head[1]);
}
}
 
/*向下运动*/
void move_down(){
if(cursor[1]<=DOWN_EDGE){
gotoxy(head[0],head[1]);
putchar('*');
gotoxy(head[0],head[1]+1);
putchar(snake[0]);
gotoxy(tail[0],tail[1]);
//_sleep(1000);//查看尾部光标
putchar(0);
update_tail_position();
head[1]+=1;
cursor[0]=head[0];
cursor[1]=head[1]+1;
gotoxy(cursor[0],cursor[1]);
}else{
gotoxy(head[0],head[1]);
}
}
 
/*向左运动*/
void move_left(){
if(cursor[0]>=LEFT_EDGE){
gotoxy(head[0],head[1]);
putchar('*');
gotoxy(head[0]-1,head[1]);
putchar(snake[0]);
gotoxy(tail[0],tail[1]);
//_sleep(1000);//查看尾部光标
putchar(0);
update_tail_position();
head[0]-=1;
cursor[0]=head[0]-1;
cursor[1]=head[1];
gotoxy(cursor[0],cursor[1]);
}else{
gotoxy(head[0],head[1]);
}
}
 
/*向右运动*/
void move_right(){
if(cursor[0]<=RIGHT_EDGE){
gotoxy(head[0],head[1]);
putchar('*');
putchar(snake[0]);
gotoxy(tail[0],tail[1]);
//_sleep(1000);//查看尾部光标
putchar(0);
update_tail_position();
head[0]+=1;
cursor[0]=head[0]+1;
cursor[1]=head[1];
gotoxy(cursor[0],cursor[1]);
}else{
gotoxy(head[0],head[1]);
}
}
 
/*更新尾巴的坐标*/
void update_tail_position(){
old_tail[0]=tail[0];
old_tail[1]=tail[1];//保存上次尾巴的位置
if(tail[0]==food[0] && tail[1]==food[1]){
gotoxy(tail[0],tail[1]);
putchar(FOOD);
}
if(tail_turn_num<head_turn_num){
if(tail[0]<turn_point[tail_turn_num%TURN_NUM][0]){
tail[0]+=1;
}else if(tail[0]>turn_point[tail_turn_num%TURN_NUM][0]){
tail[0]-=1;
}else if(tail[1]<turn_point[tail_turn_num%TURN_NUM][1]){
tail[1]+=1;
}else if(tail[1]>turn_point[tail_turn_num%TURN_NUM][1]){
tail[1]-=1;
}else if(tail[0]==turn_point[(tail_turn_num-1)%TURN_NUM][0] && tail[1]==turn_point[(tail_turn_num-1)%TURN_NUM][1]){
if(tail[0]<turn_point[tail_turn_num%TURN_NUM][0]){
tail[0]+=1;
}else if(tail[0]>turn_point[tail_turn_num%TURN_NUM][0]){
tail[0]-=1;
}else if(tail[1]<turn_point[tail_turn_num%TURN_NUM][1]){
tail[1]+=1;
}else if(tail[1]>turn_point[tail_turn_num%TURN_NUM][1]){
tail[1]-=1;
}
}
if(tail[0]==turn_point[tail_turn_num%TURN_NUM][0] && tail[1]==turn_point[tail_turn_num%TURN_NUM][1]){
tail_turn_num+=1;
}
}else if(tail_turn_num==head_turn_num){
if(tail[0]<head[0]){
tail[0]+=1;
}else if(tail[0]>head[0]){
tail[0]-=1;
}else if(tail[1]<head[1]){
tail[1]+=1;
}else if(tail[1]>head[1]){
tail[1]-=1;
}
}
}
 
void generate_food(){
int i=0,j=0;
do{
i=rand()%DOWN_EDGE;
}while(i<UP_EDGE || i>DOWN_EDGE);
 
do{
j=rand()%DOWN_EDGE;
}while(j<LEFT_EDGE || j>RIGHT_EDGE);
food[0]=i;
food[1]=j;
gotoxy(food[0],food[1]);//抵达食物投放点
putchar(FOOD);//放置食物
gotoxy(cursor[0],cursor[1]);//返回光标当前位置
}
 
void eat_food(){
if(tail[0]==turn_point[(tail_turn_num-1)%TURN_NUM][0] && tail[1]==turn_point[(tail_turn_num-1)%TURN_NUM][1]){
tail_turn_num-=1;
}
snake[snake_length++]=snake[1];
tail[0]=old_tail[0];
tail[1]=old_tail[1];//将尾巴回退到上一步所在的位置
gotoxy(tail[0],tail[1]);
putchar(snake[1]);
food_num++;
score=food_num;
gotoxy(cursor[0],cursor[1]);
}