C语言电梯模拟程序
2015-05-30 20:38
162 查看
C语言电梯模拟程序
一直以来我对电梯很感兴趣,起初认为用C语言不可能实现电梯模拟,需要多线程的支持,因此一直以来也没有想着做。最近数据结构习题书的这道题引起了我的注意,通过几天的努力终于实现了,先将程序的实现与大家分享出来。在这个程序关键是处理好电梯运行状态转换与乘客进出的同步进行。好在题目要求每次输入时要输入下一个乘客到来的时间,使得程序变简单了。通过一个模拟时钟,根据模拟时钟判断该运行哪个函数。以下是模拟时钟的代码。
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++; } }在这个先不管TestPeople()、Controler()是什么,其中activity是关键,它是一个链表在链表的头部是计时器时间最小的函数,根据模拟时钟判断是否调用这个函数以及删除这个节点。以下是Activity的具体定义。
typedef struct Activity{ int time; void(*fn)(void); struct Activity* next; }Activity;以及全局变量activity
Activity activity={0,NULL,NULL};下面的代码用于将一个函数加入activity链表,这是根据时钟值从小到大插入activity的。
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 Input(void){//输入人员信息,这个需要手动调用一次,之后就根据定时器调用了 Person* p = (Person*)malloc(sizeof(Person)); int infloor,outfloor,giveuptime,intertime; while(1){ printf("请输入用户的起始楼层:"); scanf("%d",&infloor); printf("请输入用户的目标的楼层:"); scanf("%d",&outfloor); printf("请输入用户的最长容忍时间:"); scanf("%d",&giveuptime); printf("请输入下一个用户的到来时间:"); scanf("%d",&intertime); if(!(infloor<0||infloor>MaxFloor-1||outfloor<0||outfloor>MaxFloor-1)&&(infloor!=outfloor)) break; printf("错误的用户信息录入!\n"); } 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); }这使得main函数可以写的很简单。
int main(){ Init(); Input(); DoTime(); return 0; }这样整个电梯程序大体就搭建起来了。下面看Controler()这个函数,它就是判断电梯的运行状态,然后决定电梯的下一个运行状态。AddAct()很重要,这很好的实现了一个需要时间的过程,如电梯的开门,上升,减速。
void Controler(void){ if(State==Idle||State==Stop){ if(CallUp[Floor]||CallDown[Floor]||CallCar[Floor]){ //当前层有请求,需要开门进出 if(CallCar[BaseFloor]==2){ CallCar[BaseFloor]=0; State=Idle; printf("现在在%d层,无人请求电梯!\n",BaseFloor); 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=Idle; if(Floor!=BaseFloor) AddAct(OverTime,tofirst); } } } //否则电梯忙碌 return; }下面是一些用到宏定义以及全局变量。
#define GoingUp 1//匀速上升下面是Controler()具体调用细节。
#define GoingDown 2//匀速下降
#define SpeedUp 3//加速上升
#define SpeedDown 4//加速下降
#define SlowUp 5//减速上升准备停靠
#define SlowDown 6//减速下降准备停靠
#define Idle 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 5
#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;
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 Time=0;
int CallUp[MaxFloor]={0,};
int CallDown[MaxFloor]={0,};
int CallCar[MaxFloor]={0,};
int Floor=BaseFloor;
int State=Idle;
int PersonId=0;
Activity activity={0,NULL,NULL};
Person_Ele Stack[5]={0,};
Person Queue[5]={0,};
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("电梯门关了\n"); State=Stop; } void doopendoor(void){//打开电梯门 printf("电梯门开了\n"); 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("用户%d走出电梯\n",p->Id); 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("用户%d走入电梯\n",p->Id); 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("在选择方向时发生错误!\n"); return old; } void tofirst(void){//去第一层 if(State!=Idle||Floor==BaseFloor) return; printf("长时间没人请求电梯!将进入%d层\n",BaseFloor); CallCar[BaseFloor]=2;//给电梯一个虚拟的去1层的请求,这并不会开门 } void doslow(void){//电梯停了 printf("电梯停了,当前层是%d\n",Floor); State=Stop; } void doup(void){ Floor++; printf("电梯正在上升!现已到了%d层!\n",Floor); 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("电梯正在下降!现已到了%d层!\n",Floor); 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("电梯已加速上升!\n"); State=GoingUp; AddAct(UpTime,doup); }else{ printf("电梯已加速下降!\n"); State=GoingDown; AddAct(DownTime,dodown); } }他们之间尽管没有直接调用关系,但都是通过AddAct()联系起来的。下面是TestPeople()的实现,我知道DoTime()每次都调用它严重影响效率,但是这需要修改AddAct(),增加复杂性。
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>=Idle)) break; q->next=p->next; printf("用户%d放弃了等待!\n",p->Id); free(p); p=q->next; continue; } q=p; p=p->next; } } }下面是所有的源代码:
Dianti.h
#ifndef _DIANTI_H_Dianti.c
#define _DIANTI_H_
#include <stdio.h>
#include <stdlib.h>
#define GoingUp 1//匀速上升
#define GoingDown 2//匀速下降
#define SpeedUp 3//加速上升
#define SpeedDown 4//加速下降
#define SlowUp 5//减速上升准备停靠
#define SlowDown 6//减速下降准备停靠
#define Idle 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 5
#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;
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);
#endif
#include "Dianti.h"附程序运行结果:
int Time=0;
int CallUp[MaxFloor]={0,};
int CallDown[MaxFloor]={0,};
int CallCar[MaxFloor]={0,};
int Floor=BaseFloor;
int State=Idle;
int PersonId=0;
Activity activity={0,NULL,NULL};
Person_Ele Stack[5]={0,};
Person Queue[5]={0,};
int main(){ Init(); Input(); DoTime(); 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>=Idle)) break; q->next=p->next; printf("用户%d放弃了等待!\n",p->Id); free(p); p=q->next; continue; } q=p; p=p->next; } } }
void Input(void){//输入人员信息,这个需要手动调用一次,之后就根据定时器调用了 Person* p = (Person*)malloc(sizeof(Person)); int infloor,outfloor,giveuptime,intertime; while(1){ printf("请输入用户的起始楼层:"); scanf("%d",&infloor); printf("请输入用户的目标的楼层:"); scanf("%d",&outfloor); printf("请输入用户的最长容忍时间:"); scanf("%d",&giveuptime); printf("请输入下一个用户的到来时间:"); scanf("%d",&intertime); if(!(infloor<0||infloor>MaxFloor-1||outfloor<0||outfloor>MaxFloor-1)&&(infloor!=outfloor)) break; printf("错误的用户信息录入!\n"); } 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("电梯门关了\n"); State=Stop; } void doopendoor(void){//打开电梯门 printf("电梯门开了\n"); 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("用户%d走出电梯\n",p->Id); 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("用户%d走入电梯\n",p->Id); 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("在选择方向时发生错误!\n"); return old; } void tofirst(void){//去第一层 if(State!=Idle||Floor==BaseFloor) return; printf("长时间没人请求电梯!将进入%d层\n",BaseFloor); CallCar[BaseFloor]=2;//给电梯一个虚拟的去1层的请求,这并不会开门 } void doslow(void){//电梯停了 printf("电梯停了,当前层是%d\n",Floor); State=Stop; } void doup(void){ Floor++; printf("电梯正在上升!现已到了%d层!\n",Floor); 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("电梯正在下降!现已到了%d层!\n",Floor); 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("电梯已加速上升!\n"); State=GoingUp; AddAct(UpTime,doup); }else{ printf("电梯已加速下降!\n"); State=GoingDown; AddAct(DownTime,dodown); } }
void Controler(void){ if(State==Idle||State==Stop){ if(CallUp[Floor]||CallDown[Floor]||CallCar[Floor]){ //当前层有请求,需要开门进出 if(CallCar[BaseFloor]==2){ CallCar[BaseFloor]=0; State=Idle; printf("现在在%d层,无人请求电梯!\n",BaseFloor); 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=Idle; 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++; } }
相关文章推荐
- C语言实现原码补码输出
- 【学习笔记】【C语言】变量
- c++中友元机制
- C++ 学习笔记(三) 编写makefile
- 复习c++
- sizeof和sizeof(string)的问题
- c++ 多态
- LeetCode的medium题集合(C++实现)十七
- C++ 语法实验室之指针、常量const、字符串和等号初学误区理解
- C语言:判断一个字符串是否为十进制整数
- C++用模板求解开方(你不得不知道的模板带给我们的运行效率)
- C++ 构造与析构的执行顺序
- 【Maximum Subarray 】cpp
- C语言编程优化运行速度
- C++ 学习笔记(二) 如何向Main函数传递参数
- C语言产生随机数的方法
- c++移动语义
- char[]数组名与指针,以及字符串数组与string的一些比较
- c++ try_catch throw
- c++:不要重新定义继承而来的non-virtual函数