Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge branch 'master' of http://github.com/Th0ar/Elevator-Emulator

Conflicts:
	Headers/qt/emulator.h
  • Loading branch information...
commit bca5f80bb5be298673d355065c89de5424f9d619 2 parents de3775f + 8a3a149
鲜染 authored
103 Docs/API-шп┤цШО.md
Source Rendered
... ... @@ -0,0 +1,103 @@
  1 +经过不懈的努力,终于将框架和具体实现区分开来了。从此算法的设计者不需要再考虑底层模型的实现和整个机制的运行细节。为了更方便的设计算法,在此详细地介绍设计算法可能用到的 API,如果觉得 API 有任何不足和需要改进的地方,一定提出修改,提高整体的工作效率。
  2 +
  3 +###1. 嵌入算法
  4 +
  5 +在此,用我的写的 FCFS(First Come First Service)做例子,FCFS 算法是一种优先处理请求队列头的算法,也就是“先按电梯的楼层先服务”,为了嵌入这一种算法:
  6 +
  7 +1 在 **Headers/controller.h** 中声明新的算法函数 **static void Fcfs()**, 务必声明为静态函数
  8 +
  9 +```
  10 +class Controller
  11 +{
  12 +public:
  13 + static void Fcfs();
  14 + /* 在这里补充更多算法 */
  15 +};
  16 +```
  17 +
  18 +2 在 **Sources** 目录下创建算法的实现 fcfs.cpp
  19 +
  20 +```
  21 +#include "../Headers/models.h"
  22 +
  23 +/* 找到最为空闲的电梯 */
  24 +Elevator* Idlest() {
  25 + /* SOME CODE */
  26 +}
  27 +
  28 +/* 调度 */
  29 +void Controller::Fcfs() {
  30 + while(Idlest() != NULL) {
  31 + if (Emulator::orders.empty()) return;
  32 + Elevator* idle = Idlest();
  33 + Order* order = Emulator::orders.front();
  34 + Emulator::orders.pop_front();
  35 + idle->PushInst(new Instruction(order->from, 1));
  36 + }
  37 +}
  38 +```
  39 +
  40 +在这个文件里,首先包含了 models.h 这个文件,这个文件包含了所有的基本的类,所谓基本类就是指除了特种电梯意外的所有类,如果算法对数据结构没有特殊的要求(比如要求改写 Elevator 类),那么这个头文件就足够了。
  41 +
  42 +接下来我写了一个叫 Idlest 的 helper 函数,在接下来就是刚才在 controller.h 里声明的调度函数。
  43 +
  44 +至此,嵌入算法的基本流程就结束了。
  45 +
  46 +###2. 算法设计的输入与输出
  47 +
  48 +
  49 +仍然是一 Fcfs 为例子,在刚才的 fcfs.cpp 中,实现了这样一个函数
  50 +
  51 +```
  52 +/* 调度 */
  53 +void Controller::Fcfs() {
  54 + while(Idlest() != NULL) {
  55 + if (Emulator::orders.empty()) return;
  56 + Elevator* idle = Idlest();
  57 + Order* order = Emulator::orders.front();
  58 + Emulator::orders.pop_front();
  59 + idle->PushInst(new Instruction(order->from, 1));
  60 + }
  61 +}
  62 +```
  63 +整个代码的大意是:有空闲的电梯时,并且有未处理的 order 时,把请求队列的 front 弹出,根据这个order 的信息向空闲的电梯发送一条指令,这条指令指定电梯去 order 发出的地方,行进的方向是上下两个方向皆可(行进方向待会讨论)。
  64 +
  65 +从这个算法的实现过程中,可以看出算法实现是基于 Emulator::orders 和 Emulator::elevators 的,并且在最后向某一台电梯推送了一条指令。简要的说:
  66 +
  67 +输入 = 当前情况,这些情况由 Emulator 中的静态成员(类似于全局变量)表现
  68 +输出 = 向某台电梯推送一条或多条 Instruction
  69 +
  70 +附
  71 +
  72 +```
  73 +/* instruction.h */
  74 +class Instruction
  75 +{
  76 +public:
  77 + Instruction(int dest_, int dirCode_) : dest(dest_), dirCode(dirCode_){};
  78 + int dest; // 目的地
  79 + int dirCode; // 电梯行进过程中可接受请求的方向
  80 +};
  81 +```
  82 +###3. 程序运行的流程
  83 +
  84 +* Born( ), 产生新的乘客和新的请求
  85 +* Control( ), 执行 Controller 中不同的算法
  86 +* Move( ), 每个电梯依据指令移动
  87 +* Update( ), 更新统计数据,绘制图形界面等
  88 +
  89 +
  90 +###3. 一些需要注意的细节说明
  91 +
  92 +* 电梯会优先依据给定的指令(Instruction, 下用 inst 代替一个实例)工作,朝着 inst.dest 前进。
  93 +* 电梯运行途中如果开门的话,会把本层楼 inst.dirCode 对应的上、下请求接受,并且从全局请求序列中去除掉对应的请求。
  94 +* inst.dirCode == 1, 电梯开门会接受本层上下两个方向的请求; inst.dirCode == 2,电梯开门会接受向上的请求; inst.dirCode == 3,电梯开门会本层接受向下的请求; inst.dirCode == 0, 电梯开门不会再接受请求,停在原地直到 controller 调度。
  95 +* 如果电梯没有得到指令的话,会将楼层里的人按照从 0 层到顶层的顺序送达。
  96 +* 假设乘客是知道电梯运行的方向的,比如当 dirCode == 2 时,只有向上走的乘客会进入电梯。
  97 +* 当一台电梯要去的目的地中途被另一座电梯通过 dirCode 给取消的时候,这台电梯会 pop 掉现有的以该层楼为 dest,dirCode 比取消请求的 dirCode 小的指令。
  98 +* Emulator 保证,只要楼层有人,那么这层楼一定会有请求,所以如果电梯来却没有装完所有人的时候,这层楼的人会重新请求电梯。
  99 +
  100 +###4. API 细节
  101 +
  102 +请大家在设计算法的时候参考 emulator.h 中的 static member,值得注意的几个是 elevators(所有电梯), floors(所有楼层), orders(所有请求,动态更新),一些对象的细节可以去对应的头文件中去看,更实用简明的文档会被不断的更新补充。
  103 +
