贪吃蛇
编译环境: 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;
}
评论