转自:http://bbs.chinaunix.net/viewthread.php?tid=1170202&extra=page%3D1%26amp%3Bfilter%3Ddigest
1 /***snake.c***/ 2 #include <stdio.h>
3 #include <malloc.h>
4 #include <sys/time.h>
5 #include <sys/types.h>
6 #include <sys/select.h>
7 #include <termio.h>
8 #include <fcntl.h>
9 10 #define SNAKE_INITX 5
11 #define SNAKE_INITY 5
12 #define SNAKE_SHAPE '*'
13 #define SNAKE_INITLEN 8
14 15 #define WIN_X1 1
16 #define WIN_X2 80
17 #define WIN_Y1 1
18 #define WIN_Y2 24
19 20 #define MAX_LEVEL 20
21 #define MAX_INTER 200000
22 #define MIN_INTER 0
23 #define MAX_RICH 10
24 #define DEVRATE 5
25 #define OVER "Game Over!!!"
26 27 struct stNode
28 {
29 int x;
30 int y;
31 char shape;
32 struct stNode *next;
33 };
34 35 struct stFood
36 {
37 int x;
38 int y;
39 };
40 41 struct stNode *gpstHead,*gpstTail;
42 struct stFood gastFood[MAX_RICH];
43 int giLevel=1;
44 int giRich=1;
45 int giScore=0;
46 int giLen=0;
47 48 void settty(
int iFlag)
49 {
50 int fd;
51 struct termio stTerm;
52 53 if((fd = open(ttyname(1),O_RDWR))==-1)
return;
54 if(iFlag == 1)
55 {
56 ioctl(fd,TCGETA,&stTerm);
57 stTerm.c_lflag &= ~ICANON;
58 stTerm.c_lflag &= ~ECHO;
59 stTerm.c_cc[4] = 1;
60 stTerm.c_cc[5] = 0;
61 stTerm.c_iflag &= ~ISTRIP;
62 stTerm.c_cflag |= CS8;
63 stTerm.c_cflag &= ~PARENB;
64 ioctl(fd,TCSETA,&stTerm);
65 }
66 else 67 {
68 ioctl(fd,TCGETA,&stTerm);
69 stTerm.c_lflag |= ICANON;
70 stTerm.c_lflag |= ECHO;
71 stTerm.c_cc[4] = 4;
72 stTerm.c_cc[5] = 5;
73 stTerm.c_iflag &= ~ISTRIP;
74 stTerm.c_cflag |= CS8;
75 stTerm.c_cflag &= ~PARENB;
76 ioctl(fd,TCSETA,&stTerm);
77 }
78 close(fd);
79 }
80 81 void vDrawOneNode(
struct stNode *pstNode,
int iFlag)
82 {
83 printf("\033[%dm\033[40;%dm\033[%d;%d;H%c",
84 iFlag,iFlag*3+30,pstNode->y,pstNode->x,pstNode->shape);
85 fflush(stdout);
86 }
87 88 void vDrawOneFood(
int x,
int y)
89 {
90 printf("\033[1m\033[40;36m\033[%d;%d;H%c",y,x,'@');
91 fflush(stdout);
92 }
93 94 int iGetDir(
int iOriDir)
95 {
96 fd_set rset;
97 struct timeval hTmo;
98 int iRet,iFlag=0;
99 char cCh;
100 101 FD_ZERO(&rset);
102 FD_SET(0,&rset);
103 hTmo.tv_sec=0;
104 hTmo.tv_usec=MAX_INTER-(MAX_INTER-MIN_INTER)/MAX_LEVEL*giLevel;
105 106 iRet=select(1,&rset,NULL,NULL,&hTmo);
107 if(iRet<=0)
108 {
109 return(iOriDir);
110 }
111 for(;;)
112 {
113 cCh=getchar();
114 if(cCh != -1)
115 {
116 switch(cCh)
117 {
118 case 27 :
119 case 91 :
120 iFlag++;
121 break;
122 case 65 :
//UP
123 case 66 :
//DOWN
124 case 67 :
//RIGHT
125 case 68 :
//LEFT
126 if(iFlag==2)
127 return((!((cCh-0x41)^iOriDir^1))^(cCh-0x41));
128 default :
129 return(iOriDir);
130 }
131 }
132 }
133 }
134 void vInitScreen()
135 {
136 settty(1);
137 printf("\033[?25l\033[2J");
138 }
139 140 void vRestoreScreen()
141 {
142 printf("\033[24;1H\033[1m\033[40;34m\033[?25h");
143 settty(0);
144 }
145 146 void vDrawScope()
147 {
148 int i,j;
149 150 for(j=WIN_Y1;j<=WIN_Y2;j+=WIN_Y2-WIN_Y1)
151 {
152 printf("\033[%d;%dH+",j,WIN_X1);
153 for(i=WIN_X1+1;i<WIN_X2;i++)
154 printf("-");
155 printf("+");
156 }
157 for(i=WIN_Y1+1;i<WIN_Y2;i++)
158 printf("\033[%d;%dH|%*c|\n",i,WIN_X1,WIN_X2-WIN_X1-1,' ');
159 }
160 161 void vCreateSnake()
162 {
163 struct stNode *pstNew;
164 int i;
165 166 gpstHead=(
struct stNode*)malloc(
sizeof(
struct stNode));
167 gpstHead->x=SNAKE_INITX;
168 gpstHead->y=SNAKE_INITY;
169 gpstHead->shape=SNAKE_SHAPE;
170 gpstHead->next=NULL;
171 vDrawOneNode(gpstHead,1);
172 gpstTail=gpstHead;
173 for(i=1;i<SNAKE_INITLEN;i++)
174 {
175 pstNew=(
struct stNode*)malloc(
sizeof(
struct stNode));
176 pstNew->x=gpstHead->x+1;
177 pstNew->y=gpstHead->y;
178 pstNew->shape=SNAKE_SHAPE;
179 pstNew->next=NULL;
180 vDrawOneNode(pstNew,1);
181 gpstHead->next=pstNew;
182 gpstHead=pstNew;
183 }
184 return;
185 }
186 187 void vKillSnake()
188 {
189 struct stNode *pstNode;
190 191 for(pstNode=gpstTail;gpstTail!=NULL;)
192 {
193 gpstTail=pstNode->next;
194 free(pstNode);
195 pstNode=gpstTail;
196 }
197 }
198 199 void vGenFood(
int iIdx)
200 {
201 struct stNode *pstNode;
202 int i,iFound=0;
203 204 for(;!iFound;)
205 {
206 iFound=1;
207 gastFood[iIdx].x=rand()%(WIN_X2-WIN_X1-1)+WIN_X1+1;
208 gastFood[iIdx].y=rand()%(WIN_Y2-WIN_Y1-1)+WIN_Y1+1;
209 for(i=0;i<giRich;i++)
210 {
211 if(i!=iIdx && gastFood[iIdx].x==gastFood[i].x &&
212 gastFood[iIdx].y==gastFood[i].y)
213 {
214 iFound=0;
215 break;
216 }
217 }
218 if(!iFound)
continue;
219 for(pstNode=gpstTail;pstNode!=NULL;pstNode=pstNode->next)
220 {
221 if(gastFood[iIdx].x==pstNode->x &&
222 gastFood[iIdx].y==pstNode->y)
223 {
224 iFound=0;
225 break;
226 }
227 }
228 if(!iFound)
continue;
229 }
230 vDrawOneFood(gastFood[iIdx].x,gastFood[iIdx].y);
231 }
232 233 void vInitFood()
234 {
235 int i;
236 237 srand(getpid());
238 for(i=0;i<giRich;i++) vGenFood(i);
239 }
240 241 int iIsValid(
int x,
int y)
242 {
243 struct stNode *pstNode;
244 245 if(x<=WIN_X1 || x>=WIN_X2 || y<=WIN_Y1 || y>=WIN_Y2)
246 return(0);
247 pstNode=gpstTail;
248 for(;pstNode!=NULL;)
249 {
250 if(x==pstNode->x && y==pstNode->y)
251 return(0);
252 pstNode=pstNode->next;
253 }
254 return(1);
255 }
256 257 int iEat(
int x,
int y)
258 {
259 int i,j;
260 261 for(i=0;i<giRich;i++)
262 {
263 if(x==gastFood[i].x && y==gastFood[i].y)
264 {
265 vGenFood(i);
266 giScore+=giLevel*10;
267 giLen++;
268 if(giLevel<MAX_LEVEL)
269 if(giLen%DEVRATE==0)
270 giLevel++;
271 return(1);
272 }
273 }
274 return(0);
275 }
276 main()
277 {
278 int iDir=2,iNextX,iNextY;
279 struct stNode *pstNew;
280 char sPrompt[80];
281 282 vInitScreen();
283 vDrawScope();
284 vCreateSnake();
285 vInitFood();
286 for(;;)
287 {
288 iDir=iGetDir(iDir);
289 iNextX=gpstHead->x+(iDir>>1)*(5-(iDir<<1));
290 iNextY=gpstHead->y-(!(iDir>>1))*(1-(iDir<<1));
291 if(!iIsValid(iNextX,iNextY))
292 {
293 printf("\033[%d;%dH\033[1m\033[40;34m%s\033[0m",
294 WIN_Y2-1,(WIN_X1+WIN_X2)/2-strlen(OVER)/2,OVER);
295 break;
296 }
297 pstNew=(
struct stNode*)malloc(
sizeof(
struct stNode));
298 pstNew->x=iNextX;
299 pstNew->y=iNextY;
300 pstNew->shape=SNAKE_SHAPE;
301 pstNew->next=NULL;
302 gpstHead->next=pstNew;
303 gpstHead=pstNew;
304 vDrawOneNode(gpstHead,1);
305 if(!iEat(iNextX,iNextY))
306 {
307 vDrawOneNode(gpstHead,1);
308 vDrawOneNode(gpstTail,0);
309 pstNew=gpstTail;
310 gpstTail=pstNew->next;
311 free(pstNew);
312 }
313 sprintf(sPrompt,"Score:%7d Level:%2d",giScore,giLevel);
314 printf("\033[%d;%dH\033[1m\033[40;34m%s\033[0m",
315 WIN_Y2,(WIN_X1+WIN_X2)/2-strlen(sPrompt)/2,sPrompt);
316 }
317 vKillSnake();
318 vRestoreScreen();
319 }