Last active
February 6, 2024 14:04
-
-
Save Mroik/3cd6756bf4d1e089215c5875839250b5 to your computer and use it in GitHub Desktop.
An algorithm visualizer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![allow(arithmetic_overflow)] | |
use std::{ | |
collections::HashMap, | |
error::Error, | |
io::{stdin, stdout, Stdout}, | |
thread::sleep, | |
time::{Duration, Instant}, | |
}; | |
use crossterm::{ | |
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, | |
ExecutableCommand, | |
}; | |
use random::Source; | |
use ratatui::{backend::CrosstermBackend, text::Line, widgets::Paragraph, Terminal}; | |
const N: u64 = 240; | |
fn main() -> Result<(), Box<dyn Error>> { | |
println!("Available algorithms"); | |
print!("1. Mergesort | "); | |
print!("2. Quicksort | "); | |
print!("3. Bubblesort | "); | |
println!("4. Radixsort"); | |
let mut buf = String::new(); | |
print!("Choice: "); | |
stdin().read_line(&mut buf)?; | |
let choice: u8 = buf.trim().parse()?; | |
let mut a = random::default(Instant::now().elapsed().as_secs()); | |
let mut to_sort = vec![]; | |
for _ in 0..N { | |
to_sort.push(a.read_u64() % 60); | |
} | |
stdout().execute(EnterAlternateScreen)?; | |
enable_raw_mode()?; | |
let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?; | |
terminal.clear()?; | |
let ll = to_sort.len(); | |
let mut sup = Vec::new(); | |
for _ in 0..N { | |
sup.push(0); | |
} | |
match choice { | |
1 => mergesort(&mut to_sort, &mut sup, 0, ll, &mut terminal), | |
2 => quicksort(&mut to_sort, 0, ll - 1, &mut terminal), | |
3 => bubblesort(&mut to_sort, ll, &mut terminal), | |
4 => radixsort(&mut to_sort, &mut terminal), | |
_ => panic!(), | |
}; | |
stdout().execute(LeaveAlternateScreen)?; | |
disable_raw_mode()?; | |
Ok(()) | |
} | |
fn radixsort(to_sort: &mut [u64], terminal: &mut Terminal<CrosstermBackend<Stdout>>) { | |
let mut buckets: HashMap<u64, Vec<u64>> = HashMap::new(); | |
for x in 0..10 { | |
buckets.insert(x, Vec::new()); | |
} | |
for x in 0..to_sort.len() { | |
let cur = buckets.get_mut(&(to_sort[x] % 10)).unwrap(); | |
cur.push(to_sort[x]); | |
} | |
let mut i = 0; | |
for x in 0..10 { | |
let cur = buckets.get_mut(&x).unwrap(); | |
while !cur.is_empty() { | |
to_sort[i] = cur.remove(0); | |
i += 1; | |
render(terminal, to_sort); | |
} | |
} | |
for x in 0..to_sort.len() { | |
let cur = buckets.get_mut(&(to_sort[x] / 10)).unwrap(); | |
cur.push(to_sort[x]); | |
} | |
let mut i = 0; | |
for x in 0..10 { | |
let cur = buckets.get_mut(&x).unwrap(); | |
while !cur.is_empty() { | |
to_sort[i] = cur.remove(0); | |
i += 1; | |
render(terminal, to_sort); | |
} | |
} | |
} | |
fn bubblesort(to_sort: &mut [u64], size: usize, terminal: &mut Terminal<CrosstermBackend<Stdout>>) { | |
let mut changed; | |
loop { | |
changed = false; | |
for i in 0..(size - 1) { | |
if to_sort[i] > to_sort[i + 1] { | |
(to_sort[i], to_sort[i + 1]) = (to_sort[i + 1], to_sort[i]); | |
changed = true; | |
} | |
render(terminal, to_sort); | |
} | |
if !changed { | |
break; | |
} | |
} | |
} | |
fn quicksort( | |
to_sort: &mut [u64], | |
start: usize, | |
finish: usize, | |
terminal: &mut Terminal<CrosstermBackend<Stdout>>, | |
) { | |
if !(start < finish) { | |
return; | |
} | |
let pivot = to_sort[start]; | |
let mut left = start - 1; | |
let mut right = finish + 1; | |
loop { | |
loop { | |
left += 1; | |
if !(to_sort[left] < pivot) { | |
break; | |
} | |
} | |
loop { | |
right -= 1; | |
if !(to_sort[right] > pivot) { | |
break; | |
} | |
} | |
if left >= right { | |
break; | |
} | |
(to_sort[left], to_sort[right]) = (to_sort[right], to_sort[left]); | |
render(terminal, to_sort); | |
} | |
quicksort(to_sort, start, right, terminal); | |
quicksort(to_sort, right + 1, finish, terminal); | |
} | |
fn mergesort( | |
to_sort: &mut [u64], | |
sup: &mut [u64], | |
start: usize, | |
finish: usize, | |
terminal: &mut Terminal<CrosstermBackend<Stdout>>, | |
) { | |
if !(start < finish) || !(finish - start > 1) { | |
return; | |
} | |
let middle = (start + finish) / 2; | |
mergesort(to_sort, sup, start, middle, terminal); | |
mergesort(to_sort, sup, middle, finish, terminal); | |
let mut vv = start; | |
let mut l_s = start; | |
let mut r_s = middle; | |
while vv < finish as usize { | |
if r_s >= finish as usize { | |
sup[vv] = to_sort[l_s]; | |
l_s += 1; | |
} else if l_s >= middle as usize { | |
sup[vv] = to_sort[r_s]; | |
r_s += 1; | |
} else if to_sort[l_s] < to_sort[r_s] { | |
sup[vv] = to_sort[l_s]; | |
l_s += 1; | |
} else { | |
sup[vv] = to_sort[r_s]; | |
r_s += 1; | |
} | |
vv += 1; | |
} | |
vv = start; | |
while vv < finish { | |
to_sort[vv] = sup[vv]; | |
vv += 1; | |
render(terminal, to_sort); | |
} | |
} | |
fn render(terminal: &mut Terminal<CrosstermBackend<Stdout>>, data: &[u64]) { | |
let lines = to_line(data); | |
let par = Paragraph::new(lines); | |
terminal | |
.draw(|frame| { | |
frame.render_widget(par, frame.size()); | |
}) | |
.unwrap(); | |
sleep(Duration::from_millis(1000 / 30)); | |
} | |
fn to_line(fr: &[u64]) -> Vec<Line> { | |
let mut ris = Vec::new(); | |
for x in 0..60 { | |
let mut sup = String::new(); | |
for y in 0..fr.len() { | |
let a = if fr[y] > x { ' ' } else { 'o' }; | |
sup.push(a); | |
} | |
ris.push(sup.into()); | |
} | |
return ris; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment