#include "Conio.h"
#include<graphics.h>
#include<stdlib.h>
#include<dos.h>
#include<stdio.h>
#define closegr closegraph
#define NULL 0
#define LEFT 0x4b00
#define RIGHT 0x4d00
#define DOWN 0x5000
#define UP    0x4800
#define ESC   0x011b
int t=1,scord=0,speed=1;
char scordc[20],speedc[12];
void initgr(void) /* BGI初始化 */
{
int gd = DETECT, gm = 0; /* 和gd = VGA,gm = VGAHI是同样效果 */
registerbgidriver(EGAVGA_driver);/* 注册BGI驱动后可以不需要.BGI文件的支持运行 */
initgraph(&gd, &gm, "");
}
typedef struct node{ /*蛇每个节点的结构体*/
    int x;
    int y;
    struct node *next;
}snake,*snakep;
typedef struct{   /*食物的结构体*/
    int x;
    int y;
}foodf,*foodp;
int main(void)
{
    snakep init();
    void draw(int x,int y,int p);
    void start();
    void drawsnake(snakep sn);
    void sport(snakep *sn,int f,foodp food);
    int check(snakep sn);
    int foodcheck(snakep,foodp);
    char ch;
    start();
    while((ch=getch())!='Q'&&ch!='q')
    {}; /* 按Q退出*/
    closegr(); /* 恢复TEXT屏幕模式 */
    return 0;
}
snakep init()
{
    int i;
    snakep L,p;
    initgr(); /* BGI初始化 */
    setbkcolor(6);/*设置屏幕背景色*/
    setviewport(80,50,550,450,1);/*设置可活动区域*/
    sprintf(scordc,"SCORD:%d",scord);
    outtextxy(20,20,scordc);/*分数和速度栏*/
    sprintf(speedc,"SPEED:%d",speed);
    outtextxy(200,20,speedc);
    outtextxy(350,20,"SM VS ZG");
    for(i=0;i<=390;i+=10)/*初始化场景*/
    {
        draw(0,i,2);
        draw(460,i,2);
    }
    for(i=10;i<=450;i+=10)
    {
        draw(i,0,2);
        draw(i,30,2);
        draw(i,390,2);
    }
    for(i=10;i<=40;i+=10)/*蛇身初始化,i=40时,为头结点*/
    {
        p=(snake *)malloc(sizeof(snake));
        p->x=i;p->y=40;
        if(i==10)
        {
            p->next=NULL;
            L=p;
        }
        else
        {
            p->next=L;
            L=p;
        }
    }
    return L;
}
void draw(int x,int y,int p)    /*画小元件*/
{
    setcolor(p);
    rectangle(x+1,y+1,x+9,y+9);
    rectangle(x+3,y+3,x+7,y+7);
}
void start()
{
    int f=0,p=1,i,key;
    snakep sn;
    foodp food;
    randomize();
    sn=init();
    drawsnake(sn);              /*初始化场景和蛇身*/
    food=(foodf *)malloc(sizeof(foodf));
    while(1)
    {
    while(!kbhit())
    {
            while(t==1)        /*需要实物*/
            {
                food->x=(rand()%45+1)*10;
                food->y=(rand()%35+4)*10;
                if(foodcheck(sn,food))
                {
                    draw(food->x,food->y,15);
                    t=0;
                }
            }
        delay(31000-2000*speed);
        sport(&sn,f,food); /*蛇运动*/
        if(check(sn)==1)
        {
            p=0;
            break;
        }
    }
    if(p==0)
    {
        setcolor(RED);
        settextstyle(0,0,4);
        outtextxy(80,160,"GAME OVER");
        settextstyle(0,0,1);
        outtextxy(100,200,"PRESS \"Q\" TO QUIT GAME");
        break;
    }
    key=bioskey(0);
        if(key==ESC)
            break;
        else if(key==RIGHT&&f!=2)
            f=0;
        else if(key==DOWN&&f!=3)
            f=1;
        else if(key==LEFT&&f!=0)
            f=2;
        else if(key==UP&&f!=1)
            f=3;
    }
}
void drawsnake(snakep sn)       /*在屏幕上画出初始蛇*/
{
    snakep p=sn->next;
    while(p)
    {
        draw(p->x,p->y,4);
        p=p->next;
    }
}
void sport(snakep *k,int f,foodp food)     /*蛇运动图像*/
{
    snakep snb,h,p=(*k)->next;
    while(p->next->next)
        p=p->next;
    snb=p;
    h=p;                  /*snb,k是蛇的尾节点的前一个节点指针*/
    p=(*k)->next;                      /*把蛇的最后一个节点放在最前面*/
    snb->next->next=p;
    p=snb->next;
    snb->next=NULL;
    draw(p->x,p->y,6);      /*最后一个节点与背景色相同(即去掉最后一个节点)*/
    snb=p->next;
    switch(f)
    {
        case 0:                 /*蛇往右走*/
        {
            p->x=snb->x+10;
            p->y=snb->y;
            break;
        }
        case 1:                /*蛇往下走*/
        {
            p->x=snb->x;
            p->y=snb->y+10;
            break;
        }
        case 2:                /*蛇往左走*/
        {
            p->x=snb->x-10;
            p->y=snb->y;
            break;
        }
        case 3:              /*蛇往上走*/
        {
            p->x=snb->x;
            p->y=snb->y-10;
            break;
        }
    }
    draw(p->x,p->y,4);
    if(p->x==food->x&&p->y==food->y) /*吃到食物,蛇加长*/
    {
     snb=(snake *)malloc(sizeof(snake));
     snb->next=NULL;
     snb->x=h->x;
     snb->y=h->y;
     h->next=snb;
     t=1;
     setcolor(6);
     outtextxy(20,20,scordc);
     scord++;
     if(scord%5==0)/*若吃了5个,则升级,速度加快*/
     {
        setcolor(6);
        outtextxy(200,20,speedc);
        speed++;
        setcolor(15);
        sprintf(speedc,"SPEED:%d",speed);
        outtextxy(200,20,speedc);
     }
     setcolor(15);
     sprintf(scordc,"SCORD:%d",scord);
     outtextxy(20,20,scordc);
    }
    (*k)->next=p;
}
int check(snakep sn)/*检测蛇是否撞墙或撞自己的身体*/
{
    snakep p=sn->next;
    if(p->x<10||p->x>450||p->y<40||p->y>380)
        return 1;
    while(p->next)
    {
        p=p->next;
        if(sn->next->x==p->x&&sn->next->y==p->y)
            return 1;
    }
    return 0;
}
int foodcheck(snakep sn,foodp food)/*检测食物出现的位置是否和蛇的身体重合*/
{
    while(sn->next)
    {
        sn=sn->next;
        if(sn->x==food->x&&sn->y==food->y)
            return 0;
    }
    return 1;
}