From 3a05b90f09ee0ab991f1497d32f06e2ad2234f2a Mon Sep 17 00:00:00 2001 From: polsevev Date: Fri, 3 Mar 2023 23:56:56 +0100 Subject: [PATCH] restructured algorithms, added tests and tests in actions --- .github/workflows/main.yml | 2 + src/Algorithm.rs | 265 --------------------------------- src/GuiHookVec.rs | 2 +- src/algorithm.rs | 47 ++++++ src/algorithm/binaryHeap.rs | 47 ++++++ src/algorithm/bogoSort.rs | 33 ++++ src/algorithm/bubbleSort.rs | 34 +++++ src/algorithm/coctailShaker.rs | 53 +++++++ src/algorithm/insertSort.rs | 33 ++++ src/algorithm/quickSort.rs | 69 +++++++++ src/algorithm/radixSort.rs | 74 +++++++++ src/main.rs | 4 +- 12 files changed, 395 insertions(+), 268 deletions(-) delete mode 100644 src/Algorithm.rs create mode 100644 src/algorithm.rs create mode 100644 src/algorithm/binaryHeap.rs create mode 100644 src/algorithm/bogoSort.rs create mode 100644 src/algorithm/bubbleSort.rs create mode 100644 src/algorithm/coctailShaker.rs create mode 100644 src/algorithm/insertSort.rs create mode 100644 src/algorithm/quickSort.rs create mode 100644 src/algorithm/radixSort.rs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index baab498..ad9a0d0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,6 +15,8 @@ jobs: toolchain: stable override: true components: rustfmt, clippy + - name : Run Tests + run: cargo test --all - name: Add wasm with rustup run: | rustup target add wasm32-unknown-unknown diff --git a/src/Algorithm.rs b/src/Algorithm.rs deleted file mode 100644 index 8ba214c..0000000 --- a/src/Algorithm.rs +++ /dev/null @@ -1,265 +0,0 @@ - -use crate::GuiHookVec::GuiVec; -use crate::GuiHookVec::SortingList; - - - - -use std::collections::BinaryHeap; -use std::collections::HashMap; - - -#[derive(Debug, Clone)] -pub struct Algorithm{ - -} - -impl Algorithm{ - - pub async fn run(length:i32, delay:f32, functionName:String){ - let mut list:GuiVec = SortingList::new(length, delay); - list.randomize(); - - - match functionName.as_str() { - "insertSort" => Algorithm::insertSort(&mut list).await, - "bubbleSort" => Algorithm::bubbleSort(&mut list).await, - "bogoSort" => Algorithm::bogoSort(&mut list).await, - "cocktailShaker" => Algorithm::cocktailShaker(&mut list).await, - "binaryHeap" => Algorithm::binaryHeap(&mut list).await, - "quickSort" => Algorithm::quickSort(&mut list).await, - "radixSort" => Algorithm::radixSort(&mut list).await, - "stalinSort" => Algorithm::stalinSort(&mut list).await, - _ => panic!("No algorithm with that name implemented!") - } - - - - if !list.done{ - list.show().await - } - } - - pub async fn insertSort(list:&mut impl SortingList){ - for index in 0..list.len(){ - let mut j = index; - while j>0 && list.lessThan(j, j-1){ - if list.swap(j, j - 1).await {return}; - j -= 1; - } - } - } - - - pub async fn stalinSort(list:&mut impl SortingList){ - - let mut cur = 1; - loop{ - if cur == list.len() { - break; - } - if list.lessThan(cur, cur-1){ - let mut temp = list.get(cur).clone(); - temp.position = 0; - if list.set(cur, temp).await {return}; - }else{ - cur += 1; - } - - } - - } - - - pub async fn bubbleSort(list:&mut impl SortingList){ - let n = list.len(); - for i in 0..n { - for j in 0..(n - i - 1) { - if list.lessThan(j + 1, j) { - if list.swap(j, j + 1).await {return}; - } - } - } - - } - - pub async fn bogoSort(list:&mut impl SortingList){ - - loop{ - if list.swap(0,0).await {return}; - if list.isSorted() { - break; - } - list.randomize(); - } - } - - pub async fn cocktailShaker(list:&mut impl SortingList){ - 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) { - if list.swap(i+1, i).await {return}; - swapped = true; - } - } - if !swapped{ - break; - } - swapped = false; - upperBound = upperBound-1; - for i in ((lowerBound)..(upperBound)).rev() { - if list.lessThan(i+1, i) { - if list.swap(i+1, i).await {return}; - swapped = true; - } - } - - lowerBound = lowerBound+1; - } - - - - } - - pub async fn binaryHeap(list:&mut impl SortingList){ - - let mut indexMap:HashMap = HashMap::new(); - let mut binHeap:BinaryHeap = BinaryHeap::new(); - - let mut ind = 0; - for bar in list.elements(){ - binHeap.push(bar.position); - indexMap.insert(bar.position, ind); - ind += 1; - } - for i in (0..list.len()).rev(){ - let bar = binHeap.pop().unwrap(); - let barIndex = *indexMap.get(&bar).unwrap(); - if list.swap(i, barIndex).await {return}; - let temp = list.get(barIndex).position; - indexMap.insert(temp, barIndex); - - } - - } - - - - pub async fn partition(list:&mut impl SortingList, mut low:usize, mut high:usize, p:i32) -> i32{ - let mut pIndex = low; - - for i in low..high{ - if list.lessThanEqual(i, p){ - if list.swap(i, pIndex).await {return -1} - pIndex += 1; - } - } - if list.swap(pIndex, high).await {return -1}; - - return pIndex as i32 - } - - - pub async fn quickSort(list:&mut impl SortingList) { - 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).position; - let temp = Algorithm::partition(list, start, end, p).await; - let pivot = if temp >= 0 {temp} else {return}; - - 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)) - } - } - - } - - pub async fn radixSort(list:&mut impl SortingList) { - - let mut max = usize::MAX; - for i in list.getListClone().into_iter().map(|x| x.position.to_string()){ - if max < i.len(){ - max = i.len(); - } - } - - for i in 0..(max){ - if Algorithm::radix(list, i).await {return}; - } - } - - pub async fn radix(list:&mut impl SortingList, radix:usize) -> bool{ - let mut bucket = vec![vec![];10]; - - for (i, bar) in list.elements().enumerate(){ - - let cur = bar.position.to_string().chars().rev().collect::>(); - if cur.len() > radix{ - bucket[cur[radix].to_digit(10).unwrap() as usize].push(i); - }else{ - bucket[0].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(){ - if list.set(count, listClone[i]).await {return true}; - count += 1; - - } - - false - } - - - -} - -#[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 test_str_len_async_2() { - let mut list:NonGuiVec = SortingList::new(1000,0.0); - aw!(Algorithm::insertSort(&mut list)); - assert_eq!( list.isSorted(), true); - } -} \ No newline at end of file diff --git a/src/GuiHookVec.rs b/src/GuiHookVec.rs index f435b47..7302bb3 100644 --- a/src/GuiHookVec.rs +++ b/src/GuiHookVec.rs @@ -13,7 +13,7 @@ use macroquad::time::{get_frame_time, get_fps}; use macroquad::ui::root_ui; use macroquad::window::{next_frame, screen_height, screen_width}; use crate::BarPlugin::Bar; -use crate::Algorithm::Algorithm; +use crate::algorithm::Algorithm; diff --git a/src/algorithm.rs b/src/algorithm.rs new file mode 100644 index 0000000..c789836 --- /dev/null +++ b/src/algorithm.rs @@ -0,0 +1,47 @@ +mod radixSort; +mod insertSort; +mod bubbleSort; +mod binaryHeap; +mod coctailShaker; +mod quickSort; +mod bogoSort; + + +use crate::GuiHookVec::GuiVec; +use crate::GuiHookVec::SortingList; + + + +#[derive(Debug, Clone)] +pub struct Algorithm{ + +} + +impl Algorithm{ + + pub async fn run(length:i32, delay:f32, functionName:String){ + let mut list:GuiVec = SortingList::new(length, delay); + list.randomize(); + + + match functionName.as_str() { + "insertSort" => insertSort::insertSort(&mut list).await, + "bubbleSort" => bubbleSort::bubbleSort(&mut list).await, + "bogoSort" => bogoSort::bogoSort(&mut list).await, + "cocktailShaker" => coctailShaker::cocktailShaker(&mut list).await, + "binaryHeap" => binaryHeap::binaryHeap(&mut list).await, + "quickSort" => quickSort::quickSort(&mut list).await, + "radixSort" => radixSort::radixSort(&mut list).await, + _ => panic!("No algorithm with that name implemented!") + } + + + + if !list.done{ + list.show().await + } + } + + +} + diff --git a/src/algorithm/binaryHeap.rs b/src/algorithm/binaryHeap.rs new file mode 100644 index 0000000..89ba758 --- /dev/null +++ b/src/algorithm/binaryHeap.rs @@ -0,0 +1,47 @@ +use std::collections::{HashMap, BinaryHeap}; + +use crate::GuiHookVec::SortingList; + +pub async fn binaryHeap(list:&mut impl SortingList){ + + let mut indexMap:HashMap = HashMap::new(); + let mut binHeap:BinaryHeap = BinaryHeap::new(); + + let mut ind = 0; + for bar in list.elements(){ + binHeap.push(bar.position); + indexMap.insert(bar.position, ind); + ind += 1; + } + for i in (0..list.len()).rev(){ + let bar = binHeap.pop().unwrap(); + let barIndex = *indexMap.get(&bar).unwrap(); + if list.swap(i, barIndex).await {return}; + let temp = list.get(barIndex).position; + indexMap.insert(temp, barIndex); + + } + +} + +#[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 = 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..619220f --- /dev/null +++ b/src/algorithm/bogoSort.rs @@ -0,0 +1,33 @@ +use crate::GuiHookVec::SortingList; + +pub async fn bogoSort(list:&mut impl SortingList){ + + loop{ + if list.swap(0,0).await {return}; + if list.isSorted() { + break; + } + list.randomize(); + } +} +#[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 = SortingList::new(5,0.0); + aw!(bogoSort(&mut list)); + assert_eq!( list.isSorted(), true); + } +} \ No newline at end of file diff --git a/src/algorithm/bubbleSort.rs b/src/algorithm/bubbleSort.rs new file mode 100644 index 0000000..2bae986 --- /dev/null +++ b/src/algorithm/bubbleSort.rs @@ -0,0 +1,34 @@ +use crate::GuiHookVec::SortingList; + +pub async fn bubbleSort(list:&mut impl SortingList){ + let n = list.len(); + for i in 0..n { + for j in 0..(n - i - 1) { + if list.lessThan(j + 1, j) { + if list.swap(j, j + 1).await {return}; + } + } + } + +} +#[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 = SortingList::new(1000,0.0); + aw!(bubbleSort(&mut list)); + assert_eq!( list.isSorted(), true); + } +} \ No newline at end of file diff --git a/src/algorithm/coctailShaker.rs b/src/algorithm/coctailShaker.rs new file mode 100644 index 0000000..77ba61d --- /dev/null +++ b/src/algorithm/coctailShaker.rs @@ -0,0 +1,53 @@ +use crate::GuiHookVec::SortingList; + +pub async fn cocktailShaker(list:&mut impl SortingList){ + 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) { + if list.swap(i+1, i).await {return}; + swapped = true; + } + } + if !swapped{ + break; + } + swapped = false; + upperBound = upperBound-1; + for i in ((lowerBound)..(upperBound)).rev() { + if list.lessThan(i+1, i) { + if list.swap(i+1, i).await {return}; + swapped = true; + } + } + + lowerBound = lowerBound+1; + } + + + +} +#[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 = SortingList::new(1000,0.0); + aw!(cocktailShaker(&mut list)); + assert_eq!( list.isSorted(), true); + } +} \ No newline at end of file diff --git a/src/algorithm/insertSort.rs b/src/algorithm/insertSort.rs new file mode 100644 index 0000000..5610521 --- /dev/null +++ b/src/algorithm/insertSort.rs @@ -0,0 +1,33 @@ +use crate::GuiHookVec::SortingList; + +pub async fn insertSort(list:&mut impl SortingList){ + for index in 0..list.len(){ + let mut j = index; + while j>0 && list.lessThan(j, j-1){ + if list.swap(j, j - 1).await {return}; + j -= 1; + } + } +} + +#[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 insertsort_correct() { + let mut list:NonGuiVec = SortingList::new(1000,0.0); + aw!(insertSort(&mut list)); + assert_eq!( list.isSorted(), true); + } +} \ No newline at end of file diff --git a/src/algorithm/quickSort.rs b/src/algorithm/quickSort.rs new file mode 100644 index 0000000..670c2ec --- /dev/null +++ b/src/algorithm/quickSort.rs @@ -0,0 +1,69 @@ +use crate::GuiHookVec::SortingList; + + + +pub async fn quickSort(list:&mut impl SortingList) { + 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).position; + let temp = partition(list, start, end, p).await; + let pivot = if temp >= 0 {temp} else {return}; + + 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)) + } + } + +} + + + +async fn partition(list:&mut impl SortingList, mut low:usize, mut high:usize, p:i32) -> i32{ + let mut pIndex = low; + + for i in low..high{ + if list.lessThanEqual(i, p){ + if list.swap(i, pIndex).await {return -1} + pIndex += 1; + } + } + if list.swap(pIndex, high).await {return -1}; + + return 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 = SortingList::new(1000,0.0); + aw!(quickSort(&mut list)); + assert_eq!( list.isSorted(), true); + } +} \ No newline at end of file diff --git a/src/algorithm/radixSort.rs b/src/algorithm/radixSort.rs new file mode 100644 index 0000000..cebfde8 --- /dev/null +++ b/src/algorithm/radixSort.rs @@ -0,0 +1,74 @@ +use crate::GuiHookVec::SortingList; + + + +pub async fn radixSort(list:&mut impl SortingList) { + + let mut max = usize::MIN; + for i in list.getListClone().into_iter().map(|x| x.position.to_string()){ + + if max < i.len(){ + max = i.len(); + } + + } + + for i in 0..(max){ + if radix(list, i).await {return}; + } +} + +async fn radix(list:&mut impl SortingList, radix:usize) -> bool{ + let mut bucket = vec![vec![];10]; + + for (i, bar) in list.elements().enumerate(){ + + let cur = bar.position.to_string().chars().rev().collect::>(); + if cur.len() > radix{ + bucket[cur[radix].to_digit(10).unwrap() as usize].push(i); + }else{ + bucket[0].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(){ + if list.set(count, listClone[i]).await {return true}; + count += 1; + + } + + false +} + +#[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 = SortingList::new(10000,0.0); + aw!(radixSort(&mut list)); + assert_eq!( list.isSorted(), true); + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index c253f8c..1dde168 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ mod BarPlugin; mod GuiHookVec; -mod Algorithm; +mod algorithm; use macroquad::prelude::*; use macroquad::prelude::scene::clear; @@ -66,7 +66,7 @@ async fn main() { if algo != ""{ - Algorithm::Algorithm::run(length, 1.0, algo.to_string()).await; + algorithm::Algorithm::run(length, 1.0, algo.to_string()).await; } next_frame().await }