贪吃蛇实验报告

一:概要设计

  1. 程序功能:通过“w a s d”按键实现对蛇移动方向的控制,通过吃豆增加蛇身长度, 同时获得并记录游戏分数;game over之后可以选择结束或再次进行游戏

  1. 函数定义调用关系:

int main():主函数; 调用所有函数;

void setpos(int x,int y):坐标设置函数;

int HitWall():判断是否撞墙函数;调用void setpos(int x,int y);

int SelfBite():判断蛇身是否打结;调用void setpos(int x,int y);system();

int Move():移动函数;调用int HitWall();int SelfBite();void setpos(int x,int y);sleep();free();

void Welcome():初始界面函数;调用void setpos(int x,int y);

void DrawFrame():画边框函数;

void InitSnake():初始化蛇函数;

void CreateFood():创建豆函数;调用void setpos(int x,int y);

void PlayGame():游戏移动循环函数;调用void setpos(int x,int y);

void free_snake(Snake*head):释放资源函数;

char GetKeyBoard():键盘控制函数;

void Restart():重新开始函数;调用 void setpos(int x,int y);

  1. 程序流程:

将蛇身,食物,墙数据化: 蛇身用链表表示并用“@”打印,食物位置由随机数函数确认并用“?”打印,而墙的范围 可随意改变,确认一组长宽后,用“#”打印。

设定初始参数:

规定一个适当的初始速度,一个初始蛇身长度。

获取键位指示,模拟蛇的移动:

规定蛇初始的移动方向为向右方向,用GetAsyncKeyState()函数来判断键位指令判断其合理性,如果键位输入的命令是有效命令,则执行这条命令。蛇的运动过程则用链表头插法表示,同时去除蛇尾。

判断吃到食物和撞到自己和撞到墙:

吃食物:

通过比较蛇头下一次出现的位置和目标处的物体,使用if-else语句做出判断如果目标处是食物,则将其变为新的蛇头,蛇尾不变。

撞到墙:

比较蛇头下一次出现的位置和目标处的物体,使用if-else语句做出判断,如果目标处是墙或者自己身体则游戏结束。

细节处理和游戏引导:

在游戏开始和结束出给出相应文字引导,过程中给出分数等基本信息。

  1. 调用库函数:stdio.h;conio.h;stdlib.h;time.h;string.h;windows.h;

二:详细设计

  1. 地图初始化

void DrawFrame(){
    int i=0;
    for(i=0;i<60;i+=2)
    {
        setpos(i,0);
        printf("#");
        setpos(i,DOWN_WALL);
        printf("#");
    }
    for(i=0;i<DOWN_WALL;i++)
    {
        setpos(0,i);
        printf("#");
        setpos(RIGHT_WALL,i);
        printf("#");
    }
 return 0;
} 
  1. 豆的创建

void CreateFood(){
    srand(time(0));
flag:
    while(1)
    {foody=rand()%(DOWN_WALL-1+1-1)+1;
     foodx=rand()%(RIGHT_WALL-2+1-3)+3;
     if(foodx%2==0)
     break;
    }
    p=head;
    while(1)
    {
        if(p->x==foodx&&p->y==foody)
        {goto flag;
        }
        if(p->next==NULL)
        {break;
        }
        p=p->next;
        
    }
    setpos(foodx,foody);
    printf("?");
}
  1. 控制蛇身移动

int Move()
{int ret;
  if((key!='a')&&(key!='w')&&(key!='s')&&(key!='d'))
  {return 0;
  }
  ret=HitWall();
  ret+=SelfBite();
  if(ret==1)
  { 
  return 1;

  }
  p=(Snake*)malloc(sizeof(Snake));
  p->next=head;
  switch(key)
  {case'd':
      p->x=head->x+2;
      p->y=head->y;
      break;
      case'w':
      p->x=head->x;
      p->y=head->y-1;
      break;
      case's':
      p->x=head->x;
      p->y=head->y+1;
      break;
      case'a':
      p->x=head->x-2;
      p->y=head->y;
      break;
  }
  setpos(p->x,p->y);
  printf("@");
  head=p;
  Sleep(speed);
  if(p->x==foodx&&p->y==foody)
  {
      CreateFood();
      score+=10;
      setpos(60,7);
      printf("得分%d",score);
  }
  else{
  while(p->next->next!=NULL)
  p=p->next;
  setpos(p->x,p->y);
  printf(" ");
  free(p->next);
  p->next=NULL;
  p=head;
  }
  return 0;
}
  1. 判断game是否over

