电梯调度系统编程
1、编程题目
电梯调度。
2、结对编程组员
黄冠译,刘畅。
3、编程语言
C语言图形库。
4、题目要求:
5、代码运行及结果调试:
① 运行界面为C++图形库支持,开始运行的初始界面如图,且默认所有电梯初始状态都为1楼,此时不分奇偶层:
② 我设置了鼠标响应事件,左边上下箭头为当前楼层有人要上或下的按钮,可以用鼠标直接点击响应,点击后要输入有多少人在此楼层等待,示例点击5楼,输入15人,如图所示:
③ 输入完毕后,电梯会根据单双层或全部楼层4个电梯的忙碌状态调度一个电梯过去,第一个调度1号电梯,因为1号电梯只能容纳10人,剩余5人还在等待,此时会再调度另一个电 梯过去接人,优先调度全部楼层的,所以调度4号电梯,如图所示:
④ 当两个电梯都接完人后,右侧电梯状态的1号和4号显示如图,1号10人,满状态,4号5人:
⑤ 1号和4号电梯此时可以点击右侧电梯内部按钮,若有人在电梯内才可以点击,否则无法点击,我们对1号电梯选择12楼,此时会出现输入12楼下电梯的人数,我们输入4人,电 梯就会到12楼去送人,如图所示:
⑥ 1号电梯送完人后的状态如图,我们将1号和4号电梯人全部送到,1号到19楼送6人,4号到20楼送4人,地下室送1人,如图所示:
⑦ 电梯的大致功能如此,最后实现所有电梯一起运转,如图所示:
6、总结
这次的编程用C语言图形库,界面不是现成的,而是需要自己画的,就画这个界面就花了大约一星期的时间,虽然麻烦,但是一个程序如果有一个好的界面用起来还是比较舒服的,所以再苦也值得了。代码不多,一共才500行不到,功能都实现了,主要用结构体来存储每个电梯和楼层的状态,再用图形学的画图函数,通过刷新率来统一绘制,相当于在统一的频率下更新状态并绘制图形。大致的思路是这样的,代码完完全全是我们自己编写,没有参考任何资料。
电梯调度基本算法:
所用的调度算法与大家的大同小异,基本都是判断距离。如果有人按楼层上或下,则先判断4个电梯是否在此楼层停留筛选出一部分电梯,其次判断电梯上或下,是否与要乘坐电梯的人方向相同,筛选出一部分电梯,最后剩下的电梯如果大于1部,则判断电梯距离此楼层的距离,选出一部电梯进行调动。
7、easyx图形库下载及exe文件博客内地址下载:
要运行源码需要easyx图形库,点击安装到VC或VS目录即可:http://files.cnblogs.com/files/hgcrown/EasyX%E5%9B%BE%E5%BD%A2%E5%BA%93.zip
http://files.cnblogs.com/files/hgcrown/%E7%94%B5%E6%A2%AF%E8%B0%83%E5%BA%A6%E7%B3%BB%E7%BB%9F.zip
8、源代码
# include <stdio.h>
# include <graphics.h>
# include <conio.h>
# include <time.h>
# include <memory.h> int x[] = {,,,},k[]={,,,},t[]={,,,},di[]={,,,};
int cro,col;
char s[];
int refresh_rate = ; //刷新率定义大小
MOUSEMSG M;
IMAGE ima,ima1,ima2,back,block; struct elevator //定义4个电梯结构体数组
{
int num,msum,dir,flo,mflo,numm,summ,elein[],eleof[],peom[];
}ele[]={{,,,,,,},{,,,,,,},{,,,,,,},{,,,,,,}}; struct floors //定义21个楼层结构体数组
{
int num[],go,emin;
}floor[]; void Draw1(int e) //电梯接人路线绘制函数
{
if(t[e]==) //如果电梯没有到达目的楼层,则继续绘制路线
{
if (ele[e].dir==) //电梯上楼绘制
{
putimage(+e*,(-ele[e].flo)*-k[e],&ima);
k[e]++;
if (k[e]==)
{
ele[e].flo++;
k[e]=;
}
}
if (ele[e].dir==) //电梯下楼绘制
{
putimage(+e*,(-ele[e].flo)*+k[e],&ima);
k[e]++;
if (k[e]==)
{
ele[e].flo--;
k[e]=;
}
}
if (ele[e].dir==) //电梯停歇状态绘制
putimage(+e*,(-ele[e].flo)*,&ima);
if ((ele[e].flo==ele[e].mflo)&&(ele[e].dir!=)) //电梯到达目的楼层后的数值重新赋值
{
int h;
ele[e].dir=;
floor[ele[e].flo].emin=;
t[e]=;
k[e]=;
while (floor[ele[e].mflo].num[]!=) //接人后电梯内部状态赋值
{
h=rand()%+;
if ((ele[e].num+<=ele[e].numm)&&(ele[e].msum+h<=ele[e].summ))
{
ele[e].num++;
ele[e].peom[ele[e].num-]=h;
ele[e].msum=ele[e].msum+h;
floor[ele[e].flo].num[]--;
}
else
break;
}
while (floor[ele[e].mflo].num[]!=)
{
h=rand()%+;
if ((ele[e].num+<=ele[e].numm)&&(ele[e].msum+h<=ele[e].summ))
{
ele[e].num++;
ele[e].peom[ele[e].num-]=h;
ele[e].msum=ele[e].msum+h;
floor[ele[e].flo].num[]--;
}
else
break;
}
}
}
if (t[e]!=) //如果电梯到达目的楼层,则绘制电梯开门关门状态
{
if (t[e]>) //开门
{
putimage(+e*-+t[e]+,(-ele[e].flo)*,&ima1);
putimage(+e*+-t[e]+,(-ele[e].flo)*,&ima2);
t[e]--;
}
else if (t[e]>)
{
putimage(+e*-+,(-ele[e].flo)*,&ima1);
putimage(+e*++,(-ele[e].flo)*,&ima2);
t[e]--;
}
else if (t[e]>) //关门
{
putimage(+e*-t[e]+,(-ele[e].flo)*,&ima1);
putimage(+e*+t[e]+,(-ele[e].flo)*,&ima2);
t[e]--;
}
}
} void Draw2(int e) //电梯接人结束后,进入送客绘制模式
{
for (int v=;v<=;v++) //电梯内部按钮绘制
{
if ((v==)&&(ele[e].elein[v]==))
putimage(+%*,+/*19.3+e*,&block);
else if (ele[e].elein[v]==)
putimage(+(v-)%*,+(v-)/*+e*,&block);
}
if(t[e]==) //如果电梯没有到达目的楼层,则继续绘制路线
{
if (ele[e].dir==) //电梯上楼绘制
{
putimage(+e*,(-ele[e].flo)*-k[e],&ima);
k[e]++;
if (k[e]==)
{
ele[e].flo++;
k[e]=;
}
}
if (ele[e].dir==) //电梯下楼绘制
{
putimage(+e*,(-ele[e].flo)*+k[e],&ima);
k[e]++;
if (k[e]==)
{
ele[e].flo--;
k[e]=;
}
}
if (ele[e].flo==ele[e].mflo) //到达目的楼层后绘制
{
ele[e].elein[ele[e].flo]=;
di[e]=;
for (int v=;v<=;v++)
if (ele[e].elein[v]==)
di[e]=;
k[e]=;
ele[e].dir=;
while(ele[e].eleof[ele[e].flo]!=) //电梯下人操作,重新赋值
{
ele[e].num--;
ele[e].msum=ele[e].msum-ele[e].peom[ele[e].num];
ele[e].eleof[ele[e].flo]--;
if (ele[e].num==)
break;
}
t[e]=;
}
}
if (t[e]!=) //如果电梯到达目的楼层,则绘制电梯开门关门状态
{
if (t[e]>) //开门
{
putimage(+e*-+t[e]+,(-ele[e].flo)*,&ima1);
putimage(+e*+-t[e]+,(-ele[e].flo)*,&ima2);
t[e]--;
}
else if (t[e]>)
{
putimage(+e*-+,(-ele[e].flo)*,&ima1);
putimage(+e*++,(-ele[e].flo)*,&ima2);
t[e]--;
}
else if (t[e]>) //关门
{
putimage(+e*-t[e]+,(-ele[e].flo)*,&ima1);
putimage(+e*+t[e]+,(-ele[e].flo)*,&ima2);
t[e]--;
}
}
} void run () //电梯运行总调度函数
{
int o,p,mine;
setcolor(BLACK);
while() //电梯运行状态循环
{
if(MouseHit()) //如果触发鼠标时间
{
M = GetMouseMsg(); //鼠标事件获取
if (M.uMsg == WM_LBUTTONDOWN) //如果鼠标左键单击
{
if (M.x>=&&M.x<=) //判断鼠标指针所在范围是否上楼
{
o=-(M.y+)/;
InputBox(s, , "请输入进电梯的人数"); //弹窗响应,要求输入
sscanf(s,"%d",&p);
floor[o].num[]=p;
}
if (M.x>=&&M.x<=) //判断鼠标指针所在范围是否下楼
{
o=-(M.y+)/;
InputBox(s, , "请输入进电梯的人数"); //弹窗响应,要求输入
sscanf(s,"%d",&p);
floor[o].num[]=p;
}
if ((ele[].num!=)&&(M.x>=&&M.x<=&&M.y>=&&M.y<=)) //判断电梯内部按钮是否由鼠标响应
{
int r;
cro=(M.x-)/;
col=(M.y-)/;
r=cro+col*+;
if (r==)
r=;
di[]=;
ele[].mflo=r;
ele[].elein[ele[].mflo]=;
InputBox(s, , "请输入此楼层要下电梯的人数"); //弹窗响应,要求输入
sscanf(s,"%d",&p);
ele[].eleof[ele[].mflo]=p;
}
if ((ele[].num!=)&&(M.x>=&&M.x<=&&M.y>=&&M.y<=)) //判断电梯内部按钮是否由鼠标响应
{
int r;
cro=(M.x-)/;
col=(M.y-)/;
r=cro+col*+;
if (r==)
r=;
if (r%==)
{
di[]=;
ele[].mflo=r;
ele[].elein[ele[].mflo]=;
InputBox(s, , "请输入此楼层要下电梯的人数"); //弹窗响应,要求输入
sscanf(s,"%d",&p);
ele[].eleof[ele[].mflo]=p;
}
}
if ((ele[].num!=)&&(M.x>=&&M.x<=&&M.y>=&&M.y<=)) //判断电梯内部按钮是否由鼠标响应
{
int r;
cro=(M.x-)/;
col=(M.y-)/;
r=cro+col*+;
if (r==)
r=;
if (r%==)
{
di[]=;
ele[].mflo=r;
ele[].elein[ele[].mflo]=;
InputBox(s, , "请输入此楼层要下电梯的人数"); //弹窗响应,要求输入
sscanf(s,"%d",&p);
ele[].eleof[ele[].mflo]=p;
}
}
if ((ele[].num!=)&&(M.x>=&&M.x<=&&M.y>=&&M.y<=)) //判断电梯内部按钮是否由鼠标响应
{
int r;
cro=(M.x-)/;
col=(M.y-)/;
r=cro+col*+;
if (r==)
r=;
di[]=;
ele[].mflo=r;
ele[].elein[ele[].mflo]=;
InputBox(s, , "请输入此楼层要下电梯的人数"); //弹窗响应,要求输入
sscanf(s,"%d",&p);
ele[].eleof[ele[].mflo]=p;
}
}
}
for(int j=;j>=;j--) //每个楼层开始判断是否有客人要上电梯的响应
{
mine=;
if (floor[j].num[]!=) //有上电梯响应且客人要上楼,开始电梯调度
{
if ((ele[].num<)&&(ele[].msum<)) //1号电梯条件是否满足
{
if ((j>=ele[].flo)&&(ele[].dir!=))
if (floor[j].emin>(j-ele[].flo))
{
floor[j].emin=j-ele[].flo;
mine=;
}
if ((j<ele[].flo)&&(ele[].dir==))
if (floor[j].emin>(ele[].flo-j))
{
floor[j].emin=ele[].flo-j;
mine=;
}
}
if ((ele[].num<)&&(ele[].msum<)) //4号电梯条件是否满足
{
if ((j>=ele[].flo)&&(ele[].dir!=))
if (floor[j].emin>(j-ele[].flo))
{
floor[j].emin=j-ele[].flo;
mine=;
}
if ((j<ele[].flo)&&(ele[].dir==))
if (floor[j].emin>(ele[].flo-j))
{
floor[j].emin=ele[].flo-j;
mine=;
}
}
if (j%==)
{
if ((ele[].num<)&&(ele[].msum<)) //3号电梯条件是否满足
{
if ((j>=ele[].flo)&&(ele[].dir!=))
if (floor[j].emin>(j-ele[].flo))
{
floor[j].emin=j-ele[].flo;
mine=;
}
if ((j<ele[].flo)&&(ele[].dir==))
if (floor[j].emin>(ele[].flo-j))
{
floor[j].emin=ele[].flo-j;
mine=;
}
}
}
if (j%==) //2号电梯条件是否满足
{
if ((ele[].num<)&&(ele[].msum<))
{
if ((j>=ele[].flo)&&(ele[].dir!=))
if (floor[j].emin>(j-ele[].flo))
{
floor[j].emin=j-ele[].flo;
mine=;
}
if ((j<ele[].flo)&&(ele[].dir==))
if (floor[j].emin>(ele[].flo-j))
{
floor[j].emin=ele[].flo-j;
mine=;
}
}
}
if (j>=ele[mine].flo) //用距离判断满足条件的电梯,在此筛选出满足条件电梯
ele[mine].dir=;
else
ele[mine].dir=; //满足条件的电梯设置目的楼层
ele[mine].mflo=j;
}
if (floor[j].num[]!=) //有上电梯响应且客人要下楼,开始电梯调度
{
if ((ele[].num<)&&(ele[].msum<))
{
if ((j<=ele[].flo)&&(ele[].dir!=))
if (floor[j].emin>(ele[].flo-j))
{
floor[j].emin=ele[].flo-j;
mine=;
}
if ((j>ele[].flo)&&(ele[].dir==))
if (floor[j].emin>(j-ele[].flo))
{
floor[j].emin=j-ele[].flo;
mine=;
}
}
if ((ele[].num<)&&(ele[].msum<))
{
if ((j<=ele[].flo)&&(ele[].dir!=))
if (floor[j].emin>(ele[].flo-j))
{
floor[j].emin=ele[].flo-j;
mine=;
}
if ((j>ele[].flo)&&(ele[].dir==))
if (floor[j].emin>(j-ele[].flo))
{
floor[j].emin=j-ele[].flo;
mine=;
}
}
if (j%==)
{
if ((ele[].num<)&&(ele[].msum<))
{
if ((j<=ele[].flo)&&(ele[].dir!=))
if (floor[j].emin>(ele[].flo-j))
{
floor[j].emin=ele[].flo-j;
mine=;
}
if ((j>ele[].flo)&&(ele[].dir==))
if (floor[j].emin>(j-ele[].flo))
{
floor[j].emin=j-ele[].flo;
mine=;
}
}
}
if (j%==)
{
if ((ele[].num<)&&(ele[].msum<))
{
if ((j<=ele[].flo)&&(ele[].dir!=))
if (floor[j].emin>(ele[].flo-j))
{
floor[j].emin=ele[].flo-j;
mine=;
}
if ((j>ele[].flo)&&(ele[].dir==))
if (floor[j].emin>(j-ele[].flo))
{
floor[j].emin=j-ele[].flo;
mine=;
}
}
}
if (j>=ele[mine].flo)
ele[mine].dir=;
else
ele[mine].dir=;
ele[mine].mflo=j;
}
}
BeginBatchDraw(); //开始画图
putimage(,,&back);
for (int i=;i<;i++) //四个电梯一次绘制当前状态
{
if (di[i]==) //接客的电梯绘制
Draw1(i);
if (di[i]==) //送客的电梯绘制
{
if (ele[i].mflo>=ele[i].flo) //上楼绘制
{
ele[i].dir=;
for (int w=ele[i].flo;w<=;w++)
{
if (ele[i].elein[w]==)
{
ele[i].mflo=w;
break;
}
}
}
else //下楼绘制
{
ele[i].dir=;
for (int w=ele[i].flo;w>=;w--)
{
if (ele[i].elein[w]==)
{
ele[i].mflo=w;
break;
}
}
}
Draw2(i);
}
setbkmode(TRANSPARENT); //输出电梯当前状态数值
sprintf(s,"%d",ele[i].num); //电梯当前人数
outtextxy(,+i*,s);
sprintf(s,"%d",ele[i].msum); //电梯当前重量
outtextxy(,+i*,s);
sprintf(s,"%d",ele[i].flo); //电梯当前楼层
outtextxy(,+i*,s);
}
EndBatchDraw(); //结束绘制
Sleep(refresh_rate); //延时绘制,否则会本次绘制会遮挡下一次绘制
} } void main() //主函数
{
for (int i=;i<;i++) //初始化
{
floor[i].num[]=;
floor[i].num[]=;
floor[i].emin=;
}
initgraph(,); //构建窗口大小
loadimage(&back,"pic//2.jpg"); //载入图片2
putimage(,,&back);
loadimage(&ima,"pic//1.jpg"); //载入图片1
loadimage(&ima1,"pic//3.jpg"); //载入图片3
loadimage(&ima2,"pic//4.jpg"); //载入图片4
loadimage(&block,"pic//5.jpg"); //载入图片5
BeginBatchDraw(); //初始化绘制
for (int j=;j<;j++)
putimage(+j*,(-ele[j].flo)* ,&ima);
EndBatchDraw(); //结束绘制
run(); //进入电梯调度函数开始电梯总调度
closegraph(); //关闭窗口
}