Skip to content

Instantly share code, notes, and snippets.

@Mroik
Last active February 6, 2024 14:04
Show Gist options
  • Save Mroik/3cd6756bf4d1e089215c5875839250b5 to your computer and use it in GitHub Desktop.
Save Mroik/3cd6756bf4d1e089215c5875839250b5 to your computer and use it in GitHub Desktop.
An algorithm visualizer
#![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