资源描述
[贪吃蛇程序设计]
一、 设计课题
贪吃蛇程序设计
二、 设计内容
1. 工作说明
(1)实现贪吃蛇小游戏运行,各功效模块分别为食物类型定义,蛇类型定义,界面光标位置显示,蛇初始化,计分方向控制显示,边界及界面显示,食物输出,控制蛇死亡,游戏实现过程等等。
以字符形式输入数据,控制程序运行,经过ASCII码转换输出边界、食物、蛇形等界面,并经过字符形式输出分数,操作控制方法,等具体界面显示内容。
否
进入游戏
(2) 主函数步骤图游戏初始界面
否
蛇初始化
随机输出食物
蛇移动
是
否
蛇吃食物
随机生成食物
蛇增加
是
否
是
是
继续
否
结束
蛇死亡
(3) 所用到数据结构知识及相关数据结构描述形式
数据类型表示及实现,算法和算法分析,线性表链式表示和实现,数组次序表示,动态存放管理等。
(4) 函数介绍
a界面光标位置函数:控制界面光标位置,为显示边界、食物等界面显示内容提供依据。
b.方向控制函数:经过键盘输入指定字母实现对蛇移动方向控制。
c.初始化蛇函数:经过链表方法显示蛇形象,并控制蛇初始长度、初始移动方向及初始分数。
d.边界及界面显示函数:经过引用界面光标位置函数,实现在指定位置输出上下左右边界,显示操作方法。
e.计分显示函数:经过引用界面光标位置函数,实现在指定界面位置输出分数。
f.控制蛇死亡函数:讨论当蛇碰到左右上下边界和咬到本身等多个情况时,经过引用库函数清除目前屏幕,再经过界面光标位置函数在指定位置输出"Game Over!"、"Press ESC to exit,any other key to retry!",接着经过选择是否继续游戏,假如是,经过引用库函数中跳跃函数,回到指定位置循环程序;假如否,则结束游戏。
g.食物输出函数:经过引用库函数中随机数函数随机输出食物,并当蛇吃到食物时,控制蛇长度增加,同时使用递归函数循环输出食物。
h.游戏实现过程函数:调用以上函数,实现蛇移动、增加、死亡具体游戏实现过程。
(5) 函数调用关系
(1)调用了gotoxy()函数有:boundary()函数,getscoresys()函数,isdead()函数,play()函数。
(2)play()函数调用函数有:gotoxy()函数,boundary()函数,getscoresys()函数,isdead()函数。
(3)主函数main()调用了play()函数。
3、任务实现
(1) 在程序中,首先调用蛇初始化函数initialization()得到蛇,再经过食物输出函数getfood()随机输出一个食物,然后经过使用一个do-while循环。在这个循环中先调用边界及界面显示函数和界面光标位置函数控制边界及食物显示,然后判定食物是否被吃掉,假如是,那么继续输出食物;假如否,那么经过调用库函数_kbhit()输入使蛇移动指令w、a、s、d,和当输入空格键时暂停程序,当输入ESC键时退出程序。接着经过判定蛇每吃到一次食物使蛇长度增加1,然后继续经过一个switch()循环不停控制蛇移动方向,接着调用控制蛇死亡函数isdead(),然后判定当蛇每吃到一个食物分数加10,长度加1,食物消失,然后调用分数统计函数在界面指定位置输出,最终调用库函数控制蛇移动速度,完成整个屏幕和缓冲区清除。经过该do-while循环达成该程序中蛇移动,蛇吃食物增加,分数增加等关键关键部分功效实现。
(2) 时间复杂度T(n)=O(n^2)
(3) 源代码
#include "stdio.h"
#include "windows.h"
#include "time.h"
#include "setjmp.h"
#include"conio.h"
#define MAXNOD 500
#define UP 1
#define DOWN -1
#define LEFT -2
#define RIGHT 2
#define YES 1
#define NO 0
jmp_buf retry; //定义retry为跳跃状态变量
typedef struct //定义食物类型
{ int x;
int y;
int status;
}Food;
typedef struct //定义蛇类型
{ int *px;
int *py;
int direction;
int nodlen;
int score;
}Snack;
int gotoxy(int x, int y) //界面光标位置
{ COORD cd;
cd.X=x-12;
cd.Y=y;
return SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),cd);
}
void initialization(Snack *pss) //初始化蛇
{ system("color 0a");
pss->px=(int *)malloc(MAXNOD*sizeof(int));
pss->py=(int *)malloc(MAXNOD*sizeof(int));
// memset(pss->px,0,MAXNOD); //转换为ASCII码
// memset(pss->py,0,MAXNOD);
pss->px[0]=0;pss->py[0]=0;
pss->px[1]=1;
pss->py[1]=0;
pss->direction=RIGHT;
pss->nodlen=2;
pss->score=0;
}
void getscoresys(Snack scr) //计分
{ gotoxy(62,7);
cprintf("分数: %d",scr.score);
}
int ctrltoi(char ctr) //方向控制
{ switch(ctr)
{ case 'w': return UP;
case 's': return DOWN;
case 'a': return LEFT;
case 'd': return RIGHT ;
}
}
void boundary() //边界及界面显示
{ int cnt,y;
gotoxy(15,3);
for (cnt=0;cnt<45;cnt++)
{ cprintf("%c",31); }
gotoxy(15,20);
for (cnt=0;cnt<45;cnt++)
{ cprintf("%c",30); }
for (y=4;y<20;y++)
{ gotoxy(15,y);
cprintf("%c",16);
gotoxy(59,y);
cprintf("%c",17);
}
gotoxy(62,9);
cprintf("上: W");
gotoxy(62,10);
cprintf("下: S");
gotoxy(62,11);
cprintf("左: A");
gotoxy(62,12);
cprintf("右: D");
gotoxy(62,14);
cprintf("暂停: 空格");
gotoxy(62,15);
cprintf("退出: ESC");
}
int isdead(Snack ts) //蛇死
{ int i;
char select;
for(i=0;i<ts.nodlen-1;i++)
if((ts.px[i]==ts.px[ts.nodlen-1]&&ts.py[i]==ts.py[ts.nodlen-1])||((ts.px[ts.nodlen-1]<0))||(ts.px[ts.nodlen-1]>42)||(ts.py[ts.nodlen-1]<0)||(ts.py[ts.nodlen-1]>15))
{ system("cls");
gotoxy(15,12);
cprintf("\t\t\t\tGame Over! \n\t\tPress ESC to exit, any other key to retry!\a\n");
flushall();
select=getch();
if(select==27) exit(0);
system("cls");
longjmp(retry,1); //跳到指定位置
}
}
void getfood(Snack s,Food *pf) //输出食物
{ int i;
cnt: do
{ pf->x=rand()%43;
pf->y=rand()%16;
for (i=0;i<s.nodlen;i++)
{ if (s.px[i]==pf->x&&s.py[i]==pf->y)
{ goto cnt; }
}
break;
}
while(1);
pf->status=YES;
}
void start()
{
char s;
system("color 0e");
cprintf("\n\n\n\t\t\t 欢迎来玩贪吃蛇经典小游戏!\n\n");
cprintf("\n\n\n\t\t\t\t请选择关卡!!!\n\n");
cprintf("\t\t\t\t1:简单\n\n");
cprintf("\t\t\t\t2:通常\n\n");
cprintf("\t\t\t\t3:困难\n\n");
s=getche();
switch(s)
{
case '1':_sleep(300);break;
case '2':_sleep(250);break;
case '3':_sleep(200);break;
}
}
void play()
{ Snack ss;
Food foo;
int i,j,dire;
char ctrl;
srand((unsigned)time(NULL)); //设置随机数种子
setjmp(retry); //跳跃函数
initialization(&ss);
getfood(ss,&foo);
do
{ boundary();
gotoxy(foo.x+16,foo.y+4);
if (foo.status==NO)
getfood(ss,&foo);
cprintf("%c",1);
if(_kbhit())
{ ctrl=getch();
if (ctrl=='w'||ctrl=='s'||ctrl=='a'||ctrl=='d')
{ dire=ctrltoi(ctrl);
if(ss.direction==(0-dire)) ;
else ss.direction=dire;
}
else if (ctrl==' ') system("pause");
else if (ctrl==27) exit(0);
}
for (i=0;i<ss.nodlen-1;i++)
{ ss.px[i]=ss.px[i+1];
ss.py[i]=ss.py[i+1];
}
switch(ss.direction)
{ case UP: ss.py[ss.nodlen-1]=ss.py[ss.nodlen-1]-1; break;
case DOWN: ss.py[ss.nodlen-1]=ss.py[ss.nodlen-1]+1; break;
case LEFT: ss.px[ss.nodlen-1]=ss.px[ss.nodlen-1]-1; break;
case RIGHT: ss.px[ss.nodlen-1]=ss.px[ss.nodlen-1]+1;
}
for(i=0;i<ss.nodlen;i++)
{ gotoxy(ss.px[i]+16,ss.py[i]+4);
cprintf("%c",2);
}
isdead(ss);
if (ss.px[ss.nodlen-1]==foo.x&&ss.py[ss.nodlen-1]==foo.y)
{ for (j=0;j<ss.nodlen;j++)
{ ss.px[ss.nodlen-j]=ss.px[ss.nodlen-j-1];
ss.py[ss.nodlen-j]=ss.py[ss.nodlen-j-1];
}
ss.score +=10;
ss.nodlen++;
foo.status=NO;
}
getscoresys(ss);
system("cls"); //清除屏幕
flushall(); //清除全部缓冲区
}
while(1);
}
int main() //贪吃蛇游戏主函数
{
start(); //开始界面,关卡选择
play();
}
4、调试分析
开始界面:
游戏进程:
暂停界面:
游戏结束:
5、不足和改善
不足1:蛇运行速度过快或过慢。
处理方案:设置一个可调变量,使得能够依据个人喜好改变速度。
不足2:程序开始运行时,会出现蛇和随机出现食物重合情况。
处理方案:去除掉食物随机输出时和蛇重合位置食物输出。
不足3:纵向边界无法封闭,有间距。
处理方案:暂无。
不足4:蛇死了以后无法跳回最初程序继续实施。
处理方案:使用库函数非局部跳跃函数实现操作。
3.算法改善设想:
我期望在该程序中使蛇变为可实现变速,即吃掉一个食物速度加紧一定值;另外期望该程序能够实现选择关卡能力;还有期望该程序能够进行全屏模式。
三、 设计收获及心得体会
(1).收获
经过这次课程设计我收获了很多,也愈加让我认识到数据结构这门课程关键,同时也巩固和加深了我对数据结构了解,提升了综合利用本课程所学知识能力。另外还培养了我独立思索,深入研究,分析问题,处理问题能力,和查阅文件资料能力,而且提升了我调试程序和对编译器使用能力。经过这次课程设计,也培养了我严厉认真工作作风,和团体协作意识和能力。另外,经过这次课程设计也使我了解了之前在数据结构课上没能了解部分问题,使我认识到理论起源于实践,实践是检验真理唯一标准。
(2).心得体会
经过这次课程设计,不仅让我在知识上得到了很大程度提升,认识到数据结构对我们这个专业关键性,而且在精神上也使我丰收甚多,让我清楚认识到学无止境。这次当程序成功运行时我激动心情其它人极难了解,而其中挫折也只有我一个人深有体会,这次课程设计经历让我感受很多,也让我受益匪浅,我相信在以后课程设计中我会愈加自信,也会愈加高质量完成。
展开阅读全文