这一版贪吃蛇功能还不完全,我将继续更新,十分希望各位大神帮助完善
/************************************
终端控制和键盘输入部分
keyboard.h
************************************/
#ifndef __KEYBOARD_H_
#define __KEYBOARD_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
//非阻塞无回显输入
int readch(void);
//光标移动至指定位置
void gotoxy(int x,int y);
//移动至指定位置并输出字符
void gotoxy_putc(int x,int y,char c);
//移动至指定位置并输出字符串
void gotoxy_puts(int x,int y,char* c);
//初始化键盘输入和终端
void initkey();
//恢复键盘输入和终端属性
void relaykey();
//清屏
void clrter();
void clrter()
{
system("clear");
}
int readch(void)
{
struct termios tm, tm_old;
int fd = STDIN_FILENO, c=0;
fd_set rfds;
struct timeval tv;
int retval;
if(tcgetattr(fd, &tm) < 0)
return -1;
tm_old = tm;
cfmakeraw(&tm);
FD_ZERO(&rfds);
FD_SET(0, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 10;
if(tcsetattr(fd, TCSANOW, &tm) < 0)
c = 0;
retval = select(1, &rfds, NULL, NULL, &tv);
if (retval == -1) {
c = 0;
} else if (retval)
c = fgetc(stdin);
if(tcsetattr(fd, TCSANOW, &tm_old) < 0)
c = 0;
return c;
}
void gotoxy(int x,int y)
{
printf("\033[%d;%df\n",y,x);
}
void gotoxy_putc(int x,int y,char c)
{
printf("\033[0m");
printf("\033[%d;%df%c\n",y,x,c);
printf("\033[8m");
}
void gotoxy_puts(int x,int y,char* c)
{
printf("\033[0m");
printf("\033[%d;%df%s\n",y,x,c);
printf("\033[8m");
}
void initkey()
{
clrter();
system("stty -echo");
printf("\033[8m");
printf("\033[?25l");
}
void relaykey()
{
printf("\033[0m");
system("stty echo");
printf("\033[?25h");
}
#endif
/************************************
双向循环链表的实现(套用Linux内核)
List.h
************************************/
#ifndef __QUEUE_H__
#define __QUEUE_H__
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// 队 列
//
/////////////////////////////////////////////////////////////////////////////////////////////////
#if defined(_WIN32) || defined(_WIN64) //Windows
#define NETLIST_EXPORT __declspec(dllexport)
#else
#define NETLIST_EXPORT
#endif //defined(_WIN32) || defined(_WIN64)
#ifndef LIST_HEAD_DEF
#define LIST_HEAD_DEF
typedef struct LIST_HEAD
{
struct LIST_HEAD *Next;
struct LIST_HEAD *Prev;
} LIST_HEAD;
#endif /*LIST_HEAD_DEF*/
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->Next = ptr; (ptr)->Prev = ptr; \
} while (0)
#define EMPTY_LIST_HEAD(ptr) do { \
(ptr)->Next = 0; (ptr)->Prev = 0; \
} while (0)
#ifdef WIN32
#define offset_of(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) (type *)((char *)ptr - offset_of(type, member))
#else
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE,MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#define container_of(ptr, type, member) \
( \
{ \
typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) ); \
} \
)
#endif
#define list_entry(ptr, type, member) container_of(ptr, type, member)
#define ListForEachEntry(type,pos, head, member) \
for (pos = list_entry((head)->Next, type, member); \
pos->member.Next, &(pos->member) != (head); \
pos = list_entry(pos->member.Next, type, member) \
)
#define ListForEachEntrySafe(type,pos, n, head, member) \
for (pos = list_entry((head)->Next, type, member), \
n = list_entry(pos->member.Next, type, member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.Next, type, member))
NETLIST_EXPORT void ListAddHead(LIST_HEAD *New, LIST_HEAD *Head);
NETLIST_EXPORT void ListInsert(LIST_HEAD *New, LIST_HEAD *Pos);
NETLIST_EXPORT void ListAddTail(LIST_HEAD *New, LIST_HEAD *Head);
NETLIST_EXPORT void ListDel(LIST_HEAD *entry);
NETLIST_EXPORT int ListIsEmpty(const LIST_HEAD *Head);
#endif /* __QUEUE_H__ */
static void ListAdd(LIST_HEAD *New,LIST_HEAD *Prev,LIST_HEAD *Next)
{
Next->Prev = New;
New->Next = Next;
New->Prev = Prev;
Prev->Next = New;
}
void ListAddHead(LIST_HEAD *New, LIST_HEAD *Head)
{
ListAdd(New, (LIST_HEAD *)Head->Next, Head);
}
void ListAddTail(LIST_HEAD *New, LIST_HEAD *Head)
{
ListAdd(New, (LIST_HEAD *)Head->Prev, Head);
}
void ListInsert(LIST_HEAD *New, LIST_HEAD *Pos)
{
Pos->Prev->Next = New;
New->Next = Pos;
New->Prev = Pos->Prev;
Pos->Prev = New;
}
static void __ListDel(LIST_HEAD * Prev, LIST_HEAD * Next)
{
Next->Prev = Prev;
Prev->Next = Next;
}
void ListDel(LIST_HEAD *entry)
{
if (entry->Prev)
{
__ListDel((LIST_HEAD *)entry->Prev, (LIST_HEAD *)entry->Next);
entry->Prev = 0;
entry->Next = 0;
}
}
int ListIsEmpty(const LIST_HEAD *Head)
{
return (LIST_HEAD *)Head->Next == Head;
}
/************************************
贪吃蛇的实现
************************************/
#include "keyboard.h"
#include "List.h"
#define ENVLENGTH 40
#define ENVWIDTH 20
static int snack_head_x = 20;
static int snack_head_y = 10;
static int snack_last_x = 0;
static int snack_last_y = 0;
typedef enum{UP,LEFT,DOWN,RIGHT} DIRECTION;
typedef enum{YES,NO} ISFOOD;
typedef struct food{
int x;
int y;
ISFOOD f;
}food;
static food sfood;
static DIRECTION AIM = RIGHT;
static DIRECTION oldAIM;
const char snacknode = '@';
LIST_HEAD SHEAD;
typedef struct snack{
int x;
int y;
LIST_HEAD snode;
}snack;
int ifinsnack(int x,int y)
{
snack *pos;
int st = 0;
ListForEachEntry(snack,pos,(SHEAD.Next), snode)
{
if(pos->x == x && pos->y == y)
{
st = 1;
break;
}
}
return st;
}
void add_food()
{
snack *pos;
while(1)
{
srand((int)time(0));
sfood.x=2+(int)(rand()%(ENVLENGTH-2));
srand(sfood.x);
sfood.y=2+(int)(rand()%(ENVWIDTH-2));
if(ifinsnack(sfood.x,sfood.y) == 0)
break;
}
gotoxy_putc(sfood.x,sfood.y,'$');
sfood.f = YES;
}
void add_snode(int x,int y)
{
snack *sn = (snack*)malloc(sizeof(snack));
sn->x = x;
sn->y = y;
ListAddTail(&(sn->snode),&SHEAD);
}
void initsnack()
{
int x,y;
INIT_LIST_HEAD(&SHEAD);
add_snode(snack_head_x,snack_head_y);
add_snode(snack_head_x-1,snack_head_y);
add_snode(snack_head_x-2,snack_head_y);
sfood.f = NO;
for(x=1;x<=ENVLENGTH;x++)
{
gotoxy_putc(x,1,'*');
gotoxy_putc(x,ENVWIDTH,'*');
}
for(y=1;y<=ENVWIDTH;y++)
{
gotoxy_putc(1,y,'*');
gotoxy_putc(ENVLENGTH,y,'*');
}
gotoxy_puts(ENVLENGTH+2,3,"欢迎来到魔蛇峡谷");
gotoxy_puts(ENVLENGTH+2,5,"w(W) 向上移动");
gotoxy_puts(ENVLENGTH+2,7,"a(A) 向左移动");
gotoxy_puts(ENVLENGTH+2,9,"s(S) 向下移动");
gotoxy_puts(ENVLENGTH+2,11,"d(D) 向右移动");
gotoxy_puts(ENVLENGTH+2,11,"q(Q) 退出游戏");
gotoxy_puts(ENVLENGTH+2,13,"预祝您玩的愉快");
gotoxy_puts(ENVLENGTH+2,15,"后续游戏功能会持续更新");
gotoxy_puts(ENVLENGTH+2,17,"也欢迎各位大神优化一下");
}
void showsnack()
{
snack *pos;
ListForEachEntry(snack,pos,&SHEAD, snode)
gotoxy_putc(pos->x,pos->y,snacknode);
gotoxy_putc(snack_last_x,snack_last_y,' ');
}
void movesnack()
{
snack *pos,*posr;
LIST_HEAD *p = SHEAD.Prev;
pos = list_entry((p),snack,snode);
snack_last_x = pos->x;
snack_last_y = pos->y;
while(p->Prev != &SHEAD)
{
pos = list_entry((p),snack,snode);
posr = list_entry((p->Prev),snack,snode);
pos->x = posr->x;
pos->y = posr->y;
p = p->Prev;
}
pos = list_entry((p),snack,snode);
pos->x = snack_head_x;
pos->y = snack_head_y;
}
void ifremove()
{
if(AIM == UP)
{
if(oldAIM == DOWN)
AIM = oldAIM;
}
if(AIM == DOWN)
{
if(oldAIM == UP)
AIM = oldAIM;
}
if(AIM == LEFT)
{
if(oldAIM == RIGHT)
AIM = oldAIM;
}
if(AIM == RIGHT)
{
if(oldAIM == LEFT)
AIM = oldAIM;
}
}
int ifout()
{
if(snack_head_x > 1 && snack_head_x < ENVLENGTH &&
snack_head_y > 1 && snack_head_y < ENVWIDTH )
{
return 0;
}
else
return 1;
}
void run()
{
int st = 1;
char c = 0;
for(;;)
{
usleep(400*1000);
if(sfood.f == NO)
add_food();
c = 0;
c = readch();
oldAIM = AIM;
if(c)
{
if(c == 'q'){
return ;
}
if(c == 'w' || c == 'W')
AIM = UP;
if(c == 'a' || c == 'A')
AIM = LEFT;
if(c == 's' || c == 'S')
AIM = DOWN;
if(c == 'd' || c == 'D')
AIM = RIGHT;
}
ifremove();
gotoxy_putc(snack_head_x,snack_head_y,' ');
if(AIM == UP)
snack_head_y -= 1;
if(AIM == LEFT)
snack_head_x -= 1;
if(AIM == DOWN)
snack_head_y += 1;
if(AIM == RIGHT)
snack_head_x += 1;
if(snack_head_x == sfood.x && snack_head_y == sfood.y)
{
add_snode(0,0);
sfood.f = NO;
}
movesnack();
showsnack();
if(ifout()) break;
if(ifinsnack(snack_head_x,snack_head_y)) break;
}
gotoxy_puts(20,10,"宝宝还需努力哦");
gotoxy_puts(20,11,"Enter键推出");
getchar();
}
int main()
{
initkey();
initsnack();
run();
relaykey();
clrter("clear");
return 0;
}
效果图如下:
各位大神快来优化吧!