mod baselines;
mod patterns;
mod runner;
mod scenarios;
mod trajectory_runner;
use baselines::{EmotionModulatedStrategy, FixedPriorityStrategy, RandomSelectionStrategy};
use oxyde::oxyde_game::behavior::{
AggressiveBehavior, CautiousBehavior, FleeBehavior, FriendlyBehavior, JoyfulBehavior,
NeutralGreetingBehavior, ConfusedBehavior, PoliteDeclineBehavior,
ThoughtfulPauseBehavior, DefaultAcknowledgeBehavior,
};
use std::fs;
use std::path::Path;
use std::sync::Arc;
#[tokio::main]
async fn main() -> oxyde::Result<()> {
env_logger::init();
println!("==================================================");
println!("EXTENDED TRAJECTORY STUDY");
println!("Emotional Memory and Character Development");
println!("==================================================\n");
let strategies = vec![
Box::new(EmotionModulatedStrategy) as Box<dyn baselines::SelectionStrategy>,
Box::new(FixedPriorityStrategy),
Box::new(RandomSelectionStrategy),
];
let behaviors = vec![
Arc::new(FleeBehavior::new(0.7)) as Arc<dyn oxyde::oxyde_game::behavior::Behavior>,
Arc::new(AggressiveBehavior::new(0.6)),
Arc::new(JoyfulBehavior::new()),
Arc::new(FriendlyBehavior::new(0.3)),
Arc::new(CautiousBehavior::new()),
Arc::new(NeutralGreetingBehavior::new()),
Arc::new(ConfusedBehavior::new()),
Arc::new(PoliteDeclineBehavior::new()),
Arc::new(ThoughtfulPauseBehavior::new()),
Arc::new(DefaultAcknowledgeBehavior::new()),
];
println!("Running 900 interactions (10 patterns × 3 strategies × 30 turns)...\n");
let (results, stats) = trajectory_runner::run_trajectory_study(strategies, behaviors).await?;
println!("✓ Completed {} total interactions\n", results.len());
println!("==================================================");
println!("TRAJECTORY STATISTICS");
println!("==================================================\n");
for stat in &stats {
print_trajectory_stats(stat);
}
let results_dir = Path::new("experiments/behavior_priority_study/results");
fs::create_dir_all(results_dir)?;
let results_json = serde_json::to_string_pretty(&results)?;
fs::write(results_dir.join("trajectory_results.json"), results_json)?;
println!("\n✓ Saved detailed trajectory data to results/trajectory_results.json");
let stats_json = serde_json::to_string_pretty(&stats)?;
fs::write(results_dir.join("trajectory_statistics.json"), stats_json)?;
println!("✓ Saved statistics to results/trajectory_statistics.json");
save_trajectory_csv(&results, results_dir)?;
println!("✓ Saved CSV data to results/trajectory_data.csv\n");
println!("==================================================");
println!("Next Steps:");
println!("1. Run: python3 experiments/behavior_priority_study/plot_trajectories.py");
println!("2. View 30 trajectory plots in results/plots/");
println!("3. Use trajectory_data.csv + PAPER_GENERATION_BRIEF.md for paper");
println!("==================================================");
Ok(())
}
fn print_trajectory_stats(stats: &trajectory_runner::TrajectoryStatistics) {
println!("Strategy: {}", stats.strategy.to_uppercase());
println!(" Total Turns: {}", stats.total_turns);
println!(" True Override Rate: {:.1}%", stats.true_override_rate);
println!(" Neutral Fallback Rate: {:.1}%", stats.neutral_fallback_rate);
println!(" Emotional Behavior Rate: {:.1}%", stats.emotional_behavior_rate);
println!(" Stuck Emotions: {}", stats.stuck_emotions);
println!(" Behavior Variety: {:.3}", stats.behavior_variety);
println!(" Trajectory Coherence: {:.3}", stats.trajectory_coherence);
println!(" Avg Emotion Persistence: {:.1} turns", stats.avg_emotion_persistence);
println!();
}
fn save_trajectory_csv(results: &[trajectory_runner::TrajectoryTurnResult], results_dir: &Path) -> oxyde::Result<()> {
let mut csv = String::new();
csv.push_str("pattern,strategy,turn,player_action,intent_type,");
csv.push_str("joy_before,trust_before,fear_before,surprise_before,sadness_before,disgust_before,anger_before,anticipation_before,");
csv.push_str("valence_before,arousal_before,dominant_emotion_before,");
csv.push_str("selected_behavior,behavior_type,base_priority,emotional_modifier,effective_priority,priority_override,");
csv.push_str("joy_after,trust_after,fear_after,surprise_after,sadness_after,disgust_after,anger_after,anticipation_after,");
csv.push_str("valence_after,arousal_after,dominant_emotion_after\n");
for result in results {
csv.push_str(&format!(
"{},{},{},{},{},",
result.pattern,
result.strategy,
result.turn,
result.player_action.replace(',', ";"), result.intent_type,
));
csv.push_str(&format!(
"{:.3},{:.3},{:.3},{:.3},{:.3},{:.3},{:.3},{:.3},",
result.emotions_before.joy,
result.emotions_before.trust,
result.emotions_before.fear,
result.emotions_before.surprise,
result.emotions_before.sadness,
result.emotions_before.disgust,
result.emotions_before.anger,
result.emotions_before.anticipation,
));
csv.push_str(&format!(
"{:.3},{:.3},{},",
result.emotions_before.valence,
result.emotions_before.arousal,
result.emotions_before.dominant_emotion,
));
csv.push_str(&format!(
"{},{},{},{},{},{},",
result.selected_behavior,
result.behavior_type,
result.base_priority,
result.emotional_modifier,
result.effective_priority,
result.priority_override_occurred,
));
csv.push_str(&format!(
"{:.3},{:.3},{:.3},{:.3},{:.3},{:.3},{:.3},{:.3},",
result.emotions_after.joy,
result.emotions_after.trust,
result.emotions_after.fear,
result.emotions_after.surprise,
result.emotions_after.sadness,
result.emotions_after.disgust,
result.emotions_after.anger,
result.emotions_after.anticipation,
));
csv.push_str(&format!(
"{:.3},{:.3},{}\n",
result.emotions_after.valence,
result.emotions_after.arousal,
result.emotions_after.dominant_emotion,
));
}
fs::write(results_dir.join("trajectory_data.csv"), csv)?;
Ok(())
}