import uuid import logging from typing import Any, Callable, Dict, List, Union log = logging.getLogger(__name__) MorphologyType = Union[str, Callable[[str], List[Dict[str, Any]]]] def generate_id() -> str: return uuid.uuid4().hex def get_InitSensor(morphology: MorphologyType): sensors = get_Sensors(morphology) if not sensors: log.error("Morphology has no sensors.") raise ValueError("Morphology has no sensors.") return [sensors[0]] def get_InitActuator(morphology: MorphologyType): actuators = get_Actuators(morphology) if not actuators: log.error("Morphology has no actuators.") raise ValueError("Morphology has no actuators.") return [actuators[0]] def get_Sensors(morphology: MorphologyType) -> List[Dict[str, Any]]: fn = _resolve_morphology(morphology) return fn("sensors") def get_Actuators(morphology: MorphologyType) -> List[Dict[str, Any]]: fn = _resolve_morphology(morphology) return fn("actuators") def _resolve_morphology(morphology: MorphologyType) -> Callable[[str], List[Dict[str, Any]]]: if callable(morphology): return morphology if isinstance(morphology, str): reg = { "xor_mimic": xor_mimic, "car_racing_features": car_racing_features } if morphology in reg: return reg[morphology] log.error(f"Unknown morphology name: {morphology}") raise ValueError(f"Unknown morphology name: {morphology}") try: if hasattr(morphology, "xor_mimic") and callable(getattr(morphology, "xor_mimic")): return getattr(morphology, "xor_mimic") except Exception: pass log.error("morphology must be a callable, a module with 'xor_mimic', or a registered string key") raise TypeError("morphology must be a callable, a module with 'xor_mimic', or a registered string key") def xor_mimic(kind: str) -> List[Dict[str, Any]]: if kind == "sensors": return [ { "name": "xor_GetInput", "vector_length": 2, "scape": "xor_sim" } ] elif kind == "actuators": return [ { "name": "xor_SendOutput", "vector_length": 1, "scape": "xor_sim" } ] else: log.error(f"xor_mimic: unsupported kind '{kind}', expected 'sensors' or 'actuators'") raise ValueError(f"xor_mimic: unsupported kind '{kind}', expected 'sensors' or 'actuators'") def car_racing_features(kind: str) -> List[Dict[str, Any]]: """ car racing morphology """ LOOK_AHEAD = 10 feature_len = LOOK_AHEAD + 6 if kind == "sensors": return [ { "name": "car_GetFeatures", "vector_length": feature_len, "scape": "car_racing" } ] elif kind == "actuators": return [ { "name": "car_ApplyAction", "vector_length": 3, "scape": "car_racing" } ] else: log.error(f"car_racing_features: unsupported kind '{kind}', expected 'sensors' or 'actuators'") raise ValueError("car_racing_features: kind must be 'sensors' or 'actuators'")