Files
Elevator/docs/models.rst
2025-10-01 17:23:30 +08:00

348 lines
9.2 KiB
ReStructuredText

Data Models
===========
The Elevator Saga system uses a unified data model architecture defined in ``elevator_saga/core/models.py``. These models ensure type consistency and serialization between the client and server components.
Overview
--------
All data models inherit from ``SerializableModel``, which provides:
- **to_dict()**: Convert model to dictionary
- **to_json()**: Convert model to JSON string
- **from_dict()**: Create model instance from dictionary
- **from_json()**: Create model instance from JSON string
This unified serialization approach ensures seamless data exchange over HTTP between client and server.
Core Enumerations
-----------------
Direction
~~~~~~~~~
Represents the direction of elevator movement or passenger travel:
.. code-block:: python
class Direction(Enum):
UP = "up" # Moving upward
DOWN = "down" # Moving downward
STOPPED = "stopped" # Not moving
ElevatorStatus
~~~~~~~~~~~~~~
Represents the elevator's operational state in the state machine:
.. code-block:: python
class ElevatorStatus(Enum):
START_UP = "start_up" # Acceleration phase
START_DOWN = "start_down" # Deceleration phase
CONSTANT_SPEED = "constant_speed" # Constant speed phase
STOPPED = "stopped" # Stopped at floor
**Important**: ``START_UP`` and ``START_DOWN`` refer to **acceleration/deceleration states**, not movement direction. The actual movement direction is determined by the ``target_floor_direction`` property.
State Machine Transition:
.. code-block:: text
STOPPED → START_UP → CONSTANT_SPEED → START_DOWN → STOPPED
1 tick 1 tick N ticks 1 tick
PassengerStatus
~~~~~~~~~~~~~~~
Represents the passenger's current state:
.. code-block:: python
class PassengerStatus(Enum):
WAITING = "waiting" # Waiting at origin floor
IN_ELEVATOR = "in_elevator" # Inside an elevator
COMPLETED = "completed" # Reached destination
CANCELLED = "cancelled" # Cancelled (unused)
EventType
~~~~~~~~~
Defines all possible simulation events:
.. code-block:: python
class EventType(Enum):
UP_BUTTON_PRESSED = "up_button_pressed"
DOWN_BUTTON_PRESSED = "down_button_pressed"
PASSING_FLOOR = "passing_floor"
STOPPED_AT_FLOOR = "stopped_at_floor"
ELEVATOR_APPROACHING = "elevator_approaching"
IDLE = "idle"
PASSENGER_BOARD = "passenger_board"
PASSENGER_ALIGHT = "passenger_alight"
Core Data Models
----------------
Position
~~~~~~~~
Represents elevator position with sub-floor granularity:
.. code-block:: python
@dataclass
class Position(SerializableModel):
current_floor: int = 0 # Current floor number
target_floor: int = 0 # Target floor number
floor_up_position: int = 0 # Position within floor (0-9)
- **floor_up_position**: Represents position between floors with 10 units per floor
- **current_floor_float**: Returns floating-point floor position (e.g., 2.5 = halfway between floors 2 and 3)
Example:
.. code-block:: python
position = Position(current_floor=2, floor_up_position=5)
print(position.current_floor_float) # 2.5
ElevatorState
~~~~~~~~~~~~~
Complete state information for an elevator:
.. code-block:: python
@dataclass
class ElevatorState(SerializableModel):
id: int
position: Position
next_target_floor: Optional[int] = None
passengers: List[int] = [] # Passenger IDs
max_capacity: int = 10
speed_pre_tick: float = 0.5
run_status: ElevatorStatus = ElevatorStatus.STOPPED
last_tick_direction: Direction = Direction.STOPPED
indicators: ElevatorIndicators = field(default_factory=ElevatorIndicators)
passenger_destinations: Dict[int, int] = {} # passenger_id -> floor
energy_consumed: float = 0.0
last_update_tick: int = 0
Key Properties:
- ``current_floor``: Integer floor number
- ``current_floor_float``: Precise position including sub-floor
- ``target_floor``: Destination floor
- ``target_floor_direction``: Direction to target (UP/DOWN/STOPPED)
- ``is_idle``: Whether elevator is stopped
- ``is_full``: Whether elevator is at capacity
- ``is_running``: Whether elevator is in motion
- ``pressed_floors``: List of destination floors for current passengers
- ``load_factor``: Current load as fraction of capacity (0.0 to 1.0)
FloorState
~~~~~~~~~~
State information for a building floor:
.. code-block:: python
@dataclass
class FloorState(SerializableModel):
floor: int
up_queue: List[int] = [] # Passenger IDs waiting to go up
down_queue: List[int] = [] # Passenger IDs waiting to go down
Properties:
- ``has_waiting_passengers``: Whether any passengers are waiting
- ``total_waiting``: Total number of waiting passengers
PassengerInfo
~~~~~~~~~~~~~
Complete information about a passenger:
.. code-block:: python
@dataclass
class PassengerInfo(SerializableModel):
id: int
origin: int # Starting floor
destination: int # Target floor
arrive_tick: int # When passenger appeared
pickup_tick: int = 0 # When passenger boarded elevator
dropoff_tick: int = 0 # When passenger reached destination
elevator_id: Optional[int] = None
Properties:
- ``status``: Current PassengerStatus
- ``wait_time``: Ticks waited before boarding
- ``system_time``: Total ticks in system (arrive to dropoff)
- ``travel_direction``: UP/DOWN based on origin and destination
SimulationState
~~~~~~~~~~~~~~~
Complete state of the simulation:
.. code-block:: python
@dataclass
class SimulationState(SerializableModel):
tick: int
elevators: List[ElevatorState]
floors: List[FloorState]
passengers: Dict[int, PassengerInfo]
metrics: PerformanceMetrics
events: List[SimulationEvent]
Helper Methods:
- ``get_elevator_by_id(id)``: Find elevator by ID
- ``get_floor_by_number(number)``: Find floor by number
- ``get_passengers_by_status(status)``: Filter passengers by status
- ``add_event(type, data)``: Add new event to queue
Traffic and Configuration
-------------------------
TrafficEntry
~~~~~~~~~~~~
Defines a single passenger arrival:
.. code-block:: python
@dataclass
class TrafficEntry(SerializableModel):
id: int
origin: int
destination: int
tick: int # When passenger arrives
TrafficPattern
~~~~~~~~~~~~~~
Collection of traffic entries defining a test scenario:
.. code-block:: python
@dataclass
class TrafficPattern(SerializableModel):
name: str
description: str
entries: List[TrafficEntry]
metadata: Dict[str, Any]
Properties:
- ``total_passengers``: Number of passengers in pattern
- ``duration``: Tick when last passenger arrives
Performance Metrics
-------------------
PerformanceMetrics
~~~~~~~~~~~~~~~~~~
Tracks simulation performance:
.. code-block:: python
@dataclass
class PerformanceMetrics(SerializableModel):
completed_passengers: int = 0
total_passengers: int = 0
average_wait_time: float = 0.0
p95_wait_time: float = 0.0 # 95th percentile
average_system_time: float = 0.0
p95_system_time: float = 0.0 # 95th percentile
Properties:
- ``completion_rate``: Fraction of passengers completed (0.0 to 1.0)
API Models
----------
The models also include HTTP API request/response structures:
- ``APIRequest``: Base request with ID and timestamp
- ``APIResponse``: Base response with success flag
- ``StepRequest/StepResponse``: Advance simulation time
- ``StateRequest``: Query simulation state
- ``ElevatorCommand``: Send command to elevator
- ``GoToFloorCommand``: Specific command to move elevator
Example Usage
-------------
Creating a Simulation State
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: python
from elevator_saga.core.models import (
create_empty_simulation_state,
ElevatorState,
Position,
)
# Create a building with 3 elevators, 10 floors, capacity 8
state = create_empty_simulation_state(
elevators=3,
floors=10,
max_capacity=8
)
# Access elevator state
elevator = state.elevators[0]
print(f"Elevator {elevator.id} at floor {elevator.current_floor}")
Working with Traffic Patterns
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: python
from elevator_saga.core.models import (
create_simple_traffic_pattern,
TrafficPattern,
)
# Create traffic pattern: (origin, destination, tick)
pattern = create_simple_traffic_pattern(
name="morning_rush",
passengers=[
(0, 5, 10), # Floor 0→5 at tick 10
(0, 8, 15), # Floor 0→8 at tick 15
(2, 0, 20), # Floor 2→0 at tick 20
]
)
print(f"Pattern has {pattern.total_passengers} passengers")
print(f"Duration: {pattern.duration} ticks")
Serialization
~~~~~~~~~~~~~
All models support JSON serialization:
.. code-block:: python
# Serialize to JSON
elevator = state.elevators[0]
json_str = elevator.to_json()
# Deserialize from JSON
restored = ElevatorState.from_json(json_str)
# Or use dictionaries
data = elevator.to_dict()
restored = ElevatorState.from_dict(data)
This enables seamless transmission over HTTP between client and server.