python 电梯模拟器(命令行终端下极速版)

简介

拥有较为良好的界面,完善的模拟电梯实现思路。

电梯模拟器实现逻辑

电梯模拟器分为三个部分:

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

你可能感兴趣的:(python)