int HitWall(){//判断是否撞墙
    if(head->x==0||head->x==RIGHT_WALL||head->y==0||head->y==DOWN_WALL)
    {
    setpos(DOWN_WALL,14);
    printf("Game Over!");
    return 1;        
    }
    return 0;
} 
int SelfBite(){//判断是否打结
    while(p->next!=NULL)
    {
        p=p->next;
        if(head->x==p->x&&head->y==p->y)
        {setpos(DOWN_WALL,14);
         printf("Game Over!");
         
         return 1;
         system("cls");
         main();
        }    
    }
    return 0;    
}
  1. 通过键盘控制

char GetKeyBoard() {//获取键盘输入
   char key=0;
   if(_kbhit()){
       key=_getch();
   } 
return key;

}

三:功能展示

  1. 游戏开始

  1. 吃豆并获得分数

  1. game over之后可以选择重开gg下一把或者摆烂不玩了

四:成员分工

  1. @assassin_zzy :代码创建

  1. @dlkd20:代码优化

  1. @MySQL搬砖人:实验报告撰写

五:总结与建议

c语言功能之简陋实在是令人叹为观止,但不断编写新函数并使用也确实增强了我们的代码编写能力。在编写贪吃蛇的过程中,需要思考并逐步完成游戏的各项功能,并在不断修改调试之中对程序代码进行纠错与完善,无形之中提升了c语言能力,也给我们带来无与伦比的成就感与收获感。简而言之,获益良多。

六:于文末附上完整代码

