程序设计课程设计文档.docx
- 文档编号:8771856
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:22
- 大小:75.81KB
程序设计课程设计文档.docx
《程序设计课程设计文档.docx》由会员分享,可在线阅读,更多相关《程序设计课程设计文档.docx(22页珍藏版)》请在冰豆网上搜索。
程序设计课程设计文档
编号:
《C语言程序设计》
课程设计文档
题目:
贪吃蛇
姓名:
王志刚
学号:
20112480126
院(系):
信息工程学院
2012年06月21日
一.题目意义和设计思想
1、题目意义及分工情况
意义:
通过编写一个独立的程序来检验自己学习的知识情况,并且同时也在扎实贯通基本知识的的基础上对自己的能力进行一些锻炼和提升。
同时能够写出来属于自己的一个应用程序也是一种对自己的肯定,有利于促进个人以后的积极性。
分工:
我是和王盈分为一组,王盈主要负责的是主函数以及贪吃蛇的移动核心算法,即贪吃蛇的移动、增长,吃食物等等,我写的是另一个判断蛇的移动方向的begin函数,食物的随机出现函数,以及游戏开始的界面,游戏运行中的颜色等。
在编写函数的过程中需要使用计时器和光标定位,但是由于我们对计时器还有光标的控制不熟悉,所以我们是采取从网上找一些类似的函数,然后作出适当的一些修改,变成符合我们要求的函数。
2、设计思想
1)、最初的设计思想:
(1)最初的总体的设计思想框架是王盈提出来的,贪吃蛇要在一定的区域框框里面进行运动,这点用二维数组进行解决,就是把一个区域按一定精度划分成一个二维数组,形成“网格”贪吃蛇的身体可以用一个链表控制,一个结点就是身体的一节,贪吃蛇的头就是链表的头结点
(2)贪吃蛇的移动问题,当贪吃蛇遇到它的食物也就是说是链表头结点此时指向的那个数组元素跟食物出现的位置相等了的时候就要建立一个新的链表,然后食物这个结点作为新的链表的头结点,原来链表从头结点开始顺次向后移动一位,这样就可以保证贪吃蛇按照正确的轨迹进行前进,即身体后面的节点跟着前面的节点走
(3)贪吃蛇当撞到边上的框框的时候是要停止的,这点需要每移动一步进行一次判断,看看头结点指向的数组元素和所设边框的所有数组元素中的任何一个是否相等,如果相等就表明贪吃蛇此时已经撞到了墙上,此时游戏应该中止,当然,当贪吃蛇没有撞到墙上而且没有转弯的时候可以让它一直向前,但是此时为了简化难度,可以设成每点击一下方向键就移动一下。
(4)贪吃蛇的移动:
这里将贪吃蛇的移动设置为按一下动一下的形式,这里用循环的形式,判断当贪吃蛇的头部不等于食物和边框的数的时候就允许下一次移动,否则就要根据他是等于食物还是等于边框作出相应反应
(5)食物的随机出现:
这是个问题,因为食物的随机出现可以用随机数二维数组来解决,然后要把食物限制在规定的区域范围内这个用随机数也是可以做到的,但是随机数产生什么是不确定的,如果它产生了一个数,而这个数恰好又在蛇的身体上,这个时候显然不可以。
所以我想这里又是需要判断,即每次产生随机数都要进行判断,看看这个数和贪吃蛇身体的每一个结点是不是相等,如果不相等就可以产生,如果恰好有某个结点和所产生的随机数相等,解决的办法可以是再次调用产生随机数的函数直到不相等的位置(这里不相等的判断可以让产生随机数的函数有个返回值,从而进行判断和操作)
(6)食物的产生是利用随机数的思想,每次当判断蛇遇到食物并且将蛇进行重新输出后调用随机产生食物的函数。
(7)但是随着程序设计的程度不断成熟却发现其中的right函数一直无法正确执行,进过一次次的修改也无法成功,后来发现就是利用链表的时候总是引起内存分配的问题,所以最后选择换了一种思路
2)、改变后的思想
鉴于双向链表和内存分配的关系紧密,所以经过考虑和参考资料最后决定用两个一维数组来表示蛇出现位置的坐标,这样不涉及到内存的问题,但是感觉上没有用链表的那样整体性强。
用数组的方法就是当没有遇到事物的时候就重复的执行蛇头加一,蛇尾置0然后后一个点给前一个的操作,当遇到食物的时候将食物的ASCII码值更换成蛇的然后进行输出,其余的想法跟之前类似。
二、采用的主要技术、遇到的难点和解决方法
主要技术:
数组的操作,循环控制,随机数的应用,if判断语句,ASCII码值的应用,界面函数,计时器,光标定位
遇到的难点和解决方法:
1、我最初写的是food产生随机食物函数。
这个函数比较简单,只是在产生时候会产生0这个值,而这个值正好是位于边框区域的位置,所以处理方法就是每次产生随机数以后看看是不是0,如果是0就在food函数本身里面调用food函数,这种想法觉得很好
2、就是right函数的问题,这可以说是我们遇到的最大的难题,蛇的移动问题,本来是想用双链表来实现操作,因为每个节点都有两个指针指向上一个节点和下一个节点,我们刚开始有两种思路:
一种是蛇每前进一步就建立一个节点作为头节点再把为节点释放另一种是采用循环语句每次将上一个节点的值赋值给下一个节点,然后将头节点按照移动的方向进行操作,但是由于总是涉及内存的分配和释放,很难控制,所以最后的解决方法就选择了用数组来表示蛇。
3、蛇的移动问题,最开始是想要基本先完成程序的整体框架,所以蛇的移动采用的是每次都要输入方向然后按一下回车动一下,这样实现的功能很弱。
当总体程序基本完成后我们就开始优化这个问题,想的是有没有一中循环可以按照一定时间不断地执行某个操作,这样经过查找就在网上找到了计时器函数,经过我们的改造和添加设计使得计时器函数满足我们的要求,可以按照一定时间一直调用方向函数
4、界面变换问题,开始的思路是每次蛇的移动对数组这个全局变量进行操作,然后重新输出,这样就造成了界面不断刷新,不停闪动的问题。
经过老师的指导和网上查找光标定位函数并进行修改以后就实现了在同一个界面改变光标的位置,从而进行重置,赋值,移动等操作。
三、实现的主要功能和系统结构
主要功能:
1、可以进行正常的上下左右移动
2、吃到食物或者撞到墙的时候可以做出相应的反应
3、每次吃到食物后会计入相应的分数
4、当吃的食物超过五个以后会自动加速
5、可以实现暂停继续的功能
系统结构:
因为游戏刚开始主要的就是界面,为了是界面足够清晰,所以就将界面函数放在了主函数,而将控制蛇运动的函数放在了另一个重要的函数:
begin()函数里面(控制蛇的主要运动),通过此函数来调用计时器函数(控制蛇的运动速度),然后计时器函数调用移动函数,由移动函数的if语句来判断是否是前进还是吃到食物或者撞墙进而调用尾部清零加头部或者报错函数。
Main函数
移动函数
蛇尾
蛇头添加
吃到食物添加
四、核心算法描述和相关技术说明
核心算法描述:
通过一个二维数组来控制蛇界面,通过两个一维数组来表示蛇所在的地方的ASCII码值借此来写if语句以判断蛇是否吃到食物,撞墙或者继续前进。
通过计时器来满足蛇按照一定的速度不断地继续前进,通过一个变量来调控蛇的运行速度来达到控制游戏的等级的目的,通过if语句来来判断键盘是否有输入来进行蛇的方向的改变的问题。
通过定位函数来实现只对整个界面的部分操作,即实现蛇运动的地方光标指向那里,把那里的ASCII码值进行调换,并在那里输出ASCII码值对应的符号,以此来显示蛇和食物。
食物的出现是依靠随机函数,自己本身写的函数依靠随机数来进行出现。
还有界面的实现也是依靠光标制定的函数。
相关技术说明:
这个程序主要考察人的反映能力,是娱乐休闲的小游戏,包含的技术有:
对代码的操作能力:
即各种语句的实现,结合。
对全局变量和局部变量的操控
对各种函数的不断调用
对两个人写的不同的程序的调控
对从网上下的函数调控修改满足自己的需要
五、总结和体会
1、这次课程设计给我最大的一点体会就是有一个整体顾全大局能力的重要性,就像这个程序最开始的框架雏形是王盈提出来的,虽然有很多的漏洞和不足,但是这给我们指明了一个努力地方向,朝着这个方向努力至少不会让我们觉得有能力没处用,所有出现的问题都是可以在按照这个基本思路进行设计的时候进行修改和不断完善,所以一个人对于整体的框架的建设能力是很重要的,我觉得这点以后我要着重注意锻炼
2、这次课程设计是我更加意识到了我能力的缺陷,敲代码这个能力我相信只要每个人只要够勤快都可以练的很熟练,但是考虑问题的思想,设计问题的算法,解决问题的渠道,这些方面才是真正衡量一个人才华的尺子。
所以在以后的学习中一定会更加注重思想,算法,这些自己平时认为很枯燥的东西的掌握能力的培养,因为这才是一个人真正的能力的一个衡量标尺
3、写程序不能一步要求过高,在开始的时候可以把功能制定的弱一点,比如我们开始想的蛇的移动是用scanf来判断的,这样每次输入要调用的方向函数都要输入相应的按键,然后敲回车动一下。
随着后来程序的基本完成我们又进行了逐步完善,比如按一下动一下用了计时器,界面一直闪烁用了光标定位函数来解决等等……
4、对于网上的资源我们知道有很多,但是我们学会了合理的利用,在全程编写程序的过程中我们有自己的思路和逻辑,只是在实现其中的某个版块的时候可能会遇到各种各样的问题和知识点,比如计时器函数,光标定位函数,这样涉及到具体某一个问题又是我们没有学过的东西的时候我们会到网上论坛上去问去寻找解决办法,这样做跟直接找源代码参考的区别就是更能增加自己独立思考的能力,遇到问题解决问题,把网络当成一种解决问题的工具,而不是直接给你答案的东西,这样才可以在锻炼自己的同时从网络上学到东西,真正的让自己的能力强大起来
附录
源代码:
#include
#include
#include
#include
#include
#include
voidmenu();
voidbegin();
voidcreat1();//是用来创造界面的
voidcreat2();//是用来创造蛇的身体的
voidleft();
voidright();
voidup();
voiddown();//左右移动函数
voidfood();//随即产生食物的函数
voidtime();
voidfault();
voidinput();
voidtimer();
voidtimel();
voidtimeu();
voidtimed();
intinput1(intx,inty);//对蛇头进行改变操作
intinput2(intp,intq);//对蛇尾进行改变操作
intinput3(intr,ints);//对出现的食物进行操作
voidinput4();
voidstruction();
chara[22][60];
inthead[2];//定义蛇头的坐标
intb[50],c[50];//分别用这两个数组来表示蛇的头部和尾部
intm,n=3;//全局变量用来控制游戏再次开始,dit\rection是用来控制方向的,1代表上,2代表下,3代表左,4代表右,n用来记录蛇的节数
intu;
intnum=0,speed=230;//用来控制计时器是否继续,speed通过玩游戏者分的多少来控制速度
chardirection='D';
intf;
HANDLEhConsole;
voidgotoxy(intx,inty)
{
COORDcoord;
coord.X=x;
coord.Y=y;
SetConsoleCursorPosition(hConsole,coord);
}
intmain()
{
intt;
hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole,FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_INTENSITY);
creat1();
input();
gotoxy(16,8);
printf("欢迎来到贪吃蛇的世界!
!
\n\n\n\n");
printf("*新手指导:
I\n\n\n");
printf("*继续(Y)/退出(N)?
");
scanf("%c",&f);
system("cls");
if(f==73||f==105)
{struction();}
while(f==89||f==121)
{
system("cls");
creat1();
input();
gotoxy(10,10);
printf("选择游戏等级:
1(初级)2(中级)3(高级)\n\n");
printf("*请输入您的选择:
");
scanf("%d",&t);
n=3;
if(t==1)
speed=240;
elseif(t==2)
speed=140;
else
speed=100;
menu();
direction='D';
m=0;creat1();
begin();
getchar();
scanf("%c",&f);
}
system("cls");
gotoxy(16,8);
printf("人民会永远记得你的!
!
!
\n\n\n");
printf("你永远活在我们心中!
!
@!
!
!
\n\n\n");
printf("BYBE!
");
getchar();
getchar();
}
voidcreat1()
{
inti,j;
for(i=0;i<22;i++)
for(j=0;j<60;j++)
a[i][j]=0;
for(j=0;j<60;j++)
{a[0][j]=42;a[21][j]=42;}
for(i=0;i<22;i++)
{a[i][0]=42;a[i][59]=42;}
}
voidinput()
{
inti,j;
system("cls");
for(i=0;i<22;i++)
{
for(j=0;j<60;j++)
printf("%c",a[i][j]);
printf("\n");
}
printf("SCORE:
0");
if((n-3+1)%5==0)
speed=speed-1;
}
voidleft()
{
inti,l,k;
l=b[n-1];k=c[n-1];//记录原来蛇的头的位置
k--;
if(a[l][k]==0)
{
input2(b[0],c[0]);
for(i=1;i {b[i-1]=b[i];c[i-1]=c[i];} c[n-1]--;//将蛇头的纵坐标加一 input1(b[n-1],c[n-1]); } else { if(a[l][k]==2) { n=n+1;//蛇的节点加一 b[n-1]=b[n-2];c[n-1]=c[n-2]-1;//蛇的节点加一,并对蛇头进行操作 a[b[n-1]][c[n-1]]=1;input1(b[n-1],c[n-1]); food();a[head[0]][head[1]]=0; input4(); } else {fault();m=1;num=1;}//失败的话m等于1,就使得函数跳出begin而进入主函数 } } voidright() { inti,l,k; l=b[n-1];k=c[n-1];/*记录原来蛇的头的位置*/ k++;/*K是修改后蛇头的位置*/ if(a[l][k]==0) {input2(b[0],c[0]); for(i=1;i {b[i-1]=b[i];c[i-1]=c[i];} c[n-1]++;//将蛇头的纵坐标加一 input1(b[n-1],c[n-1]);/*光标移动到指定位置,输出新的蛇头*/ } else { if(a[l][k]==2) { n=n+1;//蛇的节点加一 b[n-1]=b[n-2];c[n-1]=c[n-2]+1;//蛇的节点加一,并对蛇头进行操作 a[b[n-1]][c[n-1]]=1;/*让新的蛇头处变为0*/ input1(b[n-1],c[n-1]);/*光标移动到新的蛇头处,将他输出*/ food(); a[head[0]][head[1]]=0; input4(); } else { fault(); m=1; num=1; }//失败的话m等于1,就使得函数跳出begin而进入主函数 } } voidup() { inti,l,k; l=b[n-1];k=c[n-1];//记录原来蛇的头的位置 l--; if(a[l][k]==0) { input2(b[0],c[0]); for(i=1;i {b[i-1]=b[i];c[i-1]=c[i];} b[n-1]--;//将蛇头的纵坐标加一 input1(b[n-1],c[n-1]); } else { if(a[l][k]==2) { n=n+1;//蛇的节点加一 b[n-1]=b[n-2]-1;c[n-1]=c[n-2];//蛇的节点加一,并对蛇头进行操作 a[b[n-1]][c[n-1]]=1; input1(b[n-1],c[n-1]);food();a[head[0]][head[1]]=0;input4(); } else {fault();m=1;num=1;}//失败的话m等于1,就使得函数跳出begin而进入主函数 } } voiddown() { inti,l,k; l=b[n-1];k=c[n-1];//记录原来蛇的头的位置 l++; if(a[l][k]==0) { input2(b[0],c[0]); for(i=1;i {b[i-1]=b[i];c[i-1]=c[i];} b[n-1]++; input1(b[n-1],c[n-1]); } else { if(a[l][k]==2) { n=n+1;//蛇的节点加一 b[n-1]=b[n-2]+1;c[n-1]=c[n-2];//蛇的节点加一,并对蛇头进行操作 a[b[n-1]][c[n-1]]=1; input1(b[n-1],c[n-1]);food();a[head[0]][head[1]]=0;input4(); } else {fault();m=1;num=1;}//失败的话m等于1,就使得函数跳出begin而进入主函数 } } voidfault() { system("cls"); gotoxy(16,8); printf("您已英勇就义,是否还要继续? \n\n"); printf("继续按Y,退出按N\n"); printf(""); } voidcreat2() { inti; b[0]=b[1]=b[2]=1; c[0]=1;c[1]=2;c[2]=3; for(i=1;i<=3;i++) a[1][i]=1;} voidfood() { intx,y; do { x=rand()%21; y=rand()%61; }while(x==0||y==0); while(a[x][y]! =0) food(); a[x][y]=2; head[0]=x;head[0]=y; input3(x,y); } voidbegin() { creat2();//创造蛇 input();//第一次输出蛇的界面 food(); while(m==0) { switch(direction)/*direction初始值为D,当没有输入的时候一直执行向右走的函数*/ { case'D': case'd': timer();break; case'A': case'a': timel();break; case'W': case'w': timeu();break; case's': case'S': timed();break; default: direction=getch(); } } } voidtimer()//向右走的计时器 { time_t*clock=(time_t*)malloc(sizeof(time_t));//创建链表 structtm*mytime=(tm*)malloc(sizeof(tm)); intsec,curTime; num=0;//需要减一的数,为0结束 while(num==0) { time(clock); mytime=localtime(clock); sec=mytime->tm_sec; right(); if(kbhit()! =0) {num=1;direction=getch(); } curTime=sec; Sleep(speed); } } voidtimel()//向左走的计时器 { time_t*clock=(time_t*)malloc(sizeof(time_t));//创建链表 structtm*mytime=(tm*)malloc(sizeof(tm)); intsec,curTime; num=0;//需要减一的数,为0结束 while(num==0) { time(clock); mytime=localtime(clock); sec=mytime->tm_sec; left(); if(kbhit()! =0)/*判断键盘是否有输入*/ {num=1;direction=getch();/*当键盘有输入的时候就执行,不用敲回车*/ } curTime=sec; Sleep(speed); } } voidtimeu()//向上走的计时器 { time_t*clock=(time_t*)malloc(sizeof(time_t));//创建链表 structtm*mytime=(tm*)malloc(sizeof(tm)); intsec,curTime; num=0;//需要减一的数,为0结束 while(num==0) { time(clock); mytime=localtime(clock); sec=mytime->tm_sec; up(); if
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 程序设计 课程设计 文档