C语言流星雨的实现.docx
《C语言流星雨的实现.docx》由会员分享,可在线阅读,更多相关《C语言流星雨的实现.docx(17页珍藏版)》请在冰点文库上搜索。
C语言流星雨的实现
HUNANUNIVERSITY
程序设计训练报告
题目
流星雨的实现
学生姓名
毛宇锋
学生学号
201208060116
专业班级
信息安全一班
学院名称
信息科学与工程学院
指导老师
李丽娟
2013年7月8日
(一)程序要求及功能简介
程序模拟一组流星飞向地面的情景。
地面用多行#来表示,流星用大写字母表示。
程序产生一组流星(比如10个),从屏幕顶部下降飞向地面。
一组流星中,每个流星的字符颜色是随机的,下降的位置是随机的,下降的速度也是随机的。
一个流星下落只能去掉一个#号,当最后一行地面有#被去掉时,程序终止,程序在下降过程中,程序必须知道流星的字符、颜色、位置、速度。
(二)基本算法思想说明
定义一个二维数组screen[24][80],代表25行80列的程序界面,由于DOS界面在输出第25行的时候会发生滚屏的现象,所以只利用上面24行,通过sky数组和ground数组对screen数组进行初始化和更改。
利用随机数产生一组十个流星的数据,包括流星的字符、出现位置、颜色和速度,分别保存在letter,lie,color,speed数组里。
流星坠落的实现就是将上一行出现的字符在下一行出现并将上一行的字符更改为0,坠落的速度是每次替换的行数,替换的多则坠落的快,少则坠落的慢,流星的颜色可以用SetConsoleTextAttribute函数进行更改。
(三)模块的功能及程序说明
调用函数介绍
load函数:
初始化sky,ground,heng,lie数组,给他们赋初始值。
make函数:
用随机数制造一组流星的数据,包括流星的字符、颜色、初始位置、速度。
combine函数:
将经过初始化或者经过改变后的sky与ground数组赋给screen数组。
output函数:
程序界面的输出,将包含流星信息的screen函数输出到屏幕上。
gotoxy函数:
光标移动函数,将光标移动到初始位置重新输出以达到替换屏幕从而实现流星坠落的效果。
这个函数也可以用clearscreen这个系统函数来代替,可是clearscreen函数会造成屏幕的闪烁,影响最终效果。
fall函数:
通过替换和替换的次数来实现流星在screen数组里的位置改变和改变速度的快慢,达到流星坠落的效果。
exist_or函数:
判断屏幕上是否还有流星,如果没有流星则产生新的流星。
(四)算法流程图
否
是
(五)核心源程序
本程序的核心部分是流星雨的制造和通过替换实现流星雨的下落,在源程序中分别被定义为make函数和fall函数。
make函数通过随机数产生流星的字符、颜色、速度性质并传给其他函数进行运算,它所要解决的最重要的问题是如何使流星产生在不同的列和如何将列序号从小到大排列,使得在output函数里能通过SetConsoleTextAttribute函数给流星不同的颜色而不影响整个背景的颜色。
解决第一个问题的方法是通过产生随机数逐次比较来筛选掉出现重复的流星列位置,解决第二个问题的方法是将所有产生的列位置进行冒泡排序。
该函数的源代码如下:
voidmake(charscreen[24][80],charsky[24][80],charletter[10],intlie[10],intheng[10],intcolor[10],intspeed[10],intexist[10])
{
inti1,i2,t,change,base=1;
for(i1=0;i1<10;i1++)
{
heng[i1]=0;
letter[i1]=(abs(rand())%26+65);//随机产生一个字母作为流星
color[i1]=abs(rand())%3;
while
(1)//保证流星不产生在同一列的筛选函数
{
base=0;
t=(abs(rand())%80);
for(i2=0;i2<10;i2++)
if(t==lie[i2])base=1;
if(base==0)break;
}
lie[i1]=t;
speed[i1]=(abs(rand())%3)+1;
sky[0][lie[i1]]=letter[i1];
exist[i1]=1;
}
for(i1=0;i1<10;i1++)//每一列冒泡排序
for(i2=0;i2<9;i2++)
{
if(lie[i2]>lie[i2+1])
{
change=lie[i2];
lie[i2]=lie[i2+1];
lie[i2+1]=change;
}
}
}
fall函数的主要作用是让流星以不同的速度实现逐行的替换,并且保证流星撞到地面时消失。
流星的速度是产生一个大于0的随机数来作为循环最大值,在每一次下落中因为循环的不同导致第二次出现的位置不同,在主函数中通过Sleep来加强屏幕的滞留时间,从而加深了下落速度不同的效果。
fall函数的源代码如下:
voidfall(charscreen[24][80],charsky[24][80],intspeed[10],charground[9][80],intexist[10],intheng[10],intlie[10])
{
inti1,i2;
for(i1=0;i1<10;i1++)
{
if(exist[i1]==1)
{
for(i2=1;i2<=speed[i1];i2++)
{
sky[heng[i1]+1][lie[i1]]=sky[heng[i1]][lie[i1]];
sky[heng[i1]][lie[i1]]='';
heng[i1]+=1;
if(heng[i1]>=20)
{
if(ground[heng[i1]-20][lie[i1]]=='#')
{
sky[heng[i1]][lie[i1]]='';
ground[heng[i1]-20][lie[i1]]='';
exist[i1]=0;
break;
}
}
}
}
}
}
(六)实验结果
程序运行情况如图:
(七)设计体会
该程序在编译时,困扰我的最大问题就是如何让屏幕清空重新输出。
我曾经采用clearscreen清屏函数,可是该函数在清屏时会使屏幕闪烁,效果不好,最终我从网上查找了相关资料,得知了在turboC里面有gotoxy函数,在进一步的学习中我得到了gotoxy在头文件中的源代码,设计了该调用函数并学会通过光标移动重新输出数组。
在设计字符颜色时,也经常出现很多不正常的地方,要么整个背景都在跟着变颜色,要么只有几个字符出现颜色,要么一列是白色一列是红色,在一遍一遍的更改并设置了比较复杂的判断条件后,才得以实现效果。
由于对算法的不够熟悉和通过c语言编写较长程序的经验相对缺乏,我的程序在设计的时候有很多语句不够简洁、语法不够规范的地方,希望能在将来的学习中对此进行完善,进一步加强我对C语言的理解,最后谢谢李丽娟老师和两位助教在我编写程序时对我的帮助。
(八)源代码
#include
#include
#include
#include
voidload(charsky[24][80],charground[9][80],intheng[10],intlie[10]);//初始化各数组数据
voidoutput(charscreen[24][80],intlie[10],intcolor[10]);//界面初始化
voidmake(charscreen[24][80],charsky[24][80],charletter[10],intlie[10],intheng[10],intcolor[10],intspeed[10],intexist[10]);//定义流星的字符、颜色、速度
voidfall(charscreen[24][80],charsky[24][80],intspeed[10],charground[9][80],intexist[10],intheng[10],intlie[10]);//实现流星下降
voidend();
voidgotoxy(intx,inty);//光标移动函数
voidcombine(charscreen[24][80],charstar[24][80],charground[9][80]);//将ground数组与star数组结合起来形成screen
intexist_or(charsky[24][80]);//当屏幕上没有流星时自动产生新的流星
voidmain()
{
charscreen[24][80],sky[24][80],letter[10];
inti,a=0;
intexist[10],lie[10],heng[10],color[10],speed[10];
charground[9][80]={"╭⌒╮○ ","╭╭⌒╮●╭○╮ ","╰----╯/█∨█\\ ","~~~~~~~~~~∏~~∏~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"};
load(sky,ground,heng,lie);
srand((int)time(0));
combine(screen,sky,ground);
output(screen,lie,color);
for(;;)
{
make(screen,sky,letter,lie,heng,color,speed,exist);
for(;;)
{
combine(screen,sky,ground);
output(screen,lie,color);
for(i=0;i<80;i++)
if(ground[8][i]=='')
{
end();
getchar();
}
Sleep(50);
fall(screen,sky,speed,ground,exist,heng,lie);
if(exist_or(sky)==0)break;
}
}
}
voidload(charsky[24][80],charground[9][80],intheng[10],intlie[10])
{
inti1,i2;
for(i1=0;i1<24;i1++)
for(i2=0;i2<80;i2++)
sky[i1][i2]='';
for(i1=4;i1<9;i1++)
for(i2=0;i2<80;i2++)
ground[i1][i2]='#';
for(i1=0;i1<10;i1++)
{
heng[i1]=0;
lie[i1]=i1;
}
}
voidoutput(charscreen[24][80],intlie[10],intcolor[10])//输出screen数组
{
inti1,i2,i3=0;
gotoxy(0,0);
for(i1=0;i1<24;i1++)
{
i3=0;
for(i2=0;i2<80;i2++)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY);//将背景设定为白色
if(i2==lie[i3])
{
if(screen[i1][i2]>='A'&&screen[i1][i2]<='Z')
switch(color[i3])
{
case0:
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED);break;
case1:
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN);break;
case2:
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_BLUE);break;
}
i3+=1;
}
printf("%c",screen[i1][i2]);
}
}
}
voidmake(charscreen[24][80],charsky[24][80],charletter[10],intlie[10],intheng[10],intcolor[10],intspeed[10],intexist[10])
{
inti1,i2,t,change,base=1;
for(i1=0;i1<10;i1++)
{
heng[i1]=0;
letter[i1]=(abs(rand())%26+65);//随机产生一个字母作为流星
color[i1]=abs(rand())%3;
while
(1)
{
base=0;
t=(abs(rand())%80);
for(i2=0;i2<10;i2++)
if(t==lie[i2])base=1;
if(base==0)break;
}
lie[i1]=t;
speed[i1]=(abs(rand())%3)+1;
sky[0][lie[i1]]=letter[i1];
exist[i1]=1;
}
for(i1=0;i1<10;i1++)
for(i2=0;i2<9;i2++)
{
if(lie[i2]>lie[i2+1])
{
change=lie[i2];
lie[i2]=lie[i2+1];
lie[i2+1]=change;
}
}//流星列冒泡排序
}
voidfall(charscreen[24][80],charsky[24][80],intspeed[10],charground[9][80],intexist[10],intheng[10],intlie[10])
{
inti1,i2;
for(i1=0;i1<10;i1++)
{
if(exist[i1]==1)
{
for(i2=1;i2<=speed[i1];i2++)
{
sky[heng[i1]+1][lie[i1]]=sky[heng[i1]][lie[i1]];
sky[heng[i1]][lie[i1]]='';
heng[i1]+=1;
if(heng[i1]>=20)
{
if(ground[heng[i1]-20][lie[i1]]=='#')
{
sky[heng[i1]][lie[i1]]='';
ground[heng[i1]-20][lie[i1]]='';
exist[i1]=0;
break;
}
}
}
}
}
}
intexist_or(charsky[24][80])//判断是否还有流星,如果没有就开始新的make函数
{
inti1,i2,t=0;
for(i1=0;i1<25;i1++)
for(i2=0;i2<80;i2++)
{
if(sky[i1][i2]!
='')
{
t=1;
break;
}
}
returnt;
}
voidcombine(charscreen[24][80],charsky[24][80],charground[9][80])//将流行数组与地面数组整合到out数组中
{
inti1,i2;
for(i1=0;i1<24;i1++)
for(i2=0;i2<80;i2++)
screen[i1][i2]=sky[i1][i2];
for(i1=16;i1<19;i1++)
for(i2=0;i2<18;i2++)
screen[i1][i2]=ground[i1-16][i2];
for(i1=19;i1<24;i1++)
for(i2=0;i2<80;i2++)
screen[i1][i2]=ground[i1-16][i2];
}
voidend()
{
system("cls");
printf("\n\n\n\n\t\t\t************\n");
printf("\t\t\t********************\n");
printf("\t\t\t**************************\n");
printf("\t\t\t*****************************\n");
printf("\t\t\t*****************************\n");
printf("\t\t\t*****************************\n");
printf("\t\t\t***************************\n");
printf("\t\t\t***********************\n");
printf("\t\t\t*******************\n");
printf("\t\t\t***************\n");
printf("\t\t\t***********\n");
printf("\t\t\t*******\n");
printf("\t\t\t***\n");
printf("\t\t\t*\n");
printf("\n\t\tthanksforwatching,haveagoodtime!
\n");
}
voidgotoxy(intx,inty)
{
COORDcoord;
coord.X=x;
coord.Y=y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);
}