利用C语言的双向循环链表做一个简单的贪吃蛇

网上其实关于这类程序有很多,但是今天本人想使用双向链表来实现。

一般说来,此程序分为3部分

  1. 游戏背景区域

  2. 蛇和食物

  3. 移动以及死亡判断

由于我使用的ide是dev c++,内置的编译器是gcc,所以并没移动光标的gotoxy()函数,需要自己来实现,好在利用win api也不难。

蛇在移动过程中,如下图,

不难发现,虽然在移动时,身体的坐标都改变了,,向左移动时,是x轴分别+1.下移时,是y轴-1.如果单凭人眼的观察,我们可以这样认为,把尾节点插入到头节点,然后根据移动方向,改变这个新插入的节点的坐标。这样绘画起来,实际只操作了2块。

双向循环链表其实是在单链表上加入了一个上节指针而形成的,这样就可以形成一个闭环。这样在实际操作过程中,我们只需要把头部的指针地址变成尾地址,然后改变这个新的头节点的坐标即可。

如图(图片来自网络)

我们首先定义蛇的结构体

struct node {
    int x;
    int y;
    struct node * next;
    struct node * last; 
};
typedef struct node NODE;

首先需要初始化蛇,并插入身体

NODE * createSnake() {
    NODE * head;
    head = (NODE *)malloc(sizeof(NODE));
    head->y =1; head->x = 6;
    head->next = head;
    head->last = head;

    insertSnake(head,5,1);
    insertSnake(head,4,1);
    insertSnake(head,3,1);
    insertSnake(head,2,1);
    insertSnake(head,1,1);

    return head;
}
void insertSnake(NODE * head,int x,int y) {
    NODE * current;
    current = (NODE *)malloc(sizeof(NODE));
    current->last = head->last;
    current->x = x;
    current->y = y ;
    current->next = head;
    head->last->next = current;
    head->last = current;


}

当然,在移动的过程中,还需要判断是否越界,是否相撞。还要随机生成食物,蛇本身在吃食物的过程中会自增长。

所有代码如下(windows下gcc编译通过)

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
const int W = 36;
const int H = 36;
struct node {
    int x;
    int y;
    struct node * next;
    struct node * last;
};
struct food {
    int x;
    int y;
};
typedef struct node NODE;
struct info {
    struct food food;
    int error;
    char sign;
    int score;
    int speed;

};
typedef struct info INFO;

//function
void initMap();
NODE * createSnake();
void insertSnake();
void showSnake(NODE * head);
void gotoxy(int x,int y);
INFO * createInfo();
void getSign(INFO * info);
NODE * moveSnake(NODE * snake,INFO * info);
void createFood(NODE * snake,INFO * info);
int checkFood(NODE * snake,INFO * info);
NODE * eatFood(NODE * snake,INFO * info);
void showInFo(INFO * info);
int checkCollision(NODE * snake,INFO * info);

