电梯调度系统编程
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、源代码
1 # include <stdio.h> 2 # include <graphics.h> 3 # include <conio.h> 4 # include <time.h> 5 # include <memory.h> 6 7 int x[4] = {570,570,570,570},k[4]={0,0,0,0},t[4]={0,0,0,0},di[4]={0,0,0,0}; 8 int cro,col; 9 char s[10]; 10 int refresh_rate = 10; //刷新率定义大小 11 MOUSEMSG M; 12 IMAGE ima,ima1,ima2,back,block; 13 14 struct elevator //定义4个电梯结构体数组 15 { 16 int num,msum,dir,flo,mflo,numm,summ,elein[21],eleof[21],peom[21]; 17 }ele[5]={{0,0,2,1,1,10,800},{0,0,2,1,1,10,800},{0,0,2,1,1,20,1600},{0,0,2,1,1,20,2000}}; 18 19 struct floors //定义21个楼层结构体数组 20 { 21 int num[3],go,emin; 22 }floor[21]; 23 24 void Draw1(int e) //电梯接人路线绘制函数 25 { 26 if(t[e]==0) //如果电梯没有到达目的楼层,则继续绘制路线 27 { 28 if (ele[e].dir==0) //电梯上楼绘制 29 { 30 putimage(140+e*100,(20-ele[e].flo)*30-k[e],&ima); 31 k[e]++; 32 if (k[e]==30) 33 { 34 ele[e].flo++; 35 k[e]=0; 36 } 37 } 38 if (ele[e].dir==1) //电梯下楼绘制 39 { 40 putimage(140+e*100,(20-ele[e].flo)*30+k[e],&ima); 41 k[e]++; 42 if (k[e]==30) 43 { 44 ele[e].flo--; 45 k[e]=0; 46 } 47 } 48 if (ele[e].dir==2) //电梯停歇状态绘制 49 putimage(140+e*100,(20-ele[e].flo)*30,&ima); 50 if ((ele[e].flo==ele[e].mflo)&&(ele[e].dir!=2)) //电梯到达目的楼层后的数值重新赋值 51 { 52 int h; 53 ele[e].dir=2; 54 floor[ele[e].flo].emin=22; 55 t[e]=60; 56 k[e]=0; 57 while (floor[ele[e].mflo].num[0]!=0) //接人后电梯内部状态赋值 58 { 59 h=rand()%41+50; 60 if ((ele[e].num+1<=ele[e].numm)&&(ele[e].msum+h<=ele[e].summ)) 61 { 62 ele[e].num++; 63 ele[e].peom[ele[e].num-1]=h; 64 ele[e].msum=ele[e].msum+h; 65 floor[ele[e].flo].num[0]--; 66 } 67 else 68 break; 69 } 70 while (floor[ele[e].mflo].num[1]!=0) 71 { 72 h=rand()%41+50; 73 if ((ele[e].num+1<=ele[e].numm)&&(ele[e].msum+h<=ele[e].summ)) 74 { 75 ele[e].num++; 76 ele[e].peom[ele[e].num-1]=h; 77 ele[e].msum=ele[e].msum+h; 78 floor[ele[e].flo].num[1]--; 79 } 80 else 81 break; 82 } 83 } 84 } 85 if (t[e]!=0) //如果电梯到达目的楼层,则绘制电梯开门关门状态 86 { 87 if (t[e]>50) //开门 88 { 89 putimage(140+e*100-60+t[e]+5,(20-ele[e].flo)*30,&ima1); 90 putimage(140+e*100+60-t[e]+5,(20-ele[e].flo)*30,&ima2); 91 t[e]--; 92 } 93 else if (t[e]>10) 94 { 95 putimage(140+e*100-10+5,(20-ele[e].flo)*30,&ima1); 96 putimage(140+e*100+11+5,(20-ele[e].flo)*30,&ima2); 97 t[e]--; 98 } 99 else if (t[e]>0) //关门 100 { 101 putimage(140+e*100-t[e]+5,(20-ele[e].flo)*30,&ima1); 102 putimage(140+e*100+t[e]+5,(20-ele[e].flo)*30,&ima2); 103 t[e]--; 104 } 105 } 106 } 107 108 void Draw2(int e) //电梯接人结束后,进入送客绘制模式 109 { 110 for (int v=0;v<=20;v++) //电梯内部按钮绘制 111 { 112 if ((v==0)&&(ele[e].elein[v]==1)) 113 putimage(528+20%5*55,47+20/5*19.3+e*150,&block); 114 else if (ele[e].elein[v]==1) 115 putimage(528+(v-1)%5*55,47+(v-1)/5*19+e*150,&block); 116 } 117 if(t[e]==0) //如果电梯没有到达目的楼层,则继续绘制路线 118 { 119 if (ele[e].dir==0) //电梯上楼绘制 120 { 121 putimage(140+e*100,(20-ele[e].flo)*30-k[e],&ima); 122 k[e]++; 123 if (k[e]==30) 124 { 125 ele[e].flo++; 126 k[e]=0; 127 } 128 } 129 if (ele[e].dir==1) //电梯下楼绘制 130 { 131 putimage(140+e*100,(20-ele[e].flo)*30+k[e],&ima); 132 k[e]++; 133 if (k[e]==30) 134 { 135 ele[e].flo--; 136 k[e]=0; 137 } 138 } 139 if (ele[e].flo==ele[e].mflo) //到达目的楼层后绘制 140 { 141 ele[e].elein[ele[e].flo]=0; 142 di[e]=0; 143 for (int v=0;v<=20;v++) 144 if (ele[e].elein[v]==1) 145 di[e]=1; 146 k[e]=0; 147 ele[e].dir=2; 148 while(ele[e].eleof[ele[e].flo]!=0) //电梯下人操作,重新赋值 149 { 150 ele[e].num--; 151 ele[e].msum=ele[e].msum-ele[e].peom[ele[e].num]; 152 ele[e].eleof[ele[e].flo]--; 153 if (ele[e].num==0) 154 break; 155 } 156 t[e]=60; 157 } 158 } 159 if (t[e]!=0) //如果电梯到达目的楼层,则绘制电梯开门关门状态 160 { 161 if (t[e]>50) //开门 162 { 163 putimage(140+e*100-60+t[e]+5,(20-ele[e].flo)*30,&ima1); 164 putimage(140+e*100+60-t[e]+5,(20-ele[e].flo)*30,&ima2); 165 t[e]--; 166 } 167 else if (t[e]>10) 168 { 169 putimage(140+e*100-10+5,(20-ele[e].flo)*30,&ima1); 170 putimage(140+e*100+10+5,(20-ele[e].flo)*30,&ima2); 171 t[e]--; 172 } 173 else if (t[e]>0) //关门 174 { 175 putimage(140+e*100-t[e]+5,(20-ele[e].flo)*30,&ima1); 176 putimage(140+e*100+t[e]+5,(20-ele[e].flo)*30,&ima2); 177 t[e]--; 178 } 179 } 180 } 181 182 void run () //电梯运行总调度函数 183 { 184 int o,p,mine; 185 setcolor(BLACK); 186 while(1) //电梯运行状态循环 187 { 188 if(MouseHit()) //如果触发鼠标时间 189 { 190 M = GetMouseMsg(); //鼠标事件获取 191 if (M.uMsg == WM_LBUTTONDOWN) //如果鼠标左键单击 192 { 193 if (M.x>=5&&M.x<=24) //判断鼠标指针所在范围是否上楼 194 { 195 o=20-(M.y+1)/30; 196 InputBox(s, 10, "请输入进电梯的人数"); //弹窗响应,要求输入 197 sscanf(s,"%d",&p); 198 floor[o].num[0]=p; 199 } 200 if (M.x>=25&&M.x<=45) //判断鼠标指针所在范围是否下楼 201 { 202 o=20-(M.y+1)/30; 203 InputBox(s, 10, "请输入进电梯的人数"); //弹窗响应,要求输入 204 sscanf(s,"%d",&p); 205 floor[o].num[1]=p; 206 } 207 if ((ele[0].num!=0)&&(M.x>=527&&M.x<=801&&M.y>=46&&M.y<=142)) //判断电梯内部按钮是否由鼠标响应 208 { 209 int r; 210 cro=(M.x-528)/55; 211 col=(M.y-46)/20; 212 r=cro+col*5+1; 213 if (r==21) 214 r=0; 215 di[0]=1; 216 ele[0].mflo=r; 217 ele[0].elein[ele[0].mflo]=1; 218 InputBox(s, 10, "请输入此楼层要下电梯的人数"); //弹窗响应,要求输入 219 sscanf(s,"%d",&p); 220 ele[0].eleof[ele[0].mflo]=p; 221 } 222 if ((ele[1].num!=0)&&(M.x>=527&&M.x<=801&&M.y>=196&&M.y<=292)) //判断电梯内部按钮是否由鼠标响应 223 { 224 int r; 225 cro=(M.x-528)/55; 226 col=(M.y-197)/20; 227 r=cro+col*5+1; 228 if (r==21) 229 r=0; 230 if (r%2==1) 231 { 232 di[1]=1; 233 ele[1].mflo=r; 234 ele[1].elein[ele[1].mflo]=1; 235 InputBox(s, 10, "请输入此楼层要下电梯的人数"); //弹窗响应,要求输入 236 sscanf(s,"%d",&p); 237 ele[1].eleof[ele[1].mflo]=p; 238 } 239 } 240 if ((ele[2].num!=0)&&(M.x>=527&&M.x<=801&&M.y>=346&&M.y<=442)) //判断电梯内部按钮是否由鼠标响应 241 { 242 int r; 243 cro=(M.x-528)/55; 244 col=(M.y-346)/20; 245 r=cro+col*5+1; 246 if (r==21) 247 r=0; 248 if (r%2==0) 249 { 250 di[2]=1; 251 ele[2].mflo=r; 252 ele[2].elein[ele[2].mflo]=1; 253 InputBox(s, 10, "请输入此楼层要下电梯的人数"); //弹窗响应,要求输入 254 sscanf(s,"%d",&p); 255 ele[2].eleof[ele[2].mflo]=p; 256 } 257 } 258 if ((ele[3].num!=0)&&(M.x>=527&&M.x<=801&&M.y>=496&&M.y<=592)) //判断电梯内部按钮是否由鼠标响应 259 { 260 int r; 261 cro=(M.x-528)/55; 262 col=(M.y-496)/20; 263 r=cro+col*5+1; 264 if (r==21) 265 r=0; 266 di[3]=1; 267 ele[3].mflo=r; 268 ele[3].elein[ele[3].mflo]=1; 269 InputBox(s, 10, "请输入此楼层要下电梯的人数"); //弹窗响应,要求输入 270 sscanf(s,"%d",&p); 271 ele[3].eleof[ele[3].mflo]=p; 272 } 273 } 274 } 275 for(int j=20;j>=0;j--) //每个楼层开始判断是否有客人要上电梯的响应 276 { 277 mine=4; 278 if (floor[j].num[0]!=0) //有上电梯响应且客人要上楼,开始电梯调度 279 { 280 if ((ele[0].num<10)&&(ele[0].msum<800)) //1号电梯条件是否满足 281 { 282 if ((j>=ele[0].flo)&&(ele[0].dir!=1)) 283 if (floor[j].emin>(j-ele[0].flo)) 284 { 285 floor[j].emin=j-ele[0].flo; 286 mine=0; 287 } 288 if ((j<ele[0].flo)&&(ele[0].dir==2)) 289 if (floor[j].emin>(ele[0].flo-j)) 290 { 291 floor[j].emin=ele[0].flo-j; 292 mine=0; 293 } 294 } 295 if ((ele[3].num<20)&&(ele[3].msum<2000)) //4号电梯条件是否满足 296 { 297 if ((j>=ele[3].flo)&&(ele[3].dir!=1)) 298 if (floor[j].emin>(j-ele[3].flo)) 299 { 300 floor[j].emin=j-ele[3].flo; 301 mine=3; 302 } 303 if ((j<ele[3].flo)&&(ele[3].dir==2)) 304 if (floor[j].emin>(ele[3].flo-j)) 305 { 306 floor[j].emin=ele[3].flo-j; 307 mine=3; 308 } 309 } 310 if (j%2==0) 311 { 312 if ((ele[2].num<20)&&(ele[2].msum<1600)) //3号电梯条件是否满足 313 { 314 if ((j>=ele[2].flo)&&(ele[2].dir!=1)) 315 if (floor[j].emin>(j-ele[2].flo)) 316 { 317 floor[j].emin=j-ele[2].flo; 318 mine=2; 319 } 320 if ((j<ele[2].flo)&&(ele[2].dir==2)) 321 if (floor[j].emin>(ele[2].flo-j)) 322 { 323 floor[j].emin=ele[2].flo-j; 324 mine=2; 325 } 326 } 327 } 328 if (j%2==1) //2号电梯条件是否满足 329 { 330 if ((ele[1].num<10)&&(ele[1].msum<800)) 331 { 332 if ((j>=ele[1].flo)&&(ele[1].dir!=1)) 333 if (floor[j].emin>(j-ele[1].flo)) 334 { 335 floor[j].emin=j-ele[1].flo; 336 mine=1; 337 } 338 if ((j<ele[1].flo)&&(ele[1].dir==2)) 339 if (floor[j].emin>(ele[1].flo-j)) 340 { 341 floor[j].emin=ele[1].flo-j; 342 mine=1; 343 } 344 } 345 } 346 if (j>=ele[mine].flo) //用距离判断满足条件的电梯,在此筛选出满足条件电梯 347 ele[mine].dir=0; 348 else 349 ele[mine].dir=1; //满足条件的电梯设置目的楼层 350 ele[mine].mflo=j; 351 } 352 if (floor[j].num[1]!=0) //有上电梯响应且客人要下楼,开始电梯调度 353 { 354 if ((ele[0].num<10)&&(ele[0].msum<800)) 355 { 356 if ((j<=ele[0].flo)&&(ele[0].dir!=1)) 357 if (floor[j].emin>(ele[0].flo-j)) 358 { 359 floor[j].emin=ele[0].flo-j; 360 mine=0; 361 } 362 if ((j>ele[0].flo)&&(ele[0].dir==2)) 363 if (floor[j].emin>(j-ele[0].flo)) 364 { 365 floor[j].emin=j-ele[0].flo; 366 mine=0; 367 } 368 } 369 if ((ele[3].num<20)&&(ele[3].msum<2000)) 370 { 371 if ((j<=ele[3].flo)&&(ele[3].dir!=1)) 372 if (floor[j].emin>(ele[3].flo-j)) 373 { 374 floor[j].emin=ele[3].flo-j; 375 mine=3; 376 } 377 if ((j>ele[3].flo)&&(ele[3].dir==2)) 378 if (floor[j].emin>(j-ele[3].flo)) 379 { 380 floor[j].emin=j-ele[3].flo; 381 mine=3; 382 } 383 } 384 if (j%2==0) 385 { 386 if ((ele[2].num<20)&&(ele[2].msum<1600)) 387 { 388 if ((j<=ele[2].flo)&&(ele[2].dir!=1)) 389 if (floor[j].emin>(ele[2].flo-j)) 390 { 391 floor[j].emin=ele[2].flo-j; 392 mine=2; 393 } 394 if ((j>ele[2].flo)&&(ele[2].dir==2)) 395 if (floor[j].emin>(j-ele[2].flo)) 396 { 397 floor[j].emin=j-ele[2].flo; 398 mine=2; 399 } 400 } 401 } 402 if (j%2==1) 403 { 404 if ((ele[1].num<10)&&(ele[1].msum<800)) 405 { 406 if ((j<=ele[1].flo)&&(ele[1].dir!=1)) 407 if (floor[j].emin>(ele[1].flo-j)) 408 { 409 floor[j].emin=ele[1].flo-j; 410 mine=1; 411 } 412 if ((j>ele[1].flo)&&(ele[1].dir==2)) 413 if (floor[j].emin>(j-ele[1].flo)) 414 { 415 floor[j].emin=j-ele[1].flo; 416 mine=1; 417 } 418 } 419 } 420 if (j>=ele[mine].flo) 421 ele[mine].dir=0; 422 else 423 ele[mine].dir=1; 424 ele[mine].mflo=j; 425 } 426 } 427 BeginBatchDraw(); //开始画图 428 putimage(0,0,&back); 429 for (int i=0;i<4;i++) //四个电梯一次绘制当前状态 430 { 431 if (di[i]==0) //接客的电梯绘制 432 Draw1(i); 433 if (di[i]==1) //送客的电梯绘制 434 { 435 if (ele[i].mflo>=ele[i].flo) //上楼绘制 436 { 437 ele[i].dir=0; 438 for (int w=ele[i].flo;w<=20;w++) 439 { 440 if (ele[i].elein[w]==1) 441 { 442 ele[i].mflo=w; 443 break; 444 } 445 } 446 } 447 else //下楼绘制 448 { 449 ele[i].dir=1; 450 for (int w=ele[i].flo;w>=0;w--) 451 { 452 if (ele[i].elein[w]==1) 453 { 454 ele[i].mflo=w; 455 break; 456 } 457 } 458 } 459 Draw2(i); 460 } 461 setbkmode(TRANSPARENT); //输出电梯当前状态数值 462 sprintf(s,"%d",ele[i].num); //电梯当前人数 463 outtextxy(890,49+i*150,s); 464 sprintf(s,"%d",ele[i].msum); //电梯当前重量 465 outtextxy(890,74+i*150,s); 466 sprintf(s,"%d",ele[i].flo); //电梯当前楼层 467 outtextxy(890,99+i*150,s); 468 } 469 EndBatchDraw(); //结束绘制 470 Sleep(refresh_rate); //延时绘制,否则会本次绘制会遮挡下一次绘制 471 } 472 473 } 474 475 void main() //主函数 476 { 477 for (int i=0;i<21;i++) //初始化 478 { 479 floor[i].num[0]=0; 480 floor[i].num[1]=0; 481 floor[i].emin=22; 482 } 483 initgraph(1000,630); //构建窗口大小 484 loadimage(&back,"pic//2.jpg"); //载入图片2 485 putimage(0,0,&back); 486 loadimage(&ima,"pic//1.jpg"); //载入图片1 487 loadimage(&ima1,"pic//3.jpg"); //载入图片3 488 loadimage(&ima2,"pic//4.jpg"); //载入图片4 489 loadimage(&block,"pic//5.jpg"); //载入图片5 490 BeginBatchDraw(); //初始化绘制 491 for (int j=0;j<4;j++) 492 putimage(140+j*100,(20-ele[j].flo)*30 ,&ima); 493 EndBatchDraw(); //结束绘制 494 run(); //进入电梯调度函数开始电梯总调度 495 closegraph(); //关闭窗口 496 }