44 Docs/ASCIIчХМщЭвшп┤цШО.md
Source Rendered
... ... @@ -0,0 +1,44 @@
  1 +为了方便大家编译和调试,推出了 ascii 版的模拟系统,该系统与 Qt 界面的系统类似,每 1 单位时间刷新一场景,
  2 +现在的单位时间是 0.2 秒。由于调用的是 Linux/Gnu 系操作系统的 clear 和 sleep 函数,因此 windows 系统
  3 +下无法正常的工作,见谅(或者谁有空写一下。。)。
  4 +
  5 +在此将关于 ascii 界面程序的编译和算法设计相关事项阐述一下:
  6 +
  7 +###编译和运行
  8 +
  9 +编译直接在根目录下 `$ make` 就行了,会生成一个叫做 `ascii` 的可执行文件。这个程序的主函数在 Sources/ascii.cpp 中,从主函数中可以见到,为了方便,楼层数固定为 10,电梯固定为 4 架,泊松参数为 0.02, 程序持续 100 个单位时间,在没有命令行参数的情况下,运行程序还要求输入算法的名字。如果需要指定参数可以用命令行参数指定 `./ascii 10 4 0.02 100 FCFS`。不过。。。这个功能还没做。。先忍一忍或者谁写一下。。
  10 +
  11 +###插入算法
  12 +插入算法的顺序的基本方法还是和本目录下的《API-说明》中叙述的一样,只是为了配合 main 函数,需要在 Sources/ascii.cpp 中添加一个分支。
  13 +
  14 +具体的步骤是
  15 +
  16 +* 按照《API-说明》完成算法设计
  17 +* 在 `Sources/ascii.cpp` 中的 `Control()` 函数中增添分支,代码片段如下,相信看注释就懂了
  18 +
  19 +```
  20 +void Control() {
  21 + if (Emulator::elevatorType == "PFCFS") {
  22 + Controller::Fcfs();
  23 + } /* else if (Emulator::elevatorType == "costflow") {
  24 + /* Controller::costflow();
  25 + /*
  26 + /* } */
  27 +}
  28 +```
  29 +* 更新 Makefile
  30 +
  31 +打开根目录下的 Makefile
  32 +
  33 +```
  34 +ascii: Sources/ascii.cpp Sources/elevator.cpp Sources/emulator.cpp Sources/fcfs.cpp Sources/passenger.cpp \
  35 + Sources/floor.cpp Sources/PoissRand.cpp Headers/controller.h Headers/elevator.h \
  36 + Headers/emulator.h Headers/fcfs.h Headers/floor.h Headers/instruction.h Headers/models.h Headers/internlib.h \
  37 + Headers/passenger.h Headers/PoissRand.h Sources/order.cpp Sources/Print.cpp /* 在这里添加新创建的文件, 如 xx_algorithm.cpp */
  38 +
  39 + $(CC) $(CFLAGS) $(LIBS) -o ascii Sources/ascii.cpp Sources/elevator.cpp Sources/emulator.cpp Sources/fcfs.cpp Sources/passenger.cpp \
  40 + Sources/floor.cpp Sources/PoissRand.cpp Sources/order.cpp Sources/Print.cpp
  41 + /* 在这里添加新创建的需要编译和链接的文件, 如 xx_algorithm.cpp */
  42 +```
  43 +
  44 +* `$ make`, 执行,就能够看见输出了~
