evolution_ternary/
population.rs1use core::fmt;
4
5pub type TernaryValue = u8;
7
8fn valid_ternary(v: TernaryValue) -> bool {
10 matches!(v, 0 | 1 | 2)
11}
12
13#[derive(Clone, PartialEq)]
15pub struct TernaryAgent {
16 pub strategy: Vec<TernaryValue>,
18 pub fitness: f64,
20}
21
22impl TernaryAgent {
23 pub fn new(strategy: Vec<TernaryValue>) -> Option<Self> {
25 if strategy.iter().all(|&v| valid_ternary(v)) {
26 Some(Self { strategy, fitness: 0.0 })
27 } else {
28 None
29 }
30 }
31
32 pub fn new_unchecked(strategy: Vec<TernaryValue>) -> Self {
34 Self { strategy, fitness: 0.0 }
35 }
36
37 pub fn len(&self) -> usize {
39 self.strategy.len()
40 }
41
42 pub fn is_empty(&self) -> bool {
44 self.strategy.is_empty()
45 }
46}
47
48impl fmt::Debug for TernaryAgent {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 write!(f, "Agent({:?}, fit={:.3})", self.strategy, self.fitness)
51 }
52}
53
54#[derive(Clone)]
56pub struct TernaryPopulation {
57 pub agents: Vec<TernaryAgent>,
58 pub strategy_len: usize,
60}
61
62impl TernaryPopulation {
63 pub fn new(agents: Vec<TernaryAgent>) -> Option<Self> {
67 if agents.is_empty() {
68 return None;
69 }
70 let len = agents[0].len();
71 if !agents.iter().all(|a| a.len() == len) {
72 return None;
73 }
74 Some(Self { agents, strategy_len: len })
75 }
76
77 pub fn random(n: usize, strategy_len: usize) -> Self {
79 let mut rng = SimpleRng::from_seed(42);
80 let agents = (0..n)
81 .map(|_| {
82 let strategy: Vec<TernaryValue> = (0..strategy_len)
83 .map(|_| (rng.next_u32() % 3) as TernaryValue)
84 .collect();
85 TernaryAgent::new_unchecked(strategy)
86 })
87 .collect();
88 Self { agents, strategy_len }
89 }
90
91 pub fn random_seeded(n: usize, strategy_len: usize, seed: u64) -> Self {
93 let mut rng = SimpleRng::from_seed(seed);
94 let agents = (0..n)
95 .map(|_| {
96 let strategy: Vec<TernaryValue> = (0..strategy_len)
97 .map(|_| (rng.next_u32() % 3) as TernaryValue)
98 .collect();
99 TernaryAgent::new_unchecked(strategy)
100 })
101 .collect();
102 Self { agents, strategy_len }
103 }
104
105 pub fn size(&self) -> usize {
107 self.agents.len()
108 }
109
110 pub fn sort_by_fitness(&mut self) {
112 self.agents.sort_by(|a, b| b.fitness.partial_cmp(&a.fitness).unwrap_or(std::cmp::Ordering::Equal));
113 }
114
115 pub fn best(&self) -> &TernaryAgent {
117 self.agents.iter().max_by(|a, b| a.fitness.partial_cmp(&b.fitness).unwrap_or(std::cmp::Ordering::Equal)).unwrap()
118 }
119
120 pub fn avg_fitness(&self) -> f64 {
122 if self.agents.is_empty() { return 0.0; }
123 self.agents.iter().map(|a| a.fitness).sum::<f64>() / self.agents.len() as f64
124 }
125
126 pub fn worst(&self) -> &TernaryAgent {
128 self.agents.iter().min_by(|a, b| a.fitness.partial_cmp(&b.fitness).unwrap_or(std::cmp::Ordering::Equal)).unwrap()
129 }
130}
131
132#[derive(Clone)]
134pub struct SimpleRng {
135 state: u64,
136}
137
138impl SimpleRng {
139 pub fn from_seed(seed: u64) -> Self {
140 Self { state: if seed == 0 { 0xDEAD_BEEF_CAFE_BABE } else { seed } }
142 }
143
144 pub fn next_u32(&mut self) -> u32 {
145 self.state ^= self.state << 13;
147 self.state ^= self.state >> 7;
148 self.state ^= self.state << 17;
149 self.state as u32
150 }
151
152 pub fn next_u64(&mut self) -> u64 {
153 let hi = self.next_u32() as u64;
154 let lo = self.next_u32() as u64;
155 (hi << 32) | lo
156 }
157
158 pub fn next_f64(&mut self) -> f64 {
160 (self.next_u32() as f64) / (u32::MAX as f64)
161 }
162}