proof_engine/narrative/
motivation.rs1use crate::worldgen::Rng;
4use std::collections::HashMap;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub enum Need { Survival, Safety, Belonging, Esteem, SelfActualization, Power, Revenge, Love, Knowledge, Wealth }
8
9#[derive(Debug, Clone)]
10pub struct Motivation {
11 pub needs: HashMap<Need, f32>,
12 pub goals: Vec<Goal>,
13 pub beliefs: Vec<Belief>,
14 pub personality: Personality,
15}
16
17#[derive(Debug, Clone)]
18pub struct Goal { pub description: String, pub need: Need, pub priority: f32, pub progress: f32, pub completed: bool }
19
20#[derive(Debug, Clone)]
21pub struct Belief { pub subject: String, pub value: f32 }
22
23#[derive(Debug, Clone, Copy)]
24pub struct Personality {
25 pub openness: f32, pub conscientiousness: f32, pub extraversion: f32,
26 pub agreeableness: f32, pub neuroticism: f32,
27}
28
29impl Motivation {
30 pub fn random(rng: &mut Rng) -> Self {
31 let mut needs = HashMap::new();
32 for &need in &[Need::Survival, Need::Safety, Need::Belonging, Need::Esteem, Need::Power, Need::Knowledge, Need::Wealth] {
33 needs.insert(need, rng.range_f32(0.2, 0.8));
34 }
35 Self {
36 needs,
37 goals: Vec::new(),
38 beliefs: Vec::new(),
39 personality: Personality {
40 openness: rng.next_f32(), conscientiousness: rng.next_f32(),
41 extraversion: rng.next_f32(), agreeableness: rng.next_f32(),
42 neuroticism: rng.next_f32(),
43 },
44 }
45 }
46
47 pub fn evaluate_action(&self, need_impacts: &[(Need, f32)]) -> f32 {
49 need_impacts.iter().map(|(need, impact)| {
50 let weight = self.needs.get(need).copied().unwrap_or(0.0);
51 weight * impact
52 }).sum()
53 }
54
55 pub fn active_goal(&self) -> Option<&Goal> {
57 self.goals.iter().filter(|g| !g.completed)
58 .max_by(|a, b| a.priority.partial_cmp(&b.priority).unwrap())
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn test_motivation_random() {
68 let mut rng = Rng::new(42);
69 let m = Motivation::random(&mut rng);
70 assert!(!m.needs.is_empty());
71 }
72
73 #[test]
74 fn test_evaluate_action() {
75 let mut rng = Rng::new(42);
76 let m = Motivation::random(&mut rng);
77 let score = m.evaluate_action(&[(Need::Survival, 1.0), (Need::Wealth, 0.5)]);
78 assert!(score > 0.0);
79 }
80}