#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#include<windows.h>
#define DOWN_WALL 20
#define RIGHT_WALL 58
typedef struct s_snake
{
    int x; //蛇头横坐标
    int y;//蛇头纵坐标
    struct s_snake*next ;
} Snake;
void setpos(int x,int y);
int HitWall();
int SelfBite();
int Move();
Snake *head, *end;
Snake *p;
int speed=310;
int level=0, score=0;
int foodx, foody;
char key;
void Welcome();
void DrawFrame();
void InitSnake();
void CreateFood();
void PlayGame();
void free_snake(Snake*head);
char GetKeyBoard();
void Restart();
int main(){
    GetKeyBoard();
     ConsoleSettings();
     Welcome();
     DrawFrame();
    InitSnake();
    CreateFood();
    PlayGame();
    Restart();
    free_snake(head);
    return 0;
}
void setpos( int x, int y){//设置光标 
  SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),(COORD){
      x,y
  });
}
int HitWall(){
    if(head->x==0||head->x==RIGHT_WALL||head->y==0||head->y==DOWN_WALL)
    {
    setpos(DOWN_WALL,14);
    printf("Game Over!");
    return 1;        
    }
    return 0;
} 
int SelfBite(){
    while(p->next!=NULL)
    {
        p=p->next;
        if(head->x==p->x&&head->y==p->y)
        {setpos(DOWN_WALL,14);
         printf("Game Over!");
         
         return 1;
         system("cls");
         main();
        }    
    }
    return 0;    
}
void DrawFrame(){
    int i=0;
    for(i=0;i<60;i+=2)
    {
        setpos(i,0);
        printf("#");
        setpos(i,DOWN_WALL);
        printf("#");
    }
    for(i=0;i<DOWN_WALL;i++)
    {
        setpos(0,i);
        printf("#");
        setpos(RIGHT_WALL,i);
        printf("#");
    }
 return 0;
} 
void InitSnake()
{int i=0;
end=(Snake*)malloc(sizeof(Snake));
end->x=20;
end->y=15;
end->next=NULL;
for(i=1;i<=3;i++)
{
    head=(Snake*)malloc(sizeof(Snake));
    head->x=20+2*i;
    head->y=15;
    head->next=end;
    end=head;
}
while(end->next!=NULL)
{setpos(end->x,end->y);
printf("@");
end=end->next;
}
}
void CreateFood(){
    srand(time(0));
flag:
    while(1)
    {foody=rand()%(DOWN_WALL-1+1-1)+1;
     foodx=rand()%(RIGHT_WALL-2+1-3)+3;
     if(foodx%2==0)
     break;
    }
    p=head;
    while(1)
    {
        if(p->x==foodx&&p->y==foody)
        {goto flag;
        }
        if(p->next==NULL)
        {break;
        }
        p=p->next;
        
    }
    setpos(foodx,foody);
    printf("?");
}
void PlayGame(){
    int mv_ret=0;
    key='d';
    while(1)
    {if((GetAsyncKeyState(0x57)&&0x8000)&&key!='s')
    {key='w';
    }
    else if((GetAsyncKeyState(0x53)&&0x8000)&&key!='w')
    {key='s';
    }
    else if((GetAsyncKeyState(0x44)&&0x8000)&&key!='a')
    {key='d';
    }
    else if((GetAsyncKeyState(0x41)&&0x8000)&&key!='d')
    {key='a';
    }
    else if (GetAsyncKeyState(0x50)&&0x8000)
    {while(p->next!=NULL)
    p=p->next;
    setpos(p->x,p->y);
    printf("@");
    while(1)
    {
        Sleep(100);
        if(GetAsyncKeyState(0x50)&&0x8000)
        {break;
        }
    }
    setpos(p->x,p->y);
    printf(" ");
    }
    else if(GetAsyncKeyState(0x51)&&0x8000)
    {return ;
    }
    if(score==level&&speed>10)
    {speed-=10;
    level+=30;
    }
    mv_ret=Move();
    if(mv_ret==1)
    {break;
    }
     } 
}
int Move()
{int ret;
  if((key!='a')&&(key!='w')&&(key!='s')&&(key!='d'))
  {return 0;
  }
  ret=HitWall();
  ret+=SelfBite();
  if(ret==1)
  { 
  return 1;

  }
  p=(Snake*)malloc(sizeof(Snake));
  p->next=head;
  switch(key)
  {case'd':
      p->x=head->x+2;
      p->y=head->y;
      break;
      case'w':
      p->x=head->x;
      p->y=head->y-1;
      break;
      case's':
      p->x=head->x;
      p->y=head->y+1;
      break;
      case'a':
      p->x=head->x-2;
      p->y=head->y;
      break;
  }
  setpos(p->x,p->y);
  printf("@");
  head=p;
  Sleep(speed);
  if(p->x==foodx&&p->y==foody)
  {
      CreateFood();
      score+=10;
      setpos(60,7);
      printf("得分%d",score);
  }
  else{
  while(p->next->next!=NULL)
  p=p->next;
  setpos(p->x,p->y);
  printf(" ");
  free(p->next);
  p->next=NULL;
  p=head;
  }
  return 0;
}
void Welcome()
{DrawFrame();
 setpos(25,8);
 printf("press any key to start!");
 while((getch())==1)
 continue ;
 system("cls");
}
char GetKeyBoard() {//获取键盘输入
   char key=0;
   if(_kbhit()){
       key=_getch();
   } 
return key;

}
 void ConsoleSettings(){//设置控制台字体
 CONSOLE_CURSOR_INFO cursor;
 cursor.bVisible=FALSE;
 cursor.dwSize=sizeof(cursor);
 HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);
 SetConsoleCursorInfo(handle, &cursor);
 CONSOLE_FONT_INFOEX cfi;
 cfi.cbSize=sizeof cfi;
 cfi.nFont=0;
 cfi.dwFontSize.X=20; 
 cfi.dwFontSize.Y=20;
 cfi.FontFamily=FF_DONTCARE;
 cfi.FontWeight=FW_NORMAL;
 wcscpy_s(cfi.FaceName,_countof(cfi.FaceName),L"Raster");
 SetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE),FALSE,&cfi);
 }
void free_snake(Snake*head)
 {if(head==NULL||head->next==NULL){
     return;
 }
 while((p=head)!=NULL)
 {head=head->next;
 free(p);
 }
 }
 void Restart(){
     while(1)
     {
      setpos(60,8);
      printf("Try again? y/n");
      flag:
      getch();
      if(getch()=='y')
    {
     system("cls");
     score=0;
      main();
    } 
    if(getch()=='n')
    { exit (0);
    }
    else 
    {setpos(60,9);
    printf("please choose one right key");
    goto flag;
    }    
    
     }
 } 

感谢观看!take care of yourself and be well!

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值