Source code for models.boat
"""Boat model for the electric recreational port simulator."""
from dataclasses import dataclass, field
from enum import Enum
[docs]
class BoatState(Enum):
"""Boat state: idle, charging, or sailing."""
IDLE = "idle"
CHARGING = "charging"
SAILING = "sailing"
[docs]
@dataclass
class Boat:
"""
Electric boat at the port.
Attributes:
motor_power: Motor power (kW).
weight: Weight (kg).
length: Length (m).
battery_capacity: Battery capacity (kWh).
range_speed: Range speed (knots).
soc: State of charge in [0, 1]; default 1.0 (full).
name: Identifier; auto-generated as Boat_N if empty.
_state: Internal state (BoatState); use .state property.
"""
motor_power: int
weight: float
length: float
battery_capacity: float
range_speed: float
soc: float = 1.0
name: str = ""
_state: BoatState = field(default=BoatState.IDLE, init=False)
_boat_count: int = field(default=0, init=False, repr=False)
def __post_init__(self):
"""Validate attributes and set default name if empty."""
if not self.name:
Boat._boat_count = getattr(Boat, "_boat_count", 0) + 1
self.name = f"Boat_{Boat._boat_count}"
if self.motor_power <= 0:
raise ValueError("Motor power must be positive")
if self.weight <= 0:
raise ValueError("Weight must be positive")
if self.length <= 0:
raise ValueError("Length must be positive")
if self.battery_capacity <= 0:
raise ValueError("Battery capacity must be positive")
if self.range_speed <= 0:
raise ValueError("Range speed must be positive")
if not 0 <= self.soc <= 1:
raise ValueError("SOC must be between 0 and 1")
@property
def k(self) -> float:
"""Return k-factor for cube law: motor_power / range_speed^3 (used in trip energy estimates)."""
return self.motor_power / (self.range_speed**3)
@property
def state(self) -> BoatState:
"""Current boat state."""
return self._state
@state.setter
def state(self, new_state: BoatState):
"""Set boat state; new_state must be a BoatState enum."""
if not isinstance(new_state, BoatState):
raise ValueError(f"State must be a BoatState enum, got {type(new_state)}")
self._state = new_state
def __repr__(self) -> str:
return (
f"Boat(name='{self.name}', motor_power={self.motor_power}kW, "
f"battery={self.battery_capacity}kWh, soc={self.soc:.1%}, "
f"state={self.state.value})"
)