模拟九层电梯系统。有七个状态:正在开门(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; //number
int 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,返回值也必须是void
struct 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;
else
CallDown[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;
else
printf("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--); //电梯停了,当前层是%d
State = 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++;
}
}