LINUX 控制台运行的贪吃蛇程序 测试定时函数使用
编译 命令 gcc ./eat_snake.c -I/usr/include -L/usr/lib -lncurses
方向键 或者 wasd 或者 小键盘 4568 控制
开局选择速度 值越小 越快(建议10)
p键暂停
x键退出
实现思路很简单 重新绘制输出缓冲

1 #include <stdio.h> //这个程序是写在用户空间运行的,非内核程序 2 #include <sys/types.h> //中文名称为基本系统数据类型,此头文件还包含适当时应使用的多个基本派生类型。 3 #include <sys/stat.h> //这个头文件和文件调用相关 4 #include <linux/input.h> 5 #include <unistd.h> 6 #include <fcntl.h> //ioctl 与底层驱动交接 7 #include <time.h> 8 #include <curses.h> 9 #include <stdlib.h> 10 #include <signal.h> 11 12 #define MAP_X_LEN 30 13 #define MAP_Y_LEN 102 14 15 int set_timer(int n_us); 16 void timer_do(); 17 18 char snake_map[MAP_X_LEN][MAP_Y_LEN]; 19 int control=1;//决定执行怎么样的控制 20 int sum_sec=0; 21 int sum_get=0; 22 char new_direct='V'; 23 int le=5,ifselectle=1; 24 int restart=1; 25 struct snake_body 26 { 27 struct snake_body *next; 28 struct snake_body *pre; 29 int x; 30 int y; 31 int if_fist; 32 }; 33 struct snake_head 34 { 35 struct snake_body *first_body; 36 struct snake_body *last_body; 37 int x; 38 int y; 39 char direct; 40 char keepdir; 41 int len; 42 }; 43 44 struct snake_head head; 45 46 47 void make_apple() 48 { 49 int x,y; 50 int xmax=MAP_X_LEN-2; 51 int ymax=MAP_Y_LEN-2; 52 srand((unsigned)time(NULL)); 53 x=rand()%xmax+1; 54 y=rand()%ymax+1; 55 while(snake_map[x][y]!=' ') 56 { 57 srand((unsigned)time(NULL)); 58 x=rand()%xmax+1; 59 y=rand()%ymax+1; 60 } 61 snake_map[x][y]='@'; 62 } 63 void snake_insertbody() 64 { 65 struct snake_body *node = (struct snake_body *)malloc(sizeof(struct snake_body)); 66 node->if_fist = 1; 67 node->x=head.x; 68 node->y=head.y; 69 node->next=head.first_body; 70 node->next->if_fist= 0 ; 71 node->pre=NULL; 72 head.first_body->pre=node; 73 head.first_body=node; 74 } 75 void snake_delbody() 76 { 77 struct snake_body *node = (struct snake_body *)malloc(sizeof(struct snake_body)); 78 node = head.last_body; 79 head.last_body = head.last_body->pre; 80 head.last_body->next=NULL; 81 free(node); 82 snake_map[node->x][node->y]=' '; 83 } 84 void snake_redraw() 85 { 86 struct snake_body *temp = head.first_body; 87 snake_map[head.x][head.y]=head.direct; 88 while (temp->next!=NULL) 89 { 90 snake_map[temp->x][temp->y]='#'; 91 temp=temp->next; 92 } 93 } 94 void snake_body_clean() 95 { 96 struct snake_body *temp = head.first_body; 97 snake_map[head.x][head.y]=head.direct; 98 while (temp->next!=NULL) 99 { 100 temp=temp->next; 101 if(temp->pre) 102 free(temp->pre); 103 } 104 105 } 106 int snake_move() 107 { 108 char direct = head.direct; 109 int x=head.x; 110 int y=head.y; 111 112 switch (direct) 113 { 114 case 'A': 115 x=x-1; 116 break; 117 case 'V': 118 x=x+1; 119 break; 120 case '>': 121 y=y+1; 122 break; 123 default: 124 y=y-1; 125 break; 126 } 127 if(x<1 || x>MAP_X_LEN-2) 128 return 2; 129 if(y<1 || y>MAP_Y_LEN-2) 130 return 2; 131 132 if(snake_map[x][y]!='@') 133 snake_delbody(); 134 else 135 { 136 head.len++; 137 make_apple(); 138 } 139 if(snake_map[x][y]== '*' || snake_map[x][y]== '#') 140 return 1; 141 142 snake_insertbody(); 143 head.x=x; 144 head.y=y; 145 snake_redraw(); 146 147 148 head.keepdir = head.direct; 149 return 0; 150 } 151 void snake_init() 152 { 153 int x,y; 154 int direct; 155 struct snake_body *fist = (struct snake_body *)malloc(sizeof(struct snake_body)); 156 struct snake_body *last = (struct snake_body *)malloc(sizeof(struct snake_body)); 157 158 srand((unsigned)time(NULL)); 159 x=rand()%10+10; 160 y=rand()%50+25; 161 head.x=x; 162 head.y=y; 163 head.first_body=fist; 164 head.last_body=last; 165 head.len=0; 166 167 fist->if_fist=1; 168 last->if_fist=0; 169 fist->next=last; 170 fist->pre=NULL; 171 last->next=NULL; 172 last->pre=fist; 173 174 direct=rand()%4; 175 switch (direct) 176 { 177 case 0: 178 head.direct='V'; 179 head.keepdir='V'; 180 fist->x=x-1; 181 fist->y=y; 182 last->x=x-2; 183 last->y=y; 184 break; 185 case 1: 186 head.direct='<'; 187 head.keepdir='<'; 188 fist->x=x; 189 fist->y=y+1; 190 last->x=x; 191 last->y=y+2; 192 break; 193 case 2: 194 head.direct='>'; 195 head.keepdir='>'; 196 fist->x=x; 197 fist->y=y-1; 198 last->x=x; 199 last->y=y-2; 200 break; 201 default: 202 head.direct='A'; 203 head.keepdir='A'; 204 fist->x=x+1; 205 fist->y=y; 206 last->x=x+2; 207 last->y=y; 208 break; 209 } 210 snake_redraw(); 211 } 212 213 void get_key() 214 { 215 char ch,ch1; 216 char direct = head.direct; 217 218 //new_direct=direct; 219 //printf("\r Get key %c! \n",ch); 220 ch=getchar(); 221 sum_get++; 222 223 if(ch == 27) 224 if(getchar()=='[') 225 { 226 ch1=getchar(); 227 if(ch1=='A') 228 ch='8'; 229 if(ch1=='B') 230 ch='5'; 231 if(ch1=='C') 232 ch='6'; 233 if(ch1=='D') 234 ch='4'; 235 } 236 switch (ch) 237 { 238 case '8':; 239 case 'W':; 240 case 'w': 241 if(head.keepdir != 'V') //direct!='V') 242 { 243 head.direct='A'; 244 245 } 246 break; 247 case 's':; 248 case '5':; 249 case 'S': 250 if(head.keepdir !='A')//direct!='A') 251 { 252 head.direct='V'; 253 254 } 255 break; 256 case 'a':; 257 case '4':; 258 case 'A': 259 if(head.keepdir !='>')//direct!='>') 260 { 261 head.direct='<'; 262 263 } 264 break; 265 case 'd':; 266 case '6':; 267 case 'D': 268 if(head.keepdir !='<')//direct!='<') 269 { 270 head.direct='>'; 271 272 } 273 break; 274 case 'p': 275 if(control==2) 276 control=1; 277 else 278 control=2; 279 break; 280 case 'x': 281 control = 0; 282 break; 283 284 default: 285 break; 286 } 287 } 288 289 290 291 void map_init(int x) 292 { 293 int i; 294 if(x>=MAP_X_LEN) 295 return; 296 if(x == 0 || x == MAP_X_LEN-1) 297 { 298 for(i=0;i<MAP_Y_LEN;i++) 299 snake_map[x][i] = '*'; 300 } 301 else 302 { 303 for(i=0;i<MAP_Y_LEN;i++) 304 snake_map[x][i] = ' '; 305 snake_map[x][0] = '*'; 306 snake_map[x][MAP_Y_LEN-1] = '*'; 307 } 308 } 309 310 void map_draw() 311 { 312 int i,j; 313 if(control==1) 314 printf("\r\033[32mRUN.......... \033[0mTIME:%d SCORE:%d || KEEP_DIRECT:%c , DIRECT:%c , SUM_GET:%d \n",sum_sec/2,head.len,head.keepdir,head.direct,sum_get); 315 else if(control==2) 316 printf("\r\033[33mPAUSE........ \033[0mTIME:%d SCORE:%d \n",sum_sec/2,head.len); 317 for(i=0;i<MAP_X_LEN;i++) 318 for(j=0;j<MAP_Y_LEN;j++) 319 { 320 if(j == 0) 321 printf("\r"); 322 printf("%c",snake_map[i][j]); 323 if(j == MAP_Y_LEN-1) 324 printf("\n"); 325 } 326 327 printf("\033[31A"); 328 } 329 void map_clean() 330 { 331 int i,j; 332 printf("\n"); 333 for(i=0;i<MAP_X_LEN;i++) 334 for(j=0;j<MAP_Y_LEN;j++) 335 { 336 if(j == 0) 337 printf("\r"); 338 printf(" "); 339 if(j == MAP_Y_LEN-1) 340 printf("\n"); 341 } 342 printf("\033[30A"); 343 } 344 345 int set_timer(int n_us) 346 { 347 signal(SIGALRM, timer_do); 348 struct itimerval tick; 349 tick.it_value.tv_sec=0; 350 tick.it_value.tv_usec=n_us; 351 352 tick.it_interval.tv_sec=0; 353 tick.it_interval.tv_usec=n_us; 354 return setitimer(ITIMER_REAL, &tick, NULL); 355 } 356 357 void timer_do() 358 { 359 int i; 360 //head.direct = new_direct; 361 if(control<2) 362 { 363 364 i=snake_move(); 365 if(i) 366 { 367 control = 0; 368 set_timer(0); 369 printf("\r\033[31mGAME OVER.... \033[0mTIME:%d SCORE:%d || N_DIRECT:%c , DIRECT:%c , SUM_GET:%d \n",sum_sec/2,head.len,new_direct,head.direct,sum_get); 370 } 371 else; 372 map_draw(); 373 } 374 else 375 map_draw(); 376 377 sum_sec++; 378 } 379 380 void control_init() 381 { 382 int res; 383 384 initscr(); 385 raw(); 386 noecho(); 387 control=1; 388 sum_sec=0; 389 printf("\033[?25l"); 390 //signal(SIGIO,get_key); 391 //fcntl(STDIN_FILENO,F_SETOWN,getpid()); 392 //fcntl(STDIN_FILENO,F_SETFL, fcntl(STDIN_FILENO,F_GETFL) | O_ASYNC); 393 if(set_timer(le*10000)) 394 { 395 printf("SET TIMER FAILED \n"); 396 control=0; 397 } 398 399 } 400 void control_exit() 401 { 402 endwin(); 403 printf("\033[?25h"); 404 } 405 void list_draw() 406 { 407 char str[5][50] = {"CMD 1 : RESTART (WITHOUT SELECT LEVEL) ", 408 "CMD 2 : RESTART (SELECT NEW LEVEL) ", 409 "CMD x : EXIT ", 410 "CMD 3 : NOTING TO DO ", 411 "CMD 4 : NOTING TO DO "}; 412 // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 413 int i,j,N_CMD=5; 414 415 for(i=1;i<MAP_X_LEN-1;i++) 416 for(j=1;j<MAP_Y_LEN-1;j++) 417 snake_map[i][j] = ' '; 418 419 for(i=0;i<N_CMD;i++) 420 { 421 for(j=0;j<49;j++) 422 { 423 snake_map[3*i+5][j+5]=str[i][j]; 424 425 } 426 427 usleep(200000); 428 printf("\n"); 429 map_draw(); 430 } 431 432 433 } 434 void list_select() 435 { 436 char ch; 437 int i; 438 439 440 441 list_draw(); 442 443 printf("\033[2A"); 444 445 donothing: 446 447 for(i=0;i<MAP_Y_LEN;i++) 448 printf(" "); 449 printf("\rSELECT CMD ......."); 450 ch = getchar(); 451 switch (ch) 452 { 453 case '1'://restart 454 control_exit(); 455 snake_body_clean(); 456 snake_init(); 457 restart=1; 458 //printf("\033[1A"); 459 break; 460 case '2'://restart 461 control_exit(); 462 snake_body_clean(); 463 snake_init(); 464 restart=1; 465 ifselectle = 1; 466 printf("\033[1A"); 467 break; 468 case 'X':; 469 case 'x': 470 control_exit(); 471 snake_body_clean(); 472 printf("\033[31B"); 473 break; 474 default: 475 //printf("\n\033[2A"); 476 //printf("\033[u"); 477 goto donothing; 478 break; 479 } 480 printf("\n"); 481 } 482 483 int main() 484 { 485 int fd = 0,err = 0,i,j; 486 unsigned long cmd; //与底层驱动使用相同的定义 此处使用int应该也是可以的 487 int *arg ; //这里底层命令使用的是地址 所以这里也是地址 个人认为地址传送与内核写法比较一致 488 int argint = 0; 489 char progress_bar[101],background_bar[101];//需要绘制的进度条和进度条的背景 490 491 char level; 492 493 for(i=0;i<101;i++) //进度条初始化 101是用来保证progress_bar的队尾不被输出 494 { 495 progress_bar[i] = 0; 496 background_bar[i] = ' '; 497 } 498 499 //进度条没什么作用,就是为了好看 500 for(i=1;i<=100;i++)//循环打印 //这种方式绘制进度条思路比较简单 501 { 502 progress_bar[i-1] = ' '; 503 background_bar[100-i] = 0; 504 505 printf("\033[?25lSET UP %3d%% \033[42m%s\033[47m%s\033[0m\r", 506 i,progress_bar,background_bar);//绘制进度条 //格式控制,优化访问缓冲区的次数 507 508 509 fflush(stdout);//清空输出缓冲区 510 usleep(10000); 511 } 512 printf("SET UP DONE\n"); 513 514 515 while(restart) 516 { 517 restart=0; 518 for (i = 0; i < MAP_X_LEN; i++) 519 { 520 map_init(i); 521 } 522 523 printf("CHOOSE LEVEL(1-100):"); 524 525 if(ifselectle) 526 { 527 scanf("%d",&le); 528 //printf("\033[1A"); 529 ifselectle=0; 530 if(le<1) 531 le=1; 532 else if(le>100) 533 le=100; 534 } 535 536 snake_init(); 537 make_apple(); 538 control_init(); 539 540 541 while(control) 542 { 543 get_key(); 544 } 545 546 list_select(); 547 548 //map_clean(); 549 550 551 } 552 return 0; 553 }

浙公网安备 33010602011771号