链表实现贪吃蛇

链表实现贪吃蛇

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#include <conio.h>

//蛇的状态
#define U 1  //上
#define D 2  //下
#define L 3  //左
#define R 4  //右

/*********** 全局变量 **********/
typedef struct SNAKE //蛇身的一个节点
{
    int x;
    int y;
    struct SNAKE *next;
}snake;

int score = 0, add = 10; //总得分与每次吃食物得分
int status, sleeptime = 200; //蛇前进状态,每次运行的时间间隔
snake *head, *food;      //蛇头指针, 食物指针
snake *q; //遍历蛇的时候用到的指针

int endgamestatus = 0;
/* 游戏结束的情况: 1.撞到墙 2.撞到自己 3.主动退出游戏 */

HANDLE hOut;       //控制台句柄

/*********** 函数声明 **********/
void gotoxy(int x, int y);   //设置光标位置
void mycolor(int c);         //更改文字颜色
void createmap();            //绘制地图
void welcometogame();        //开始界面
void scoreandtips();         //游戏界面右侧得分和小提示
void initsnake();            //初始化蛇身,画蛇身
void createfood();           //创建并随机出现食物
int biteself();             //判断是否咬到了自己
void cantcrosswall();        //设置蛇撞墙的情况
void speedup();              //加速
void speeddown();            //减速
void snakemove();            //控制蛇前进方向
void keyboardcontrol();      //控制键盘按键
void lostdraw();             //游戏结束界面
void endgame();              //游戏结束
void choose();               //游戏失败之后的选择
void explation();            //游戏说明
/**********************************/


int main(void)
{
    system("mode con cols=100 lines=30"); //设置控制台宽高
    welcometogame();
    keyboardcontrol();
    endgame();
   
    getchar();
    return 0;
}

//设置光标位置
void gotoxy(int x, int y)
{
    COORD c;
    c.X = x;
    c.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
}

//更改文字颜色
void mycolor(int c)
{
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c);
        return 0;
}

//绘制地图
void createmap()
{
    int i, j;
    for (i = 0; i < 58; i += 2) //打印上下边框
    {
        gotoxy(i, 0);
        mycolor(5);
        printf("□");
        gotoxy(i, 26);
        printf("□");
    }

    for (i = 1; i < 26; i++)  //打印左右边框
    {
        gotoxy(0, i);
        printf("□");
        gotoxy(56, i);
        printf("□");
    }

    for (i = 2; i < 56; i += 2)  //打印中间网格
    {
        for (j = 1; j < 26; j++)
        {
            gotoxy(i, j);
            mycolor(3);
            printf("■");
        }
    }   
}

//开始界面
void welcometogame()
{
    int n;
    gotoxy(43, 10);
    mycolor(11);
    printf("贪 吃 蛇 大 作 战");
    mycolor(12);
    gotoxy(25, 22);
    printf("1.开始游戏");
    gotoxy(45, 22);
    printf("2.游戏说明");
    gotoxy(65, 22);
    printf("3.退出游戏");
    gotoxy(40, 27);
    mycolor(3);
    printf("请选择 1 2 3:");
    mycolor(14);
    scanf("%d", &n);
    switch ( n )
    {
        case 1:
            system("cls");
            createmap();   //创建食物
            initsnake();   //初始化蛇身
            createfood();  //创建食物
            keyboardcontrol(); //按键控制
            break;
        case 2:
            explation();
            break;
        case 3:
            exit(0);
            break;
        default:
            mycolor(12);
            gotoxy(40, 28);
            printf("请输入1-3之间的数!");
            getchar();
            system("cls");
            welcometogame();
    }
}

//游戏界面右侧得分和小提示
void scoreandtips()
{
    gotoxy(64, 8);
    mycolor(14);
    printf("得分: %d", score);

    gotoxy(64, 14);
    printf("每个食物得分: %d 分", add);
    gotoxy(64, 16);
    printf("不能穿墙,不能咬到自己");
    gotoxy(64, 18);
    printf("用↑ ↓ ← →分别控制蛇的移动");
    gotoxy(64, 20);
    printf("F1为加速,F2为减速");
    gotoxy(64, 22);
    printf("space:暂停游戏");
    gotoxy(64, 24);
    printf("ESC: 退出游戏");
}

