模拟九层电梯系统。有七个状态:正在开门(Opening)、已开门(opened)、正在关门(closing)、已关门(closed)、等待(waiting)、移动(moving)、减速(Decelerate)。
对于每个乘客有一个最长容忍时间,超过这个候电梯时间,他就会放弃。
模拟始终从0开始,时间单位为0.1s。人和电梯各种动作均要消耗一定时间单位(简记为t),比如:
有人进出时,电梯每隔40t测试一次,若无人进出,则关门。
关门开门各需要20t
每隔人进出电梯均需要25t
电梯加速需要15t
上升时,每一层需要51t,减速需要14t
下降时,每一层需要61t,减速需要23t
如果电梯在某层超过300t,则回一层待命
要求:按时序显示系统状态变化过程,即发生的全部人和电梯动作序列
扩展要求:实现电梯模拟可视化界面
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>#define GoingUp 1//匀速上升
#define GoingDown 2//匀速下降
#define SpeedUp 3//加速上升
#define SpeedDown 4//加速下降
#define SlowUp 5//减速上升准备停靠
#define SlowDown 6//减速下降准备停靠
#define Free 7//空闲
#define Stop 8//停止且已关门
#define DoorOpen 9//停止且门已打开
#define DoorOpening 10
#define DoorCloseing 11#define CloseTest 40 //电梯关门测试时间
#define OverTime 300 //电梯停候超时时间
#define Accelerate 15 //加速时间
#define UpTime 51 //上升时间
#define DownTime 61 //下降时间
#define UpDecelerate 14 //上升减速
#define DownDecelerate 23 //下降减速
#define DoorTime 20 //开门关门时间
#define InOutTime 25 //进出电梯时间#define MaxTime 10000 //最大容忍时间
#define MaxFloor 10 //最大层数9
#define BaseFloor 1//初始每层电梯等待队列和栈
/*#define Init() ({int i;\for(i=0;i<MaxFloor;i++){\Stack[i].next=NULL;\Queue[i].next=NULL;\}\activity.next=NULL;\
})*/
typedef struct Person {int Id; //numberint OutFloor; //目标楼层int GiveupTime; //容忍时间struct Person* next;
}Person;typedef struct Activity {int time;void(*fn)(void);struct Activity* next;
}Activity;typedef struct Person_Ele {int Id;struct Person_Ele* next;
}Person_Ele;int AddQueue(int floor, struct Person* p); //加入相应层的客户等待队列
void AddAct(int time, void(*fn)(void));
void TestPeople(); //检查是否有客户放弃等待
void DoTime();
void Input(void);//电梯状态
void testinout(void); //检测有无人进出
void doclosedoor(void); //电梯关门
void doopendoor(void); //电梯开门
void doout(void); //出人
void doin(void); //进人
void doup(void); //上升
void dodown(void); //下降
void domove(void); //加速
void doslow(void); //停止
void tofirst(); //回一层
int GetWhere(void); //电梯行走方向int Time = 0;
int CallUp[MaxFloor] = { 0, };
int CallDown[MaxFloor] = { 0, };
int CallCar[MaxFloor] = { 0, };
int Floor = BaseFloor;
int State = Free;
int PersonId = 0;
Activity activity = { 0,NULL,NULL };
Person_Ele Stack[5] = { 0, };
Person Queue[5] = { 0, };int main() {// Init();Input(); //输入用户信息DoTime();system("pause");return 0;
}int AddQueue(int floor, Person* p) {//加入相应层的客户等待队列 Person* tmp = &Queue[floor];//这始终加在链表的最后一位, while (tmp->next != NULL) {tmp = tmp->next;}tmp->next = p;return 0;
}void AddAct(int time, void(*fn)(void)) {//将一个活动加入定时器,时间到了调用这个函数 time = Time + time; //这个函数参数必须是void,返回值也必须是voidstruct Activity* act;act = (struct Activity*)malloc(sizeof(struct Activity));act->next = NULL;act->fn = fn;act->time = time;struct Activity* p = &activity;while (p->next != NULL) {if (p->next->time>time)break;p = p->next;}act->next = p->next;p->next = act;
}void TestPeople() {//这是检测每层队列是否有人放弃,有人放弃就将他踢出队列 int i; //每个时间都会被调用,效率相对较低 for (i = 0; i<MaxFloor; i++) {Person* p = Queue[i].next;Person* q = &Queue[i];if (p == NULL)continue;while (p != NULL) {if (p->GiveupTime <= Time) {if (Floor == i && (State >= Free))break;q->next = p->next;printf("User %d gave up and left ——%d\n", p->Id,Time); //用户放弃等待,已离开free(p);p = q->next;continue;}q = p;p = p->next;}}
}int eexit = 0; //退出参数
int people = 0;
void Input(void) {//输入人员信息,这个需要手动调用一次,之后就根据定时器调用了 Person* p = (Person*)malloc(sizeof(Person));int infloor, outfloor, giveuptime, intertime;while (1) {printf("\n*********************************************\n");printf(" ▲ 请输入用户%d起始楼层:",people++);scanf("%d", &infloor);printf(" ▲ 请输入用户%d目标楼层:", --people);scanf("%d", &outfloor);printf(" ▲ 请输入用户%d最长容忍时间:", people++);scanf("%d", &giveuptime);printf(" ▲ 请输入下一个用户的到来时间:");scanf("%d", &intertime);printf(" ▲ 退出--1,继续--2 ");scanf("%d", &eexit);if (eexit == 1)exit(0); //退出函数printf("*********************************************\n\n");if (!(infloor<0 || infloor>MaxFloor - 1 || outfloor<0 || outfloor>MaxFloor - 1) && (infloor != outfloor))break;printf("录入错误请重输\n");}//giveuptime = OverTime;p->Id = PersonId++;p->GiveupTime = giveuptime + Time;p->next = NULL;p->OutFloor = outfloor;if (outfloor>infloor)CallUp[infloor] = 1;elseCallDown[infloor] = 1;AddQueue(infloor, p);AddAct(intertime, Input);
}void testinout(void) { //检测有无人进出 if (Queue[Floor].next || Stack[Floor].next)AddAct(CloseTest, testinout);else {State = DoorCloseing;CallUp[Floor] = 0;CallDown[Floor] = 0;CallCar[Floor] = 0;AddAct(DoorTime, doclosedoor);}
}void doclosedoor(void) //关闭电梯门
{ printf("door's closed ——%d\n\n",Time);State = Stop;
}void doopendoor(void) //打开电梯门
{printf("\ndoor's opened ——%d\n",Time);State = DoorOpen; //门打开了 AddAct(CloseTest, testinout);if (Stack[Floor].next)AddAct(InOutTime, doout);else { //没人出,就看有没有进的 if (Queue[Floor].next)AddAct(InOutTime, doin);}
}void doout(void) {//根据栈出人,如果没有看是否有人进 if (Stack[Floor].next) {Person_Ele* p = Stack[Floor].next;Stack[Floor].next = p->next;//;//显示信息 printf("User %d ------- get out of the elevator ——%d\n", p->Id, Time); //出电梯free(p);}if (Stack[Floor].next) {AddAct(InOutTime, doout);}else {if (Queue[Floor].next)AddAct(InOutTime, doin);}
}void doin(void) {//人进入电梯,这里不用关电梯门它会定时关的 Person* p = Queue[Floor].next;if (p) {Queue[Floor].next = p->next;Person_Ele* pe = (Person_Ele*)malloc(sizeof(Person_Ele));int in = p->OutFloor;CallCar[in] = 1;//置位请求 pe->next = Stack[in].next;pe->Id = p->Id;Stack[in].next = pe;printf("User %d ------- get into the elevator ——%d\n", p->Id,Time); //进电梯free(p);}if (Queue[Floor].next) {AddAct(InOutTime, doin);}
}int GetWhere(void) {static int old = 0;//保存上一次电梯的方向,保证电梯尽可能在一个方向走 int isup = 0, isdown = 0;int i;for (i = Floor + 1; i<MaxFloor; i++) {if (CallDown[i] || CallUp[i] || CallCar[i])isup = 1;}for (i = Floor - 1; i >= 0; i--) {if (CallDown[i] || CallUp[i] || CallCar[i])isdown = 1;}if (isup == 0 && isdown == 0) {return 0;}if (old == 0) {if (isdown) old = GoingDown;if (isup) old = GoingUp;return old;}if (old == GoingUp&&isup)return old;else if (old == GoingDown&&isdown)return old;else if (isdown)old = GoingDown;else if (isup)old = GoingUp;elseprintf("Error!\n"); //在选择方向时发生错误return old;
}void tofirst(void) {//回第一层if (State != Free || Floor == BaseFloor)return;printf("No one asked for a long time,ready to return to %d floor ——%d\n", BaseFloor, --Time); Time--;//长时间没人请求电梯,将进入%d层CallCar[BaseFloor] = 2;//给电梯一个虚拟的去1层的请求,不会开门
}void doslow(void) {//电梯停了 printf("Stop ------%d ——%d\n", Floor,Time--); //电梯停了,当前层是%dState = Stop;
}void doup(void) { //电梯上升Floor++;printf("going up --------%d ——%d\n", Floor,Time);if (CallDown[Floor] || CallUp[Floor] || CallCar[Floor]) {State = SlowUp;AddAct(UpDecelerate, doslow);}else {if (Floor == MaxFloor - 1) {State = SlowUp;AddAct(UpDecelerate, doslow);}else {AddAct(UpTime, doup);}}
}void dodown(void) { //电梯下降Floor--;printf("going down ------%d ——%d\n", Floor,--Time);if (CallUp[Floor] || CallDown[Floor] || CallCar[Floor]) {State = SlowDown;AddAct(DownDecelerate, doslow);}else {if (Floor == 0) {State = SlowDown;AddAct(DownDecelerate, doslow);}else {AddAct(DownTime, dodown);}}
}void domove(void) {//加速完成,将进入正常速度 if (State == SpeedUp) {printf("Accelerating up ——%d\n",--Time); //电梯加速上升State = GoingUp;AddAct(UpTime, doup);}else {printf("Accelerating Down ——%d\n",--Time); //电梯加速下降State = GoingDown;AddAct(DownTime, dodown);}
}void Controler(void) {if (State == Free || State == Stop) {if (CallUp[Floor] || CallDown[Floor] || CallCar[Floor]) {//当前层有请求,需要开门进出if (CallCar[BaseFloor] == 2) //在一楼{CallCar[BaseFloor] = 0;State = Free;printf("Nobody asked ------%d ——%d\n", BaseFloor,Time--); //现在在%d层,无人请求电梯return;}State = DoorOpening;AddAct(DoorTime, doopendoor);}else {//当前层无请求,判断其他层请求int whitch = GetWhere();if (whitch == GoingUp) {State = SpeedUp;AddAct(Accelerate, domove);}else if (whitch == GoingDown) {State = SpeedDown;AddAct(Accelerate, domove);}else {State = Free;if (Floor != BaseFloor)AddAct(OverTime, tofirst);}}}//否则电梯忙碌 return;
}void DoTime() {//此函数用于模拟时钟 while (1) {if (Time>MaxTime)return;TestPeople(); //两个始终都会被调用的函数 Controler();struct Activity* p = activity.next;if (p == NULL) {Time = MaxTime;}if (p&&Time >= p->time) {//取出活动队头的,检测定时是否到了 activity.next = p->next;p->fn();free(p);}Time++;}
}