贪吃蛇

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <memory.h>
  4 #include <time.h>
  5 #include <signal.h>
  6 
  7 #define WIDTH 10
  8 #define HEIGHT 10
  9 #define SUCCESS 0
 10 #define FAILURE 1
 11 #define EATEN_FOOD 2
 12 #define GAME_OVER 3
 13 
 14 const int width = WIDTH;
 15 const int height = HEIGHT;
 16 static int area[WIDTH][HEIGHT];
 17 
 18 #define CHECK_FALSE_RET(expr, ret) if(!(expr)) return ret;
 19 
 20 #define LOG(format, ...) //printf(format, ##__VA_ARGS__)
 21 
 22 typedef enum Direct {
 23     NO_DIRECT,
 24     UP,
 25     DOWN,
 26     LEFT,
 27     RIGHT
 28 }Direct;
 29 
 30 typedef struct Point {
 31     int x;
 32     int y;
 33     Point *next;
 34 }Point;
 35 
 36 typedef struct Snake {
 37     Point *head;
 38     Point *tail;
 39     int length;
 40     Direct direct;
 41 }Snake;
 42 
 43 Point* NewPoint()
 44 {
 45     Point *np = (Point*)malloc(sizeof(Point));
 46     if(np != NULL)
 47     {
 48         memset(np, 0, sizeof(Point));
 49     }
 50     return np;
 51 }
 52 
 53 Point* NewPointWithParam(int x, int y)
 54 {
 55     Point *np = NewPoint();
 56     if(np != NULL)
 57     {
 58         np->x = x;
 59         np->y = y;
 60     }
 61     return np;
 62 }
 63 
 64 Direct DecideForwardDirect(Snake *snake, Point *food)
 65 {
 66     if(snake == NULL || food == NULL)
 67     {
 68         LOG("[error]: DecideForwardDirect failed. snake=NULL|food=NULL
");
 69          return NO_DIRECT;
 70     }
 71     Direct dir = NO_DIRECT;
 72     Point *head = snake->head;
 73     if(head == NULL) 
 74     {
 75         LOG("[error]: DecideForwardDirect failed. head=NULL
");
 76         return NO_DIRECT;
 77     }
 78     
 79     switch(snake->direct)
 80     {
 81         case UP:
 82             if(head->x == 0) dir = RIGHT;
 83             else if(head->x == width-2) dir = LEFT;
 84             break;
 85         case DOWN:
 86             if(head->x == width - 1)
 87             {
 88                 if(head->y == height - 1) dir = LEFT;
 89                 else dir = DOWN;
 90             }
 91             break;
 92         case LEFT:
 93             if(head->x == 0) dir = UP;
 94             else dir = LEFT;
 95             break;
 96         case RIGHT:
 97             if(head->y == 0 && head->x == width - 1) dir = DOWN;
 98             else if(head->y != 0 && head->x == width - 2) dir = UP;
 99             else dir = RIGHT;
100             break;
101         default:
102             break;
103     }
104     snake->direct = dir;
105     return dir;
106 }
107 
108 Point *CreateOneFood(Snake *snake)
109 {    
110     if(snake == NULL) return NULL;
111  
112     Point *np = NULL;
113     Point *food = NULL;
114     int unusedNum = width*height - snake->length;
115     int randPos;
116     int x, y;
117     int foodX = -1, foodY = -1;
118     memset(area, 0, width*height*sizeof(int));
119     np = snake->head;
120     while(np != NULL)
121     {
122         area[np->x][np->y] = 1;
123         np = np->next;
124     }
125     randPos = rand() % unusedNum;
126     for(x=0; x<width; x++)
127     {
128         if(randPos < 0) break;
129         for(y=0; y<height; y++)
130         {
131             if(area[x][y] == 0) randPos--;
132             if(randPos < 0)
133             {
134                 foodX = x;
135                 foodY = y;
136                 break;
137             }
138         }
139     }
140 
141     if((foodX >= 0 && foodX < width) && (foodY >= 0 && foodY < height))
142     {
143         food = NewPointWithParam(foodX, foodY);
144     }
145     
146     return food;
147 }
148 
149 int FortainEatFood(Snake *snake, Point *food)
150 {
151     if(snake == NULL || food == NULL) return FAILURE;
152     food->next = snake->head;
153     snake->head = food;
154     if(snake->tail == NULL) snake->tail = food;
155     snake->length++;
156     return SUCCESS;
157 }
158 
159 Point *GetPreviousTail(Snake *snake)
160 {
161     if(snake == NULL) return NULL;
162     Point *np = snake->head;
163      while(np->next != snake->tail && np->next != NULL) np = np->next;
164     if(np->next == NULL) return NULL;
165     return np;
166 }
167 
168 
169 int FortainForward(Snake *snake, Direct dir, Point *food)
170 {
171     if(snake == NULL) return FAILURE;
172     if(dir == NO_DIRECT) return FAILURE;
173     if(food == NULL) return FAILURE;
174     Point *preTail;
175     preTail = GetPreviousTail(snake);
176     if(preTail == NULL) return FAILURE;
177     int currX = snake->head->x;
178     int currY = snake->head->y;
179     int nextX = currX;
180     int nextY = currY;
181     
182     switch(dir)
183     {
184         case UP:
185             nextY = currY - 1;
186             break;
187         case DOWN:
188             nextY = currY + 1;
189             break;
190         case LEFT:
191             nextX = currX - 1;
192             break;
193         case RIGHT:
194             nextX = currX + 1;
195         default:
196             break;
197     }
198     if(nextX == food->x && nextY == food->y)
199     {
200         FortainEatFood(snake, food);
201         return EATEN_FOOD;
202     }
203     else
204     {
205         snake->tail->x = nextX;
206         snake->tail->y = nextY;
207         snake->tail->next = snake->head;
208         snake->head = snake->tail;
209         snake->tail = preTail;
210         snake->tail->next = NULL;
211     }
212     
213     return SUCCESS;
214 }
215 
216 int FortainGameInit(Snake *snake)
217 {
218     if(snake == NULL) return FAILURE;
219     Point *np1 = NewPointWithParam(width-1, height-1);
220     Point *np2 = NewPointWithParam(width-2, height-1);
221     Point *np3 = NewPointWithParam(width-3, height-1);
222     if(np1 == NULL || np2 == NULL || np3 == NULL) return FAILURE;
223     
224     FortainEatFood(snake, np1);
225     FortainEatFood(snake, np2);
226     FortainEatFood(snake, np3);
227 
228     snake->direct = LEFT;
229     return SUCCESS;
230 }
231 
232 int FortainGameCheck(Snake *snake)
233 {
234     if(snake == NULL) return FAILURE;
235     memset(area, 0, width*height*sizeof(int));
236     Point *np = snake->head;
237     while(np != NULL)
238     {
239         CHECK_FALSE_RET(np->x >= 0, FAILURE);
240         CHECK_FALSE_RET(np->x < width, FAILURE);
241         CHECK_FALSE_RET(np->y >= 0, FAILURE);
242         CHECK_FALSE_RET(np->y < height, FAILURE);
243 
244         CHECK_FALSE_RET(area[np->x][np->y] == 0, GAME_OVER);
245         area[np->x][np->y] = 1;
246         np = np->next;
247     }
248     CHECK_FALSE_RET(snake->length != width*height, GAME_OVER);
249     return SUCCESS;
250 }
251 
252 void FortainGameMain()
253 {
254     Snake snake;
255     Point *food;
256     int ret;
257     int count = 0;
258     Direct dir;
259 
260     memset(&snake, 0, sizeof(Snake));
261     ret = FortainGameInit(&snake);
262     if(ret == FAILURE) 
263     {
264         LOG("[error]: GameInit failed!
");
265         return;
266     }
267     LOG("[info]: GameInit done! length=%d
", snake.length);
268     
269     Point *np = snake.head;
270     while(np != NULL)
271     {
272         LOG("x=%d,y=%d,next=%x
", np->x, np->y, np->next);
273         np = np->next;
274     }
275     
276     food = CreateOneFood(&snake);
277     if(food == NULL) LOG("[error]: CreateFood failed!
");
278     else LOG("[info]: CreateFood success! P(%d, %d)
", food->x, food->y);
279     while(true)
280     {
281         dir = DecideForwardDirect(&snake, food);
282         LOG("[info]: DecideDirect, dir=%d
", dir);
283         ret = FortainForward(&snake, dir, food);
284         LOG("[info]: Forward, dir=%d, food=(%d,%d), head=(%d,%d), length=%d
", dir, food->x, food->y, snake.head->x, snake.head->y, snake.length);
285         if(ret == FAILURE)
286         {
287             LOG("[error]: Forward failed.dir|%d,length|%d.
", dir, snake.length);
288             break;
289         }
290         else if(ret == EATEN_FOOD)
291         {
292             LOG("[info]: Eat food. length|%d
", snake.length);
293             if(snake.length < width*height)
294             {
295                 food = CreateOneFood(&snake);
296                 if(food == NULL)
297                 {
298                     LOG("[error]: CreateFood failed!
");
299                     break;
300                 }
301                 else LOG("[info]: CreateFood success! P(%d, %d)
", food->x, food->y);
302             }
303         }
304         ret = FortainGameCheck(&snake);
305         if(ret == FAILURE)
306         {
307             LOG("[error]: GameCheck failed!
");
308             break;
309         }
310         else if(ret == GAME_OVER)
311         {
312             printf("[info]: Game over!!! length=%d, count=%d
", snake.length, count);
313             break;
314         }
315         count++;
316     }
317 }
318 
319 void SignHandler(int sign)
320 {
321     switch(sign)
322     {
323         case SIGABRT:
324             printf("signal: SIGABRT. 
 程序异常终止。
");
325             break;
326         case SIGFPE:
327             printf("signal: SIGFPE. 
 算术运算出错,如除数为 0 或溢出(不一定是浮点运算)。
");
328             break;
329         case SIGILL:
330             printf("signal: SIGILL. 
 非法函数映象,如非法指令,通常是由于代码中的某个变体或者尝试执行数据导致的。
");
331             break;
332         case SIGINT:
333             printf("signal: SIGINT. 
 中断信号,如 ctrl-C,通常由用户生成。
");
334             break;
335         case SIGSEGV:
336             printf("signal: SIGSEGV. 
 非法访问存储器,如访问不存在的内存单元。
");
337             break;
338         case SIGTERM:
339             printf("signal: SIGTERM. 
 发送给本程序的终止请求信号。
");
340             break;
341     }
342 }
343 
344 int main()
345 {
346     signal(SIGABRT, SignHandler);
347     signal(SIGFPE, SignHandler);
348     signal(SIGILL, SignHandler);
349     signal(SIGINT, SignHandler);
350     signal(SIGSEGV, SignHandler);
351     signal(SIGTERM, SignHandler);
352     for(int i=0; i<100; i++)
353     {
354         clock_t start = clock();
355         srand(time(NULL));
356         FortainGameMain();
357         printf("Time: %d ms
", clock()-start);
358     }
359     return 0;
360 }
原文地址:https://www.cnblogs.com/rmthy/p/6404980.html