//初始化蛇身,画蛇身
void initsnake()
{
    snake *tail;
    int i;

    //从蛇尾开始,头插法,以x,y设定开始的位置
    tail = (snake *)malloc(sizeof(snake));
    tail->x = 24;
    tail->y = 5;
    tail->next = NULL;

    for (i = 1; i <= 3; i++) //设置蛇身,长度为3
    {
        head = (snake *)malloc(sizeof(snake)); //初始化蛇头
        head->next = tail;
        head->x = 24 + 2 * i;
        head->y = 5;
        tail = head;  //蛇头变蛇尾,重复循环
    }

    while ( tail != NULL )
    {
        gotoxy(tail->x, tail->y);
        mycolor(14);
        printf("★"); //输出蛇身
        tail = tail->next;
    }
}

//创建并随机出现食物
void createfood()
{
    snake *food1 = NULL;
    srand((unsigned)time(NULL));
    food1 = (snake *)malloc(sizeof(snake));
    if ( !food1 )
    {
        exit(1);
    }

    //保证为偶数,使食物能与蛇头对齐,然后食物会出现在网格线上
    while ( (food1->x % 2) != 0 )
    {
        food1->x = rand() % 52 + 2; //食物随机出现
    }
    food1->y = rand() % 24 + 1;
    q = head;
    while ( q->next == NULL )
    {
        //判断蛇身是否与食物生命
        if (q->x == food1->x && q->y == food1->y)
        {
            free(food1); //如果重合,那么释放食物指针
            createfood(); //重新创建食物
        }
        q = q->next;
    }
    gotoxy(food1->x, food1->y);
    food = food1;
    mycolor(12);
    printf("●"); //输出食物
}

//判断是否咬到了自己
int biteself()
{
    snake *self;        //定义self为蛇身上的一个结点
    self = head->next;  //self是蛇头之外的蛇身上的结点
    while ( self != NULL )
    {
        //如果self和蛇身上的结点重合
        if (self->x == head->x && self->y == head->y)
        {
            return 1;
        }
        self = self->next;
    }
    return 0;
}

//设置蛇撞墙的情况
void cantcrosswall()
{
    //如果蛇头碰到了墙壁
    if (head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26)
    {
        endgamestatus = 1;  //返回第一种情况
        endgame();          //出现游戏结束界面
    }
}

//加速,蛇吃到食物会自动提速,并且按F1会加速
void speedup()
{
    if (sleeptime >= 50)
    {
        sleeptime = sleeptime - 10;
        add = add + 10;
    }
}

//减速
void speeddown()
{
    if (sleeptime < 350) //如果时间间隔小于350
    {
        sleeptime = sleeptime + 30; //时间间隔加上30
        add = add - 5;  //每吃一次食物的得分减5
    }
}

