encounter/
value_argument.rs1#[derive(Debug, Clone)]
8pub struct ValueArgumentInput {
9 pub attacker: String,
11 pub defender: String,
13 pub value_at_stake: String,
15 pub attacker_conviction: f64,
17 pub defender_conviction: f64,
19 pub defender_openness: f64,
21}
22
23#[derive(Debug, Clone)]
25pub struct ValueArgumentResult {
26 pub winner: String,
28 pub loser: String,
30 pub value_at_stake: String,
32 pub loser_value_shift: f64,
34 pub winner_value_shift: f64,
36}
37
38pub fn resolve_value_argument(input: &ValueArgumentInput) -> ValueArgumentResult {
45 let attacker_wins = input.attacker_conviction >= input.defender_conviction;
46
47 let (winner, loser) = if attacker_wins {
48 (input.attacker.clone(), input.defender.clone())
49 } else {
50 (input.defender.clone(), input.attacker.clone())
51 };
52
53 let conviction_gap = (input.attacker_conviction - input.defender_conviction).abs();
54
55 let loser_value_shift = (conviction_gap * input.defender_openness).clamp(0.0, 1.0);
56
57 let winner_value_shift = (conviction_gap * 0.1).clamp(0.0, 0.1);
58
59 ValueArgumentResult {
60 winner,
61 loser,
62 value_at_stake: input.value_at_stake.clone(),
63 loser_value_shift,
64 winner_value_shift,
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn winner_shifts_loser_value() {
74 let input = ValueArgumentInput {
75 attacker: "Alice".to_string(),
76 defender: "Bob".to_string(),
77 value_at_stake: "Benevolence".to_string(),
78 attacker_conviction: 0.8,
79 defender_conviction: 0.4,
80 defender_openness: 0.6,
81 };
82 let result = resolve_value_argument(&input);
83 assert_eq!(result.winner, "Alice");
84 assert!(result.loser_value_shift > 0.0);
85 assert!(result.loser_value_shift <= 1.0);
86 }
87
88 #[test]
89 fn defender_wins_when_more_convinced() {
90 let input = ValueArgumentInput {
91 attacker: "Alice".to_string(),
92 defender: "Bob".to_string(),
93 value_at_stake: "Power".to_string(),
94 attacker_conviction: 0.3,
95 defender_conviction: 0.9,
96 defender_openness: 0.5,
97 };
98 let result = resolve_value_argument(&input);
99 assert_eq!(result.winner, "Bob");
100 }
101
102 #[test]
103 fn winner_gets_small_self_reinforcement() {
104 let input = ValueArgumentInput {
105 attacker: "Alice".to_string(),
106 defender: "Bob".to_string(),
107 value_at_stake: "Security".to_string(),
108 attacker_conviction: 0.8,
109 defender_conviction: 0.4,
110 defender_openness: 0.6,
111 };
112 let result = resolve_value_argument(&input);
113 assert!(result.winner_value_shift > 0.0);
114 assert!(result.winner_value_shift < result.loser_value_shift);
115 }
116
117 #[test]
118 fn equal_conviction_favors_attacker() {
119 let input = ValueArgumentInput {
120 attacker: "Alice".to_string(),
121 defender: "Bob".to_string(),
122 value_at_stake: "Tradition".to_string(),
123 attacker_conviction: 0.5,
124 defender_conviction: 0.5,
125 defender_openness: 0.8,
126 };
127 let result = resolve_value_argument(&input);
128 assert_eq!(result.winner, "Alice");
129 assert_eq!(result.loser_value_shift, 0.0);
130 }
131}