use std::collections::HashMap;
use std::sync::{Arc, RwLock};
#[derive(Debug, Clone)]
pub struct Scenario {
pub id: String,
pub description: String,
pub actions: Vec<String>,
pub outcome_probability: f32,
pub risk_score: f32,
pub reward_potential: f32,
}
const MAX_SCENARIOS: usize = 100;
pub struct MentalSandbox {
scenarios: Arc<RwLock<HashMap<String, Scenario>>>,
current_simulation: Arc<RwLock<Option<String>>>,
long_term_goals: Vec<String>,
}
impl Default for MentalSandbox {
fn default() -> Self {
Self::new()
}
}
impl MentalSandbox {
pub fn new() -> Self {
Self {
scenarios: Arc::new(RwLock::new(HashMap::new())),
current_simulation: Arc::new(RwLock::new(None)),
long_term_goals: Vec::new(),
}
}
pub fn add_goal(&mut self, goal: &str) {
self.long_term_goals.push(goal.to_string());
}
pub fn simulate_scenario(&self, description: &str, actions: Vec<&str>) -> Scenario {
let id = format!("scenario_{}", rand::random::<u32>());
let goal_alignment = self.calculate_goal_alignment(description);
let complexity_factor = actions.len() as f32 * 0.1;
let scenario = Scenario {
id: id.clone(),
description: description.to_string(),
actions: actions.iter().map(|s| s.to_string()).collect(),
outcome_probability: 0.7, risk_score: (1.0 - goal_alignment) * complexity_factor,
reward_potential: goal_alignment * (1.0 - complexity_factor.min(1.0)),
};
let mut scenarios = crate::sync_guard::write_lock(&self.scenarios);
scenarios.insert(id.clone(), scenario.clone());
if scenarios.len() > MAX_SCENARIOS {
let excess = scenarios.len() - MAX_SCENARIOS;
let keys: Vec<String> = scenarios.keys().take(excess).cloned().collect();
for k in keys {
scenarios.remove(&k);
}
}
let mut current = crate::sync_guard::write_lock(&self.current_simulation);
*current = Some(id);
scenario
}
fn calculate_goal_alignment(&self, description: &str) -> f32 {
if self.long_term_goals.is_empty() {
return 0.5; }
let keywords = description.to_lowercase();
let mut matches = 0.0;
for goal in &self.long_term_goals {
let goal_lower = goal.to_lowercase();
if keywords.contains(&goal_lower) {
matches += 1.0;
}
}
matches / self.long_term_goals.len() as f32
}
pub fn get_best_scenario(&self) -> Option<Scenario> {
let scenarios = crate::sync_guard::read_lock(&self.scenarios);
scenarios
.values()
.max_by(|a, b| {
let a_score = a.reward_potential / (a.risk_score + 0.01);
let b_score = b.reward_potential / (b.risk_score + 0.01);
a_score.total_cmp(&b_score)
})
.cloned()
}
pub fn clear(&mut self) {
crate::sync_guard::write_lock(&self.scenarios).clear();
*crate::sync_guard::write_lock(&self.current_simulation) = None;
}
}
pub fn run_parallel_simulations(
sandbox: &MentalSandbox,
scenario_descriptions: &[(&str, Vec<&str>)],
) -> Vec<Scenario> {
scenario_descriptions
.iter()
.map(|(desc, actions)| sandbox.simulate_scenario(desc, actions.clone()))
.collect()
}