mirror of
https://github.com/ZGCA-Forge/Elevator.git
synced 2026-02-04 21:35:17 +00:00
Add tests and docs
This commit is contained in:
347
docs/models.rst
Normal file
347
docs/models.rst
Normal file
@@ -0,0 +1,347 @@
|
||||
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.
|
||||
Reference in New Issue
Block a user