结对编程项目--电梯调度
从本次开始,我们改变了作业模式,由起初的个人编程到结对编程的过渡,很好的让我们了解和认识别人的编程方法和习惯,同时也避开了以往个人编程中所遇到的诸多问题,让我想起了一句话,“一个人或许可以走的很快,但一定走的不远。”。
接下来我们来回顾一下本次作业的内容及要求:
电梯调度
现有一新建办公大厦,共有21层,共有四部电梯,所有电梯基本参数如下表所示:
电梯编号 |
可服务楼层 |
最大乘客数量 |
最大载重量 |
1 |
全部楼层 |
10 |
800 kg |
2 |
单层 |
10 |
800 kg |
3 |
双层 |
20 |
1600 kg |
4 |
全部楼层 |
20 |
2000 kg |
其使用规定如下:
1、楼层号为0~20,其中0号为地下一层;
2、有楼层限制的电梯不在响应楼层停靠,如单双层;
3、所有电梯采用统一按钮控制
关于本次作业,刚看到的时候觉得各种问题好复杂,但是仔细分析之后思路便明了了,我和我的队友最终决定把问题条形化,分成一个个子问题逐一分析进而用一个个子函数来实现,这样复杂的问题就简单化了。当然这次的编程语言我们选了自我感觉最能解决也是我们比较熟悉的C++,感觉C语言好像不能完全实现诶>.<...
我和我的小伙伴首先简单分析了一下实现的过程。
一、电梯类,电梯类要能实现单双层的判断以及对所要去的电梯进行存储,最初我们打算默认让哪几个电梯跑单层,哪几个电梯跑双层,后来决定采用属性值来标识的做法,其次是电梯的存储,最开始我们用一个int型的数来存储目标楼层,但是测试过程中发现,如果只用一个int型变量的话,当电梯的目标楼层为多个或者需要中途改变的时候电梯会无法实现既定的目标,于是我提出用数组来直接存储多个目标,这样可以满足当多个用户使用电梯的需求。随之改变的是电梯的运行,以前的电梯运行只要判断当前楼层和目标楼层就可以做相应的执行,改变的电梯想要运行需要判断数组是否为空,当数组不为空时判断电梯的运行。电梯类中最难实现的方法应该是将目标楼层添加进数组了,因为情况很多,当时也没有分析明白,导致开发的进度一度毫无进展,经过伙伴的四方求助以及分析,我们最终将各种情况分化,化为一个一个小的情况,接下来的就简单多了,针对每一个小的情况,将目标楼层加入电梯的数组,接下来只要让电梯运行就可以。
1 class Elevator{ 2 private: 3 int id;//电梯号 4 int floor;//电梯当前楼层 5 int max;//最大人数 6 int Pnum;//当前人数 7 int state;//0:全部 1:单层 2:双层 8 int RunState;//0:不动 1:向上 2:向下 9 int Queue[21]; 10 int start = 0, end = 0; 11 int pState, toP;//pState 奇数时进人 偶数时出人 12 public: 13 Elevator(int Enum, int floor, int Pnum, int state,int max);//构造函数 14 int getId(){ return id; }//获取电梯号 15 int getfloor(){ return floor; }//获取当前楼层数 16 int getPnum(){ return Pnum; }//获取人数 17 void Run();//电梯上下行 18 void show();//显示函数 19 void Add(int Pfloor, int Runstate, int tofloor, int Pnum);//根据方向添加进数组 20 int countDistance(int pFloor, int runDirection);//计算电梯与人的距离 21 }; 22 Elevator::Elevator(int id, int floor, int Pnum, int state,int max) :id(id), floor(floor), Pnum(Pnum),state(state),max(max){ 23 RunState = 0; 24 pState = 1; 25 toP = 0; 26 } 27 void Elevator::Run(){ 28 if (end != start)//需要电梯运行的情况 29 { 30 if (floor > Queue[start])//向下 31 { 32 RunState = 2; 33 floor--; 34 35 } 36 if (floor < Queue[start])//向上 37 { 38 39 RunState = 1; 40 floor++; 41 } 42 if (floor == Queue[start])//到达目的地 43 { 44 RunState = 0; 45 start = (start++) % 21;//start指针向后移 46 if (pState % 2 == 0){//出人 47 if (start == end) 48 Pnum = 0; 49 else 50 Pnum = Pnum - abs(rand() % Pnum); 51 pState++; 52 } 53 else{//进人 54 Pnum += toP; 55 if (Pnum > max) 56 { 57 cout << "超重了,需要下" << Pnum - max << "人"; 58 Pnum = max; 59 } 60 pState++; 61 } 62 } 63 } 64 else{ 65 RunState = 0; 66 } 67 68 } 69 void Elevator::Add(int Pfloor, int runDirection, int tofloor,int person){ 70 toP = person; 71 if (end - start < 1)//end指向下一个地址 72 { 73 Queue[(end++) % 21] = Pfloor; 74 Queue[(end++) % 21] = tofloor; 75 76 } 77 else 78 { 79 if (runDirection == 1)//人向上 80 { 81 if (Queue[end - 1]>Queue[end - 2])//电梯向上 82 { 83 if (Queue[end - 1] > Pfloor)//电梯的目标楼层大于人当前的楼层 84 { 85 Queue[end] = Queue[end - 1]; 86 Queue[end - 1] = Pfloor; 87 end = (end++) % 21; 88 } 89 else//小于 90 { 91 Queue[end] = Pfloor; 92 end = (end++) % 21; 93 } 94 if (Queue[end - 1] > tofloor)//队列中的最后一个数大于人的目标楼层时 95 { 96 Queue[end] = Queue[end - 1]; 97 Queue[end - 1] = tofloor; 98 end = (end++) % 21; 99 } 100 else 101 { 102 Queue[end] = tofloor; 103 end = (end++) % 21; 104 } 105 } 106 if (Queue[end - 1]<Queue[end - 2])//电梯向下 107 { 108 if (Queue[end - 1] > Pfloor)//电梯的目标楼层大于人当前的楼层 109 { 110 Queue[end] = Pfloor; 111 end = (end++) % 21; 112 Queue[end] = tofloor; 113 end = (end++) % 21; 114 } 115 } 116 } 117 if (runDirection == 2)//人向下 118 { 119 if (Queue[end - 1]>Queue[end - 2])//电梯向上 120 { 121 if (Queue[end - 1] < Pfloor)//电梯的目标楼层小于人当前的楼层 122 { 123 Queue[end] = Pfloor; 124 end = (end++) % 21; 125 Queue[end] = tofloor; 126 end = (end++) % 21; 127 } 128 } 129 else//电梯向下 130 { 131 if (Queue[end - 1]<Pfloor)//电梯的目标楼层小于人当前的楼层 132 { 133 Queue[end] = Queue[end - 1]; 134 Queue[end - 1] = Pfloor; 135 end = (end++) % 21; 136 } 137 else 138 { 139 Queue[end] = Pfloor; 140 end = (end++) % 21; 141 } 142 if (Queue[end - 1] < tofloor)//队列中的最后一个数小于人的目标楼层时 143 { 144 Queue[end] = Queue[end - 1]; 145 Queue[end - 1] = tofloor; 146 end = (end++) % 21; 147 } 148 else 149 { 150 Queue[end] = tofloor; 151 end = (end++) % 21; 152 } 153 } 154 } 155 } 156 } 157 void Elevator::show(){ 158 cout << "id:" << id; 159 cout << "电梯,在" << floor << "楼"; 160 cout << " 运行方向:"; 161 if (0 == RunState)//不动 162 { 163 cout << " -"; 164 } 165 if (1 == RunState)//向上 166 { 167 cout << " ↑"; 168 } 169 if (2 == RunState)//向下 170 { 171 cout << " ↓"; 172 } 173 cout << "人:" << Pnum << endl; 174 cout << endl; 175 } 176 int Elevator::countDistance(int pFloor, int runDirection){ 177 if (state == 1&&pFloor%2==0)//电梯单层 人在双层 178 { 179 return 100; 180 } 181 if (state==2&&pFloor%2!=0)//电梯双层 人在单层 182 { 183 return 100; 184 } 185 if (end == start)//电梯静止时 186 { 187 return abs(floor-pFloor); 188 } 189 if (end - start == 1)//电梯只有一个目标楼层时 190 { 191 if (floor<Queue[start])//电梯上行 192 { 193 if (runDirection == 1)//人上行 194 { 195 if (pFloor<floor)//人在当前楼层下方 196 { 197 return (2 * (Queue[start] - floor) + (floor - pFloor)); 198 } 199 if (pFloor>=floor)//人在当前楼层上方 200 { 201 return (pFloor - floor); 202 } 203 } 204 if (runDirection == 2)//人下行 205 { 206 if (pFloor<floor)//人在当前楼层下方 207 { 208 return (2 * (Queue[start] - floor) + (floor - pFloor)); 209 } 210 if (pFloor >Queue[start])//人在当前楼层上方 211 { 212 return (pFloor - floor); 213 } 214 if (pFloor >= floor&&pFloor <= Queue[start])//人在当前楼层和目标楼层之间 215 { 216 return (Queue[start] - floor + Queue[start] - pFloor); 217 } 218 } 219 } 220 else//电梯下行 221 { 222 if (runDirection == 1)//人上行 223 { 224 if (pFloor < floor)//人在当前楼层下方 225 { 226 return (floor-Queue[start]+pFloor-Queue[start]); 227 } 228 if (pFloor >= floor)//人在当前楼层上方 229 { 230 return (2*(floor-Queue[start])+pFloor-floor); 231 } 232 if (pFloor >= floor&&pFloor <= Queue[start])//人在当前楼层和目标楼层之间 233 { 234 return (floor-Queue[start]+pFloor-Queue[start]); 235 } 236 } 237 if (runDirection == 2)//人下行 238 { 239 if (pFloor<floor)//人在当前楼层下方 240 { 241 return (floor-pFloor); 242 } 243 if (pFloor >Queue[start])//人在当前楼层上方 244 { 245 return (2*(floor-Queue[start])+pFloor-floor); 246 } 247 } 248 } 249 } 250 if (end-start>1)//电梯有两个或两个以上目标楼层时 251 { 252 if (Queue[end-2]<Queue[end-1])//电梯上行 253 { 254 if (runDirection == 1)//人上行 255 { 256 if (pFloor>=Queue[end-2])//人在目标楼层1上方 257 { 258 return (pFloor-Queue[end-2]); 259 } 260 if (pFloor<Queue[end-2])//人在目标楼层1下方 261 { 262 return (2*(Queue[end-1]-Queue[end-2])+Queue[end-2]-pFloor); 263 } 264 } 265 if (runDirection == 2)//人下行 266 { 267 if (pFloor<Queue[end - 2])//人在目标楼层1下方 268 { 269 return (2 * (Queue[end - 1] - Queue[end - 2]) + (Queue[end - 2] - pFloor)); 270 } 271 if (pFloor >Queue[end - 1])//人在目标楼层2上方 272 { 273 return (pFloor - Queue[end - 2]); 274 } 275 if (pFloor >= Queue[end - 2] && pFloor <= Queue[end - 1])//人在目标楼层1和目标楼层2之间 276 { 277 return (Queue[end - 1] - Queue[end - 2] + Queue[end - 1] - pFloor); 278 } 279 } 280 } 281 else//电梯下行 282 { 283 if (runDirection == 1)//人上行 284 { 285 if (pFloor<Queue[end-1])//人在目标楼层2下方 286 { 287 return (Queue[end-2]-pFloor); 288 } 289 if (pFloor>Queue[end-2])//人在目标楼层1上方 290 { 291 return (2*(Queue[end-2]-Queue[end-1])+pFloor-Queue[end-2]); 292 } 293 if (pFloor>=Queue[end-1]&&pFloor<=Queue[end-2])//人在目标楼层1和2之间 294 { 295 return (Queue[end-2]-Queue[end-1]+pFloor-Queue[end-1]); 296 } 297 } 298 if (runDirection == 2)//人下行 299 { 300 if (pFloor>Queue[end-2])//人在目标楼层1上方 301 { 302 return (2*(Queue[end-2]-Queue[end-1])+pFloor-Queue[end-2]); 303 } 304 if (pFloor<=Queue[end-2])//人在目标楼层1下方 305 { 306 return (Queue[end - 2] - pFloor); 307 } 308 } 309 } 310 } 311 }
电梯类中主要有id 电梯号 floor 电梯当前楼层 Pnum当前人数等属性,方法有add方法,run方法 show方法以及countDistance方法
二、电梯的运行,起初我们以为电梯的运行是一件很简单的事情,只要让它上上下下就可以,但后来我发现的我们大错特错了,电梯本身的运行很简单,但是当电梯的数目增加时,电梯的运行变得很难实现,首先是如何判断多个电梯中的哪个电梯去响应对应楼层的按钮,其次是判断后怎么让相应的电梯去到按钮所在的楼层,响应按钮后如何将人所在的楼层和人要去的楼层合理的添加进数组的相应位置,在这里我们给电梯类添加了一个新的方法,通过判断电梯与人之间所隔的楼层数来判断哪个电梯去响应按钮,最后是电梯的状态判断,在电梯的run方法中,当电梯的运行状态改变时,更改电梯当前的运动状态。
1 // cout << e1.countDistance(pFloor, runDirection); 2 // cout << e2.countDistance(pFloor, runDirection); 3 // cout << e3.countDistance(pFloor, runDirection); 4 // cout << e4.countDistance(pFloor, runDirection); 5 //电梯最优解 6 int num; 7 num = compareDistance(e1.countDistance(pFloor, runDirection), e2.countDistance(pFloor, runDirection), e3.countDistance(pFloor, runDirection), e4.countDistance(pFloor, runDirection)); 8 if (num==1)//e1最近 9 { 10 e1.Add(pFloor, runDirection, toFloor,person); 11 } 12 if (num==2)//e2最近 13 { 14 e2.Add(pFloor, runDirection, toFloor, person); 15 } 16 if (num==3)//e3最近 17 { 18 e3.Add(pFloor, runDirection, toFloor, person); 19 } 20 if (num==4)//e4最近 21 { 22 e4.Add(pFloor, runDirection, toFloor, person); 23 }
三、人数的判断,最初的电梯人数的限制很简单,因为电梯目标只有一个,所以只要判断响应按钮时进入的人少于最大人数就可以,更改后的电梯则不行,因为存在电梯有多个目标中途下人的情况,所以我们又为电梯添加了两个新的属性,用以判断电梯是应该上人还是应该下人,以及电梯上人的时候有多少人,下人时则采取随机数方式。人数的增减则增加在电梯的运行方法中,并且改变时予以判断,如果应该下人是否为目标楼层,是的话将人数清零;如果上人超限的话则输出应下电梯多少人,以及将电梯人数设置成最大值(依据现实情况)。
1 void Elevator::Run(){ 2 if (end != start)//需要电梯运行的情况 3 { 4 if (floor > Queue[start])//向下 5 { 6 RunState = 2; 7 floor--; 8 9 } 10 if (floor < Queue[start])//向上 11 { 12 13 RunState = 1; 14 floor++; 15 } 16 if (floor == Queue[start])//到达目的地 17 { 18 RunState = 0; 19 start = (start++) % 21;//start指针向后移 20 if (pState % 2 == 0){//出人 21 if (start == end) 22 Pnum = 0; 23 else 24 Pnum = Pnum - abs(rand() % Pnum); 25 pState++; 26 } 27 else{//进人 28 Pnum += toP; 29 if (Pnum > max) 30 { 31 cout << "超重了,需要下" << Pnum - max << "人"; 32 Pnum = max; 33 } 34 pState++; 35 } 36 } 37 } 38 else{ 39 RunState = 0; 40 } 41 42 }
四、数据的输入,由于设计的不断改变,输入的数据也不断变化,因为界面的不到位,这里采用纯手工输入的方式,输入人所在的楼层,按的按钮的方向,人要去的楼层以及要上电梯的人数。由于采用循环的方式,应该有输入数据无效的情况,这时应让电梯自行运行。
1 int Pnum, pFloor, toFloor, runDirection ,person,t=0;// pFloor:人当前所在楼层 toFloor:人的目标楼层 runDirection:1向上 2向下 person:进电梯的人数 2 cout << "请输入指令,\n格式为: 人所在楼层 按钮方向 人的目标楼层 人数"<<endl; 3 while (true) 4 { 5 cin >> pFloor >> runDirection >> toFloor>>person; 6 if (pFloor == -1) 7 { 8 //无效操作 9 e1.show(); 10 e2.show(); 11 e3.show(); 12 e4.show(); 13 e1.Run(); 14 e2.Run(); 15 e3.Run(); 16 e4.Run(); 17 continue; 18 }
五、界面的实现,电梯类的实现耗费了多天的时间,本来兴致满满的打算写一个界面,然而当我们去实现时,才发现时间所剩不多,现学现做一个图形化界面已经来不及,所以草草的写了个输出函数,在控制台中输出电梯的运行情况
1 void Elevator::show(){ 2 cout << "id:" << id; 3 cout << "电梯,在" << floor << "楼"; 4 cout << " 运行方向:"; 5 if (0 == RunState)//不动 6 { 7 cout << " -"; 8 } 9 if (1 == RunState)//向上 10 { 11 cout << " ↑"; 12 } 13 if (2 == RunState)//向下 14 { 15 cout << " ↓"; 16 } 17 cout << "人:" << Pnum << endl; 18 cout << endl; 19 }
六、代码运行结果如下:
总结:
结对编程对于我们来讲,是一次全新的编程作业模式,作业过程中有与队友思想的冲突,也有共同改进完善的欣喜,一点点的进步直到整个编程作业的完成,让我体验到了结对编程的益处,也使自己的编程习惯得到了很大的改善和提高。另外,逐步分析使问题化繁为简也是我们这次编程作业的关键点,拿到一个问题,刚开始也许会一头雾水,但是把一个复杂的问题拆分为若干个子问题,这样整个思路就十分清晰了,希望自己以后对待任何问题也能如此解决,沉着冷静。
工作照: