3. 电梯控制器
任务目标
实现一个电梯控制器的有限状态机(FSM),管理空闲、运行、开门、关门四个核心状态,并响应外部楼层请求与内部指令。电梯在空闲时等待请求,收到请求后运行至目标楼层,到达后自动开门,延时后关门并回到空闲。
状态定义与转移逻辑
| 当前状态 | 触发事件 | 动作 | 下一状态 |
|---|---|---|---|
| IDLE(空闲) | request(floor) | 记录目标楼层,开始移动 | MOVING(运行) |
| MOVING(运行) | 到达目标楼层 | 停止,开门 | DOOR_OPEN(开门) |
| DOOR_OPEN(开门) | 延时结束(3秒) | 关门 | DOOR_CLOSED(关门) |
| DOOR_CLOSED(关门) | 关门完成 | 清空目标,回到待命 | IDLE(空闲) |
若电梯在MOVING状态收到新请求,仅当新楼层与当前运行方向一致且更近时更新目标;否则暂存请求,待空闲后处理。
完整实现(Python)
from enum import Enum
import time
class State(Enum):
IDLE = 1
MOVING = 2
DOOR_OPEN = 3
DOOR_CLOSED = 4
class ElevatorFSM:
def __init__(self, start_floor=1):
self.state = State.IDLE
self.current_floor = start_floor
self.target_floor = None
self.pending_floors = set()
self.door_open_time = 3 # 秒
def request(self, floor):
"""外部或内部请求电梯到指定楼层"""
if floor == self.current_floor:
return # 已在当前楼层,无需响应
if self.state == State.IDLE:
self.target_floor = floor
self.state = State.MOVING
print(f"请求楼层 {floor},电梯从 {self.current_floor} 出发")
elif self.state == State.MOVING:
# 同方向且更近则更新目标,否则暂存
if self._is_on_way(floor):
self.target_floor = floor
print(f"更新目标楼层为 {floor}")
else:
self.pending_floors.add(floor)
print(f"暂存请求楼层 {floor}")
else:
# 开门或关门中,暂存请求
self.pending_floors.add(floor)
print(f"暂存请求楼层 {floor}")
def _is_on_way(self, floor):
"""判断新请求是否在当前运行路径上"""
if self.target_floor is None:
return False
direction = 1 if self.target_floor > self.current_floor else -1
return (floor - self.current_floor) * direction > 0
def tick(self):
"""模拟一个时间步的推进"""
if self.state == State.MOVING:
# 向目标楼层移动一层
step = 1 if self.target_floor > self.current_floor else -1
self.current_floor += step
print(f"运行中,当前楼层 {self.current_floor}")
if self.current_floor == self.target_floor:
self.state = State.DOOR_OPEN
print("到达目标楼层,开门")
elif self.state == State.DOOR_OPEN:
# 模拟延时后自动关门
time.sleep(self.door_open_time)
self.state = State.DOOR_CLOSED
print("关门")
elif self.state == State.DOOR_CLOSED:
self.state = State.IDLE
self.target_floor = None
print("关门完成,回到空闲")
# 处理暂存请求
if self.pending_floors:
next_floor = self.pending_floors.pop()
self.request(next_floor)
def run_until_idle(self, max_steps=100):
"""驱动电梯运行直到回到空闲状态"""
steps = 0
while self.state != State.IDLE and steps < max_steps:
self.tick()
steps += 1
return self.state == State.IDLE
# 最小验证闭环
if __name__ == "__main__":
# 场景1:单次请求
print("=== 场景1:从1楼到5楼 ===")
e = ElevatorFSM(start_floor=1)
e.request(5)
e.run_until_idle()
assert e.current_floor == 5, "电梯应停在5楼"
assert e.state == State.IDLE, "电梯应回到空闲"
print("场景1通过\n")
# 场景2:运行中收到同向更近请求
print("=== 场景2:从1楼到5楼,途中收到3楼请求 ===")
e = ElevatorFSM(start_floor=1)
e.request(5)
e.tick() # 到2楼
e.request(3) # 同向更近,应更新目标
e.run_until_idle()
assert e.current_floor == 3, "电梯应停在3楼"
print("场景2通过\n")
# 场景3:运行中收到反向请求,暂存后处理
print("=== 场景3:从1楼到5楼,途中收到2楼请求(反向) ===")
e = ElevatorFSM(start_floor=1)
e.request(5)
e.tick() # 到2楼
e.tick() # 到3楼
e.request(2) # 反向,应暂存
e.run_until_idle()
assert e.current_floor == 2, "电梯最终应处理暂存请求到2楼"
print("场景3通过\n")
print("所有验证场景通过")
运行方式
python elevator_fsm.py
验证方法与判定标准
- 场景1:电梯从1楼出发,运行至5楼后开门、关门、回到空闲。控制台输出应依次显示“请求楼层 5”“运行中…”“到达目标楼层,开门”“关门”“关门完成,回到空闲”。
- 场景2:电梯在去5楼途中(2楼时)收到3楼请求,因同向且更近,目标更新为3楼,最终停在3楼。
- 场景3:电梯在去5楼途中(3楼时)收到2楼请求,因反向被暂存;完成5楼任务回到空闲后,自动处理暂存请求,最终停在2楼。
- 程序退出码为0且打印“所有验证场景通过”即判定实现正确。
关键设计说明
本实现采用时间步推进(tick())模拟电梯逐层移动,而非真实时间驱动,便于确定性验证。开门延时使用time.sleep模拟,实际工程中应替换为定时器回调。状态转移完全由tick()和request()触发,无外部直接修改状态字段,保证状态机封装性。