//控制蛇前进方向
void snakemove()
{
    snake *nexthead;
    cantcrosswall();
    nexthead = (snake *)malloc(sizeof(snake));
    if ( !nexthead )
    {
        exit(1);
    }
    if (status == U)
    {
        nexthead->x = head->x; //向上前进时,x坐标不变,y坐标-1
        nexthead->y = head->y - 1;
        nexthead->next = head;
        head = nexthead;
        q = head;    //指针q指向蛇头

        //如果下一个有食物下一个位置的坐标和食物的坐标相同
        if (nexthead->x == food->x && nexthead->y == food->y)
        {
            while ( q != NULL )
            {
                gotoxy(q->x, q->y);
                mycolor(14);
                printf("★"); //原来食物的位置,从●换成★,表示吃掉了
                q = q->next;
            }
            score += add;  //吃一个食物,总分加10
            speedup();     //加速
            createfood();  //创建食物
        }
        else
        {
            while ( q->next->next != NULL ) //如果没遇到食物
            {
                gotoxy(q->x, q->y);
                mycolor(14);
                printf("★"); //蛇正常往前走,输出当前位置的蛇身
                q = q->next;  //继续输出整个蛇身
            }

            //经过上面的循环,q指向蛇尾,蛇尾的下一位就是蛇走过去的位置
            gotoxy(q->next->x, q->next->y);
            mycolor(3);
            printf("■");
            free(q->next);  //输出■后,释放指向下一位的指针
            q->next = NULL;
        }
    }

        if ( status == D )
        {
                nexthead->x = head->x; //向下前进时,x坐标不变,y坐标+1
                nexthead->y = head->y + 1;
                nexthead->next = head;
                head = nexthead;
                q = head;    //指针q指向蛇头

                //有食物
                if ( nexthead->x == food->x && nexthead->y == food->y )
                {
                        while ( q != NULL )
                        {
                                gotoxy(q->x, q->y);
                                mycolor(14);
                                printf("★"); //原来食物的位置,从●换成★,表示吃掉了
                                q = q->next;
                        }
                        score += add;  //吃一个食物,总分加10
                        speedup();     //加速
                        createfood();  //创建食物
                }
                else //没有食物
                {
                        while ( q->next->next != NULL )
                        {
                                gotoxy(q->x, q->y);
                                mycolor(14);
                                printf("★"); //蛇正常往前走,输出当前位置的蛇身
                                q = q->next;  //继续输出整个蛇身
                        }

                        //经过上面的循环,q指向蛇尾,蛇尾的下一位就是蛇走过去的位置
                        gotoxy(q->next->x, q->next->y);
                        mycolor(3);
                        printf("■");
                        free(q->next);  //输出■后,释放指向下一位的指针
                        q->next = NULL;
                }
        }

        if ( status == L )
        {
                nexthead->x = head->x - 2; //向左前进时,x坐标-2,y坐标不变
                nexthead->y = head->y;
                nexthead->next = head;
                head = nexthead;
                q = head;    //指针q指向蛇头

                //如果下一个有食物下一个位置的坐标和食物的坐标相同
                if ( nexthead->x == food->x && nexthead->y == food->y )
                {
                        while ( q != NULL )
                        {
                                gotoxy(q->x, q->y);
                                mycolor(14);
                                printf("★"); //原来食物的位置,从●换成★,表示吃掉了
                                q = q->next;
                        }
                        score += add;  //吃一个食物,总分加10
                        speedup();     //加速
                        createfood();  //创建食物
                }
                else
                {
                        while ( q->next->next != NULL ) //如果没遇到食物
                        {
                                gotoxy(q->x, q->y);
                                mycolor(14);
                                printf("★"); //蛇正常往前走,输出当前位置的蛇身
                                q = q->next;  //继续输出整个蛇身
                        }

                        //经过上面的循环,q指向蛇尾,蛇尾的下一位就是蛇走过去的位置
                        gotoxy(q->next->x, q->next->y);
                        mycolor(3);
                        printf("■");
                        free(q->next);  //输出■后,释放指向下一位的指针
                        q->next = NULL;
                }
        }

        if ( status == R )
        {
                nexthead->x = head->x + 2; //向右前进时,x坐标+2,y坐标不变
                nexthead->y = head->y;
                nexthead->next = head;
                head = nexthead;
                q = head;    //指针q指向蛇头

                //有食物
                if ( nexthead->x == food->x && nexthead->y == food->y )
                {
                        while ( q != NULL )
                        {
                                gotoxy(q->x, q->y);
                                mycolor(14);
                                printf("★"); //原来食物的位置,从●换成★,表示吃掉了
                                q = q->next;
                        }
                        score += add;  //吃一个食物,总分加10
                        speedup();     //加速
                        createfood();  //创建食物
                }
                else //没有食物
                {
                        while ( q->next->next != NULL )
                        {
                                gotoxy(q->x, q->y);
                                mycolor(14);
                                printf("★"); //蛇正常往前走,输出当前位置的蛇身
                                q = q->next;  //继续输出整个蛇身
                        }

                        //经过上面的循环,q指向蛇尾,蛇尾的下一位就是蛇走过去的位置
                        gotoxy(q->next->x, q->next->y);
                        mycolor(3);
                        printf("■");
                        free(q->next);  //输出■后,释放指向下一位的指针
                        q->next = NULL;
                }
        }

    if (biteself() == 1) //判断是否会咬到自己
    {
        endgamestatus = 2;
        endgame();
    }
}

