fix downstairs

This commit is contained in:
Xuwznln
2025-09-28 20:23:11 +08:00
parent 16d2fec0ac
commit 6a3b312e41
6 changed files with 203 additions and 173 deletions

View File

@@ -72,7 +72,7 @@ class ElevatorAPIClient:
p95_wait_time=metrics_data.get("p95_wait", 0),
average_system_time=metrics_data.get("avg_system", 0),
p95_system_time=metrics_data.get("p95_system", 0),
total_energy_consumption=metrics_data.get("energy_total", 0),
# total_energy_consumption=metrics_data.get("energy_total", 0),
)
else:
metrics = PerformanceMetrics()
@@ -106,7 +106,20 @@ class ElevatorAPIClient:
if "error" not in response_data:
# 使用服务端返回的真实数据
events_data = response_data.get("events", [])
events = [SimulationEvent.from_dict(event) for event in events_data]
events = []
for event_data in events_data:
# 手动转换type字段从字符串到EventType枚举
event_dict = event_data.copy()
if "type" in event_dict and isinstance(event_dict["type"], str):
# 尝试将字符串转换为EventType枚举
try:
from elevator_saga.core.models import EventType
event_dict["type"] = EventType(event_dict["type"])
except ValueError:
debug_log(f"Unknown event type: {event_dict['type']}")
continue
events.append(SimulationEvent.from_dict(event_dict))
step_response = StepResponse(
success=True,
@@ -122,7 +135,7 @@ class ElevatorAPIClient:
def send_elevator_command(self, command: Union[GoToFloorCommand, SetIndicatorsCommand]) -> bool:
"""发送电梯命令"""
endpoint = self._get_elevator_endpoint(command)
debug_log(f"Sending elevator command: {command.command_type} to elevator {command.elevator_id}")
debug_log(f"Sending elevator command: {command.command_type} to elevator {command.elevator_id} To:F{command.floor}")
response_data = self._send_post_request(endpoint, command.parameters)
@@ -191,10 +204,10 @@ class ElevatorAPIClient:
debug_log(f"Reset failed: {e}")
return False
def next_traffic_round(self) -> bool:
def next_traffic_round(self, full_reset = False) -> bool:
"""切换到下一个流量文件"""
try:
response_data = self._send_post_request("/api/traffic/next", {})
response_data = self._send_post_request("/api/traffic/next", {"full_reset": full_reset})
success = response_data.get("success", False)
if success:
# 清空缓存,因为流量文件已切换,状态会改变
@@ -211,7 +224,6 @@ class ElevatorAPIClient:
"""获取当前流量文件信息"""
try:
response_data = self._send_get_request("/api/traffic/info")
debug_log(str())
if "error" not in response_data:
return response_data
else:
@@ -231,7 +243,7 @@ class ElevatorAPIClient:
req = urllib.request.Request(url, data=request_body, headers={"Content-Type": "application/json"})
try:
with urllib.request.urlopen(req, timeout=60) as response:
with urllib.request.urlopen(req, timeout=600) as response:
response_data = json.loads(response.read().decode("utf-8"))
# debug_log(f"POST {url} -> {response.status}")
return response_data

View File

@@ -3,6 +3,8 @@
Elevator Controller Base Class
电梯调度基础控制器类 - 提供面向对象的算法开发接口
"""
import os
import time
from abc import ABC, abstractmethod
from pprint import pprint
from typing import Any, Dict, List, Optional
@@ -34,9 +36,9 @@ class ElevatorController(ABC):
self.debug = debug
self.elevators: List[Any] = []
self.floors: List[Any] = []
self.current_tick = -2
self.current_tick = 0
self.is_running = False
self.current_traffic_max_tick: Optional[int] = None
self.current_traffic_max_tick: int = 0
# 初始化API客户端
self.api_client = ElevatorAPIClient(server_url)
@@ -91,7 +93,7 @@ class ElevatorController(ABC):
print(f"停止 {self.__class__.__name__} 算法")
@abstractmethod
def on_passenger_call(self, floor: ProxyFloor, direction: str):
def on_passenger_call(self, passenger: ProxyPassenger, floor: ProxyFloor, direction: str):
"""
乘客呼叫时的回调 - 可选实现
@@ -125,7 +127,7 @@ class ElevatorController(ABC):
@abstractmethod
def on_passenger_board(self, elevator: ProxyElevator, passenger: ProxyPassenger):
"""
乘客上时的回调 - 可选实现
乘客上时的回调 - 可选实现
Args:
elevator: 电梯代理对象
@@ -173,7 +175,7 @@ class ElevatorController(ABC):
"""内部初始化方法"""
self.elevators = elevators
self.floors = floors
self.current_tick = -2
self.current_tick = 0
# 调用用户的初始化方法
self.on_init(elevators, floors)
@@ -213,25 +215,37 @@ class ElevatorController(ABC):
def _run_event_driven_simulation(self):
"""运行事件驱动的模拟"""
try:
# 获取初始状态并初始化
state = self.api_client.get_state()
# 获取初始状态并初始化默认从0开始
try:
state = self.api_client.get_state()
except ConnectionResetError as ex:
print(f"模拟器可能并没有开启,请检查模拟器是否启动 {self.api_client.base_url}")
os._exit(1)
if state.tick > 0:
print("模拟器可能已经开始了一次模拟,执行重置...")
self.api_client.reset()
time.sleep(0.3)
return self._run_event_driven_simulation()
self._update_wrappers(state, init=True)
# 获取当前流量文件的最大tick数
self._update_traffic_info()
if self.current_tick >= self.current_traffic_max_tick:
return
if self.current_traffic_max_tick == 0:
print("模拟器接收到的最大tick时间为0可能所有的测试案例已用完请求重置...")
self.api_client.next_traffic_round(full_reset=True)
time.sleep(0.3)
return self._run_event_driven_simulation()
# if self.current_tick >= self.current_traffic_max_tick:
# return
self._internal_init(self.elevators, self.floors)
tick_count = 0
self.api_client.mark_tick_processed()
while self.is_running:
# 检查是否达到最大tick数
if tick_count >= self.current_traffic_max_tick:
if self.current_tick >= self.current_traffic_max_tick:
break
# 执行一个tick的模拟
# 执行一个tick的模拟从1开始
step_response = self.api_client.step(1)
# 更新当前状态
self.current_tick = step_response.tick
@@ -256,28 +270,21 @@ class ElevatorController(ABC):
# 事件执行后回调
self.on_event_execute_end(self.current_tick, events, self.elevators, self.floors)
# 标记tick处理完成使API客户端缓存失效
self.api_client.mark_tick_processed()
tick_count += 1
# 检查是否需要切换流量文件
if self.current_tick >= self.current_traffic_max_tick:
pprint(state.metrics.to_dict())
if not self.api_client.next_traffic_round():
# 如果没有更多流量文件,退出
break
# 重置并重新初始化
self._reset_and_reinit()
tick_count = 0
except Exception as e:
print(f"模拟运行错误: {e}")
raise
def _update_wrappers(self, state: SimulationState, init=False) -> None:
def _update_wrappers(self, state: SimulationState, init: bool = False) -> None:
"""更新电梯和楼层代理对象"""
self.current_tick = state.tick
# 检查电梯数量是否发生变化,只有变化时才重新创建
@@ -301,42 +308,46 @@ class ElevatorController(ABC):
debug_log(f"Updated traffic info - max_tick: {self.current_traffic_max_tick}")
else:
debug_log("Failed to get traffic info")
self.current_traffic_max_tick = None
self.current_traffic_max_tick = 0
except Exception as e:
debug_log(f"Error updating traffic info: {e}")
self.current_traffic_max_tick = None
self.current_traffic_max_tick = 0
def _handle_single_event(self, event: SimulationEvent):
"""处理单个事件"""
if event.type == EventType.UP_BUTTON_PRESSED.value:
floor_id = event.data.get("floor")
if event.type == EventType.UP_BUTTON_PRESSED:
floor_id = event.data["floor"]
passenger_id = event.data["passenger"]
if floor_id is not None:
floor_proxy = ProxyFloor(floor_id, self.api_client)
self.on_passenger_call(floor_proxy, "up")
passenger_proxy = ProxyPassenger(passenger_id, self.api_client)
self.on_passenger_call(passenger_proxy, floor_proxy, "up")
elif event.type == EventType.DOWN_BUTTON_PRESSED.value:
floor_id = event.data.get("floor")
elif event.type == EventType.DOWN_BUTTON_PRESSED:
floor_id = event.data["floor"]
passenger_id = event.data["passenger"]
if floor_id is not None:
floor_proxy = ProxyFloor(floor_id, self.api_client)
self.on_passenger_call(floor_proxy, "down")
passenger_proxy = ProxyPassenger(passenger_id, self.api_client)
self.on_passenger_call(passenger_proxy, floor_proxy, "down")
elif event.type == EventType.STOPPED_AT_FLOOR.value:
elif event.type == EventType.STOPPED_AT_FLOOR:
elevator_id = event.data.get("elevator")
floor_id = event.data.get("floor")
floor_id = event.data["floor"]
if elevator_id is not None and floor_id is not None:
elevator_proxy = ProxyElevator(elevator_id, self.api_client)
floor_proxy = ProxyFloor(floor_id, self.api_client)
self.on_elevator_stopped(elevator_proxy, floor_proxy)
elif event.type == EventType.IDLE.value:
elif event.type == EventType.IDLE:
elevator_id = event.data.get("elevator")
if elevator_id is not None:
elevator_proxy = ProxyElevator(elevator_id, self.api_client)
self.on_elevator_idle(elevator_proxy)
elif event.type == EventType.PASSING_FLOOR.value:
elif event.type == EventType.PASSING_FLOOR:
elevator_id = event.data.get("elevator")
floor_id = event.data.get("floor")
floor_id = event.data["floor"]
direction = event.data.get("direction")
if elevator_id is not None and floor_id is not None and direction is not None:
elevator_proxy = ProxyElevator(elevator_id, self.api_client)
@@ -345,9 +356,9 @@ class ElevatorController(ABC):
direction_str = direction if isinstance(direction, str) else direction.value
self.on_elevator_passing_floor(elevator_proxy, floor_proxy, direction_str)
elif event.type == EventType.ELEVATOR_APPROACHING.value:
elif event.type == EventType.ELEVATOR_APPROACHING:
elevator_id = event.data.get("elevator")
floor_id = event.data.get("floor")
floor_id = event.data["floor"]
direction = event.data.get("direction")
if elevator_id is not None and floor_id is not None and direction is not None:
elevator_proxy = ProxyElevator(elevator_id, self.api_client)
@@ -356,7 +367,7 @@ class ElevatorController(ABC):
direction_str = direction if isinstance(direction, str) else direction.value
self.on_elevator_approaching(elevator_proxy, floor_proxy, direction_str)
elif event.type == EventType.PASSENGER_BOARD.value:
elif event.type == EventType.PASSENGER_BOARD:
elevator_id = event.data.get("elevator")
passenger_id = event.data.get("passenger")
if elevator_id is not None and passenger_id is not None:
@@ -364,10 +375,10 @@ class ElevatorController(ABC):
passenger_proxy = ProxyPassenger(passenger_id, self.api_client)
self.on_passenger_board(elevator_proxy, passenger_proxy)
elif event.type == EventType.PASSENGER_ALIGHT.value:
elif event.type == EventType.PASSENGER_ALIGHT:
elevator_id = event.data.get("elevator")
passenger_id = event.data.get("passenger")
floor_id = event.data.get("floor")
floor_id = event.data["floor"]
if elevator_id is not None and passenger_id is not None and floor_id is not None:
elevator_proxy = ProxyElevator(elevator_id, self.api_client)
passenger_proxy = ProxyPassenger(passenger_id, self.api_client)
@@ -379,7 +390,7 @@ class ElevatorController(ABC):
try:
# 重置服务器状态
self.api_client.reset()
self.current_tick = 0
# 获取新的初始状态
state = self.api_client.get_state()
self._update_wrappers(state)