贪吃蛇
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\n"); 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\n"); 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!\n"); 265 return; 266 } 267 LOG("[info]: GameInit done! length=%d\n", snake.length); 268 269 Point *np = snake.head; 270 while(np != NULL) 271 { 272 LOG("x=%d,y=%d,next=%x\n", np->x, np->y, np->next); 273 np = np->next; 274 } 275 276 food = CreateOneFood(&snake); 277 if(food == NULL) LOG("[error]: CreateFood failed!\n"); 278 else LOG("[info]: CreateFood success! P(%d, %d)\n", food->x, food->y); 279 while(true) 280 { 281 dir = DecideForwardDirect(&snake, food); 282 LOG("[info]: DecideDirect, dir=%d\n", dir); 283 ret = FortainForward(&snake, dir, food); 284 LOG("[info]: Forward, dir=%d, food=(%d,%d), head=(%d,%d), length=%d\n", 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.\n", dir, snake.length); 288 break; 289 } 290 else if(ret == EATEN_FOOD) 291 { 292 LOG("[info]: Eat food. length|%d\n", snake.length); 293 if(snake.length < width*height) 294 { 295 food = CreateOneFood(&snake); 296 if(food == NULL) 297 { 298 LOG("[error]: CreateFood failed!\n"); 299 break; 300 } 301 else LOG("[info]: CreateFood success! P(%d, %d)\n", food->x, food->y); 302 } 303 } 304 ret = FortainGameCheck(&snake); 305 if(ret == FAILURE) 306 { 307 LOG("[error]: GameCheck failed!\n"); 308 break; 309 } 310 else if(ret == GAME_OVER) 311 { 312 printf("[info]: Game over!!! length=%d, count=%d\n", 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. \n 程序异常终止。\n"); 325 break; 326 case SIGFPE: 327 printf("signal: SIGFPE. \n 算术运算出错,如除数为 0 或溢出(不一定是浮点运算)。\n"); 328 break; 329 case SIGILL: 330 printf("signal: SIGILL. \n 非法函数映象,如非法指令,通常是由于代码中的某个变体或者尝试执行数据导致的。\n"); 331 break; 332 case SIGINT: 333 printf("signal: SIGINT. \n 中断信号,如 ctrl-C,通常由用户生成。\n"); 334 break; 335 case SIGSEGV: 336 printf("signal: SIGSEGV. \n 非法访问存储器,如访问不存在的内存单元。\n"); 337 break; 338 case SIGTERM: 339 printf("signal: SIGTERM. \n 发送给本程序的终止请求信号。\n"); 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\n", clock()-start); 358 } 359 return 0; 360 }