use super::state::KnowledgeBoardRegistry;
use super::types::{FactionId, GroundTruthFact, PerceivedFact};
use async_trait::async_trait;
use std::collections::HashMap;
#[async_trait]
pub trait PerceptionHook: Send + Sync {
async fn get_faction_accuracies(
&self,
_truth: &GroundTruthFact,
boards: &KnowledgeBoardRegistry,
) -> HashMap<FactionId, f32> {
let mut accuracies = HashMap::new();
for (faction_id, _) in boards.all_boards() {
accuracies.insert(faction_id.clone(), 0.7);
}
accuracies
}
async fn generate_misinformation(
&self,
_target_faction: &FactionId,
_boards: &mut KnowledgeBoardRegistry,
) {
}
async fn calculate_fact_priority(&self, fact: &PerceivedFact, _faction_id: &FactionId) -> f32 {
fact.accuracy
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct DefaultPerceptionHook;
#[async_trait]
impl PerceptionHook for DefaultPerceptionHook {}
#[cfg(test)]
mod tests {
use super::*;
use crate::plugin::subjective_reality::types::*;
use std::time::Duration;
#[tokio::test]
async fn test_default_hook_accuracies() {
let hook = DefaultPerceptionHook;
let mut registry = KnowledgeBoardRegistry::new();
registry.register_faction("faction_a".into());
registry.register_faction("faction_b".into());
let truth = GroundTruthFact::new(
"fact_001",
FactType::MilitaryStrength {
faction: "enemy".into(),
strength: 1000,
},
100,
);
let accuracies = hook.get_faction_accuracies(&truth, ®istry).await;
assert_eq!(accuracies.len(), 2);
assert_eq!(accuracies.get("faction_a"), Some(&0.7));
assert_eq!(accuracies.get("faction_b"), Some(&0.7));
}
#[tokio::test]
async fn test_default_hook_no_misinformation() {
let hook = DefaultPerceptionHook;
let mut registry = KnowledgeBoardRegistry::new();
registry.register_faction("faction_a".into());
hook.generate_misinformation(&"faction_a".into(), &mut registry)
.await;
let board = registry.get_board(&"faction_a".into()).unwrap();
assert_eq!(board.fact_count(), 0); }
#[tokio::test]
async fn test_default_hook_priority() {
let hook = DefaultPerceptionHook;
let fact = PerceivedFact::new(
FactType::MarketPrice {
item: "wheat".into(),
price: 15.5,
},
0.85,
Duration::from_secs(0),
None,
);
let priority = hook
.calculate_fact_priority(&fact, &"faction_a".into())
.await;
assert_eq!(priority, 0.85); }
struct CustomHook {
spy_locations: HashMap<FactionId, Vec<String>>,
}
#[async_trait]
impl PerceptionHook for CustomHook {
async fn get_faction_accuracies(
&self,
truth: &GroundTruthFact,
boards: &KnowledgeBoardRegistry,
) -> HashMap<FactionId, f32> {
let mut accuracies = HashMap::new();
for (faction_id, _) in boards.all_boards() {
let mut accuracy = 0.5;
if let Some(location) = &truth.location {
if let Some(spy_locs) = self.spy_locations.get(faction_id) {
if spy_locs.contains(location) {
accuracy = 0.95; }
}
}
accuracies.insert(faction_id.clone(), accuracy);
}
accuracies
}
}
#[tokio::test]
async fn test_custom_hook_spy_network() {
let mut spy_locations = HashMap::new();
spy_locations.insert("faction_a".into(), vec!["location_1".to_string()]);
let hook = CustomHook { spy_locations };
let mut registry = KnowledgeBoardRegistry::new();
registry.register_faction("faction_a".into());
registry.register_faction("faction_b".into());
let truth = GroundTruthFact::new(
"fact_001",
FactType::MilitaryStrength {
faction: "enemy".into(),
strength: 1000,
},
100,
)
.with_location("location_1");
let accuracies = hook.get_faction_accuracies(&truth, ®istry).await;
assert_eq!(accuracies.get("faction_a"), Some(&0.95));
assert_eq!(accuracies.get("faction_b"), Some(&0.5));
}
}