//控制键盘按键
void keyboardcontrol()
{
    status = R;  //初始蛇向右移动
    while ( 1 )
    {
        scoreandtips();
        if (GetAsyncKeyState(VK_UP) && status != D)
        {
            //如果蛇不是向下前进的时候,按上键,执行向上操作
            status = U;
        }
        else if ( GetAsyncKeyState(VK_DOWN) && status != U )
        {
            status = D;
        }
        else if (GetAsyncKeyState(VK_LEFT) && status != R )
        {
            status = L;
        }
        else if (GetAsyncKeyState(VK_RIGHT) && status != L)
        {
            status = R;
        }
        if (GetAsyncKeyState(VK_SPACE)) //执行暂停
        {
            while ( 1 )
            {
                Sleep(300);
                if (GetAsyncKeyState(VK_SPACE))
                {
                    break;
                }
            }
        }
        else if (GetAsyncKeyState(VK_ESCAPE)) //按esc结束
        {
            endgamestatus = 3;
            break;
        }
        else if (GetAsyncKeyState(VK_F1))
        {
            speedup();
        }
        else if (GetAsyncKeyState(VK_F2))
        {
            speeddown();
        }
        Sleep(sleeptime);
        snakemove();
    }
}

//游戏说明
void explation()
{
    system("cls");
    mycolor(3);
    gotoxy(30, 8);
    printf("1.不能穿墙,不能咬到自己");
    mycolor(10);
    gotoxy(30, 11);
    printf("2. 用↑.↓.←.→分别控制蛇的移动");
    mycolor(14);
    gotoxy(30, 14);
    printf("3. F1为加速,F2为减速");
    mycolor(11);
    gotoxy(30, 17);
    printf("4. 按空格键暂停游戏,再按空格键继续");
    mycolor(4);
    gotoxy(30, 20);
    printf("5. ESC: 退出游戏 SPACE: 暂停游戏");
    getchar();
    getchar();
    system("cls");
    welcometogame();
}           

//游戏结束
void endgame()
{
    system("cls");
    if (endgamestatus == 1)
    {
        lostdraw();
        gotoxy(43, 9);
        mycolor(12);
        printf("GAME OVER !");
    }
    else if (endgamestatus == 2)
    {
        gotoxy(43, 9);
        mycolor(12);
        printf("GAME OVER !");
    }
    else if (endgamestatus == 3)
    {
        gotoxy(40, 9);
        mycolor(12);
        printf("已结束游戏。");
    }
    gotoxy(43, 12);
    mycolor(13);
    printf("你的得分是 %d", score);
    choose();
}

//游戏失败之后的选择
void choose()
{
    int n;
    gotoxy(25, 23);
    mycolor(12);
    printf("继续 ----- 1");
    gotoxy(52, 23);
    printf("离开 ----- 2");
    gotoxy(45, 25);
    mycolor(11);
    printf("选择: ");
    scanf("%d", &n);

    switch ( n )
    {
        case 1:
            system("cls");
            score = 0;
            sleeptime = 200;
            add = 10;
            welcometogame();
            break;
        case 2:
            exit(0);
            break;
        default:
            gotoxy(35, 27);
            mycolor(12);
            printf("输入错误,重新输入!");
            system("pause >nul");
            endgame();
            choose();
            break;
    }
}

//游戏结束界面
void lostdraw()
{
    system("cls");
    int i;
    gotoxy(45, 2);
    mycolor(6);
        printf("\\\\\\|///");
        gotoxy(43, 3);
        printf("\\\\");
        gotoxy(47, 3);
        mycolor(15);
        printf(".-.-");
        gotoxy(54, 3);
        mycolor(6);
        printf("//");

        gotoxy(44, 4);
        mycolor(14);
        printf("(");

        gotoxy(47, 4);
        mycolor(15);
        printf(".@.@");

        gotoxy(54, 4);
        mycolor(14);
        printf(")");

        gotoxy(17, 5);
        mycolor(11);
        printf("+------------------------");

        gotoxy(35, 5);
        mycolor(14);
        printf("oOOo");

        gotoxy(39, 5);
        mycolor(11);
        printf("----------");

        gotoxy(48, 5);
        mycolor(14);
        printf("(_)");

        gotoxy(51, 5);
        mycolor(11);
        printf("----------");

        gotoxy(61, 5);
        mycolor(14);
        printf("oOOo");

        gotoxy(65, 5);
        mycolor(11);
        printf("-----------------+");

        for ( i = 6; i <= 19; i++ )        //竖边框
        {
                gotoxy(17, i);
                printf("|");
                gotoxy(82, i);
                printf("|");
        }

        gotoxy(17, 20);
        printf("+---------------------------------");

        gotoxy(52, 20);
        mycolor(14);
        printf("☆☆☆〃");

        gotoxy(60, 20);
        mycolor(11);
    printf("----------------------+");
}               

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值