分享一段伪终端贪吃蛇代码
最近看见好多人写贪吃蛇,不过都是图形界面的,本人做后台的,不善于写图形界面,前段日子看到别人在*nix端写了一段贪吃蛇代码,很不错,对终端控制码很熟悉,供大家学习学习,具体用到哪些东西我就不细说了,大家可以讨论讨论,最好谁再写个注释。不多说,代码献上
unix,red hat编译通过,telnet终端运行
/***snake.c***/#include <stdio.h>#include <malloc.h>#include <sys/time.h>#include <sys/types.h>#include <sys/select.h>#include <termio.h>#include <fcntl.h>#define SNAKE_INITX 5#define SNAKE_INITY 5#define SNAKE_SHAPE '*'#define SNAKE_INITLEN 8#define WIN_X1 1#define WIN_X2 80#define WIN_Y1 1#define WIN_Y2 24#define MAX_LEVEL 20#define MAX_INTER 200000#define MIN_INTER 0#define MAX_RICH 10#define DEVRATE 5#define OVER "Game Over!!!"struct stNode{ int x; int y; char shape; struct stNode *next;};struct stFood{ int x; int y;};struct stNode *gpstHead,*gpstTail;struct stFood gastFood[MAX_RICH];int giLevel=1;int giRich=1;int giScore=0;int giLen=0;void settty(int iFlag){ int fd; struct termio stTerm; if((fd = open(ttyname(1),O_RDWR))==-1) return; if(iFlag == 1) { ioctl(fd,TCGETA,&stTerm); stTerm.c_lflag &= ~ICANON; stTerm.c_lflag &= ~ECHO; stTerm.c_cc[4] = 1; stTerm.c_cc[5] = 0; stTerm.c_iflag &= ~ISTRIP; stTerm.c_cflag |= CS8; stTerm.c_cflag &= ~PARENB; ioctl(fd,TCSETA,&stTerm); } else { ioctl(fd,TCGETA,&stTerm); stTerm.c_lflag |= ICANON; stTerm.c_lflag |= ECHO; stTerm.c_cc[4] = 4; stTerm.c_cc[5] = 5; stTerm.c_iflag &= ~ISTRIP; stTerm.c_cflag |= CS8; stTerm.c_cflag &= ~PARENB; ioctl(fd,TCSETA,&stTerm); } close(fd);}void vDrawOneNode(struct stNode *pstNode,int iFlag){ printf("\033[%dm\033[40;%dm\033[%d;%d;H%c", iFlag,iFlag*3+30,pstNode->y,pstNode->x,pstNode->shape); fflush(stdout);}void vDrawOneFood(int x,int y){ printf("\033[1m\033[40;36m\033[%d;%d;H%c",y,x,'@'); fflush(stdout);}int iGetDir(int iOriDir){ fd_set rset; struct timeval hTmo; int iRet,iFlag=0; char cCh; FD_ZERO(&rset); FD_SET(0,&rset); hTmo.tv_sec=0; hTmo.tv_usec=MAX_INTER-(MAX_INTER-MIN_INTER)/MAX_LEVEL*giLevel; iRet=select(1,&rset,NULL,NULL,&hTmo); if(iRet<=0) { return(iOriDir); } for(;;) { cCh=getchar(); if(cCh != -1) { switch(cCh) { case 27 : case 91 : iFlag++; break; case 65 ://UP case 66 ://DOWN case 67 ://RIGHT case 68 ://LEFT if(iFlag==2) return((!((cCh-0x41)^iOriDir^1))^(cCh-0x41)); default : return(iOriDir); } } }}void vInitScreen(){ settty(1); printf("\033[?25l\033[2J");}void vRestoreScreen(){ printf("\033[24;1H\033[1m\033[40;34m\033[?25h"); settty(0);}void vDrawScope(){ int i,j; for(j=WIN_Y1;j<=WIN_Y2;j+=WIN_Y2-WIN_Y1) { printf("\033[%d;%dH+",j,WIN_X1); for(i=WIN_X1+1;i<WIN_X2;i++) printf("-"); printf("+"); } for(i=WIN_Y1+1;i<WIN_Y2;i++) printf("\033[%d;%dH|%*c|\n",i,WIN_X1,WIN_X2-WIN_X1-1,' ');}void vCreateSnake(){ struct stNode *pstNew; int i; gpstHead=(struct stNode*)malloc(sizeof(struct stNode)); gpstHead->x=SNAKE_INITX; gpstHead->y=SNAKE_INITY; gpstHead->shape=SNAKE_SHAPE; gpstHead->next=NULL; vDrawOneNode(gpstHead,1); gpstTail=gpstHead; for(i=1;i<SNAKE_INITLEN;i++) { pstNew=(struct stNode*)malloc(sizeof(struct stNode)); pstNew->x=gpstHead->x+1; pstNew->y=gpstHead->y; pstNew->shape=SNAKE_SHAPE; pstNew->next=NULL; vDrawOneNode(pstNew,1); gpstHead->next=pstNew; gpstHead=pstNew; } return;}void vKillSnake(){ struct stNode *pstNode; for(pstNode=gpstTail;gpstTail!=NULL;) { gpstTail=pstNode->next; free(pstNode); pstNode=gpstTail; }}void vGenFood(int iIdx){ struct stNode *pstNode; int i,iFound=0; for(;!iFound;) { iFound=1; gastFood[iIdx].x=rand()%(WIN_X2-WIN_X1-1)+WIN_X1+1; gastFood[iIdx].y=rand()%(WIN_Y2-WIN_Y1-1)+WIN_Y1+1; for(i=0;i<giRich;i++) { if(i!=iIdx && gastFood[iIdx].x==gastFood[i].x && gastFood[iIdx].y==gastFood[i].y) { iFound=0; break; } } if(!iFound) continue; for(pstNode=gpstTail;pstNode!=NULL;pstNode=pstNode->next) { if(gastFood[iIdx].x==pstNode->x && gastFood[iIdx].y==pstNode->y) { iFound=0; break; } } if(!iFound) continue; } vDrawOneFood(gastFood[iIdx].x,gastFood[iIdx].y);}void vInitFood(){ int i; srand(getpid()); for(i=0;i<giRich;i++) vGenFood(i);} int iIsValid(int x,int y){ struct stNode *pstNode; if(x<=WIN_X1 || x>=WIN_X2 || y<=WIN_Y1 || y>=WIN_Y2) return(0); pstNode=gpstTail; for(;pstNode!=NULL;) { if(x==pstNode->x && y==pstNode->y) return(0); pstNode=pstNode->next; } return(1);}int iEat(int x,int y){ int i,j; for(i=0;i<giRich;i++) { if(x==gastFood[i].x && y==gastFood[i].y) { vGenFood(i); giScore+=giLevel*10; giLen++; if(giLevel<MAX_LEVEL) if(giLen%DEVRATE==0) giLevel++; return(1); } } return(0);}main(){ int iDir=2,iNextX,iNextY; struct stNode *pstNew; char sPrompt[80]; vInitScreen(); vDrawScope(); vCreateSnake(); vInitFood(); for(;;) { iDir=iGetDir(iDir); iNextX=gpstHead->x+(iDir>>1)*(5-(iDir<<1)); iNextY=gpstHead->y-(!(iDir>>1))*(1-(iDir<<1)); if(!iIsValid(iNextX,iNextY)) { printf("\033[%d;%dH\033[1m\033[40;34m%s\033[0m\n\n", WIN_Y2-1,(WIN_X1+WIN_X2)/2-strlen(OVER)/2,OVER); //printf("Source file for TaiZhou Finance-Revenue-Exchequer-Bank Project\n"); //printf("Source file for TaiZhou Finance-Revenue-Exchequer-Bank Project\n"); //printf("Source file for TaiZhou Finance-Revenue-Exchequer-Bank Project\n"); //printf("Source file for TaiZhou Finance-Revenue-Exchequer-Bank Project\n"); //printf("Source file for TaiZhou Finance-Revenue-Exchequer-Bank Project\n"); break; } pstNew=(struct stNode*)malloc(sizeof(struct stNode)); pstNew->x=iNextX; pstNew->y=iNextY; pstNew->shape=SNAKE_SHAPE; pstNew->next=NULL; gpstHead->next=pstNew; gpstHead=pstNew; vDrawOneNode(gpstHead,1); if(!iEat(iNextX,iNextY)) { vDrawOneNode(gpstHead,1); vDrawOneNode(gpstTail,0); pstNew=gpstTail; gpstTail=pstNew->next; free(pstNew); } sprintf(sPrompt,"Score:%7d Level:%2d",giScore,giLevel); printf("\033[%d;%dH\033[1m\033[40;34m%s\033[0m", WIN_Y2,(WIN_X1+WIN_X2)/2-strlen(sPrompt)/2,sPrompt); } vKillSnake(); vRestoreScreen();}