正文

字符模式下的贪吃蛇2007-03-20 11:52:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/lingdlz/24128.html

分享到:

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

阅读(4091) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册