拥有较为良好的界面,完善的模拟电梯实现思路。
电梯模拟器分为三个部分:
1,将电梯堪称一台状态机,根据外界传来的信号改变自身的运动状态
2,与电梯同步运行的是信息线程,电梯的消息主要来自
a. 电梯外部的某一楼层有人按上或下按钮
b. 电梯内部有人按下某一楼层的按钮
3,开关门,电梯只有关门状态下才会上下运行。
import random
import time
import gevent
from gevent import monkey
import os
monkey.patch_all()
class Elevator():
"""定义电梯类,并且初始化"""
def __init__(self,CAPACITY):
# 电梯运行状态:0 待机,1 上行,2 下行
self.state = 0
# 最大容量
self.capacity = CAPACITY
# 电梯目前所在楼层:任意
self.curPosition = random.randint(1,TOP)
# 电梯门的开关标志:0 关,1 开
self.door = 0
# 电梯下一停靠楼层:空
self.dest_floor = None
# 电梯内人数:0
self.num = 0
# 电梯转向标志:0 不转向,1 转向
self.change_dir = 0
class People():
"""创建人类,并且初始化"""
def __init__(self):
# 起点楼层
self.pos = random.randint(1,TOP)
# 终点楼层
self.dest = random.randint(1,TOP)
# 起点楼层 不等于 终点楼层
while self.dest == self.pos:
self.dest = random.randint(1,TOP)
# 在某一楼层按 上/下楼 按钮:-1 下楼,1 上楼
if self.dest <= self.pos:
self.dir = -1
else:
self.dir = 1
# 是否在电梯内标志:0 不在,1 在
self.inside = 0
def visual_display(e):
"""可视化显示电梯运行情况"""
os.system("cls")
# 创建标题与边框
print("\r\n"*3 + "\r\t" + "&"*92)
print("\r\t" + "&" + "\t"*5 + "电梯模拟程序" + "\t"*5 + " &")
print("\r\t" + "&"*92)
# 创建列名
print("\r\t 电梯入口 \t\t" + "*楼层*" + "\t\t#电梯#\t\t" + "|电梯内人员|")
# 绘制电梯
for i in range(TOP):
floor = TOP - i
floor_img =""
# 绘制电梯外等待人员, T代表上, V代表下
if len(msgQueen) >= 1:
floor_img += "\t"
i = 0
for people in msgQueen:
if people[0] == floor and people[3] != 1:
floor_img += "呉"
if people[1] == 1:
floor_img += "T"
else:
floor_img += "V"
i+=1
if len(msgQueen) < 1:
floor_img += "\t"
# 绘制楼层号
floor_img += "\t\t\t -" + str(floor) + "-"
if (floor) < 10:
floor_img += "-"
# 绘制电梯及其内部人员
if e.curPosition == floor:
# 绘制电梯
floor_img += "\t\t囧-->%s\t\t" % str(e.dest_floor)
if e.num != 0:
# 绘制电梯内人员
for people in range(e.num):
floor_img += "呉"
print(floor_img)
print("\r\t" + "-"*92)
# 绘制下边框
if e.state == 1:
state = "上升"
elif e.state == -1:
state = "下降"
elif e.state == 0:
state = "待机"
print("\t电梯情况详细说明")
print("\t\t电梯内人数:%d\t\t\t\t电梯正在%s" % (e.num, state))
print("\t\t\t现所在楼层:%d" % e.curPosition)
print("\t\t\t\t目标楼层:%s" % str(e.dest_floor))
print("\r\t" + "-"*92)
def writeMsg():
"""写入消息序列"""
while True:
time.sleep(2)
people = People()
msg = [people.pos, people.dir , people.dest, people.inside]
msgQueen.append(msg)
def analysis_msg(e):
"""处理收到的信号"""
global up_stop, down_stop
up_stop, down_stop = list(), list()
if msgQueen:
if len(msgQueen) == 1:
only_people = msgQueen[0] # 消息序列中的第一个,复制给第一个人
if only_people[3] == 0:
if only_people[0] > e.curPosition:
e.dest_floor = only_people[0]
if e.state != 1:
print("\t正在改变运行方向")
time.sleep(0.5)
e.state = 1
elif only_people[0] < e.curPosition:
e.dest_floor = only_people[0]
if e.state != -1:
print("\t正在改变运行方向")
time.sleep(0.5)
e.state = -1
elif only_people[0] == e.curPosition:
e.door = 1
if e.state != only_people[1]:
print("\t正在改变运行方向")
time.sleep(1)
e.state = only_people[1]
elif only_people[3] == 1:
e.dest_floor = only_people[2]
if e.state != only_people[1]:
print("\t正在改变运行方向")
time.sleep(0.5)
e.state = only_people[1]
if e.curPosition == e.dest_floor:
e.door = 1
elif len(msgQueen) > 1:
for msg in msgQueen:
if msg[1] == 1:
if msg[3] == 0:
up_stop.append(msg[0])
elif msg[3] == 1:
up_stop.append(msg[2])
elif msg[1] == -1:
if msg[3] == 0:
down_stop.append(msg[0])
elif msg[3] == 1:
down_stop.append(msg[2])
up_stop = sorted(set(up_stop))
down_stop = sorted(set(down_stop))
if e.state != 0:
if e.state == 1:
temp_up = list()
for stop_point in up_stop:
temp_up = stop_point
if stop_point >= e.curPosition:
e.dest_floor = stop_point
break
if up_stop:
if temp_up != e.dest_floor:
if down_stop and e.curPosition < max(down_stop):
e.dest_floor = max(down_stop)
else:
e.change_dir = 1
else:
if e.curPosition < max(down_stop):
e.dest_floor = max(down_stop)
else:
e.change_dir = 1
elif e.state == -1:
temp_down = list()
for stop_point in down_stop:
if stop_point <= e.curPosition:
temp_down = stop_point
e.dest_floor = stop_point
continue
if down_stop:
if temp_down != e.dest_floor:
if up_stop and e.curPosition > min(up_stop):
e.dest_floor = min(up_stop)
else:
e.change_dir = 1
else:
if e.curPosition > min(up_stop):
e.dest_floor = min(up_stop)
else:
e.change_dir = 1
if e.curPosition == e.dest_floor:
e.door = 1
else:
e.state = 0
def open_door(e):
"""关了门,怎么打开门呢"""
for p in msgQueen:
if p[0] == e.curPosition and p[1] == e.state and p[3] != 1:
p[3] = 1
e.door = 0
e.num += 1
print("\t%d进来了" % p[0])
time.sleep(0.2)
if p[3] == 1 and p[2] == e.curPosition and p[1] == e.state:
msgQueen.remove(p)
e.door = 0
e.num -= 1
print("\t%d出去了" % p[0])
time.sleep(0.2)
# 一个人的时候关门
if len(msgQueen) == 1 and msgQueen[0][0] == e.curPosition and msgQueen[0][3] == 1:
e.door = 0
if e.change_dir == 1:
print("\t正在改变运行方向")
time.sleep(0.5)
e.state = e.state * (-1)
e.door = 0
e.change_dir = 0
def move(e):
"""移动电梯的所在楼层"""
if e.state == 1 and e.door == 0:
e.curPosition += 1
elif e.state == -1 and e.door == 0:
e.curPosition -= 1
elif e.door == 1:
open_door(e)
time.sleep(0.1)
def elevator_monitor(e):
while True:
# 在命令行中终端绘制画面
visual_display(e)
# 分析消息序列
analysis_msg(e)
# 控制电梯的移动
move(e)
def main():
# 电梯行驶时,接收到的消息序列
global msgQueen
msgQueen = list()
# 最大楼层高度
global TOP
TOP = 10 # random.randint(10,22)
# 最大电梯容量
CAPACITY = 10
# 创建一个电梯实例
e = Elevator(CAPACITY)
# 使用协程实现,同时->接收消息序列和运行电梯
gevent.joinall([
gevent.spawn(writeMsg),
gevent.spawn(elevator_monitor, e),
])
if __name__ == "__main__":
main()
源代码中核心的消息序列处理函数并没有标记注释:现在此补上
def analysis_msg(e):
"""处理收到的信号"""
global up_stop, down_stop
up_stop, down_stop = list(), list()
# msgQueen 是电梯实时接收到的消息序列,
# 消息序列包括 <起点楼层>,<坐电梯方向>,<终点楼层>,<是否在电梯内>
# 1 消息序列不为空
if msgQueen:
# 1.1 消息序列中仅有一条消息
if len(msgQueen) == 1:
only_people = msgQueen[0]
# 1.1.1 电梯内没有人
if only_people[3] == 0:
# 1.1.1.1 电梯外的人所在楼层大于电梯所在楼层
# 就改变电梯的目标楼层,与运行方向
if only_people[0] > e.curPosition:
e.dest_floor = only_people[0]
if e.state != 1:
print("\t正在改变运行方向")
time.sleep(0.5)
e.state = 1
# 1.1.1.2 电梯外的人所在楼层小于电梯所在楼层
elif only_people[0] < e.curPosition:
e.dest_floor = only_people[0]
if e.state != -1:
print("\t正在改变运行方向")
time.sleep(0.5)
e.state = -1
# 1.1.1.3 电梯外的人所在楼层等于电梯所在楼层
# 开门,并且运行方向由进来的人决定
elif only_people[0] == e.curPosition:
e.door = 1
if e.state != only_people[1]:
print("\t正在改变运行方向")
time.sleep(1)
e.state = only_people[1]
# 1.1.2 电梯中有人时,电梯的目标楼层为此人的终点楼层
elif only_people[3] == 1:
e.dest_floor = only_people[2]
if e.state != only_people[1]:
print("\t正在改变运行方向")
time.sleep(0.5)
e.state = only_people[1]
# 1.1.3 如果电梯所在楼层与目标楼层相同,开门
if e.curPosition == e.dest_floor:
e.door = 1
# 1.2 消息序列大于 1 时
elif len(msgQueen) > 1:
# 1.2.1 解析消息序列中,得到上行/下行序列
for msg in msgQueen:
# 1.2.1.1 得到下行序列
if msg[1] == 1:
if msg[3] == 0:
up_stop.append(msg[0])
elif msg[3] == 1:
up_stop.append(msg[2])
# 1.2.1.2 得到上行序列
elif msg[1] == -1:
if msg[3] == 0:
down_stop.append(msg[0])
elif msg[3] == 1:
down_stop.append(msg[2])
# 1.2.2 去除重复,并排序
up_stop = sorted(set(up_stop))
down_stop = sorted(set(down_stop))
# 1.2.3 电梯运行状态不为待机时
if e.state != 0:
# 1.2.3.1 电梯运行方向为 上行时
if e.state == 1:
temp_up = list()
# 1.2.3.1.1 从上行序列中解析最近的停靠楼层
for stop_point in up_stop:
temp_up = stop_point
if stop_point >= e.curPosition:
e.dest_floor = stop_point
break
# 1.2.3.1.2 如果上行序列存在,但是下一停靠楼层不属于上行序列
if up_stop:
if temp_up != e.dest_floor:
# 1.2.3.1.2.1 如果下行序列存在,检测电梯位置
# 如果电梯上方存在向下的按钮信号,则改变目标楼层
# 否则,立刻改变行驶方向
if down_stop and e.curPosition < max(down_stop):
e.dest_floor = max(down_stop)
# 1.2.3.1.2.2 如果下行序列不存在,改变电梯运行方向
else:
e.change_dir = 1
# 1.2.3.1.3 如果上行序列不存在,此时由于消息序列大于1,
# 下行序列必定存在,那么就检测电梯位置,做出改变
else:
if e.curPosition < max(down_stop):
e.dest_floor = max(down_stop)
else:
e.change_dir = 1
# 1.2.3.2 电梯行驶方向下行时,逻辑同上
elif e.state == -1:
temp_down = list()
for stop_point in down_stop:
if stop_point <= e.curPosition:
temp_down = stop_point
e.dest_floor = stop_point
continue
if down_stop:
if temp_down != e.dest_floor:
if up_stop and e.curPosition > min(up_stop):
e.dest_floor = min(up_stop)
else:
e.change_dir = 1
else:
if e.curPosition > min(up_stop):
e.dest_floor = min(up_stop)
else:
e.change_dir = 1
# 1.2.4 如果电梯所在位置,位于目标楼层,则开门
if e.curPosition == e.dest_floor:
e.door = 1
# 2 消息序列为空,重置电梯为待机状态
else:
e.state = 0
# msgQueen 是电梯实时接收到的消息序列,
# 消息序列包括 <起点楼层>,<坐电梯方向>,<终点楼层>,<是否在电梯内>
# 1 消息序列不为空
# 1.1 消息序列中仅有一条消息
# 1.1.1 电梯内没有人
# 1.1.1.1 电梯外的人所在楼层大于电梯所在楼层
# 就改变电梯的目标楼层,与运行方向
# 1.1.1.2 电梯外的人所在楼层小于电梯所在楼层
# 1.1.1.3 电梯外的人所在楼层等于电梯所在楼层
# 开门,并且运行方向由进来的人决定
# 1.1.2 电梯中有人时,电梯的目标楼层为此人的终点楼层
# 1.1.3 如果电梯所在楼层与目标楼层相同,开门
# 1.2 消息序列大于 1 时
# 1.2.1 解析消息序列中,得到上行/下行序列
# 1.2.1.1 得到下行序列
# 1.2.1.2 得到上行序列
# 1.2.2 去除重复,并排序
# 1.2.3 电梯运行状态不为待机时
# 1.2.3.1 电梯运行方向为 上行时
# 1.2.3.1.1 从上行序列中解析最近的停靠楼层
# 1.2.3.1.2 如果上行序列存在,但是下一停靠楼层不属于上行序列
# 1.2.3.1.2.1 如果下行序列存在,检测电梯位置
# 如果电梯上方存在向下的按钮信号,则改变目标楼层
# 否则,立刻改变行驶方向
# 1.2.3.1.2.2 如果下行序列不存在,改变电梯运行方向
# 1.2.3.1.3 如果上行序列不存在,此时由于消息序列大于1,
# 下行序列必定存在,那么就检测电梯位置,做出改变
# 1.2.3.2 电梯行驶方向下行时,逻辑同上
# 1.2.4 如果电梯所在位置,位于目标楼层,则开门
# 2 消息序列为空,重置电梯为待机状态
https://blog.csdn.net/okfu_dl/article/details/82900893