1use crate::models::{
4 configuration::{ConfigurationState, DistributionType},
5 config::FairnessMode,
6 traits::Sorter,
7};
8use std::time::Instant;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub enum AlgorithmType {
13 BubbleSort,
14 SelectionSort,
15 InsertionSort,
16 MergeSort,
17 QuickSort,
18 HeapSort,
19 ShellSort,
20}
21
22impl AlgorithmType {
23 pub fn all() -> Vec<AlgorithmType> {
25 vec![
26 AlgorithmType::BubbleSort,
27 AlgorithmType::SelectionSort,
28 AlgorithmType::InsertionSort,
29 AlgorithmType::MergeSort,
30 AlgorithmType::QuickSort,
31 AlgorithmType::HeapSort,
32 AlgorithmType::ShellSort,
33 ]
34 }
35
36 pub fn from_index(index: usize) -> Option<AlgorithmType> {
38 let algorithms = Self::all();
39 algorithms.get(index).copied()
40 }
41
42 pub fn to_index(self) -> usize {
44 match self {
45 AlgorithmType::BubbleSort => 0,
46 AlgorithmType::SelectionSort => 1,
47 AlgorithmType::InsertionSort => 2,
48 AlgorithmType::MergeSort => 3,
49 AlgorithmType::QuickSort => 4,
50 AlgorithmType::HeapSort => 5,
51 AlgorithmType::ShellSort => 6,
52 }
53 }
54}
55
56impl std::fmt::Display for AlgorithmType {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 match self {
59 AlgorithmType::BubbleSort => write!(f, "Bubble Sort"),
60 AlgorithmType::SelectionSort => write!(f, "Selection Sort"),
61 AlgorithmType::InsertionSort => write!(f, "Insertion Sort"),
62 AlgorithmType::MergeSort => write!(f, "Merge Sort"),
63 AlgorithmType::QuickSort => write!(f, "Quick Sort"),
64 AlgorithmType::HeapSort => write!(f, "Heap Sort"),
65 AlgorithmType::ShellSort => write!(f, "Shell Sort"),
66 }
67 }
68}
69
70#[derive(Debug, Clone)]
72pub struct RaceResult {
73 pub array_size: u32,
75 pub distribution: DistributionType,
77 pub fairness_mode: FairnessMode,
79 pub completion_times: Vec<Option<std::time::Duration>>,
81 pub memory_usage: Vec<usize>,
83 pub algorithm_names: Vec<String>,
85 pub winner: Option<AlgorithmType>,
87 pub race_start: Instant,
89 pub race_end: Option<Instant>,
91 pub total_duration: Option<std::time::Duration>,
93}
94
95impl RaceResult {
96 pub fn new(
98 array_size: u32,
99 distribution: DistributionType,
100 fairness_mode: FairnessMode,
101 algorithm_count: usize,
102 ) -> Self {
103 Self {
104 array_size,
105 distribution,
106 fairness_mode,
107 completion_times: vec![None; algorithm_count],
108 memory_usage: vec![0; algorithm_count],
109 algorithm_names: Vec::new(),
110 winner: None,
111 race_start: Instant::now(),
112 race_end: None,
113 total_duration: None,
114 }
115 }
116
117 pub fn complete(&mut self) {
119 self.race_end = Some(Instant::now());
120 self.total_duration = Some(self.race_start.elapsed());
121 }
122
123 pub fn set_completion_time(&mut self, algorithm_index: usize, duration: std::time::Duration) {
125 if algorithm_index < self.completion_times.len() {
126 self.completion_times[algorithm_index] = Some(duration);
127
128 if self.winner.is_none() {
130 self.winner = AlgorithmType::from_index(algorithm_index);
131 }
132 }
133 }
134
135 pub fn set_memory_usage(&mut self, algorithm_index: usize, memory: usize) {
137 if algorithm_index < self.memory_usage.len() {
138 self.memory_usage[algorithm_index] = memory;
139 }
140 }
141
142 pub fn is_complete(&self) -> bool {
144 self.race_end.is_some()
145 }
146}
147
148#[derive(Debug, Clone)]
150pub struct SessionState {
151 pub current_config: ConfigurationState,
153 pub run_history: Vec<RaceResult>,
155 pub session_start_time: Instant,
157 pub total_races_run: u32,
159 current_race: Option<RaceResult>,
161}
162
163impl SessionState {
164 pub fn new() -> Self {
166 Self {
167 current_config: ConfigurationState::new(),
168 run_history: Vec::new(),
169 session_start_time: Instant::now(),
170 total_races_run: 0,
171 current_race: None,
172 }
173 }
174
175 pub fn start_new_race(&mut self) -> Result<(), anyhow::Error> {
177 self.current_config.validate()?;
179
180 let algorithm_count = AlgorithmType::all().len();
182 let mut race_result = RaceResult::new(
183 self.current_config.array_size,
184 self.current_config.distribution,
185 self.current_config.fairness_mode.clone(),
186 algorithm_count,
187 );
188
189 race_result.algorithm_names = AlgorithmType::all()
191 .iter()
192 .map(|alg| alg.to_string())
193 .collect();
194
195 self.current_race = Some(race_result);
196 Ok(())
197 }
198
199 pub fn complete_current_race(&mut self) {
201 if let Some(mut race) = self.current_race.take() {
202 race.complete();
203 self.run_history.push(race);
204 self.total_races_run += 1;
205 }
206 }
207
208 pub fn update_race_progress(&mut self, algorithms: &[Box<dyn Sorter>]) {
210 if let Some(ref mut race) = self.current_race {
211 for (i, algorithm) in algorithms.iter().enumerate() {
212 let memory = algorithm.get_memory_usage();
214 race.set_memory_usage(i, memory);
215
216 if algorithm.is_complete() && race.completion_times[i].is_none() {
218 let completion_time = race.race_start.elapsed();
219 race.set_completion_time(i, completion_time);
220 }
221 }
222 }
223 }
224
225 pub fn has_current_race(&self) -> bool {
227 self.current_race.is_some()
228 }
229
230 pub fn get_current_race(&self) -> Option<&RaceResult> {
232 self.current_race.as_ref()
233 }
234
235 pub fn get_current_race_mut(&mut self) -> Option<&mut RaceResult> {
237 self.current_race.as_mut()
238 }
239
240 pub fn get_session_duration(&self) -> std::time::Duration {
242 self.session_start_time.elapsed()
243 }
244
245 pub fn get_race_statistics(&self) -> SessionStatistics {
247 SessionStatistics::from_session(self)
248 }
249
250 pub fn update_configuration(&mut self, config: ConfigurationState) {
252 self.current_config = config;
253 }
254
255 pub fn clear_history(&mut self) {
257 self.run_history.clear();
258 self.total_races_run = 0;
259 self.current_race = None;
260 }
261
262 pub fn get_average_race_duration(&self) -> Option<std::time::Duration> {
264 if self.run_history.is_empty() {
265 return None;
266 }
267
268 let total_duration: std::time::Duration = self.run_history
269 .iter()
270 .filter_map(|result| result.total_duration)
271 .sum();
272
273 Some(total_duration / self.run_history.len() as u32)
274 }
275
276 pub fn get_most_common_winner(&self) -> Option<AlgorithmType> {
278 use std::collections::HashMap;
279
280 let mut winner_counts: HashMap<AlgorithmType, u32> = HashMap::new();
281
282 for result in &self.run_history {
283 if let Some(winner) = result.winner {
284 *winner_counts.entry(winner).or_insert(0) += 1;
285 }
286 }
287
288 winner_counts
289 .into_iter()
290 .max_by_key(|(_, count)| *count)
291 .map(|(algorithm, _)| algorithm)
292 }
293}
294
295impl Default for SessionState {
296 fn default() -> Self {
297 Self::new()
298 }
299}
300
301#[derive(Debug, Clone)]
303pub struct SessionStatistics {
304 pub total_races: u32,
305 pub session_duration: std::time::Duration,
306 pub average_race_duration: Option<std::time::Duration>,
307 pub most_common_winner: Option<AlgorithmType>,
308 pub win_counts: std::collections::HashMap<AlgorithmType, u32>,
309 pub total_comparisons: u64,
310 pub total_moves: u64,
311 pub average_array_size: f32,
312}
313
314impl SessionStatistics {
315 pub fn from_session(session: &SessionState) -> Self {
317 use std::collections::HashMap;
318
319 let mut win_counts: HashMap<AlgorithmType, u32> = HashMap::new();
320 let total_comparisons = 0u64;
321 let total_moves = 0u64;
322 let mut total_array_size = 0u64;
323
324 for result in &session.run_history {
325 if let Some(winner) = result.winner {
326 *win_counts.entry(winner).or_insert(0) += 1;
327 }
328 total_array_size += result.array_size as u64;
329 }
330
331 let most_common_winner = win_counts
332 .iter()
333 .max_by_key(|(_, count)| *count)
334 .map(|(algorithm, _)| *algorithm);
335
336 let average_array_size = if session.run_history.is_empty() {
337 0.0
338 } else {
339 total_array_size as f32 / session.run_history.len() as f32
340 };
341
342 Self {
343 total_races: session.total_races_run,
344 session_duration: session.get_session_duration(),
345 average_race_duration: session.get_average_race_duration(),
346 most_common_winner,
347 win_counts,
348 total_comparisons,
349 total_moves,
350 average_array_size,
351 }
352 }
353}
354
355#[cfg(test)]
356mod tests {
357 use super::*;
358
359 #[test]
360 fn test_algorithm_type_conversions() {
361 assert_eq!(AlgorithmType::from_index(0), Some(AlgorithmType::BubbleSort));
362 assert_eq!(AlgorithmType::from_index(6), Some(AlgorithmType::ShellSort));
363 assert_eq!(AlgorithmType::from_index(7), None);
364
365 assert_eq!(AlgorithmType::BubbleSort.to_index(), 0);
366 assert_eq!(AlgorithmType::ShellSort.to_index(), 6);
367
368 assert_eq!(AlgorithmType::all().len(), 7);
369 }
370
371 #[test]
372 fn test_race_result_creation() {
373 let result = RaceResult::new(100, DistributionType::Shuffled, FairnessMode::WallTime { slice_ms: 50 }, 7);
374
375 assert_eq!(result.array_size, 100);
376 assert_eq!(result.distribution, DistributionType::Shuffled);
377 assert_eq!(result.completion_times.len(), 7);
378 assert_eq!(result.memory_usage.len(), 7);
379 assert_eq!(result.winner, None);
380 assert!(!result.is_complete());
381 }
382
383 #[test]
384 fn test_race_result_completion() {
385 let mut result = RaceResult::new(50, DistributionType::Reversed, FairnessMode::WallTime { slice_ms: 50 }, 3);
386
387 result.set_completion_time(1, std::time::Duration::from_millis(100));
388 assert_eq!(result.winner, Some(AlgorithmType::SelectionSort));
389
390 result.complete();
391 assert!(result.is_complete());
392 assert!(result.total_duration.is_some());
393 }
394
395 #[test]
396 fn test_session_state_creation() {
397 let session = SessionState::new();
398
399 assert_eq!(session.total_races_run, 0);
400 assert!(session.run_history.is_empty());
401 assert!(!session.has_current_race());
402 assert!(session.session_start_time.elapsed().as_millis() < 100); }
404
405 #[test]
406 fn test_session_race_lifecycle() {
407 let mut session = SessionState::new();
408
409 assert!(session.start_new_race().is_ok());
411 assert!(session.has_current_race());
412
413 session.complete_current_race();
415 assert!(!session.has_current_race());
416 assert_eq!(session.total_races_run, 1);
417 assert_eq!(session.run_history.len(), 1);
418 }
419
420 #[test]
421 fn test_session_statistics() {
422 let mut session = SessionState::new();
423
424 session.start_new_race().unwrap();
426 std::thread::sleep(std::time::Duration::from_millis(1)); session.complete_current_race();
428
429 session.start_new_race().unwrap();
430 std::thread::sleep(std::time::Duration::from_millis(1)); session.complete_current_race();
432
433 let stats = session.get_race_statistics();
434 assert_eq!(stats.total_races, 2);
435 assert!(stats.session_duration.as_millis() > 0);
436 }
437
438 #[test]
439 fn test_winner_tracking() {
440 let session = SessionState::new();
441 assert_eq!(session.get_most_common_winner(), None);
442
443 }
445
446 #[test]
447 fn test_configuration_validation() {
448 let mut session = SessionState::new();
449
450 assert!(session.start_new_race().is_ok());
452
453 session.current_config.array_size = 0; assert!(session.start_new_race().is_err());
456 }
457}