mirror of
https://github.com/ZGCA-Forge/Elevator.git
synced 2026-02-04 21:35:17 +00:00
fix downstairs
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user