diff --git a/src/algorithm/binaryHeap.rs b/src/algorithm/binaryHeap.rs new file mode 100644 index 0000000..7fc2ffc --- /dev/null +++ b/src/algorithm/binaryHeap.rs @@ -0,0 +1,53 @@ + +use crate::drawableVec::DrawableVec; + +use std::collections::{HashMap, BinaryHeap}; + +use color_eyre::Result; + +pub async fn sort(list: &mut DrawableVec) -> Result<()>{ + + let mut indexMap:HashMap = HashMap::new(); + let mut binHeap:BinaryHeap = BinaryHeap::new(); + + let mut ind = 0; + for bar in list.elements(){ + binHeap.push(*bar); + indexMap.insert(*bar, ind); + ind += 1; + } + for i in (0..list.len()).rev(){ + let bar = binHeap.pop().unwrap(); + let barIndex = *indexMap.get(&bar).unwrap(); + list.swap(i, barIndex).await?; + let temp = list.get(barIndex); + indexMap.insert(temp, barIndex); + + } + Ok(()) +} + +/* + +#[cfg(test)] +#[allow(non_snake_case)] +mod tests { + use crate::GuiHookVec::NonGuiVec; + +use super::*; + + + macro_rules! aw { + ($e:expr) => { + tokio_test::block_on($e) + }; + } + + #[test] + fn binartHeap_correct() { + let mut list:NonGuiVec = aw!(SortingList::new(1000,0.0)); + aw!(binaryHeap(&mut list)); + assert_eq!( list.isSorted(), true); + } +} +*/ diff --git a/src/algorithm/bogoSort.rs b/src/algorithm/bogoSort.rs new file mode 100644 index 0000000..3e532dd --- /dev/null +++ b/src/algorithm/bogoSort.rs @@ -0,0 +1,40 @@ +use crate::drawableVec::DrawableVec; + +use color_eyre::Result; +pub async fn sort(list: &mut DrawableVec) -> Result<()>{ + + loop{ + list.swap(0,0).await?; + if list.isSorted() { + break; + } + list.randomize(); + } + + Ok(()) +} +/* + +#[cfg(test)] +#[allow(non_snake_case)] +mod tests { + use crate::GuiHookVec::NonGuiVec; + +use super::*; + + + macro_rules! aw { + ($e:expr) => { + tokio_test::block_on($e) + }; + } + + #[test] + fn bogoSort_correct_this_is_a_meme() { + let mut list:NonGuiVec = aw!(SortingList::new(5,0.0)); + aw!(bogoSort(&mut list)); + assert_eq!( list.isSorted(), true); + } +} + +*/ diff --git a/src/algorithm/bubbleSort.rs b/src/algorithm/bubbleSort.rs new file mode 100644 index 0000000..131a63f --- /dev/null +++ b/src/algorithm/bubbleSort.rs @@ -0,0 +1,41 @@ +use crate::drawableVec::DrawableVec; + +use color_eyre::Result; + +pub async fn sort(list:&mut DrawableVec) -> Result<()>{ + let n = list.len(); + for i in 0..n { + for j in 0..(n - i - 1) { + if list.lessThan(j + 1, j) { + list.swap(j, j + 1).await?; + } + } + } + + Ok(()) + +} +/* +#[cfg(test)] +#[allow(non_snake_case)] +mod tests { + use crate::GuiHookVec::NonGuiVec; + +use super::*; + + + macro_rules! aw { + ($e:expr) => { + tokio_test::block_on($e) + }; + } + + #[test] + fn bubblesort_correct() { + let mut list:NonGuiVec = aw!(SortingList::new(1000,0.0)); + aw!(bubbleSort(&mut list)); + assert_eq!( list.isSorted(), true); + } +} + +*/ diff --git a/src/algorithm/coctailShaker.rs b/src/algorithm/coctailShaker.rs new file mode 100644 index 0000000..f1ec824 --- /dev/null +++ b/src/algorithm/coctailShaker.rs @@ -0,0 +1,58 @@ +use crate::drawableVec::DrawableVec; + +use color_eyre::Result; + +pub async fn sort(list:&mut DrawableVec) -> Result<()>{ + let mut lowerBound = 0; + let mut upperBound = list.len()-1; + let mut swapped = true; + while swapped{ + swapped = false; + for i in lowerBound..upperBound { + if list.lessThan(i+1, i) { + list.swap(i, i+1).await?; + swapped = true; + } + } + if !swapped{ + break; + } + swapped = false; + upperBound = upperBound-1; + for i in ((lowerBound)..(upperBound)).rev() { + if list.lessThan(i+1, i) { + list.swap(i+1, i).await?; + swapped = true; + } + } + + lowerBound = lowerBound+1; + } + + Ok(()) + +} +/* +#[cfg(test)] +#[allow(non_snake_case)] +mod tests { + use crate::GuiHookVec::NonGuiVec; + +use super::*; + + + macro_rules! aw { + ($e:expr) => { + tokio_test::block_on($e) + }; + } + + #[test] + fn coctailshakersort_correct() { + let mut list:NonGuiVec = aw!(SortingList::new(1000,0.0)); + aw!(cocktailShaker(&mut list)); + assert_eq!( list.isSorted(), true); + } +} + +*/ diff --git a/src/algorithm/mod.rs b/src/algorithm/mod.rs index 94a6bf8..e39f0ab 100644 --- a/src/algorithm/mod.rs +++ b/src/algorithm/mod.rs @@ -1,3 +1,29 @@ use crate::drawableVec::DrawableVec; -pub mod insertSort; +mod radixSort; +mod insertSort; +mod bubbleSort; +mod binaryHeap; +mod coctailShaker; +mod quickSort; +mod bogoSort; +mod radixSortLSD; +use color_eyre::{eyre::Ok, Result}; + + + + +pub async fn sort(algo: String, list: &mut DrawableVec) -> Result<()> { + match algo.as_str() { + "insertSort" => insertSort::sort(list).await?, + "bubbleSort" => bubbleSort::sort(list).await?, + "bogoSort" => bogoSort::sort(list).await?, + "cocktailShaker" => coctailShaker::sort(list).await?, + "binaryHeap" => binaryHeap::sort(list).await?, + "quickSort" => quickSort::sort(list).await?, + "radixSortMSD" => radixSort::sort(list).await?, + "radixSortLSD" => radixSortLSD::sort(list).await?, + _ => panic!("No algorithm with that name implemented!") + } + Ok(()) +} \ No newline at end of file diff --git a/src/algorithm/quickSort.rs b/src/algorithm/quickSort.rs new file mode 100644 index 0000000..73e13c6 --- /dev/null +++ b/src/algorithm/quickSort.rs @@ -0,0 +1,74 @@ +use crate::drawableVec::DrawableVec; + +use color_eyre::Result; + + + +pub async fn sort(list:&mut DrawableVec) -> Result<()> { + let mut stack:Vec<(usize,usize)> = Vec::new(); + + let start = 0; + let end = list.len()-1; + + stack.push((start,end)); + + while stack.len() > 0{ + let (start,end) = stack.pop().unwrap(); + + let p = list.get(end); + let temp = partition(list, start, end, p).await?; + let pivot = if temp >= 0 {temp} else {break;}; + + if pivot != 0 && pivot as usize -1 > start{ + + stack.push((start,pivot as usize-1)); + } + + if pivot as usize + 1 < end{ + stack.push((pivot as usize +1, end)) + } + } + + Ok(()) + +} + + + +async fn partition(list:&mut DrawableVec, low:usize, high:usize, p:u32) -> Result{ + let mut pIndex = low; + + for i in low..high{ + if list.lessThanEqual(i, p){ + list.swap(i, pIndex).await?; + pIndex += 1; + } + } + list.swap(pIndex, high).await?; + + return Ok(pIndex as i32) +} +/* +#[cfg(test)] +#[allow(non_snake_case)] +mod tests { + use crate::GuiHookVec::NonGuiVec; + +use super::*; + + + macro_rules! aw { + ($e:expr) => { + tokio_test::block_on($e) + }; + } + + #[test] + fn quicksort_correct() { + let mut list:NonGuiVec = aw!(SortingList::new(1000,0.0)); + aw!(quickSort(&mut list)); + assert_eq!( list.isSorted(), true); + } +} +*/ + diff --git a/src/algorithm/radixSort.rs b/src/algorithm/radixSort.rs new file mode 100644 index 0000000..6213075 --- /dev/null +++ b/src/algorithm/radixSort.rs @@ -0,0 +1,124 @@ +use crate::drawableVec::DrawableVec; + +use color_eyre::{eyre::Ok, Result}; + + + +pub async fn sort(list:&mut DrawableVec) -> Result<()> { + + let mut max = usize::MIN; + for i in list.getListClone().into_iter().map(|x| format!("{:b}",x)){ + + if max < i.len(){ + max = i.len(); + } + + } + + + let mut stack:Vec<(usize, usize)> = Vec::new(); + let mut stack2:Vec<(usize,usize)> = Vec::new(); + stack.push((0, list.len())); + for i in (0..(max)).rev(){ + + while stack.len() > 0{ + let cur = stack.pop().unwrap(); + + match radix(list, i, cur.0, cur.1).await?{ + Some((initial, switch, max)) => { + + if initial < switch{ + stack2.push((initial, switch)); + } + if switch < max{ + + stack2.push((switch, max)); + } + + }, + None => return Ok(()) + } + + } + + stack = stack2.clone(); + stack2.clear(); + } + + Ok(()) +} + +async fn radix(list:&mut DrawableVec, radix:usize, mut minBoundry:usize, mut maxBoundry:usize) -> Result>{ + let initialMin = minBoundry.clone(); + let initialMax = maxBoundry.clone(); + + + + loop{ + if maxBoundry == minBoundry{ + break + } + let currentBit = get_bit_at(list.get(minBoundry), radix); + + if currentBit{ + list.swap(minBoundry, maxBoundry-1).await?; + maxBoundry -= 1; + }else{ + list.swap(minBoundry, minBoundry).await?; + + minBoundry += 1; + } + } + + + + Ok(Some((initialMin, minBoundry, initialMax))) +} +fn get_bit_at(input: u32, n: usize) -> bool { + + if format!("{:b}", input).len() <= n{ + false + }else{ + input & (1 << n) != 0 + } + + +} + +/* +#[cfg(test)] +#[allow(non_snake_case)] +mod tests { + use crate::GuiHookVec::NonGuiVec; + +use super::*; + + + macro_rules! aw { + ($e:expr) => { + tokio_test::block_on($e) + }; + } + + #[test] + fn radixsort_correct() { + let mut list:NonGuiVec = aw!(SortingList::new(1000,0.0)); + aw!(radixSort(&mut list)); + assert_eq!( list.isSorted(), true); + } + + #[test] + fn get_bit_at_test(){ + let num = 0b0001; + let othernum = 2; + assert_eq!(get_bit_at(num, 0), true); + assert_eq!(get_bit_at(num, 1), false); + assert_eq!(get_bit_at(othernum, 1), true); + assert_eq!(get_bit_at(othernum, 2), false); + assert_eq!(get_bit_at(othernum, 3), false); + } +} + + + +*/ diff --git a/src/algorithm/radixSortLSD.rs b/src/algorithm/radixSortLSD.rs new file mode 100644 index 0000000..6e931ae --- /dev/null +++ b/src/algorithm/radixSortLSD.rs @@ -0,0 +1,100 @@ +use crate::drawableVec::DrawableVec; + +use color_eyre::Result; + +pub async fn sort(list:&mut DrawableVec) -> Result<()> { + + let mut max = usize::MIN; + for i in list.getListClone().into_iter().map(|x| format!("{:b}",x)){ + + if max < i.len(){ + max = i.len(); + } + + } + for i in 0..(max){ + radix(list, i).await?; + } + + Ok(()) +} + +pub async fn radix(list:&mut DrawableVec, radix:usize) -> Result<()>{ + let mut bucket = vec![vec![];2]; + + for (i, bar) in list.elements().enumerate(){ + + let cur = if get_bit_at(*bar, radix) {1} else {0}; + + bucket[cur].push(i); + + } + + + let mut sortedIndexes = Vec::new(); + for elements in bucket.into_iter(){ + for i in elements{ + sortedIndexes.push(i); + } + } + + let mut listClone = list.getListClone(); + let mut count = 0; + for i in sortedIndexes.clone(){ + list.set(count, listClone[i]).await?; + count += 1; + + } + + Ok(()) +} + +fn get_bit_at(input: u32, n: usize) -> bool { + + if format!("{:b}", input).len() <= n{ + false + }else{ + input & (1 << n) != 0 + } + + +} + +/* + +#[cfg(test)] +#[allow(non_snake_case)] +mod tests { + use crate::GuiHookVec::NonGuiVec; + +use super::*; + + + macro_rules! aw { + ($e:expr) => { + tokio_test::block_on($e) + }; + } + + #[test] + fn radixsort_correct() { + let mut list:NonGuiVec = aw!(SortingList::new(1000,0.0)); + aw!(radixSort(&mut list)); + assert_eq!( list.isSorted(), true); + } + + #[test] + fn get_bit_at_test(){ + let num = 0b0001; + let othernum = 2; + assert_eq!(get_bit_at(num, 0), true); + assert_eq!(get_bit_at(num, 1), false); + assert_eq!(get_bit_at(othernum, 1), true); + assert_eq!(get_bit_at(othernum, 2), false); + assert_eq!(get_bit_at(othernum, 3), false); + } +} + + + +*/ diff --git a/src/drawableVec.rs b/src/drawableVec.rs index a45ae61..14ec054 100644 --- a/src/drawableVec.rs +++ b/src/drawableVec.rs @@ -1,6 +1,7 @@ use std::time::Duration; use color_eyre::{eyre::Ok, Result}; +use rand::seq::SliceRandom; use ratatui::{ DefaultTerminal, Frame, crossterm::event::{self, Event, KeyCode, KeyEventKind}, @@ -12,8 +13,8 @@ use ratatui::{ use tokio::{sync::mpsc::{UnboundedReceiver, UnboundedSender}, time::sleep}; use crate::{ - algorithm::{self, insertSort::{self, sort}}, - graphics::{self, vertical_barchart}, tui::{self, Message}, + algorithm::{self}, + tui::Message, }; pub enum SortingMessage{ @@ -23,7 +24,8 @@ pub enum SortingMessage{ pub struct DrawableVec { vec: Vec, event_rx: UnboundedReceiver, - event_tx: UnboundedSender + event_tx: UnboundedSender, + algo: String } impl DrawableVec { @@ -31,12 +33,13 @@ impl DrawableVec { return DrawableVec { vec, event_rx, - event_tx: event_tx.clone() + event_tx: event_tx.clone(), + algo: "radixSortMSD".to_string(), }; } pub async fn run(mut self) -> Result<()> { - insertSort::sort(&mut self).await?; + algorithm::sort(self.algo.clone(), &mut self).await?; sleep(Duration::from_secs(100000)).await; Ok(()) } @@ -53,7 +56,47 @@ impl DrawableVec { Ok(()) } + pub async fn set(&mut self, i:usize, elem:u32) -> Result<()>{ + self.vec[i] = elem; + self.event_tx.send(Message::SetEvent(i, elem))?; + + self.event_rx.recv().await; + Ok(()) + + } + pub fn lessThan(&self, a: usize, b: usize) -> bool { self.vec[a] < self.vec[b] } + + pub fn elements(&mut self) -> std::slice::Iter<'_, u32> { + self.vec.iter() + } + + pub fn get(&mut self, i:usize)-> u32{ + *self.vec.get(i).unwrap() + } + + pub fn randomize(&mut self){ + self.vec.shuffle(&mut rand::rng()); + } + pub fn isSorted(&mut self) -> bool{ + let mut prev:u32 = 0; + for bar in self.elements() { + if *bar < prev{ + return false; + }else{ + prev = *bar; + } + } + true + } + + pub fn lessThanEqual(&mut self, a:usize, b:u32) -> bool{ + return self.get(a) <= b + } + + pub fn getListClone(&self) -> Vec{ + self.vec.clone() + } } diff --git a/src/graphics.rs b/src/graphics.rs index 265d9f1..4e929c3 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -13,11 +13,9 @@ pub fn vertical_barchart(temperatures: &[u32]) -> BarChart { .enumerate() .map(|(hour, value)| vertical_bar(hour, value)) .collect(); - let title = Line::from("Weather (Vertical)").centered(); BarChart::default() .data(BarGroup::default().bars(&bars)) - .block(Block::new().title(title)) - .bar_width(5) + .bar_width(1) } pub fn vertical_bar(hour: usize, temperature: &u32) -> Bar { diff --git a/src/tui.rs b/src/tui.rs index 0d7cc91..13a0263 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -1,19 +1,29 @@ -use std::{time::Duration}; +use std::time::Duration; +use color_eyre::{Result, eyre::Ok}; use crossterm::event::{Event, KeyCode, KeyEventKind, MouseEventKind}; use rand::seq::SliceRandom; -use ratatui::{layout::{Constraint, Layout}, prelude::CrosstermBackend, style::Stylize, Terminal}; -use tokio::{sync::mpsc::{self, UnboundedReceiver, UnboundedSender}, task::JoinHandle, time}; -use color_eyre::{eyre::Ok, Result}; +use ratatui::{ + Terminal, + layout::{Constraint, Layout}, + prelude::CrosstermBackend, + style::Stylize, +}; +use tokio::{ + sync::mpsc::{self, UnboundedReceiver, UnboundedSender}, + task::JoinHandle, + time, +}; pub enum Message { Quit, Tick, Render, StartSimulation, - SwapEvent(usize, usize) + SwapEvent(usize, usize), + SetEvent(usize, u32), } -pub struct Tui{ +pub struct Tui { terminal: Terminal>, tick_rate: f64, frame_rate: f64, @@ -23,8 +33,10 @@ pub struct Tui{ should_exit: bool, vec: Vec, } -use crate::{drawableVec::{self, DrawableVec, SortingMessage}, graphics::vertical_barchart}; - +use crate::{ + drawableVec::{self, DrawableVec, SortingMessage}, + graphics::vertical_barchart, +}; #[derive(Clone, Debug)] pub enum UpdateCommand { @@ -32,22 +44,22 @@ pub enum UpdateCommand { Quit, } -impl Tui{ - pub fn new() -> Result{ +impl Tui { + pub fn new() -> Result { let terminal = ratatui::init(); - let (event_tx, event_rx):(UnboundedSender,UnboundedReceiver) = mpsc::unbounded_channel(); + let (event_tx, event_rx): (UnboundedSender, UnboundedReceiver) = + mpsc::unbounded_channel(); let (sorting_tx, sorting_rx) = mpsc::unbounded_channel(); let mut vec = (Vec::from_iter(1..100)); vec.shuffle(&mut rand::rng()); - let drawableVec = DrawableVec::new(event_tx.clone(),sorting_rx, vec.clone()); + let drawableVec = DrawableVec::new(event_tx.clone(), sorting_rx, vec.clone()); let sorter = tokio::spawn(drawableVec.run()); - - Ok(Self{ + Ok(Self { terminal, - tick_rate: 10., - frame_rate: 60., + tick_rate: 20., + frame_rate: 120., event_rx, event_tx, sorting_tx, @@ -56,7 +68,7 @@ impl Tui{ }) } - pub async fn run(&mut self) -> Result<()>{ + pub async fn run(&mut self) -> Result<()> { let tick_rate = Duration::from_secs_f64(1.0 / self.tick_rate); let frame_rate = Duration::from_secs_f64(1.0 / self.frame_rate); let mut tick_interval = time::interval(tick_rate); @@ -87,7 +99,7 @@ impl Tui{ } false => continue, } - } + } } } Ok(()) @@ -96,18 +108,22 @@ impl Tui{ async fn update(&mut self, message: Message) -> Result { match message { Message::Quit => Ok(UpdateCommand::Quit), - Message::Tick => { - Ok(UpdateCommand::None) - } + Message::Tick => Ok(UpdateCommand::None), Message::Render => { - self.view()?; - Ok(UpdateCommand::None) - } - Message::StartSimulation => todo!(), - Message::SwapEvent(a,b) => {self.vec.swap(a, b); Ok(UpdateCommand::None)}, + self.view()?; + Ok(UpdateCommand::None) } + Message::StartSimulation => todo!(), + Message::SwapEvent(a, b) => { + self.vec.swap(a, b); + Ok(UpdateCommand::None) + } + Message::SetEvent(i, e) => { + self.vec.insert(i, e); + Ok(UpdateCommand::None) + } + } } - fn view(&mut self) -> Result<()> { self.terminal.draw(|frame| { @@ -130,7 +146,7 @@ impl Tui{ Event::Key(key) => { if key.kind == KeyEventKind::Press && key.code == KeyCode::Esc { self.event_tx.send(Message::Quit)?; - }else if key.kind == KeyEventKind::Press && key.code == KeyCode:: Enter { + } else if key.kind == KeyEventKind::Press && key.code == KeyCode::Enter { self.event_tx.send(Message::StartSimulation)?; } } @@ -138,5 +154,4 @@ impl Tui{ } Ok(()) } - -} \ No newline at end of file +}