贪吃蛇 编译环境: TC3 要求显示器能提供: 彩色 43/50 线文本模式 否则程序将退出。 功 能:有计时,升级功能,可以完家控制蛇,也可以让电脑控制蛇 完家边欣赏边喝咖啡,可以暂停,可以立即退出 。 请用记事本编辑源程序 说 明 :这个程序是上学期写的,现在看来很多缺陷 但是不想改了,这是个文本模式下的小游戏 本来想在图形模式下搞,但是在TC3下就是进 不了图形模式,偶尔进了一次,但硬盘搞挂后 又不知道怎么进了,幸亏把编译好的结果存到 了磁盘上。点击:下载完整代码snake.rar 部分代码: /**************************************************\ 编译环境: TC3 (我还没找到其它可以的) 要求显示器能提供: 彩色 43/50 线文本模式 否则程序将退出。 请用记事本编辑源程序 author:江南孤峰 data: 2006--6--11 \**************************************************/ #include <stdio.h>#include <conio.h>#include <time.h>#include <stdlib.h>#include <dos.h>#include <graphics.h> /* 功能键定义 */ #define ESC 0x011b#define DOWN 0x5000#define LEFT 0x4b00#define RIGHT 0x4d00#define UP 0x4800#define ENTER 0x1c0d /* 边缘定义,其中下边缘随模式不同而不同 */ #define EDGE_LEFT 22#define EDGE_RIGHT 80#define EDGE_TOP 5 /* 移动状态键定义 */ #define GET_FOOD 2#define LOST_GAME 1#define WIN_GAME 0#define CAN_MOVE 0#define CANT_MOVE 3 /* 时间显示中断 */ #define _CPPARGS#define SHOW_TIME 0x1c /*************** 全局变量定义 ************************/ typedef struct snake_body{ int x,y; struct snake_body *next;}snake_body; typedef struct snake_statues /* 蛇头信息 */{ int save_x,save_y; snake_body *head; snake_body *trail;}snake_statues; snake_statues *snake;snake_body *body_temp; /* 初始化都在Re_Set()函数中完成 */int EDGE_DOWN,MODE,show_time; int level,score,speed,Food_x,Food_y;char snake_head[8],snake_food[8],erase[8]; /**************** 函数申明 ****************************/ int Re_Set();int Over();void Init_Mode();void Init_Face();void Init_Block();void Init_Snake();void Set_Food();char Start_Play();void Print_Menu();char User_Key(); int User_Play();int Check_Move();int Move_Failed(); int Computer_Play();int Search_Path();int Test_Left();int Test_Right();int Test_Up();int Test_Down(); void interrupt newhandler(_CPPARGS);void My_Exit();void ReSet_Time(void interrupt(* proc)(_CPPARGS)); /********************* 主函数 *************************/ /* 这里我把这个函数注解了,如果你能进入图形模式就打开它 那样编译后的可执行文件可以直接进入全屏模式。void Init_Graph(){ int gdriver=DETECT,gmode; registerbgidriver(EGAVGA_driver); /*建立独立图形运行程序 * initgraph(&gdriver,&gmode," "); closegraph();}*/ void Hide_Cursor(void){/* 设置光标尺寸,隐藏光标 */ union REGS inregs,outregs; inregs.h.ch = 100; inregs.h.cl = 100; inregs.h.ah = 1; int86(0x10,&inregs,&outregs);} void main(){ int t; char c; /* Init_Graph(); 如果能够在图形模式下编译就打开这个函数 另外一种进入全屏模式的方法是,可以用TC2编译该函数, 在本程序中加入 system("可执行文件名"); 语句将TC2下编译 生成的可执行文件和本程序的可执行文件放一起,就可以直接进 入全屏模式。 */ system("full.exe"); Init_Mode(); /* 进入彩色 43/50 线文本模式 */ Hide_Cursor(); Init_Block(); /* 得到蛇身,蛇头内存块 */ ReSet_Time(newhandler); /* 重设时间中断过程 */ while( 1 ) { t = Re_Set(); /* 重完或初次游戏的初始化操作 */ if( t == 1) /* 观看游戏 */ { t = Computer_Play(); if( t ) { t = Over(WIN_GAME); if( !t ) break; } else { t = Over(LOST_GAME); if( !t ) break; } } else if( t == -1 ) { t = User_Play(); if( t ) { t = Over(WIN_GAME); if( !t ) break; } else { t = Over(LOST_GAME); if( !t ) break; } } else break; } My_Exit(); /* 恢复时间中断处理过程 */} /**************** 和时间显示有关的函数 *****************/ void interrupt (*oldhandler)(_CPPARGS); /* 旧时间中断处理函数指针 */ void interrupt newhandler(_CPPARGS) /* 每次时间中断都会调用此函数 */{ show_time ++; oldhandler();} /* 设置新的中断处理过程 */void ReSet_Time(void interrupt(* proc)(_CPPARGS)){ oldhandler = getvect(SHOW_TIME); /* 保存旧中断处理函数指针 */ disable(); /* 关闭所有中断 */ setvect(SHOW_TIME,proc); /* 设置新中断处理函数 */ enable(); /* 开中断 */} void My_Exit() /* 恢复中断处理过程 */{ disable(); setvect(SHOW_TIME,oldhandler); /* 恢复源时间中断处理函数 */ enable(); exit(0);} /*********** 初始化显示模式定义下边缘 ****************/ void Init_Mode(){ struct text_info text; textmode(64); gettextinfo(&text); if(text.screenheight == 43) { MODE = 43; EDGE_DOWN = 40; } else if(text.screenheight == 50) { MODE = 50; EDGE_DOWN = 46; } else { printf("\n\n\tThe text mode was not c4350 ,Try use TC3 compiler !\n"); system("ENTER"); exit( 0 ); }} /************** 初始化所有数据 *********************/ int Re_Set() { char c; level = 0; /* 全局变量初始化 */ score = 0; speed = 300; show_time = 0; snake = NULL; body_temp = NULL; Init_Face(); Init_Snake(); c = User_Key(); if( c == 'c') return 1; /* 观看电脑游戏 */ else if( c == 'e') return 0; /* 退出游戏 */ else return -1; /* 开始游戏 */} /********************* 打印菜单 **********************/ void Print_Menu(){ if(MODE == 50) window(1,6,22,45); else window(1,6,22,39); textbackground(BLUE); textcolor(WHITE); clrscr(); printf("\n\n"); printf(" Level:0-9\n"); printf("\n Current Score:0\n"); printf("\n Current Level:0\n"); printf("\n ** RUN OPTION ** \n\n"); printf("**********************\n"); printf("* *\n"); printf("* start/ENTER:[Enter]*\n"); printf("* *\n"); printf("* exit game:[Esc] *\n"); printf("* *\n"); cprintf("* move left: [%c] *",27); /* 打印方向键字符 */ cprintf("* move right: [%c] *",26); cprintf("* move down: [%c] *",25); cprintf("* move up: [%c] *",24); printf("* *\n"); printf("* Set speed: [s] *\n"); printf("* Set level: [d] *\n"); printf("* Computer_p: [c] *\n"); printf("* *\n"); printf("**********************"); printf("\n\n\n"); printf("Run in:text mode c4350\n"); printf("should at fullscreen \n\n"); printf("Run time: 00 : 00 \n\n"); printf("if you find some error\n"); printf("please send mail to me");} /****************** 获取用户输入 *********************/ char User_Key(){ int key; error: window(30,20,68,23); textcolor(WHITE); textbackground(BLUE); highvideo(); clrscr(); gotoxy(1,2); printf(" Enter your Select from left menu:"); for(key = 0; key < 8; key ++) { sound(key * 500); delay( 100 ); } nosound(); /* 铃声 */ while( !bioskey( 1 ) ) ; /* 等待用户按键 */ key = bioskey( 0 ); /* 获取按键码 */ gotoxy(1,3); switch( key ) { case 0x1f53: /* s键设置游戏速度 */ case 0x1f73: printf(" Enter your speed:"); scanf("%d",&speed); level = (300 - speed)/10; if(level >= 10) level = 9; /* 将光标置于分数栏 */ if(MODE == 50) window(1,6,22,45); else window(1,6,22,39); gotoxy(17,5); break; case 0x2044: /* d键设置运行级别 */ case 0x2064: printf(" Enter your level:"); scanf("%d",&level); if(MODE == 50) window(1,6,22,45); else window(1,6,22,39); gotoxy(17,7); printf("%d\b",level); speed = 300 - level * 10; break; case 0x2e43: /* c键观看电脑游戏 */ case 0x2e63: key = -1; break; case ENTER: key = 0; break; case ESC: return 'e'; /* 退出游戏 */ default: printf(" Input error !"); putch(7); /* 输入不正确 */ sleep(1); goto error; } if(MODE == 50) window(24,6,79,45); else window(24,6,79,39); textbackground(BLACK); clrscr(); gettext(30,18,31,19,erase); puttext(snake->head->x,snake->head->y, /* 初次绘蛇 */ snake->head->x+1,snake->head->y+1,snake_head); puttext(snake->trail->x,snake->trail->y, snake->trail->x+1,snake->trail->y+1,snake_food); Set_Food(); if(MODE == 50) window(1,6,22,45); else window(1,6,22,39); gotoxy(17,5); /* 将光标置于分数栏 */ if(key == -1 ) return 'c'; else return 'm';} /************ 获取组成蛇的两个字符块 ****************/ void Init_Block(){ textbackground(BLACK); textcolor(GREEN); clrscr(); /* 蛇身和食物块 */ gotoxy(36,18); putch('@'); /* @@ */ gotoxy(37,18); putch('@'); /* @@ */ gotoxy(36,19); putch('@'); gotoxy(37,19); putch('@'); gettext(36,18,37,19,snake_food); textcolor(RED); clrscr(); /* 蛇头块 */ gotoxy(36,18); putch('*'); /* ** */ gotoxy(37,18); putch('*'); /* ** */ gotoxy(36,19); putch('*'); gotoxy(37,19); putch('*'); gettext(36,18,37,19,snake_head);} /************** 初始化用户界面 *********************/ void Init_Face(){ clrscr(); window(1,1,80,4); { textbackground(GREEN); textcolor(WHITE); highvideo(); clrscr(); gotoxy(22,3); printf("WELCOME TO PLAY THE GAME OF SNAKE !"); } if(MODE == 50) window(1,47,80,50); else window(1,41,80,43); { textbackground(GREEN); textcolor(WHITE); clrscr(); printf("\n\t Author information: QQ:403324669 , Email:lingdlz@163.com "); } Print_Menu(); window(1,5,80,5); { textbackground(RED); clrscr(); } if(MODE == 50) window(1,46,80,46); /* 下边缘 */ else window(1,40,80,40); { textbackground(RED); clrscr(); } if(MODE == 50) window(23,5,23,46); /* 左边缘 */ else window(23,5,23,40); { textbackground(RED); clrscr(); } if(MODE == 50) window(80,5,80,46); /* 右边缘 */ else window(80,5,80,40); { textbackground(RED); clrscr(); } if(MODE == 50) window(24,6,79,45); else window(24,6,79,39); { textbackground(BLACK); clrscr(); }} /******************** 初始化构成蛇的链表 *********************/ void Init_Snake(){ snake = (snake_statues *)malloc(sizeof(snake_statues)); snake->head->x = 36; snake->head->y = 18; body_temp = (snake_body *)malloc(sizeof(snake_body)); body_temp->x = 34; body_temp->y = 18; body_temp->next = NULL; snake->head->next = body_temp; snake->trail = body_temp;} /******************** 设置随机食物 *************************/ void Set_Food() { int i = 0,down = 20; /* 这个函数不完善,因为它要求很高 */ char test[8]; /* 既要随机出现,又要保证产生速度 */ if(MODE == 43) down = 17; a: randomize(); i = rand(); do{ i /= 13; }while( i > down - 1 ); Food_y = i * 2 + 6; randomize(); i = rand(); do{ i /= 11; }while( i > 19 ); Food_x = i * 4 + 24; gettext(Food_x,Food_y,Food_x+1,Food_y+1,test); if( memcmp(test,erase,8) ) { Food_x += 2; Food_y +=2; gettext(Food_x,Food_y,Food_x+1,Food_y+1,test); if( memcmp(test,erase,8) ) { Food_x -= 2; Food_y +=2; gettext(Food_x,Food_y,Food_x+1,Food_y+1,test); if( memcmp(test,erase,8) ) { Food_x -= 2; Food_y -=2; gettext(Food_x,Food_y,Food_x+1,Food_y+1,test); if( memcmp(test,erase,8) ) { Food_x += 2; Food_y -=2; gettext(Food_x,Food_y,Food_x+1,Food_y+1,test); if( memcmp(test,erase,8) ) { Food_x = 24; Food_y = 6; gettext(Food_x,Food_y,Food_x+1,Food_y+1,test); if( memcmp(test,erase,8) ) { Food_x = 48; Food_y = 40; gettext(Food_x,Food_y,Food_x+1,Food_y+1,test); if( memcmp(test,erase,8) ) goto a; } } } /* 这里很晕吧,这样其实还不行,主要是那个随机数 */ } /* 产生器不怎么随机食物老是在一个范围里出现自己 */ } /* 又不会编写随机数函数,哎!空一声长叹 */ } puttext(Food_x,Food_y,Food_x+1,Food_y+1,snake_food);} /******************** 移动蛇 ***************************/ int Move_Snake(int add) { int save_x1,save_x2,save_y1,save_y2; char strtime[10]; if(show_time > 17) /* 显示时间 */ { if(MODE == 50) window(1,6,22,45); else window(1,6,22,39); show_time = 0; /* 恢复计时器 */ gotoxy(1,32); _strtime(strtime); printf("Run Time: %10s",strtime); } puttext(snake->head->x,snake->head->y,snake->head->x+1, snake->head->y+1,snake_head); puttext(snake->save_x,snake->save_y,snake->save_x + 1, snake->save_y + 1,snake_food); if( !add ) /* 没有得到食物的移动擦除蛇尾 */ puttext(snake->trail->x,snake->trail->y,snake->trail->x + 1, snake->trail->y + 1,erase); delay(speed); body_temp = snake->head->next; /* 改变蛇身坐标,坐标依次前移 */ save_x1 = body_temp->x; save_y1 = body_temp->y; body_temp->x = snake->save_x; body_temp->y = snake->save_y; while(body_temp->next) /* 依次将坐标值往后移动 */ { body_temp = body_temp->next; save_x2 = body_temp->x; save_y2 = body_temp->y; body_temp->x = save_x1; body_temp->y = save_y1; save_x1 = save_x2; save_y1 = save_y2; } if( add ) /* 得到食物改变蛇尾指针,增加移动速度 */ { body_temp = (snake_body *)malloc(sizeof(snake_body)); body_temp->x = save_x1; body_temp->y = save_y1; body_temp->next = NULL; snake->trail->next = body_temp; speed -= 6; /* 更新速度得分和级别 */ score += 100; if(MODE == 50) window(1,6,22,45); else window(1,6,22,39); gotoxy(17,5); printf("%d\b",score); if(score % 500 == 0) { level++; gotoxy(17,7); printf("%d\b",level); } putch(7); /* 响铃 */ } snake->trail = body_temp; /* 新尾指针 */ if(level == 9 && score >= 4500) return 1; else return 0;} /******************* 释放用户分配内存 **********************/ void Free(){ snake_body *temp; temp = snake->head; free(snake); while(temp->next) { body_temp = temp->next; free(temp); temp = body_temp; } free(temp);} /******************** 游戏结束提示是否继续 ********************/ int Over(int t){ int i; if( t == WIN_GAME) for(i = 0; i < 8; i ++) /* 响铃示警 */ { sound(300 * i); delay(100); } else for(i = 0; i < 8; i ++) { sound( 500 ); delay(100); } nosound(); /* 关闭扬声器 */ window(35,16,60,24); /* 定义游戏结束窗口 */ textattr(BLINK+WHITE+(RED<<4)); clrscr(); gotoxy(1,2); if( t == LOST_GAME ) cprintf(" GAME OVER ! "); else cprintf(" HAPPY YOU WIN ! "); gotoxy(1,4); cprintf(" Enter:[ESC] exit "); gotoxy(1,6); cprintf(" Enter:[other] continue "); while( !bioskey( 1 ) ) ; i = bioskey( 0 ); delay(500); if(i == ESC) return 0; else return 1;} /************************ 用户游戏函数 **************************/ int User_Play(){ int d = DOWN,t = 0; int key; while( 1 ) { while(!kbhit()) /* 自动移动 */ { key = Check_Move( d ); switch( key ) { case CAN_MOVE: t = Move_Snake(0); break; case LOST_GAME: return 0; case CANT_MOVE: d = Move_Failed(d); break; /* 用户按下无效移动键 */ case GET_FOOD: t = Move_Snake( 1 ); if( t ) return 1; /* 胜利,回主函数 */ else Set_Food(); break; } } key = bioskey( 0 ); /* 接收按键 */ switch( key ) { case DOWN: d = DOWN; break; case LEFT: d = LEFT; break; case RIGHT: d = RIGHT; break; case UP: d = UP; break; case ENTER: do{ while(!kbhit()) ; key = bioskey( 0 ); } while(key != ENTER); break; case ESC: window(30,20,68,23); printf(" Do you really want to exit(y/n) ?"); key = getche(); if( key == 'y' || key == 'Y' ) { Free(); My_Exit(); } /* 按下退出键释放内存退出游戏 */ else clrscr(); break; default: window(30,20,68,23); /* 无效按键处理 */ printf("\t Use direction key please !"); sleep( 1 ); clrscr(); if(MODE == 50) window(1,6,22,45); /* 光标移动到得分栏 */ else window(1,6,22,39); gotoxy(17,5); } key = Check_Move( d ); switch( key ) { case CAN_MOVE: t = Move_Snake(0); break; /* 没有食物的移动 */ case LOST_GAME: return 0; /* 失败返回主函数 */ case CANT_MOVE: d = Move_Failed(d); break; case GET_FOOD: t = Move_Snake( 1 ); if( t ) return 1; /* 胜利,回主函数 */ else Set_Food(); } }} /**************** 检查移动状态 ********************/ int Check_Move(int dest) { int x,y; char test[8]; x = snake->head->next->x; y = snake->head->next->y; snake->save_x = snake->head->x; snake->save_y = snake->head->y; switch(dest) { case DOWN: snake->head->y += 2; break; case LEFT: snake->head->x -= 2; break; case RIGHT: snake->head->x += 2; break; case UP: snake->head->y -= 2; break; default: break; } if(snake->head->x == Food_x && snake->head->y == Food_y) return GET_FOOD; if(snake->head->x >= EDGE_RIGHT || snake->head->x <= EDGE_LEFT || snake->head->y >= EDGE_DOWN || snake->head->y <= EDGE_TOP) return LOST_GAME; if(x == snake->head->x && y == snake->head->y) return CANT_MOVE; gettext(snake->head->x,snake->head->y, snake->head->x + 1,snake->head->y + 1,test); if( memcmp(snake_food,test,8) ) return CAN_MOVE; else return LOST_GAME;} /****************** 处理用户的无效按键 *******************/ int Move_Failed(int dest){ snake->head->x = snake->save_x; snake->head->y = snake->save_y; switch(dest) { case UP: dest = DOWN; break; case LEFT: dest = RIGHT; break; case RIGHT: dest = LEFT; break; case DOWN: dest = UP; break; } return dest;}

评论