sorting_race/lib/
controller.rs

1//! Main controller for the sorting race
2
3use crate::models::config::RunConfiguration;
4use crate::models::traits::{Sorter, FairnessModel};
5use crate::services::snapshot::SnapshotService;
6use std::time::Instant;
7
8/// Main controller for orchestrating the sorting race
9#[derive(Debug)]
10pub struct RaceController {
11    algorithms: Vec<Box<dyn Sorter>>,
12    fairness_model: Box<dyn FairnessModel>,
13    snapshot_service: SnapshotService,
14    current_step: usize,
15    start_time: Option<Instant>,
16    is_running: bool,
17    is_paused: bool,
18}
19
20impl RaceController {
21    /// Create a new race controller
22    pub fn new(
23        algorithms: Vec<Box<dyn Sorter>>,
24        fairness_model: Box<dyn FairnessModel>,
25        max_snapshots: usize,
26    ) -> Self {
27        Self {
28            algorithms,
29            fairness_model,
30            snapshot_service: SnapshotService::new(max_snapshots),
31            current_step: 0,
32            start_time: None,
33            is_running: false,
34            is_paused: false,
35        }
36    }
37
38    /// Start the race with the given configuration
39    pub fn start_race(&mut self, config: &RunConfiguration, data: Vec<i32>) -> Result<(), String> {
40        config.validate()?;
41
42        // Reset all algorithms with the same data
43        for algorithm in &mut self.algorithms {
44            algorithm.reset(data.clone());
45        }
46
47        self.current_step = 0;
48        self.start_time = Some(Instant::now());
49        self.is_running = true;
50        self.is_paused = false;
51        self.snapshot_service.clear();
52
53        // Take initial snapshot
54        self.snapshot_service.take_snapshot(&self.algorithms, 0);
55
56        Ok(())
57    }
58
59    /// Execute one step of the race
60    pub fn step(&mut self) -> bool {
61        if !self.is_running || self.is_paused {
62            return false;
63        }
64
65        if self.is_race_complete() {
66            self.is_running = false;
67            return false;
68        }
69
70        // Allocate budgets using fairness model
71        let budgets = self.fairness_model.allocate_budget(&self.algorithms);
72
73        // Execute steps for each algorithm
74        for (algorithm, budget) in self.algorithms.iter_mut().zip(budgets.iter()) {
75            if *budget > 0 && !algorithm.is_complete() {
76                algorithm.step(*budget);
77            }
78        }
79
80        self.current_step += 1;
81
82        // Take snapshot
83        self.snapshot_service.take_snapshot(&self.algorithms, self.current_step);
84
85        // Check if race is complete
86        if self.is_race_complete() {
87            self.is_running = false;
88        }
89
90        true
91    }
92
93    /// Run the race to completion or until a step limit
94    pub fn run_to_completion(&mut self, max_steps: Option<usize>) -> usize {
95        let limit = max_steps.unwrap_or(usize::MAX);
96        let mut steps_executed = 0;
97
98        while self.is_running && steps_executed < limit && self.step() {
99            steps_executed += 1;
100        }
101
102        steps_executed
103    }
104
105    /// Check if the race is complete
106    pub fn is_race_complete(&self) -> bool {
107        self.algorithms.iter().all(|alg| alg.is_complete())
108    }
109
110    /// Pause the race
111    pub fn pause(&mut self) {
112        self.is_paused = true;
113    }
114
115    /// Resume the race
116    pub fn resume(&mut self) {
117        self.is_paused = false;
118    }
119
120    /// Stop the race
121    pub fn stop(&mut self) {
122        self.is_running = false;
123        self.is_paused = false;
124    }
125
126    /// Reset the race
127    pub fn reset(&mut self) {
128        self.current_step = 0;
129        self.start_time = None;
130        self.is_running = false;
131        self.is_paused = false;
132        self.snapshot_service.clear();
133    }
134
135    /// Get current step number
136    pub fn get_current_step(&self) -> usize {
137        self.current_step
138    }
139
140    /// Get elapsed time since race start
141    pub fn get_elapsed_time(&self) -> Option<std::time::Duration> {
142        self.start_time.map(|start| start.elapsed())
143    }
144
145    /// Check if race is running
146    pub fn is_running(&self) -> bool {
147        self.is_running
148    }
149
150    /// Check if race is paused
151    pub fn is_paused(&self) -> bool {
152        self.is_paused
153    }
154
155    /// Get reference to algorithms
156    pub fn get_algorithms(&self) -> &[Box<dyn Sorter>] {
157        &self.algorithms
158    }
159
160    /// Get reference to snapshot service
161    pub fn get_snapshot_service(&self) -> &SnapshotService {
162        &self.snapshot_service
163    }
164
165    /// Get mutable reference to snapshot service
166    pub fn get_snapshot_service_mut(&mut self) -> &mut SnapshotService {
167        &mut self.snapshot_service
168    }
169
170    /// Get the name of the current fairness model
171    pub fn get_fairness_model_name(&self) -> &str {
172        self.fairness_model.name()
173    }
174}