C语言循环链表实现贪吃蛇游戏

本文实例为大家分享了C语言表实现贪吃蛇游戏的具体代码,供大家参考,具体内容如下

总体思想

利用循环链表将一条蛇的坐标进行存储,然后利用gotoxy()函数(可以将光标定位到指定的位置),此时根据蛇的坐标进行输出“@”,输出多几个既可以产生一条蛇。通过遍历循环链表进行蛇的移动,对循环链表的插入元素,产生蛇变长的效果。下面为各功能实现的函数

1.贪吃蛇地图函数map()
2.蛇的移动move(),up(),left()等函数
3.产生食物food()和吃到食物eat_food()
4.蛇吃到食物时产生的变长效果snake_link()函数
5.判断蛇的死亡,分别为撞墙hit_wall()和自杀suicide()

1.贪吃蛇地图函数map()
游戏地图采用的是应该封闭的区域,采用一个数组a[25][50],将此数组初始化为0,将游戏墙的边缘赋值为1,当数组为0,输出" ",数组为1,输出“#”,产生一个地图。
代码如下:

void map()   //创建蛇的地图
{
    int a[25][50] = {0};
    int i,j;
    for(i = 0; i < 50; i++)
    {
        a[0][i] = 1;
        a[24][i] =1;
    }
    for(i = 0; i < 25; i++)
    {
        a[i][0] = 1;
        a[i][49] =1;
    }
    for(i = 0; i < 25; i++)
        for(j = 0; j < 50; j++)
        {
            if(j%50 == 0)
                printf("\n");
            if(a[i][j] == 0)
            {
                printf(" ");
            }
            else
            {
                printf("#");
            }
        }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2.蛇的移动move(),up(),left()等函数
move()函数主要对蛇的上下左右进行更改在此采用switch函数进行解决(下面代码中ch为全局变量)
代码如下

void move(struct snake *p)   //蛇的移动函数
{
    while(1)
    {
        ch = getch();
        switch(ch)
        {
        case 'W':p = up(p);break;
        case 'A':p = left(p);break;
        case 'D':p = right(p);break;
        case 'S':p = down(p);break;
        }
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
让蛇动起来的即我们主要对蛇的坐标进行更改,此时蛇头移动一次我们就利用gotoxy()函数进行输出“@”,然后在蛇尾输出“ ”,循环往复就可以产生蛇移动的效果,蛇的上下左右则只需在移动一个方向的时候对单一的坐标x或y进行更改,然后对更改的坐标保存进循环链表即可。移动函数则主要有up(),left()等,因为做法差不多,在此只对up()函数进行展示
代码如下

struct snake *up(struct snake *p) //向上移动
{

int x;
    int y;
    x = p->pre->x;                 //将蛇头坐标赋值给x,y
    y = p->pre->y;
    while(p)                      //对循环链表的遍历,即蛇的遍历
    {
        Sleep(SNAKE_SPEED);        //蛇移动的速度
        y--;                       //向上移动则只需将纵坐标进行减,就可以实现蛇向上移动的效果
        gotoxy(p->x,p->y);         //定位到蛇尾,输出“ ”即蛇尾消失
        printf(" ");
        gotoxy(x, y);              //定位到蛇头输出,"@",结合上面的蛇尾消失又进行蛇头打印,产生蛇移动的效果
        printf("@");
        suicide(p,x,y);            //判断蛇头是否撞到蛇身
        p = p->next;               //将蛇头的坐标变为下一个
        p->pre->x = x;             //此时将前一个蛇头变成蛇尾,通过不断的遍历产生不断移动的效果
        p->pre->y = y;
        food();                    //产生食物
        eat_food(p,x,y);           //判断是否吃到食物
        hit_wall(y);               //判断是否撞墙
        if(kbhit()) break;        //判断是否有按键输入,有就进行蛇移动方向的改变
    }

return p;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
3.产生食物food()和吃到食物eat_food()
食物和吃到食物,产生食物则采用了产生随机数,产生一个食物的x,y坐标分别存放在全局变量food_xy[2]数组里面,最后利用gotoxy(food_xy[0],food_xy[1])随机产生食物
代码如下

void food()                       //产生食物
{
    int i;
    if(!flag)                     //根据flag的值来判断地图上是否有食物
    {
        srand( (unsigned)time( NULL ) );
        for( i = 0; i < 2; i++ )  //对food_(x,y)来随机赋值
        {
            food_xy[i] = rand()%24+2;
            while(food_xy[0] == 1 || food_xy[0] == 25) //这两个while为了防止食物
                food_xy[0] = rand()%24+2;             //的坐标与地图的边缘重叠
            while(food_xy[1] >= 49 || food_xy[1] == 1)
                food_xy[1] =rand()%24+2;
        }
        gotoxy(food_xy[0],food_xy[1]);  //打印食物
        printf("*");
        flag = 1;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
吃到食物eat_food(),则我们只需判断蛇头是否和食物的坐标重叠,若重叠则表明蛇吃到了食物
代码如下

void eat_food(struct snake *p,int x, int y)           //蛇吃到食物,即主要是对蛇头的x,y坐标和
{                                                     //food_xy的坐标进行匹配对比,若相同即调
    if(x == food_xy[0] && y == food_xy[1])            //snake_link函数即可
    {
        p = snake_link(p);
        flag = 0;                                     //表明食物被吃,准备重新产生食物
        printSnake(p);
        gotoxy(8,0);
        score = score + 1;                            //得分
        printf("%d",score);
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
4.蛇吃到食物时产生的变长效果snake_link()函数
蛇的变长,当蛇吃到食物的时候,此时我们将食物的坐标变成蛇头,然后进行重新的打印蛇,即可以有蛇变成的效果产生,实质为对循环链表进行元素的插入。
在这里插入图片描述
即通过这样将食物的坐标插进去循环链表,达到蛇变成的效果
代码如下

struct snake *snake_link(struct snake *p)      //蛇的连接
{
    struct snake *q;
    q = (struct snake *)malloc(sizeof(struct snake)); //即主要是实现了对循环链表的插入元素,再
    q->x = food_xy[0];                                //进行打印蛇,即可有吃到食物蛇变长的结果
    q->y = food_xy[1];
    q->pre = p->pre;
    p->pre->next = q;
    p->pre = q;
    q->next = p;
    return p;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
5.判断蛇的死亡,分别为撞墙hit_wall()和自杀suicide()
撞墙,则只需判断蛇头的单一坐标x轴或者y轴是否与墙壁的坐标是否相等,若相等则说明蛇撞墙了
代码如下

void hit_wall(int n)       //判断蛇是否撞墙,即对蛇的单一坐标x或者y进行判断,若等于墙壁的值,即游戏结束
{
    if(ch == 'W'|| ch == 'S' )
        if(n == 1 || n == 25)              //墙壁的坐标值
        {
            gotoxy(0,26);
            printf("游戏结束!");
            printf("你的得分:%d",score);
            exit(0);
        }
    if(ch == 'A'|| ch == 'D' )
        if(n == 0 || n == 49)
        {
            gotoxy(0,26);
            printf("游戏结束!");
            printf("你的得分:%d",score);
            exit(0);
        }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
自杀suicide()即蛇头是否有撞到了蛇身,做法是把蛇头的坐标拿出来,与蛇身的坐标进行对比如果相等,说明蛇头撞到了蛇身,本质上是循环链表的值进行匹配,遍历
代码如下

void suicide(struct snake *p, int x, int y) //自杀,即撞到自己本身的时候游戏结束
{
    struct snake *q;                         //把蛇头坐标传递进来,然后与其自己身体坐标做对比若有相等则表明,蛇头撞到了蛇身
    q = p;
    while(q != p->next)                      //即对循环链表的遍历匹配
    {
        if(p->x == x && p->y == y)
        {
            gotoxy(0,26);
            printf("游戏结束!");
            printf("你的得分:%d",score);
            exit(0);
        }
        else
            p = p->next;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
到此蛇的基本功能已经讲完,以下是全部代码。

全部代码如下

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#define SNAKE_SPEED 200 //蛇移动的速度
int score = 0;         //成绩得分
int flag = 0;          //用于判断地图上是否存在食物,0为不存在食物
int food_xy[2];         //定位食物的位置
char ch;               //用来决定蛇的移动方向
struct snake   //定义一条循环链表的蛇
{
    int x;
    int y;
    struct snake *next;
    struct snake *pre;
};

void HideCursor()//把蛇移动的时候产生的光标进行隐藏,隐藏光标函数
{
 CONSOLE_CURSOR_INFO cursor;
 cursor.bVisible = FALSE;
 cursor.dwSize = sizeof(cursor);
 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
 SetConsoleCursorInfo(handle, &cursor);
}

void gotoxy(int x, int y)   //定位光标函数,用来实现蛇的移动,和食物的出现(传送x,y可以将光标定位到x,y)
{
    HideCursor();
    COORD coord = {x,y};
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

void map()   //创建蛇的地图
{
    int a[25][50] = {0};
    int i,j;
    for(i = 0; i < 50; i++)
    {
        a[0][i] = 1;
        a[24][i] =1;
    }
    for(i = 0; i < 25; i++)
    {
        a[i][0] = 1;
        a[i][49] =1;
    }
    for(i = 0; i < 25; i++)
        for(j = 0; j < 50; j++)
        {
            if(j%50 == 0)
                printf("\n");
            if(a[i][j] == 0)
            {
                printf(" ");
            }
            else
            {
                printf("#");
            }
        }
}

struct snake *createSnake()   //给蛇进行初始化,构建一条蛇,本质为循环链表
{
    int i;
    struct snake *head,*p,*q;
    p = q = (struct snake *)malloc(sizeof(struct snake));
    head = NULL;
    head = p;
    head->pre = NULL;
    for( i = 0; i < 5; i++)
    {
        p->x = 25 - i;
        p->y = 13;
        p->pre = head->pre;
        head->pre = p;
        q->next = p;
        q = p;
        p = (struct snake *)malloc(sizeof(struct snake));
    }
    q->next = head;
    return head;

}

void printSnake(struct snake *p)   //打印蛇,利用gotoxy()来对蛇进行打印,只需遍历一次循环链表即可将坐标可视化为一条蛇
{
    struct snake *q;
    q = p;
    while(q != p->next)             //循环链表的遍历
    {
        gotoxy(p->x,p->y);          //根据坐标和定位光标函数来打@,实现输出蛇
        printf("@");
        p = p->next;
    }
    gotoxy(p->x,p->y);
    printf("@");
    gotoxy(0,0);
    printf("你的得分:");          //初始化得分
}

void food()                       //产生食物
{
    int i;
    if(!flag)                     //根据flag的值来判断地图上是否有食物
    {
        srand( (unsigned)time( NULL ) );
        for( i = 0; i < 2; i++ )  //对food_(x,y)来随机赋值
        {
            food_xy[i] = rand()%24+2;
            while(food_xy[0] == 1 || food_xy[0] == 25) //这两个while为了防止食物的坐标与地图的边缘重叠
                food_xy[0] = rand()%24+2;
            while(food_xy[1] >= 49 || food_xy[1] == 1)
                food_xy[1] =rand()%24+2;
        }
        gotoxy(food_xy[0],food_xy[1]);  //打印食物
        printf("*");
        flag = 1;
    }
}

struct snake *snake_link(struct snake *p)      //蛇的连接
{
    struct snake *q;
    q = (struct snake *)malloc(sizeof(struct snake)); //即主要是实现了对循环链表的插入元素,再进行打印蛇,即可有吃到食物蛇变长的结果
    q->x = food_xy[0];
    q->y = food_xy[1];
    q->pre = p->pre;
    p->pre->next = q;
    p->pre = q;
    q->next = p;
    return p;
}

void eat_food(struct snake *p,int x, int y)           //蛇吃到食物,即主要是对蛇头的x,y坐标和food_xy的坐标进行匹配对比,若相同即调用snake_link函数即可
{
    if(x == food_xy[0] && y == food_xy[1])
    {
        p = snake_link(p);
        flag = 0;
        printSnake(p);
        gotoxy(8,0);
        score = score + 1;
        printf("%d",score);
    }
}

void hit_wall(int n)       //判断蛇是否撞墙,即对蛇的单一坐标x或者y进行判断,若等于墙壁的值,即游戏结束
{
    if(ch == 'W'|| ch == 'S' )
        if(n == 1 || n == 25)
        {
            gotoxy(0,26);
            printf("游戏结束!");
            printf("你的得分:%d",score);
            exit(0);
        }
    if(ch == 'A'|| ch == 'D' )
        if(n == 0 || n == 49)
        {
            gotoxy(0,26);
            printf("游戏结束!");
            printf("你的得分:%d",score);
            exit(0);
        }
}

void suicide(struct snake *p, int x, int y) //自杀,即撞到自己本身的时候游戏结束
{
    struct snake *q;                         //把蛇头坐标传递进来,然后与其自己身体坐标做对比若有相等则表明,蛇头撞到了蛇身
    q = p;
    while(q != p->next)                      //即对循环链表的遍历匹配
    {
        if(p->x == x && p->y == y)
        {
            gotoxy(0,26);
            printf("游戏结束!");
            printf("你的得分:%d",score);
            exit(0);
        }

else
            p = p->next;
    }
}

struct snake *up(struct snake *p) //向上移动
{

int x;
    int y;
    x = p->pre->x;                 //将蛇头坐标赋值给x,y
    y = p->pre->y;
    while(p)                      //对循环链表的遍历,即蛇的遍历
    {

Sleep(SNAKE_SPEED);        //蛇移动的速度
        y--;                       //向上移动则只需将纵坐标进行减,就可以实现蛇向上移动的效果
        gotoxy(p->x,p->y);         //定位到蛇尾,输出“ ”即蛇尾消失
        printf(" ");
        gotoxy(x, y);              //定位到蛇头输出,"@",结合上面的蛇尾消失又进行蛇头打印,产生蛇移动的效果
        printf("@");
        suicide(p,x,y);            //判断蛇头是否撞到蛇身
        p = p->next;               //将蛇头的坐标变为下一个
        p->pre->x = x;             //此时将前一个蛇头变成蛇尾,通过不断的遍历产生不断移动的效果
        p->pre->y = y;
        food();                    //产生食物
        eat_food(p,x,y);           //判断是否吃到食物
        hit_wall(y);               //判断是否撞墙
        if(kbhit()) break;        //判断是否有按键输入,有就进行蛇移动方向的改变
    }

return p;

}

struct snake *left(struct snake *p) //向左移动
{
    int x;
    int y;
    x = p->pre->x;
    y = p->pre->y;
    while(p)
    {

Sleep(SNAKE_SPEED);
        x--;
        gotoxy(p->x,p->y);
        printf(" ");
        gotoxy(x, y);
        printf("@");
        suicide(p,x,y);
        p = p->next;
        p->pre->x = x;
        p->pre->y = y;
        food();
        eat_food(p,x,y);
        hit_wall(x);
        if(kbhit()) break;
    }
    return p;
}

struct snake *down(struct snake *p)  //向下移动
{
    int x;
    int y;
    x = p->pre->x;
    y = p->pre->y;
    while(p)
    {

Sleep(SNAKE_SPEED);
        y++;
        gotoxy(p->x,p->y);
        printf(" ");
        gotoxy(x, y);
        printf("@");
        suicide(p,x,y);
        p = p->next;
        p->pre->x = x;
        p->pre->y = y;
        food();
        eat_food(p,x,y);
        hit_wall(y);
        if(kbhit()) break;
    }
    return p;
}

struct snake *right(struct snake *p)   //向右移动
{
    int x;
    int y;
    x = p->pre->x;
    y = p->pre->y;
    while(p)
    {

Sleep(SNAKE_SPEED);
        x++;
        gotoxy(p->x,p->y);
        printf(" ");
        gotoxy(x, y);
        printf("@");
        suicide(p,x,y);
        p = p->next;
        p->pre->x = x;
        p->pre->y = y;
        food();
        eat_food(p,x,y);
        hit_wall(x);
        if(kbhit()) break;
    }
    return p;

}
void move(struct snake *p)   //蛇的移动函数
{
    while(1)
    {
        ch = getch();
        switch(ch)
        {
        case 'W':p = up(p);break;
        case 'A':p = left(p);break;
        case 'D':p = right(p);break;
        case 'S':p = down(p);break;
        }
    }
}
int main()
{
    struct snake *p;
    map();      //产生地图
    p = createSnake(); // 初始化蛇
    printSnake(p);   // 打印蛇
    move(p);        //移动蛇

return 0;
}

(0)

相关推荐

  • C语言贪吃蛇经典小游戏

    一.贪吃蛇小游戏简介: 用上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,也不能咬到自己的身体,等到了一定的分数,就能过关. 二.函数框架 三.数据结构 typedef struct Snake { size_t x; //行 size_t y; //列 struct Snake* next; }Snake, *pSnake; 定义蛇的结构体,利用单链表来表示蛇,每个结点为蛇身体的一部分. 四.代码实现(vs2010  c

  • C语言手把手教你实现贪吃蛇AI(上)

    本文实例为大家分享了手把手教你实现贪吃蛇AI的具体步骤,供大家参考,具体内容如下 1. 目标 编写一个贪吃蛇AI,也就是自动绕过障碍,去寻找最优路径吃食物. 2. 问题分析 为了达到这一目的,其实很容易,总共只需要两步,第一步抓一条蛇,第二步给蛇装一个脑子.具体来说就是,首先我们需要有一条普通的贪吃蛇,也就是我们常玩儿的,手动控制去吃食物的贪吃蛇:然后给这条蛇加入AI,也就是通过算法控制,告诉蛇怎么最方便的绕开障碍去吃食物.为了讲清楚这个问题,文章将分为三部分:上,写一个贪吃蛇程序:中,算法基础

  • C语言结构数组实现贪吃蛇小游戏

    一.设计思路 蛇身本质上就是个结构数组,数组里存储了坐标x.y的值,再通过一个循环把它打印出来,蛇的移动则是不断地刷新重新打印.所以撞墙.咬到自己只是数组x.y值的简单比较. 二.用上的知识点 结构数组Windows API函数 三.具体实现 先来实现静态页面,把地图.初始蛇身.食物搞定. 这里需要用到Windows API的知识,也就是对控制台上坐标的修改 //这段代码来自参考1 void Pos(int x, int y) { COORD pos; HANDLE hOutput; pos.X

  • 70行C语言代码实现贪吃蛇

    本文实例为大家分享了C语言实现贪吃蛇的具体代码,供大家参考,具体内容如下 #include <stdio.h> #include <Windows.h> #include <conio.h> #include <time.h> #define MAX_WIDE 50 #define MAX_HIGH 16 short dx = 1, dy = 0, randxy, score = 0; COORD coord; struct Snake{ short len

  • C语言实现贪吃蛇游戏

    最近整理下电脑,看到了自己在上个学期打的贪吃蛇游戏的c代码,觉得真的是略微有点冗长,但是实现起来应该也算是比较好理解,于是把自己的代码搬上来,网络上写贪吃蛇的c语言的文章很多,我这篇也仅是给大家作为一个参考而已. 我的代码是在Windows下运行的,因为需要用到windows.h这个库. 然后也做了一个简单的ai模式,这在没有障碍物的情况下前期还是蛮不错的,但是到了后期蛇变长了之后就会有bug了. 好了,直接上代码吧: 1)头文件和宏定义 #include<stdio.h> #include&

  • 贪吃蛇C语言代码实现(难度可选)

    本文实例为大家分享了C语言实现贪吃蛇的具体代码,供大家参考,具体内容如下 /********************************************************* ********************贪吃蛇(难度可选)******************** **************制作者:Xu Lizi 日期:2012/12/31******** ********************部分函数有借鉴************************ ****

  • C语言手把手教你实现贪吃蛇AI(下)

    本文实例为大家分享了C语言实现贪吃蛇AI的具体代码,供大家参考,具体内容如下 1. 目标 这一部分的目标是把之前写的贪吃蛇加入AI功能,即自动的去寻找食物并吃掉. 2. 控制策略 为了保证蛇不会走入"死地",所以蛇每前进一步都需要检查,移动到新的位置后,能否找到走到蛇尾的路径,如果可以,才可以走到新的位置:否则在当前的位置寻找走到蛇尾的路径,并按照路径向前走一步,开始循环之前的操作,如下图所示.这个策略可以工作,但是并不高效,也可以尝试其他的控制策略,比如易水寒的贪吃蛇AI 运行效果如

  • C语言手把手教你实现贪吃蛇AI(中)

    手把手教你实现贪吃蛇AI,具体内容如下 1. 目标 这一部分主要是讲解编写贪吃蛇AI所需要用到的算法基础. 2. 问题分析 贪吃蛇AI说白了就是寻找一条从蛇头到食物的一条最短路径,同时这条路径需要避开障碍物,这里仅有的障碍就是蛇身.而A star 算法就是专门针对这一个问题的.在A star 算法中需要用到排序算法,这里采用堆排序(当然其他排序也可以),如果对堆排序不熟悉的朋友,请移步到这里--堆排序,先看看堆排序的内容. 3. A*算法 A star(也称A*)搜寻算法俗称A星算法.这是一种在

  • C语言链表实现贪吃蛇游戏

    阅读学习了源代码,并做了简单的注释和修改,里面只用了链表数据结构,非常适合C语言入门者学习阅读. 程序可在VS2013下编译运行. #include<stdio.h> #include<time.h> #include<windows.h> #include<stdlib.h> #define U 1 #define D 2 #define L 3 #define R 4 //蛇的状态,U:上 :D:下:L:左 R:右 typedef struct SNAK

  • 基于C语言实现的贪吃蛇游戏完整实例代码

    本文以实例的形式讲述了基于C语言实现的贪吃蛇游戏代码,这是一个比较常见的游戏,代码备有比较详细的注释,对于读者理解有一定的帮助. 贪吃蛇完整实现代码如下: #include <graphics.h> #include <conio.h> #include <stdlib.h> #include <dos.h> #define NULL 0 #define UP 18432 #define DOWN 20480 #define LEFT 19200 #defi

随机推荐