2  Headers/controller.h
@@ -9,6 +9,8 @@ class Controller
9 9 static void Scan();
10 10
11 11 static void CostFLow();
  12 +
  13 + static void PickUp();
12 14
13 15 /* 在这里补充更多算法 */
14 16 };
37 Headers/qt/emulator.h
@@ -13,45 +13,46 @@
13 13 class Emulator : public QWidget
14 14 {
15 15 Q_OBJECT
16   -
  16 +
17 17 public:
18 18 Emulator(QWidget *parent = 0);
19   -
  19 +
20 20 static int dual; /* dual: Time consumed with the whole duration */
  21 +
21 22 int timer;
22 23
23 24 static int nElevator; /* Total number of all elevators */
24   -
  25 +
25 26 static int UNIT_TIME; /* Unit time is set to time consumed by moving elevator up or down a floor */
26   -
  27 +
27 28 static vector<Elevator*> elevators; /* All the elevators functioning */
28   -
  29 +
29 30 static double lambda; /* Poiss process parameter lambda */
30   -
  31 +
31 32 static Floor floors[30]; /* Floors */
32   -
  33 +
33 34 static int nFloor; /* Total number of all floors */
34   -
  35 +
35 36 static string elevatorType;
36   -
  37 +
37 38 static list<Order*> orders;
38   -
  39 +
39 40 private slots:
40 41 void startEmulationSlots(); /* Slot bundle with start push button */
41   -
  42 +
42 43 private:
43 44 void startEmulator(); /* Start Emulation, if it is already emulated, pause the process */
44   -
  45 +
45 46 bool START; /* Wether game has started, equals false if paused */
46   -
  47 +
47 48 QPushButton *start; /* Start button, placed at right buttom */
48   -
  49 +
49 50 void Born(); /* 产生新的乘客,新的请求 */
50   -
  51 +
51 52 void Control(); /* 调用电梯调度算法 */
52   -
  53 +
53 54 void Move(); /* 电梯依据指令或默认逻辑移动 */
54   -
  55 +
55 56 void Update(); /* 更新统计数据 */
56 57
57 58 QLabel *nEle; /* Label: 电梯数 */
@@ -62,7 +63,7 @@ private slots:
62 63 QLabel *mxDur; /* Label: 最大过程时间 */
63 64 QLabel *mnDur; /* Label: 最小过程时间 */
64 65 QLabel *avThr; /* Label: 平均电梯吞吐量(每小时) */
65   -
  66 +
66 67 protected: /* Below is QWidget API */
67 68 void timerEvent(QTimerEvent*);
68 69 void paintEvent(QPaintEvent*);
6 Makefile
@@ -5,9 +5,11 @@ all: ascii
5 5
6 6 ascii: Sources/ascii.cpp Sources/elevator.cpp Sources/emulator.cpp Sources/fcfs.cpp Sources/passenger.cpp \
7 7 Sources/floor.cpp Sources/PoissRand.cpp Headers/controller.h Headers/elevator.h \
  8 + Sources/Scan.cpp \
8 9 Headers/emulator.h Headers/floor.h Headers/instruction.h Headers/models.h Headers/internlib.h \
9 10 Headers/passenger.h Headers/PoissRand.h Sources/order.cpp Sources/Print.cpp Sources/costflow.cpp \
10   - Headers/costflow.h
  11 + Headers/costflow.h Sources/pickup.cpp
11 12
12 13 $(CC) $(CFLAGS) $(LIBS) -o ascii Sources/ascii.cpp Sources/elevator.cpp Sources/emulator.cpp Sources/fcfs.cpp Sources/passenger.cpp \
13   - Sources/floor.cpp Sources/PoissRand.cpp Sources/order.cpp Sources/Print.cpp Sources/costflow.cpp
  14 + Sources/floor.cpp Sources/PoissRand.cpp Sources/pickup.cpp Sources/order.cpp Sources/Print.cpp Sources/costflow.cpp \
  15 + Sources/Scan.cpp
61 Sources/Scan.cpp
... ... @@ -0,0 +1,61 @@
  1 +#include "../Headers/models.h"
  2 +#include "../Headers/emulator.h"
  3 +
  4 +Elevator *Idlest();
  5 +
  6 +Elevator* Lowest()
  7 +{
  8 + EleIter iter;
  9 + int low=1000000;
  10 + for(iter = Emulator::elevators.begin(); iter != Emulator::elevators.end(); iter++)
  11 + {
  12 + if(low>(*iter)->Get_nPassenger()) low=(*iter)->Get_nPassenger();
  13 + }
  14 + for(iter = Emulator::elevators.begin(); iter != Emulator::elevators.end(); iter++)
  15 + {
  16 + if(low==(*iter)->Get_nPassenger()) return *iter;
  17 + }
  18 +}
  19 +void Controller::Scan()
  20 +{
  21 + while(Idlest() != NULL)
  22 + {
  23 + Elevator* idle = Idlest();
  24 + if(idle->Get_pos()==0)
  25 + idle->PushInst(new Instruction(Emulator::nFloor-1, 2));
  26 + else
  27 + idle->PushInst(new Instruction(0, 3));
  28 + break;
  29 + }
  30 + EleIter iter = Emulator::elevators.begin();
  31 + int k=Emulator::orders.size();
  32 + while(k)
  33 + {
  34 + Order* order = Emulator::orders.front();
  35 + if(Lowest()->Dir()==order->dir)
  36 + {
  37 + if(Lowest()->Dir()=='^')
  38 + Lowest()->PushInst(new Instruction(order->from,2));
  39 + else if(Lowest()->Dir()=='v')
  40 + Lowest()->PushInst(new Instruction(order->from,3));
  41 + Emulator::orders.pop_front();
  42 + continue;
  43 + }
  44 + if(iter == Emulator::elevators.end())
  45 + iter = Emulator::elevators.begin();
  46 + for(; iter != Emulator::elevators.end(); iter++)
  47 + {
  48 + if((*iter)->Dir()==order->dir)
  49 + {
  50 + if((*iter)->Dir()=='^')
  51 + (*iter)->PushInst(new Instruction(order->from,2));
  52 + else if(Lowest()->Dir()=='v')
  53 + (*iter)->PushInst(new Instruction(order->from,3));
  54 + Emulator::orders.pop_front();
  55 + break;
  56 + }
  57 + }
  58 +
  59 + k--;
  60 + }
  61 +}
15 Sources/ascii.cpp
@@ -36,9 +36,8 @@ void Born() {
36 36 int nPassenger = PoissRand(Emulator::lambda);
37 37 for(int j = 0; j < nPassenger; j++) {
38 38 Passenger *pass = new Passenger(i, floor(Rand(0, Emulator::nFloor)));
39   -
40 39 Emulator::floors[i].PushPassenger(pass);
41   -
  40 +
42 41 pass->MakeAnOrder();
43 42 }
44 43 }
@@ -49,9 +48,14 @@ void Control() {
49 48 Controller::Fcfs();
50 49 } else if (Emulator::elevatorType == "costflow") {
51 50 Controller::CostFLow();
52   - }/* else if (Emulator::elevatorType == "costflow") {
  51 + } else if (Emulator::elevatorType == "pickup") {
  52 + Controller::PickUp();
  53 + } else if (Emulator::elevatorType == "scan") {
  54 + Controller::Scan();
  55 + }
  56 + /* else if (Emulator::elevatorType == "costflow") {
53 57 * Controller::costflow();
54   - *
  58 + *
55 59 * } */
56 60 }
57 61
@@ -78,13 +82,12 @@ int main(int argc, char *argv[])
78 82 {
79 83 /* Generate random number seed with current time */
80 84 srand(time(NULL));
81   -
82 85 /* Set runtime parameters */
83 86 Emulator::nFloor = 10;
84 87 Emulator::lambda = 0.02;
85 88 Emulator::nElevator = 4;
86 89 cin >> Emulator::elevatorType;
87   -
  90 +
88 91 /* Initialize elevators */
89 92 for(int i = 0; i < Emulator::nElevator; i++) {
90 93 Elevator* ele = new Elevator();
3  Sources/fcfs.cpp
@@ -10,7 +10,6 @@ Elevator* Idlest() {
10 10 return NULL;
11 11 }
12 12
13   -
14 13 void Controller::Fcfs() {
15 14 Elevator::defaultDir = 1;
16 15 while(Idlest() != NULL) {
@@ -20,4 +19,4 @@ void Controller::Fcfs() {
20 19 Emulator::orders.pop_front();
21 20 idle->PushInst(new Instruction(order->from, 1));
22 21 }
23   -}
  22 +}
40 Sources/pickup.cpp
... ... @@ -0,0 +1,40 @@
  1 +#include "../Headers/models.h"
  2 +#include "../Headers/emulator.h"
  3 +Elevator* Available(Order* order)
  4 +{
  5 + EleIter iter;
  6 + Elevator *ans=NULL,*idle=NULL;
  7 + int dist=999999999;
  8 + for(iter = Emulator::elevators.begin(); iter != Emulator::elevators.end(); iter++)
  9 + {
  10 + if ((*iter)->Dir()==order->dir)
  11 + {
  12 + if ((*iter)->Dir()=='^' && (*iter)->Get_pos()<=order->from)
  13 + ans=*iter;
  14 + else if ((*iter)->Dir()=='v' && (*iter)->Get_pos()>=order->from)
  15 + ans=*iter;
  16 + }
  17 + else if ((*iter)->Dir()=='-' && (*iter)->Get_nPassenger() == 0 && (*iter)->Get_inst()->size() == 0 && dist>abs((*iter)->Get_pos()-order->from))
  18 + {
  19 + dist=abs((*iter)->Get_pos()-order->from);
  20 + idle=*iter;
  21 + }
  22 + if (ans==NULL && idle!=NULL) ans=idle;
  23 + }
  24 + return ans;
  25 +}
  26 +void Controller::PickUp()
  27 +{
  28 + while(!Emulator::orders.empty())
  29 + {
  30 + Order* order = Emulator::orders.front();
  31 + Emulator::orders.pop_front();
  32 + Elevator* chosenone = Available(order);
  33 + if (chosenone==NULL) return;
  34 + if (chosenone->Dir()=='^')
  35 + chosenone->PushInst(new Instruction(order->from,2));
  36 + else if (chosenone->Dir()=='v')
  37 + chosenone->PushInst(new Instruction(order->from,3));
  38 + else chosenone->PushInst(new Instruction(order->from,1));
  39 + }
  40 +}
117 Sources/stillworkingon.cpp
... ... @@ -1,117 +0,0 @@
1   -
2   -#include <iostream>
3   -#include <cstdlib>
4   -#include <ctime>
5   -#include <queue>
6   -#include "PoissRand.h"
7   -using namespace std;
8   -int max_people=0,ele_num=0,Floor=0,people[100]={0};
9   -
10   -class PASS_FLOW
11   -{
12   -public:
13   - int num;
14   - int target,begin;
15   - PASS_FLOW(int a,int b,int c):num(a),begin(b),target(c){};
16   - PASS_FLOW(){num=begin=target=0;};
17   - int dir()
18   - {
19   - if(target>begin) return 1;
20   - else return -1;
21   - }
22   -};queue<PASS_FLOW*> q[100];
23   -
24   -class ELE_VATOR
25   -{
26   -public:
27   - int mov_status;
28   - int passanger_num;
29   - int target_floor,present_floor,up,flownum;
30   - queue<PASS_FLOW*> pas;
31   - ELE_VATOR():mov_status(1),passanger_num(0),up(Floor),present_floor(1){flownum=0;}
32   - void mov()
33   - {
34   - if(present_floor+mov_status>=1 && present_floor+mov_status<=up)present_floor +=mov_status;
35   -
36   - }
37   - void turn()
38   - {
39   - if(present_floor <=1 || present_floor == up) mov_status = -mov_status;
40   - }
41   - void pick()
42   - {
43   - cout<<"yes";
44   - while(!q[present_floor].empty())
45   - {
46   - PASS_FLOW *s=q[present_floor].front();
47   - if(s->num+passanger_num>max_people) break;
48   - pas.push(s);
49   - passanger_num+=s->num;
50   - q[present_floor].pop();
51   - people[present_floor]-=q[present_floor].front()->num;
52   - flownum++;
53   - }
54   - }
55   - void drop()
56   - {
57   - int round=0,f=flownum;
58   - while(!pas.empty()&&round<f)
59   - {
60   - if(pas.front()->target==present_floor)
61   - {
62   - passanger_num-=pas.front()->num;
63   - pas.pop();
64   - flownum--;
65   - }
66   - else
67   - {
68   - pas.push(pas.front());
69   - pas.pop();
70   - }
71   - round++;
72   - }
73   - }
74   -};
75   -
76   -int main(int argc, const char * argv[])
77   -{
78   - int Emulator::lambda = atoi(argv[1]),total_person = 0,tim = 0, wait_sum = 0, on_sum = 0 ;
79   - int
80   - srand(time(NULL));
81   - /* receive input */
82   - char ele_direction[3]={'^','-','V'};
83   - cin>>max_people>>ele_num>>Floor;
84   - ELE_VATOR elevator;
85   - while(1)
86   - {
87   - tim++;
88   - int a=rand()%Floor+1,b=rand()%Floor+1;
89   - if(b==a) b=a+1;
90   - /* random floor of begin and target*/
91   - PASS_FLOW *tmp=new PASS_FLOW(PoissRand(Emulator::lambda), a, b);
92   - people[a]+=tmp->num;
93   - total_person+=tmp->num;
94   - q[a].push(tmp);
95   - for(int i=Floor;i>=1;i--)
96   - {
97   - cout<<"Floor "<<i<<":"<<people[i]<<" ";
98   - if(i==elevator.present_floor)
99   - {
100   - cout<<elevator.passanger_num;
101   - }
102   - cout<<endl;
103   - }
104   - elevator.mov();
105   - cout<<"move"<<endl;
106   - elevator.pick();
107   - cout<<"pick"<<endl;
108   - elevator.drop();
109   - cout<<"drop"<<endl;
110   - elevator.turn();
111   - cin.get();
112   - system("clear");
113   - }
114   - cout << endl;
115   - return 0;
116   -}
117   -

0 comments on commit bca5f80

Please sign in to comment.
Something went wrong with that request. Please try again.