use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::Path;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnvironmentCatalog {
pub version: String,
pub environments: Vec<Environment>,
#[serde(default)]
pub tags: HashMap<String, String>,
#[serde(default)]
pub difficulty_levels: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Environment {
pub id: String,
pub path: String,
pub name: String,
pub description: String,
pub tags: Vec<String>,
pub required_sensors: Vec<String>,
#[serde(default)]
pub optional_sensors: Vec<String>,
pub robot_platforms: Vec<String>,
#[serde(default)]
pub task_nodes: Vec<String>,
pub difficulty: String,
#[serde(default)]
pub dimensions: Vec<f32>,
#[serde(default)]
pub features: EnvironmentFeatures,
#[serde(default)]
pub curriculum_stage: i32,
#[serde(default)]
pub estimated_duration_s: i32,
#[serde(default)]
pub reward_config: HashMap<String, f32>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct EnvironmentFeatures {
#[serde(default)]
pub floor: bool,
#[serde(default)]
pub walls: bool,
#[serde(default)]
pub obstacles: String,
#[serde(default)]
pub obstacle_count: i32,
#[serde(default)]
pub tables: i32,
#[serde(default)]
pub waypoints: i32,
#[serde(default)]
pub goal_zones: i32,
#[serde(default)]
pub npcs: bool,
#[serde(default)]
pub npc_count: i32,
#[serde(default)]
pub dynamic: bool,
}
impl EnvironmentCatalog {
pub fn load_default(robot_tasks_dir: &Path) -> Result<Self> {
Self::load(&robot_tasks_dir.join("catalog.json"))
}
pub fn load(path: &Path) -> Result<Self> {
super::load_json(path, "catalog file")
}
}
impl Environment {
pub fn is_compatible_with_sensors(&self, sensors: &[String]) -> bool {
self.required_sensors.iter().all(|required| sensors.contains(required))
}
pub fn is_compatible_with_platform(&self, platform: &str) -> bool {
self.robot_platforms.contains(&platform.to_string())
}
}