贪吃蛇源程序本程序为贪吃蛇游戏,想必大家都玩过这个游戏,程序源代码用 TC2.0 编译通过,需要图形驱动文件的支持, 在 TC2.0 的集成环境中有 .本程序利用数据结构中的链表,来将蛇身连接,同时当蛇吃到一定数目的东西时会自动升级,及移动速度会加 快,程序会时刻将一些信息显示在屏幕上,包括所得分数,要吃多少东西才能升级,并且游戏者可以自己手动选 择游戏级别,级别越高,蛇的移动速度越快.另外,此游戏可能与CPU的速度有关系.源代码如下:**********************************************************************************/*******************************COMMENTS**********************************//* snake_game.c*//* it is a game for entermainment.*//* in the begin,there is only a snake head,and it will have to eat food *//* to become stronger,and it eat a piece of food each time,it will *//* lengthen it's body,with the number of food the snake eats going up,it *//* will become long more and more,and the score will goes up also. *//* there is always useful information during the game process. *//* if the path by which the snake goes to eat food is the shortest,the *//* score will add up a double.*//**/*//* enjoy yourself,and any problem,contact **********************************************************************/* all head file that will be used */ #include#include#include#include#include#include/* useful MACRO */#define FOOD_SIZE 8#define SCALE 8#define UP_KEY 0x4800#define DOWN_KEY 0x5000#define LEFT_KEY 0x4b00#define RIGHT_KEY 0x4d00#define MOVE_UP 1#define MOVE_LEFT 2#define MOVE_DOWN 3#define MOVE_RIGHT 4#define INVALID_DIRECTION 0#define QUIT_KEYC 0x1051#define QUIT_KEY 0x1071#define SELECT_KEYC 0x1f53#define SELECT_KEY 0x1f73#define PAUSE_KEYC 0x1950#define PAUSE_KEY 0x1970#define DEFAULT_LEVEL 1#define HELP_COLOR WHITE#define WELCOME_COLOR WHITE#define DEFAULT_COLOR GREEN/* define the macro as follows to improve the game in future */#define FOOD_COLOR YELLOW#define SNAKE_HEAD_COLOR RED#define DEFAULT_SNAKE_COLOR YELLOW#define EXIT_COLOR WHITE#define SCORE_COLOR YELLOW/* sturcture for snake body mainly ,and food also */typedef struct food_infor *FOOD_INFOR_PTR;typedef struct food_infor{int posx; /* position for each piece of snake body */int posy;int next_move; /* next move direction */int pre_move; /* previous move direction,seems unuseful */int beEaten; /* xidentifier for snake body or food */FOOD_INFOR_PTR next; /* pointer to next piece of snake body */FOOD_INFOR_PTR pre; /* pointer to previous piece of snake body */ }FOOD_INFOR;/* structure for snake head */typedef struct _snake_head{int posx;int posy;int next_move;int pre_move;int eatenC; /* number of food that have been eaten */int hop; /* number of steps to eat food */FOOD_INFOR_PTR next; /* pointer to the first piece of eaten food */ }SNAKE_HEAD;/* the left-up corner and right-down corner */typedef struct point{int x;int y;}POINT;/* standards for game speed*//* before level 5,the time interval is level_b[level - 1] / 10,and after *//* level 5,the time interval is 1.00 / level_b[level - 1] */float level_b[9] = {10.0,8.0,6.0,3.0,1.0,20.0,40.0,160.0,640.0};/* available varary */SNAKE_HEAD snake_head;FOOD_INFOR *current; /* always point to food */POINT border_LT,border_RB;int driver,mode; /* for graphics driver */int maxx,maxy; /* max length and width of screen,in pixel */int eaten; /* identifier if the food is eaten */int score = 0; /* total score */int level = DEFAULT_LEVEL; /* level or speed */float interval; /* based on speed */int snake_color = DEFAULT_SNAKE_COLOR; /* snake body color */int hopcount = 0; /* the shortest number of steps for snake *//* to eat food *//* all sub function */void init_graphics();void generate_first_step();int judge_death();int willeatfood();void generate_food();void addonefood();void redrawsnake();void show_all();void sort_all();void change_direction();void help();void show_score(int);void change_level();void show_level();void release(SNAKE_HEAD);int can_promote();void win();void show_infor_to_level();void show_eaten();void calculate_hop();/* main function or entry */void main(){char str[50] = "YOU LOSE!!!"; /* fail information */ clock_t start;int querykey;int tempx,tempy;/* if fail and want to resume game,go here */ retry:init_graphics();show_all(); /* show wall */generate_first_step(); /* generate food and snake head */ show_score(score); /* show score to player */ eaten = 0;/* begin to play game */ while(1){ if(judge_death() == 1) /* die */ break;if(willeatfood() == 1){eaten = 1;addonefood();snake_head.hop ++;if(snake_head.hop == hopcount)score += level * 2;elsescore += level;can_promote();show_score(score);}sort_all();redrawsnake();snake_head.hop ++;show_infor_to_level();show_eaten();show_all();change_direction();if(eaten == 1){generate_food();calculate_hop();snake_head.hop = 0;eaten = 0;}if(level <= 5)interval = level_b[level - 1] / 10.0;elseinterval = 1.00 / level_b[level - 1];start = clock();while((clock() - start) / CLK_TCK < interval) {querykey = bioskey(1);if(querykey != 0){switch(bioskey(0)){case UP_KEY:break;case LEFT_KEY:snake_head.next_move = MOVE_LEFT; break;case DOWN_KEY:snake_head.next_move = MOVE_DOWN; break;case RIGHT_KEY:snake_head.next_move = MOVE_RIGHT; break;case SELECT_KEYC:case SELECT_KEY: change_level();score = 0; show_score(score);show_level();break;case PAUSE_KEYC:case PAUSE_KEY:while(!bioskey(1)); break;case QUIT_KEYC:case QUIT_KEY:goto exit_game;default:break;settextstyle(DEFAULT_FONT,0,2); setcolor(EXIT_COLOR);tempx = border_LT.x + (border_RB.x - border_LT.x - textwidth(str)) / 2; tempy = border_LT.y + (border_RB.y - border_LT.y) / 2; outtextxy(tempx,tempy,str);strcpy(str,"press to retry,or ENTER key to exit");tempy += textheight(str) * 2; settextstyle(DEFAULT_FONT,0,1);tempx = border_LT.x + (border_RB.x - border_LT.x - textwidth(str)) / 2; outtextxy(tempx,tempy,str);select:while(!bioskey(1));querykey = bioskey(0);if((querykey == 0x1372) || (querykey == 0x1352)){level = DEFAULT_LEVEL;score = 0;release(snake_head);closegraph();goto retry;if(querykey != 0x1c0d)goto select;closegraph();return;exit_game:release(snake_head);closegraph();}/* sub function show_eaten() *//* function: to show the total number piece of food *//* that have been eaten by snake any time */void show_eaten(){int tempx,tempy;int size;void *buf;char str[15];settextstyle(DEFAULT_FONT,0,1);setcolor(DEFAULT_COLOR);sprintf(str,"eaten:%d",snake_head.eatenC);tempx = 0;tempy = border_LT.y + textheight(str) * 6;size = imagesize(tempx,tempy,tempx + textwidth(str) + textwidth("A"),tempy + textheight(str));buf = malloc(size);getimage(tempx,tempy,tempx + textwidth(str) + textwidth("A"), tempy + textheight(str),buf);putimage(tempx,tempy,buf,XOR_PUT);outtextxy(tempx,tempy,str);free(buf);}/* sub function: show_infor_to_level *//* function:show information to player that how many pieces *//* of food have to been eaten to get to next level *//* ,and this is not related with score,but only *//* eaten number of food*//**//* level standard:let highlevel stand for the number of *//*pieces of food that can be put int the *//*vertical direction of play area,and *//*before level 5,as long as the snake eat *//*a quarter of highlevel,it will go to next *//*level,and between level 5 and 7,as long *//*as the snake eat one thirds of highlevel, *//*it will go to next level,and between *//*level 8 and 9,the snake will go to next *//*level as long as it eat half of highlevel *//* note: level is between 1 to 9. */ void show_infor_to_level() int highlevel;int size;int tempx,tempy;int toeat;void *buf;char str[50];highlevel = (border_RB.y - border_LT.y) / SCALE;switch(level){case 1:case 2:case 3:case 4:toeat = (highlevel / 4) * level - snake_head.eatenC;break;case 5:case 6:case 7:toeat = (highlevel + highlevel / 3 * (level - 4)) - snake_head.eatenC; break;case 8:case 9:toeat = (highlevel * 2 + highlevel / 2 * (level - 7)) -snake_head.eatenC;break;default:break;} settextstyle(DEFAULT_FONT,0,1);setcolor(DEFAULT_COLOR);if(snake_head.next == NULL){sprintf(str,"next level");tempx = 0;tempy = border_LT.y + textheight(str) * 2;outtextxy(tempx,tempy,str);}if(toeat < 0)toeat = 0;sprintf(str,"%d:%d",level + 1,toeat);tempx = 0;tempy = border_LT.y + textheight(str) * 4;size = imagesize(tempx,tempy,tempx + textwidth(str) + textwidth("A"),tempy + textheight(str));buf = malloc(size);getimage(tempx,tempy,tempx + textwidth(str) + textwidth("A"),tempy + textheight(str),buf);putimage(tempx,tempy,buf,XOR_PUT);outtextxy(tempx,tempy,str);free(buf);/* sub function: win() *//* function:if the player pass level 9,this function *//* will be called ,to show "YOU WIN information *//* and after a key is pressed,the game will go *//* on,but all is back to begin,excepte the *//* snake body length.*/void win(){char str[] = "YOU WIN";int tempx,tempy;settextstyle(DEFAULT_FONT,0,8);setcolor(WELCOME_COLOR);tempx = border_LT.x + (border_RB.x - border_LT.x - textwidth(str)) / 2;tempy = border_LT.y + (border_RB.y - border_LT.y - textheight(str)) / 2;outtextxy(tempx,tempy,str);while(!bioskey(1));}/* sub function: can_promote() *//* function:see if the snake can go to next level on basis *//* of the snake length.*/ /**/ /* note:standards of promote level is instructed above */int can_promote(){/* compare SCORE with standard level score */int high_level;static int last_score = 0;high_level = (border_RB.y - border_LT.y) / SCALE;switch(level){case 1:case 2:case 3:case 4:if(snake_head.eatenC == (high_level / 4 * level))level ++;last_score = score;break;case 5:case 6:case 7:if(snake_head.eatenC == (high_level + high_level / 3 * (level - 4)))level ++;last_score = score;break;case 8:if(snake_head.eatenC == (high_level * 2 + high_level / 2 ))level ++;last_score = score;break;case 9:if(snake_head.eatenC == (high_level * 3)) { win();score = 0;last_score = 0;level = DEFAULT_LEVEL;}break;default:break;}show_level();}/* sub function: calulate_hop() *//* function: calculate the shortest path from snake head to *//* the food it will eaten. */void calculate_hop(){hopcount = (snake_head.posx >= current->posx) ? ((snake_head.posx - current->posx) /SCALE) :((current->posx - snake_head.posx) / SCALE);hopcount += (snake_head.posy >= current->posy) ? ((snake_head.posy - current->posy) /SCALE) :((current->posy - snake_head.posy) / SCALE);}/* sub function: release()*//* function:free memory before exit game or restart */ void release(SNAKE_HEAD snake_head){FOOD_INFOR_PTR traceon,last;traceon = snake_head.next;snake_head.eatenC = 0;snake_head.next = NULL;snake_head.hop = 0;while(traceon)if(traceon->next != NULL)traceon = traceon->next;elsebreak;while(traceon){last = traceon->pre;free(traceon);traceon = last;}/* sub function: show_level()x *//* function:show level information to player anytime */void show_level(){char str[20];int size;void *buf;settextstyle(DEFAULT_FONT,0,1); setcolor(DEFAULT_COLOR);sprintf(str,"Level:%d",level);size = imagesize(0,border_LT.y,textwidth(str),border_LT.y + textheight(str)); buf = malloc(size);getimage(0,border_LT.y,textwidth(str),border_LT.y + textheight(str),buf); putimage(0,border_LT.y,buf,XOR_PUT);free(buf);outtextxy(0,border_LT.y,str);}/* sub function: change_level() *//* functions the play choose "select level "item,—*//* this function will be called */ void change_level() int c;int size,void *buf;int tempx,teimpy,char str[] = "new level (1--9).",settextstyle(DEFAULT_FONT,0,1); setcolor(DEFAULT_COLOR);tempx = 0;tempy = border_LT.y - textheight("A") * 3 / 2; outtextxy(tempx,tempy,str);goon.while(!bioskey(1));c = bioskey(0);if((c == 0x1051) || (c == 0x1071))goto exit;if(isdigit(c&0x00ff))level = (c&0x00ff) - 48;elsegoto goon;exit.size = imagesize(tempx,tempy,tempx + textwidth(str),tempy + textheight(str)); buf = malloc(size);getimage(tempx,tempy,tempx + textwidth(str),tempy + textheight(str),buf); putimage(tempx,tempy,buf,XOR_PUT);free(buf);/* function:show score information to player anytime */ void show_score(int count){int th;int size;void *buf;char str[20];settextstyle(DEFAULT_FONT,0,2);setcolor(SCORE_COLOR);sprintf(str,"Score: %d",count);th = textheight("hello");if((count == 0) && (snake_head.next == NULL)) {outtextxy(border_LT.x + (border_RB.x - border_LT.x) / 4,border_LT.y - 2 * th,str);}else{size = imagesize(border_LT.x + (border_RB.x - border_LT.x) / 4,border_LT.y - 2 * th,border_LT.x + (border_RB.x - border_LT.x) / 4 + textwidth(str) + textwidth("100"),border_LT.y - 2 * th + th);buf = malloc(size);getimage(border_LT.x + (border_RB.x - border_LT.x) / 4,border_LT.y - 2 * th, border_LT.x + (border_RB.x - border_LT.x) / 4 + textwidth(str) +textwidth("100"),border_LT.y - 2 * th + th,buf);putimage(border_LT.x + (border_RB.x - border_LT.x) / 4,border_LT.y - 2 * th,buf,XOR_PUT);outtextxy(border_LT.x + (border_RB.x - border_LT.x) / 4,border_LT.y - 2 * th,str);free(buf);}/* sub function: help() *//* function: show help information at the beginning of game *//* and let player know how to play the game */void help(){char str[100];int th;settextstyle(DEFAULT_FONT,0,1);setcolor(HELP_COLOR);th = textheight("hello");sprintf(str,"move left : %c",27);outtextxy(border_LT.x,border_RB.y,str);sprintf(str,"move up : %c",24);outtextxy(border_LT.x + (border_RB.x - border_LT.x) / 2,border_RB.y,str);sprintf(str,"move down : %c",25);outtextxy(border_LT.x,border_RB.y + th + 2,str);sprintf(str,"move right: %c",26);outtextxy(border_LT.x + (border_RB.x - border_LT.x) / 2,border_RB.y + th + 2,str);outtextxy(border_LT.x,border_RB.y + th * 2 + 4,"quit ");outtextxy(border_LT.x + textwidth("quit ") * 3 / 2,border_RB.y + th * 2 + 4,"pause ");outtextxy(border_LT.x + (border_RB.x - border_LT.x) / 2,border_RB.y + th * 2 + 4,"select level ");}/* sub function: show_all()*//* function:redraw the play area,means show wall */void show_all(){int i,j;setcolor(DEFAULT_COLOR);/*for(i = border_LT.x; i <= border_RB.x; i += SCALE)for(j = border_LT.y; j <= border_RB.y; j += SCALE)rectangle(i,j,i + SCALE, j + SCALE);*/rectangle(border_LT.x,border_LT.y,border_RB.x,border_RB.y);}/* sub function: generate_food()*//* function:after the food is eaten by snake,the function will *//* be called to generate another food,and it will *//* ensure that the generated food shouldn't appeare *//* in the snake body.*/void generate_food(){FOOD_INFOR_PTR traceon;int tempx,tempy;generate:current->posx = random(border_RB.x - SCALE / 2);while((current->posx <= border_LT.x) || ((current->posx - border_LT.x) % SCALE == 0) ||((current->posx - border_LT.x) % SCALE % (SCALE / 2) != 0))current->posx ++;current->posy = random(border_RB.y - SCALE / 2);while((current->posy <= border_LT.y) || ((current->posy - border_LT.y) % SCALE == 0) ||((current->posy - border_LT.y) % SCALE % (SCALE / 2) != 0))current->posy ++; traceon = snake_head.next;while(traceon){if((traceon->posx == current->posx) && (traceon->posy == current->posy)) goto generate;traceon = traceon->next;}if(current->posx - border_LT.x == SCALE / 2) current->posx += SCALE;if(border_RB.x - current->posx == SCALE / 2)current->posx -= SCALE;if(current->posy - border_LT.y == SCALE / 2) current->posy += SCALE;if(border_RB.y - current->posy == SCALE / 2)current->posy -= SCALE;setcolor(DEFAULT_COLOR);rectangle(current->posx - SCALE / 2,current->posy - SCALE / 2, current->posx + SCALE / 2,current->posy + SCALE / 2);setfillstyle(SOLID_FILL,YELLOW); floodfill(current->posx,current->posy,DEFAULT_COLOR);}/* sub function: init_graphics()*//* function:initialize the game interface */ void init_graphics() driver = DETECT;mode = 0;initgraph(&driver,&mode,"*.bgi");maxx = getmaxx();maxy = getmaxy();border_LT.x = maxx / SCALE;border_LT.y = maxy / SCALE;border_RB.x = maxx * (SCALE - 1) / SCALE;border_RB.y = maxy * (SCALE - 1) / SCALE;while((border_RB.x - border_LT.x) % FOOD_SIZE) (border_RB.x) ++;while((border_RB.y - border_LT.y) % FOOD_SIZE)(border_RB.y) ++;while((border_RB.y - border_LT.y) % ( 12 * SCALE)) border_RB.y += SCALE;setcolor(DEFAULT_COLOR);rectangle(border_LT.x,border_LT.y,border_RB.x,border_RB.y);help();show_level();}/* sub function: generateX_first_step() *//* function:generate snake head and first food to prepare for *//* game to start,and this function will also initialize*//* the move direction of snake head,and show welcome *//* information to player.*/void generate_first_step(){char str[] = "welcome to snake game,press ENTER key to start";int size;int tempx,tempy;void *buf;randomize();/* generate snake head */snake_head.posx = random(border_RB.x - SCALE / 2);while((snake_head.posx <= border_LT.x) || ((snake_head.posx - border_LT.x) % SCALE == 0) ||((snake_head.posx - border_LT.x) % SCALE % (SCALE / 2) != 0))snake_head.posx ++;snake_head.posy = random(border_RB.y - SCALE / 2);while((snake_head.posy <= border_LT.y) || ((snake_head.posy - border_LT.y) % SCALE == 0) ||((snake_head.posy - border_LT.y) % SCALE % (SCALE / 2) != 0))snake_head.posy ++;setcolor(DEFAULT_COLOR);rectangle(snake_head.posx - SCALE / 2,snake_head.posy - SCALE / 2,snake_head.posx + SCALE / 2,snake_head.posy + SCALE / 2);setfillstyle(SOLID_FILL,SNAKE_HEAD_COLOR);floodfill(snake_head.posx,snake_head.posy,DEFAULT_COLOR);/* generate first food */current = (FOOD_INFOR_PTR)malloc(sizeof(FOOD_INFOR));goon_generate:current->posx = random(border_RB.x - SCALE / 2);while((current->posx <= border_LT.x) || ((current->posx - border_LT.x) % SCALE == 0) ||((current->posx - border_LT.x) % SCALE % (SCALE / 2) != 0))current->posx ++;current->posy = random(border_RB.y - SCALE / 2);while((current->posy <= border_LT.y) || ((current->posy - border_LT.y) % SCALE == 0) ||((current->posy - border_LT.y) % SCALE % (SCALE / 2) != 0))current->posy ++;if((current->posx == snake_head.posx) && (current->posy == snake_head.posy))goto goon_generate;rectangle(current->posx - SCALE / 2,current->posy - SCALE / 2,current->posx + SCALE / 2,current->posy + SCALE / 2);setfillstyle(SOLID_FILL,FOOD_COLOR);floodfill(current->posx,current->posy,DEFAULT_COLOR);calculate_hop();snake_head.next = NULL;snake_head.eatenC = 0;snake_head.hop = 0;current->next = NULL;current->pre = NULL;current->beEaten = 0;current->next_move = INVALID_DIRECTION; current->pre_move = INVALID_DIRECTION;if(snake_head.posx == current->posx){if(snake_head.posy > current->posy) snake_head.next_move = MOVE_UP;elsesnake_head.next_move = MOVE_DOWN;}else{if(snake_head.posx < current->posx) snake_head.next_move = MOVE_RIGHT; elsesnake_head.next_move = MOVE_LEFT;}snake_head.pre_move = snake_head.next_move;settextstyle(DEFAULT_FONT,0,1);setcolor(WELCOME_COLOR);tempx = border_LT.x + (border_RB.x - border_LT.x - textwidth(str)) / 2;tempy = border_LT.y - textheight("A") * 6 / 2;outtextxy(tempx,tempy,str); size = imagesize(tempx,tempy,tempx + textwidth(str), tempy + textheight(str));buf = malloc(size); getimage(tempx,tempy,tempx + textwidth(str), tempy + textheight(str),buf);while(bioskey(0) != 0x1c0d);putimage(tempx,tempy,buf,XOR_PUT);free(buf);}/* sub function: judge_death()*//* function:judge if the snake will die because of incorrect *//* move,there are two thin。