网上其实关于这类程序有很多,但是今天本人想使用双向链表来实现。
一般说来,此程序分为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);
}