sorting_race/services/sorters/
bubble.rs

1//! Bubble Sort implementation
2
3use crate::models::traits::{Sorter, StepResult, Telemetry, Markers};
4use std::any::Any;
5
6/// Bubble Sort algorithm implementation
7#[derive(Debug)]
8pub struct BubbleSort {
9    data: Vec<i32>,
10    current_pass: usize,
11    current_pos: usize,
12    comparisons: u64,
13    moves: u64,
14    complete: bool,
15}
16
17impl BubbleSort {
18    /// Create a new BubbleSort instance
19    pub fn new() -> Self {
20        Self {
21            data: Vec::new(),
22            current_pass: 0,
23            current_pos: 0,
24            comparisons: 0,
25            moves: 0,
26            complete: false,
27        }
28    }
29}
30
31impl Default for BubbleSort {
32    fn default() -> Self {
33        Self::new()
34    }
35}
36
37impl Sorter for BubbleSort {
38    fn step(&mut self, budget: usize) -> StepResult {
39        if self.complete || self.data.len() <= 1 {
40            return StepResult {
41                comparisons_used: 0,
42                moves_made: 0,
43                continued: false,
44            };
45        }
46
47        let mut comparisons_used = 0;
48        let mut moves_made = 0;
49        let n = self.data.len();
50
51        while comparisons_used < budget {
52            if self.current_pos < n - 1 - self.current_pass {
53                // Compare adjacent elements
54                comparisons_used += 1;
55                self.comparisons += 1;
56
57                if self.data[self.current_pos] > self.data[self.current_pos + 1] {
58                    // Swap elements
59                    self.data.swap(self.current_pos, self.current_pos + 1);
60                    moves_made += 1;
61                    self.moves += 1;
62                }
63
64                self.current_pos += 1;
65            } else {
66                // End of current pass
67                self.current_pass += 1;
68                self.current_pos = 0;
69
70                if self.current_pass >= n - 1 {
71                    self.complete = true;
72                    break;
73                }
74            }
75        }
76
77        StepResult {
78            comparisons_used,
79            moves_made,
80            continued: !self.complete,
81        }
82    }
83
84    fn is_complete(&self) -> bool {
85        self.complete
86    }
87
88    fn get_telemetry(&self) -> Telemetry {
89        let mut markers = Markers::default();
90        
91        if !self.complete && self.current_pos < self.data.len() {
92            markers.cursors = vec![self.current_pos];
93            if self.current_pos + 1 < self.data.len() {
94                markers.cursors.push(self.current_pos + 1);
95            }
96        }
97
98        Telemetry {
99            total_comparisons: self.comparisons,
100            total_moves: self.moves,
101            memory_current: self.get_memory_usage(),
102            memory_peak: self.get_memory_usage(),
103            highlights: markers.cursors.clone(),
104            markers,
105            status_text: if self.complete {
106                "Completed".to_string()
107            } else {
108                format!("Pass {}, Position {}", self.current_pass + 1, self.current_pos)
109            },
110            progress_hint: if self.data.len() <= 1 {
111                1.0
112            } else {
113                let progress = (self.current_pass as f32) / (self.data.len() - 1) as f32;
114                progress.min(1.0).max(0.0) // Clamp to [0.0, 1.0]
115            },
116        }
117    }
118
119    fn reset(&mut self, data: Vec<i32>) {
120        self.data = data;
121        self.current_pass = 0;
122        self.current_pos = 0;
123        self.comparisons = 0;
124        self.moves = 0;
125        self.complete = self.data.len() <= 1;
126    }
127
128    fn name(&self) -> &str {
129        "Bubble Sort"
130    }
131
132    fn get_array(&self) -> &[i32] {
133        &self.data
134    }
135
136    fn get_memory_usage(&self) -> usize {
137        // Report size of the data array in bytes
138        self.data.len() * std::mem::size_of::<i32>()
139    }
140
141    fn as_any(&self) -> &dyn Any {
142        self
143    }
144
145    fn as_any_mut(&mut self) -> &mut dyn Any {
146        self
147    }
148}