use crate::models::config::RunConfiguration;
use crate::models::traits::{Sorter, FairnessModel};
use crate::services::snapshot::SnapshotService;
use std::time::Instant;
#[derive(Debug)]
pub struct RaceController {
algorithms: Vec<Box<dyn Sorter>>,
fairness_model: Box<dyn FairnessModel>,
snapshot_service: SnapshotService,
current_step: usize,
start_time: Option<Instant>,
is_running: bool,
is_paused: bool,
}
impl RaceController {
pub fn new(
algorithms: Vec<Box<dyn Sorter>>,
fairness_model: Box<dyn FairnessModel>,
max_snapshots: usize,
) -> Self {
Self {
algorithms,
fairness_model,
snapshot_service: SnapshotService::new(max_snapshots),
current_step: 0,
start_time: None,
is_running: false,
is_paused: false,
}
}
pub fn start_race(&mut self, config: &RunConfiguration, data: Vec<i32>) -> Result<(), String> {
config.validate()?;
for algorithm in &mut self.algorithms {
algorithm.reset(data.clone());
}
self.current_step = 0;
self.start_time = Some(Instant::now());
self.is_running = true;
self.is_paused = false;
self.snapshot_service.clear();
self.snapshot_service.take_snapshot(&self.algorithms, 0);
Ok(())
}
pub fn step(&mut self) -> bool {
if !self.is_running || self.is_paused {
return false;
}
if self.is_race_complete() {
self.is_running = false;
return false;
}
let budgets = self.fairness_model.allocate_budget(&self.algorithms);
for (algorithm, budget) in self.algorithms.iter_mut().zip(budgets.iter()) {
if *budget > 0 && !algorithm.is_complete() {
algorithm.step(*budget);
}
}
self.current_step += 1;
self.snapshot_service.take_snapshot(&self.algorithms, self.current_step);
if self.is_race_complete() {
self.is_running = false;
}
true
}
pub fn run_to_completion(&mut self, max_steps: Option<usize>) -> usize {
let limit = max_steps.unwrap_or(usize::MAX);
let mut steps_executed = 0;
while self.is_running && steps_executed < limit && self.step() {
steps_executed += 1;
}
steps_executed
}
pub fn is_race_complete(&self) -> bool {
self.algorithms.iter().all(|alg| alg.is_complete())
}
pub fn pause(&mut self) {
self.is_paused = true;
}
pub fn resume(&mut self) {
self.is_paused = false;
}
pub fn stop(&mut self) {
self.is_running = false;
self.is_paused = false;
}
pub fn reset(&mut self) {
self.current_step = 0;
self.start_time = None;
self.is_running = false;
self.is_paused = false;
self.snapshot_service.clear();
}
pub fn get_current_step(&self) -> usize {
self.current_step
}
pub fn get_elapsed_time(&self) -> Option<std::time::Duration> {
self.start_time.map(|start| start.elapsed())
}
pub fn is_running(&self) -> bool {
self.is_running
}
pub fn is_paused(&self) -> bool {
self.is_paused
}
pub fn get_algorithms(&self) -> &[Box<dyn Sorter>] {
&self.algorithms
}
pub fn get_snapshot_service(&self) -> &SnapshotService {
&self.snapshot_service
}
pub fn get_snapshot_service_mut(&mut self) -> &mut SnapshotService {
&mut self.snapshot_service
}
pub fn get_fairness_model_name(&self) -> &str {
self.fairness_model.name()
}
}