学习 python 后一直没有什么想要写的东西, 工作上开发使用的是 php 语言, 一时间也改变不了.
然后在某个网站(网址忘记了)看到了一个 web 版的电梯模拟器, 玩了半天, 他的电梯运行逻辑各种情况下都有问题, 这就萌生了我自己写一个 python 版的想法.
当时不会 GUI, 只能把展示内容写在文件里, 这样, 我打开展示文件(只读), 然后执行程序, 文件中的内容会一秒刷新一次 (偷懒版动画, 哈哈)
现在学了 GUI, 发呆发了大半天也没写出来, 就先放弃了
先展示一下效果:
图中红色的是 vscode 的一个插件, 检测无效空格的. 名字叫 Trailing Spaces
用 vscode 打开展示文件, 然后不要进行任何操作, 否则 vscode 会获取写权限, 这样程序就没办法更新文件了.
还有什么好玩的能写出来的吗?
接下来是代码, 大概思路就是, 把大楼, 电梯, 乘客分别封装成类, 包含属性和所有可能的动作. 执行文件中循环执行电梯运行逻辑, 并且电梯运行一次, 展示文件更新一次.
大楼
class mansion():
maximum_layer = None # 最高层数
minimum_layer = 1 # 最低层数
data = {} # 每层电梯情况
def __init__(self, maximum_layer, minimum_layer=None):
self.maximum_layer = maximum_layer
self.minimum_layer = minimum_layer if minimum_layer is not None else self.minimum_layer
self._init_data()
def _init_data(self):
'''初始化电梯具体数据'''
for i in range(self.minimum_layer, self.maximum_layer + 1):
if i != 0:
self.data.update({'%s' % (i): {'up': False, 'down': False}})
def add_task(self, layer, orientation):
'''乘客按电梯
将指定楼层的上状态或下状态设置开
'''
if orientation == 'up' or orientation == 'down':
self.data[str(layer)][orientation] = True
return True
else:
return False
def over_task(self, layer, orientation):
'''接到乘客
将指定楼层的上状态或下状态设置关
'''
if orientation == 'up' or orientation == 'down':
self.data[str(layer)][orientation] = False
return True
else:
return False
电梯
class elevator():
maximum_load = 460 # kg 最大载重
current_layer = 1 # 当前所在层数,初始化为1(电梯无0层)
passenger_number = 0 # 乘客数量,初始化为0
passenger_total_weight = 0 # 乘客总重量,初始化为0
move_task = {'up': set(), 'down': set()} # 移动任务,乘客需要到达的层数
move_orientation = 'up' # 移动方向
def __init__(self, maximum_load=None):
self.maximum_load = self.maximum_load if maximum_load is None else maximum_load
def check_mansion_data(self, mansion_obj):
'''检测大楼状态
若有新增的移动任务,则添加
'''
for key, value in mansion_obj.data.items():
if value['up'] is True:
self.move_task['up'].add(int(key))
if value['down'] is True:
self.move_task['down'].add(int(key))
def move_self(self, minimum_layer, maximum_layer):
'''移动自己
每一时间单位执行一次,移动一层
'''
if self.update_orientation() is False:
return
# 到达顶层没有停留,改变方向后向下了一格(找不到bug,无奈之举)
if maximum_layer == self.current_layer and self.move_orientation == 'up':
return
if minimum_layer == self.current_layer and self.move_orientation == 'down':
return
self.current_layer = self.current_layer + 1 if self.move_orientation == 'up' else self.current_layer - 1
if self.current_layer == 0:
self.current_layer = self.current_layer + 1 if self.move_orientation == 'up' else self.current_layer - 1
def add_move_task(self, passenger_obj):
'''乘客进入电梯完成后,添加移动任务'''
self.move_task[passenger_obj.orientation].add(passenger_obj.want_layer)
def check_overload(self, passenger_obj):
'''超载检测'''
if self.passenger_total_weight + passenger_obj.weight > self.maximum_load:
return False
else:
self.passenger_number += 1
self.passenger_total_weight += passenger_obj.weight
return True
def check_open_door(self, minimum_layer, maximum_layer):
'''检测是否开门(即停止)'''
try:
self.move_task[self.move_orientation].remove(self.current_layer)
# self.update_orientation()
return True
except BaseException:
# 不应该开门
return False
def remove_passenger(self, passenger_obj):
'''乘客到达'''
self.passenger_number -= 1
self.passenger_total_weight -= passenger_obj.weight
def update_orientation(self):
'''更新方向'''
temp = False
if self.move_orientation == 'up': # 检测向上任务中有没有大于我所在层数的
for i in (self.move_task['down'] | self.move_task['up']):
if int(i) > self.current_layer:
temp = True
break
elif self.move_orientation == 'down': # 检测向下任务中有没有小于我所在层数的
for i in (self.move_task['down'] | self.move_task['up']):
if int(i) < self.current_layer:
temp = True
break
if temp is False:
self.move_orientation = 'down' if self.move_orientation == 'up' else 'up'
return temp
乘客
import random
class passenger():
weight = None # 体重,40~100之间
current_layer = None # 当前所在层数
want_layer = None # 想要到达层数
orientation = None # 方向
status = False # 当前乘坐状态,False为等待中,True为乘坐中
def __init__(self, max_layer, min_layer, weight=None, current_layer=None, want_layer=None):
self.weight = self._random_weight() if weight is None else weight
self.current_layer = self._random_current_layer(min_layer, max_layer) if current_layer is None else current_layer
self.want_layer = self._random_want_layer(min_layer, max_layer) if want_layer is None else want_layer
self.orientation = 'up' if self.current_layer < self.want_layer else 'down'
def start_task(self):
'''开始任务
在大楼上按电梯按钮,这里只需要返回大楼对象要操作的楼层和上下方向即可
'''
return self.current_layer, 'up' if self.current_layer < self.want_layer else 'down'
def in_elevator(self):
'''进入电梯'''
self.status = True
def elevator_overload(self):
'''电梯超载
重新开始任务
'''
self.status = False
return self.start_task()
def whether_to_over(self, elevator_obj):
'''是否达到目的层数'''
if elevator_obj.current_layer == self.want_layer:
return True
else:
return False
def _random_weight(self):
'''随机生成体重
40~50公斤几率:20%
50~60公斤几率:35%
60~70公斤几率:30%
70~80公斤几率:10%
80~100公斤几率:5%
'''
weight_level = [0, 40, 50, 60, 70, 80, 100]
weight_level_random = [1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 5]
random.shuffle(weight_level_random)
return random.randint(weight_level[weight_level_random[0]], weight_level[weight_level_random[0] + 1])
def _random_current_layer(self, min_layer, max_layer):
'''随机生成所在楼层
1楼及其下楼层居多
'''
for i in range(min_layer, max_layer + 1):
if i == 0:
continue
if i <= 1:
if random.randint(0, 1) == 1:
return i
return random.randint(2, max_layer)
def _random_want_layer(self, min_layer, max_layer):
'''随机生成要去楼层(不与所在楼层相同)
根据所在楼层随机要求楼层,
1层和负层:若有负层,高层居多,负层少
高层:1层和负层居多,其他层少
'''
want_layer = 0
if self.current_layer <= 1:
want_layer = random.randint(min_layer, max_layer)
else:
if random.randint(0, 1) == 1:
want_layer = random.randint(2, max_layer)
else:
want_layer = random.randint(min_layer, 1)
if want_layer == 0 or want_layer == self.current_layer:
want_layer = self._random_want_layer(min_layer, max_layer)
return want_layer
参数
'''运行方式'''
RUN_MODE = 'auto' # manual or auto
'''运行间隔时间(自动模式生效)'''
UNIT_TIME = 2
'''楼层'''
MAXIMUM_LAYER = 7
MINIMUM_LAYER = 1
'''乘客生成概率'''
PGP = 2 # 最低为1,数值越大,概率越低
'''电梯最大载重'''
MAXIMUM_LOAD = 200 # None为默认载重
执行文件
import time
import random
import __init__
from element import mansion
from element import elevator
from element import passenger
# 大楼初始化
mansion_obj = mansion.mansion(__init__.MAXIMUM_LAYER, __init__.MINIMUM_LAYER)
# 电梯初始化
elevator_obj = elevator.elevator(__init__.MAXIMUM_LOAD)
# 乘客初始化
passenger_objs = dict()
# 开始运营
while(True):
if __init__.RUN_MODE == 'manual':
if input('请输入下一步指令:(N结束)') == 'N':
break
else:
time.sleep(__init__.UNIT_TIME)
elevator_obj.move_self(__init__.MINIMUM_LAYER, __init__.MAXIMUM_LAYER)
# 随机生成乘客
if random.randint(1, __init__.PGP) == 1:
passenger_obj = passenger.passenger(__init__.MAXIMUM_LAYER, __init__.MINIMUM_LAYER)
passenger_objs.update({str(time.time()): passenger_obj})
# 按按钮
layer, orientation = passenger_obj.start_task()
mansion_obj.add_task(layer, orientation)
# 电梯检索
elevator_obj.check_mansion_data(mansion_obj)
# 电梯移动,检测开门
pop_passenger_keys = []
if elevator_obj.check_open_door(__init__.MINIMUM_LAYER, __init__.MAXIMUM_LAYER) is True:
for key, i in passenger_objs.items():
if i.status is False: # 未上电梯
if i.current_layer == elevator_obj.current_layer: # 电梯到达当前所在楼层
if i.orientation == elevator_obj.move_orientation: # 方向相同
i.in_elevator() # 乘客上电梯
if elevator_obj.check_overload(i) is True: # 超载检测
elevator_obj.add_move_task(i) # 添加移动任务
mansion_obj.over_task(i.current_layer, i.orientation) # 大楼电梯按钮关闭
else:
layer, orientation = i.elevator_overload() # 超载,重新按电梯
mansion_obj.add_task(layer, orientation)
else: # 已上电梯
if i.whether_to_over(elevator_obj) is True: # 到达目的地
# 乘客下电梯
elevator_obj.remove_passenger(i)
pop_passenger_keys.append(key)
for key in pop_passenger_keys:
passenger_objs.pop(key)
elevator_obj.check_mansion_data(mansion_obj) # 电梯检索
# 动态打印
file_content = ''
for i in range(__init__.MAXIMUM_LAYER, __init__.MINIMUM_LAYER - 1, -1):
if i == 0:
continue
if i == elevator_obj.current_layer:
file_content += ' 电梯 '
else:
file_content += ' '
file_content += '%s ' % (i)
file_content += '%s' % (' ↓ ' if mansion_obj.data[str(i)]['down'] is True else ' ')
file_content += '%s' % (' ↑ ' if mansion_obj.data[str(i)]['up'] is True else ' ')
file_content += ' '
for key, value in passenger_objs.items():
if value.status is False and value.current_layer == i:
file_content += ' 人(%s) ' % (value.want_layer)
file_content += '\n'
# 电梯参数
file_content += '\n'
file_content += '电梯任务: %s\n电梯方向:%s\n' % (elevator_obj.move_task, elevator_obj.move_orientation)
file_content += '所在层:%s\n当前载重:%s\n' % (elevator_obj.current_layer, elevator_obj.passenger_total_weight)
file_content += '电梯乘客: '
for key, value in passenger_objs.items():
if value.status is True:
file_content += ' 人(%s) ' % (value.want_layer)
file_content += '\n'
# 乘客参数
file_content += '\n所有乘客:\n'
for key, value in passenger_objs.items():
file_content += '所在层:%s 达到层:%s 方向:%s ' % (value.current_layer, value.want_layer, value.orientation)
file_content += '乘坐状态:%s 体重:%s\n' % (value.status, value.weight)
# 保存到文件
with open('show.log', 'w+', encoding="utf-8") as f:
f.write(file_content)