proof_engine/narrative/
memory.rs1use std::collections::VecDeque;
4
5#[derive(Debug, Clone)]
6pub struct Memory {
7 pub event: String,
8 pub sentiment: f32,
9 pub timestamp: f64,
10 pub importance: f32,
11 pub fading: bool,
12}
13
14#[derive(Debug, Clone)]
16pub struct NpcMemory {
17 pub memories: VecDeque<Memory>,
18 pub max_memories: usize,
19 pub forget_threshold: f32,
20}
21
22impl NpcMemory {
23 pub fn new(capacity: usize) -> Self {
24 Self { memories: VecDeque::new(), max_memories: capacity, forget_threshold: 0.1 }
25 }
26
27 pub fn remember(&mut self, event: &str, sentiment: f32, importance: f32, time: f64) {
28 self.memories.push_back(Memory {
29 event: event.to_string(), sentiment, timestamp: time, importance, fading: false,
30 });
31 while self.memories.len() > self.max_memories {
32 self.memories.pop_front();
33 }
34 }
35
36 pub fn tick(&mut self, current_time: f64) {
38 for m in &mut self.memories {
39 let age = current_time - m.timestamp;
40 if age > 100.0 && m.importance < 0.5 {
41 m.fading = true;
42 }
43 }
44 self.memories.retain(|m| !m.fading || m.importance > self.forget_threshold);
45 }
46
47 pub fn recall(&self, keyword: &str) -> Vec<&Memory> {
49 self.memories.iter().filter(|m| m.event.contains(keyword)).collect()
50 }
51
52 pub fn strongest_memory(&self) -> Option<&Memory> {
54 self.memories.iter().max_by(|a, b| a.importance.partial_cmp(&b.importance).unwrap())
55 }
56
57 pub fn overall_sentiment(&self) -> f32 {
59 if self.memories.is_empty() { return 0.0; }
60 let sum: f32 = self.memories.iter().map(|m| m.sentiment * m.importance).sum();
61 let weight: f32 = self.memories.iter().map(|m| m.importance).sum();
62 if weight > 0.0 { sum / weight } else { 0.0 }
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn test_memory() {
72 let mut mem = NpcMemory::new(10);
73 mem.remember("helped with crops", 0.8, 0.5, 1.0);
74 mem.remember("stole an apple", -0.5, 0.3, 2.0);
75 assert_eq!(mem.memories.len(), 2);
76 assert!(mem.overall_sentiment() > 0.0);
77 }
78
79 #[test]
80 fn test_recall() {
81 let mut mem = NpcMemory::new(10);
82 mem.remember("battle at the bridge", 0.3, 0.7, 1.0);
83 mem.remember("quiet evening", 0.1, 0.2, 2.0);
84 let battles = mem.recall("battle");
85 assert_eq!(battles.len(), 1);
86 }
87}