Linux c 贪吃蛇 无curses、多线程、信号的实现
2017-04-07 17:46
302 查看
这一版贪吃蛇功能还不完全,我将继续更新,十分希望各位大神帮助完善 /************************************ 终端控制和键盘输入部分 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; }
效果图如下:
各位大神快来优化吧!
相关文章推荐
- pyqt5 使用 QTimer, QThread, pyqtSignal 实现自动执行,多线程,自定义信号触发。
- Qt实现多线程下的信号与槽通讯
- Linux C 网络编程——多线程的聊天室实现(server端)
- Qt实现多线程下的信号与槽通讯
- Linux C 网络编程——多线程的聊天室实现(服务器端)
- Linux Curses编程实现贪吃蛇
- 用户态多线程实现的基本原理
- 通过Interface的Runnable实现多线程的Yield,含setName,getName
- 使用 异步多线程TCP Socket 实现进程间通信
- java多线程消息队列的实现
- ExecutorService实现java多线程
- runnable和thread实现多线程的区别
- 多线程的实现方案
- 运用java.net.HttpURLConnection实现java多线程下载文件
- JAVA多线程实现的三种方式
- JAVA匿名实现多线程
- 黑马程序员---.NET高级之多线程的实现
- iOS 多线程的实现方式及应用示例
- Java 多线程:分析线程池的实现原理
- java多线程售票实现