int main() {
    int speed = 1000;
    srand ( time(NULL) );
    initMap();
    INFO * info;
    NODE * snake;
    info = createInfo();



    snake = createSnake();
    showSnake(snake);
    createFood(snake,info);
    showInFo(info);
    while(1) {

    getSign(info);
    snake = moveSnake(snake,info);

    Sleep(info->speed);
    }



//    gotoxy(38,1);

    return 1;
}
NODE * moveSnake(NODE * snake,INFO * info){
    if(info->error == 1) return snake;
    NODE * head = snake;
    char sign = info->sign;
    gotoxy(2*(head->last->x),head->last->y);printf("  ");


    if(sign == 77) {
        head->last->x = (head->x)+1;
        head->last->y = head->y;
    }
    if(sign == 80) {
        head->last->x = head->x;
        head->last->y = head->y+1;
    }
    if(sign == 75) {
        head->last->x = head->x-1;
        head->last->y = head->y;
    }
    if(sign == 72) {
        head->last->x = head->x;
        head->last->y = head->y-1;
    }
    if(head->last->x == 0 || head->last->x == 35 || head->last->y == 0|| head->last->y == 35 || 0 == checkCollision(head->last,info) 
)  {
        gotoxy(36,17);printf("game over !\\n");




        info->error = 1 ;
        return head->last;
    }
    gotoxy(2*(head->last->x),head->last->y);printf("¡ó");



    return eatFood( head->last,info);
}
NODE * eatFood(NODE * snake,INFO * info) {
    NODE *  head = snake;
    struct food food = info->food;
    char sign = info->sign;
    if(food.x == head->x && food.y == head->y) {
       gotoxy(2*(head->x),head->y);printf("¡ó");
               NODE * current;
               current = (NODE *)malloc(sizeof(NODE));
                   if(sign == 77) {
                    current->x = (head->x)+1;
                    current->y = head->y;
                 }
                if(sign == 80) {
                    current->x = head->x;
                    current->y = head->y+1;
                }
                if(sign == 75) {
                      current->x = head->x-1;
                     current->y = head->y;
                }
                if(sign == 72) {
                    current->x = head->x;
                    current->y = head->y-1;
                }

            current->last = head->last;

            current->next = head;
            head->last->next = current;
            head->last = current;
            gotoxy(2*(head->last->x),head->last->y);printf("¡ó");
            info->score += 50;
            if(info->score < 800) {
                info->speed = 900 - info->score;
            } else {
                info->speed = 100;
            }

            showInFo(info);




            createFood(head->last,info);

            return head->last;

    }
    return head;


}
void showInFo(INFO * info) {
    gotoxy(0,38);
    printf("score:%4d     speed:%4d",info->score,900 - info->speed);

}
void createFood(NODE * snake,INFO * info) {

    info->food.x = rand() % (34) + 1;
    info->food.y = rand() % (34) + 1;

    while (0 == checkFood(snake,info)) {
        //gotoxy(36,18);printf("dddddddddddddddddddd");
        info->food.x = rand() % (34) + 1;
        info->food.y = rand() % (34) + 1;
    }
    gotoxy(2*(info->food.x),info->food.y);printf("¡ò");

}
int checkCollision(NODE * snake,INFO * info) {
    if(snake->x == 0 || snake->x == W || snake->y == 0 || snake->y == H) {
        return 0;
    }
    NODE * temp;
    temp = snake->next;

    do {
          if(snake->x == temp->x && snake->y == temp->y) {
             return 0;
         }
        temp = temp->next;

    } while (temp != snake);
    return 1;


}
int checkFood(NODE * snake,INFO * info) {
    int x = info->food.x;
    int y = info->food.y;
    NODE * temp;
    temp = snake;

    do {
       if(x == temp->x && y == temp->y) {
             return 0;
       }
        temp = temp->next;

    } while (temp != snake);
    return 1;
}
void getSign(INFO * info) {
    char sign = 0;

    if(kbhit()) {
     sign = getch();
     if(sign == -32) sign = getch();
     //gotoxy(36,18);printf("%3d",sign);
    } else {
        return ;
    }
    if(info->sign + sign != 152) {
        info->sign = sign;
    }


}
INFO * createInfo() {
    INFO * head;
    head = (INFO *)malloc(sizeof(INFO));
    head->error = 0;
    head->score = 0;
    head->sign = 77;
    head->speed = 900;
    head->food.x = rand() % (34) + 1;
    head->food.y = rand() % (34) + 1;


    return head;
}
NODE * createSnake() {
    NODE * head;
    head = (NODE *)malloc(sizeof(NODE));
    head->y =1; head->x = 6;
    head->next = head;
    head->last = head;

    insertSnake(head,5,1);
    insertSnake(head,4,1);
    insertSnake(head,3,1);
    insertSnake(head,2,1);
    insertSnake(head,1,1);

    return head;
}
void insertSnake(NODE * head,int x,int y) {
    NODE * current;
    current = (NODE *)malloc(sizeof(NODE));
    current->last = head->last;
    current->x = x;
    current->y = y ;
    current->next = head;
    head->last->next = current;
    head->last = current;


}
void showSnake(NODE * head) {
    //printf("*\\n");
    NODE * temp;
    temp = head;

    do {
         gotoxy(2*(temp->x),temp->y);printf("¡ó");
     //  printf("%d->%d\\n",temp->x,temp->y);
        temp = temp->next;

    } while (temp != head);

}
void initMap() {



    SMALL_RECT winPon={0,0,40,74};
    HANDLE con=GetStdHandle(STD_OUTPUT_HANDLE);
    COORD buf={41,75};
    SetConsoleWindowInfo(con,1,&winPon);
    SetConsoleScreenBufferSize(con,buf);
    SetConsoleTitle("Ì°³ÔÉß power by tiyee");
    CONSOLE_CURSOR_INFO cursor_info = {1, 0};
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);






    int i,j;
    for(i=0;i<W;i++) {
        for(j=0;j<H;j++) {
            if(i == 0 ||i == W-1|| j == 0 || j==H-1) {
                printf("¨~");
            } else {
                printf("  ");
            }
        }
        printf("\n");
    }
}
void gotoxy(int x,int y)
{
    CONSOLE_SCREEN_BUFFER_INFO    csbiInfo;
    HANDLE    hConsoleOut;
    hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
    GetConsoleScreenBufferInfo(hConsoleOut,&csbiInfo);
    csbiInfo.dwCursorPosition.X = x;
    csbiInfo.dwCursorPosition.Y = y;
    SetConsoleCursorPosition(hConsoleOut,csbiInfo.dwCursorPosition);


}