Compare commits

..

No commits in common. "master" and "dev" have entirely different histories.
master ... dev

24 changed files with 325 additions and 1039 deletions

View file

@ -6,7 +6,7 @@ on:
jobs: jobs:
build: build:
name: Build name: Build
runs-on: self-hosted runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Install latest stable - name: Install latest stable
@ -18,7 +18,6 @@ jobs:
- name: Add wasm with rustup - name: Add wasm with rustup
run: | run: |
rustup target add wasm32-unknown-unknown rustup target add wasm32-unknown-unknown
- name: build-wasm-file - name: build-wasm-file
run: | run: |
cargo build --target wasm32-unknown-unknown --release cargo build --target wasm32-unknown-unknown --release
@ -28,8 +27,6 @@ jobs:
cp index.html transport/ cp index.html transport/
cp target/wasm32-unknown-unknown/release/BeepSortMacroQuad.d transport/ cp target/wasm32-unknown-unknown/release/BeepSortMacroQuad.d transport/
cp target/wasm32-unknown-unknown/release/BeepSortMacroQuad.wasm transport/ cp target/wasm32-unknown-unknown/release/BeepSortMacroQuad.wasm transport/
- name: ls
run: ls
- name: rsync files - name: rsync files
uses: burnett01/rsync-deployments@5.2 uses: burnett01/rsync-deployments@5.2
with: with:

View file

@ -1,13 +0,0 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: beepsort-cert
namespace: beepsort
spec:
secretName: beepsort-cert
issuerRef:
name: acme-issuer
kind: ClusterIssuer
dnsNames:
- "beepsort.polsevev.dev"

View file

@ -1,21 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: beepsort
namespace: beepsort
spec:
replicas: 1
selector:
matchLabels:
app: beepsort
template:
metadata:
labels:
app: beepsort
name: beepsort
spec:
containers:
- name: beepsort
image: registry.lan.polsevev.dev/beepsort:v0.1.1
ports:
- containerPort: 80

View file

@ -1,21 +0,0 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: beepsort-ingress
namespace: beepsort
spec:
rules:
- host: "beepsort.polsevev.dev"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: beepsort-service
port:
number: 99
tls:
- hosts:
- beepsort.polsevev.dev
secretName: beepsort-cert

View file

@ -1,14 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: beepsort-service
namespace: beepsort
spec:
selector:
app: beepsort
type: LoadBalancer
ports:
- name: docker-port
protocol: TCP
port: 99
targetPort: 80

142
Cargo.lock generated
View file

@ -8,7 +8,6 @@ version = "0.1.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"macroquad", "macroquad",
"tokio-test",
] ]
[[package]] [[package]]
@ -28,28 +27,6 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "async-stream"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad445822218ce64be7a341abfb0b1ea43b5c23aa83902542a4542e78309d8e5e"
dependencies = [
"async-stream-impl",
"futures-core",
"pin-project-lite",
]
[[package]]
name = "async-stream-impl"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4655ae1a7b0cdf149156f780c5bf3f1352bc53cbd9e0a361a7ef7b22947e965"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.64" version = "0.1.64"
@ -109,12 +86,6 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@ -171,12 +142,6 @@ dependencies = [
"ttf-parser", "ttf-parser",
] ]
[[package]]
name = "futures-core"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608"
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.8" version = "0.2.8"
@ -358,12 +323,6 @@ version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "pin-project-lite"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
[[package]] [[package]]
name = "png" name = "png"
version = "0.17.7" version = "0.17.7"
@ -442,41 +401,6 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "tokio"
version = "1.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64"
dependencies = [
"autocfg",
"pin-project-lite",
"windows-sys",
]
[[package]]
name = "tokio-stream"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313"
dependencies = [
"futures-core",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tokio-test"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53474327ae5e166530d17f2d956afcb4f8a004de581b3cae10f12006bc8163e3"
dependencies = [
"async-stream",
"bytes",
"futures-core",
"tokio",
"tokio-stream",
]
[[package]] [[package]]
name = "ttf-parser" name = "ttf-parser"
version = "0.15.2" version = "0.15.2"
@ -522,69 +446,3 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]]
name = "windows_i686_gnu"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]]
name = "windows_i686_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"

View file

@ -8,7 +8,7 @@ edition = "2021"
[dependencies] [dependencies]
macroquad = "0.3.25" macroquad = "0.3.25"
async-trait = "0.1.64" async-trait = "0.1.64"
tokio-test = "*" [toolchain]
channel = "nightly"
[profile.release] [profile.release]
opt-level=3 opt-level=3

View file

@ -1,3 +0,0 @@
FROM nginx:alpine3.18
COPY ./index.html /usr/share/nginx/html/
COPY ./target/wasm32-unknown-unknown/release/BeepSortMacroQuad.wasm /usr/share/nginx/html/

View file

@ -13,17 +13,3 @@ WebAssembly version can be found here [beepsort.polsevev.dev](https://beepsort.p
- Clean up user interface, perhaps move to JS? - Clean up user interface, perhaps move to JS?
- Add more visualization modes (circle, points etc) - Add more visualization modes (circle, points etc)
- Add more algorithms - Add more algorithms
## Contributing
If you wish to contribute an algorithm to this project, i encourage it!
Algorithms are located in [Algorithm.rs](./src/Algorithm.rs) and are made as follows!
1. Create a case in the match located in the function run
2. Implement the algorithm as an async function
3. Whenever you wish to swap two elements, do so in the following manner:
- ```if list.swap(a,b).await {return}```
- This ensures we can exit the run of the algorithm if the user clicks "Exit"
4. Add a button on the front page (will move to a menu in the future!)
5. Success!!!!!

246
src/Algorithm.rs Normal file
View file

@ -0,0 +1,246 @@
use crate::BarPlugin::Bar;
use crate::GuiHookVec;
use crate::GuiHookVec::GuiVec;
use crate::GuiHookVec::SortingList;
use std::collections::BinaryHeap;
use std::collections::HashMap;
use std::collections::HashSet;
use std::f32::consts::PI;
use std::hash::Hash;
#[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,
_ => 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 fn stalinSort(length:i32){
let mut list = GuiVec::new(screen_width(), screen_height(), length);
list.randomize();
let mut cur = 1;
loop{
if cur == list.len() {
break;
}
if list.lessThan(cur, cur-1){
list.delete(cur);
}else{
cur += 1;
}
yield list.clone();
}
}
*/
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<i32, usize> = HashMap::new();
let mut binHeap:BinaryHeap<i32> = 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::<Vec<char>>();
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
}
}

View file

@ -1,28 +1,20 @@
use macroquad::audio::PlaySoundParams;
use macroquad::audio::Sound;
use macroquad::audio::play_sound;
use macroquad::audio::play_sound_once;
use macroquad::color; use macroquad::color;
use macroquad::color_u8; use macroquad::color_u8;
use macroquad::rand; use macroquad::rand;
use crate::soundGenerator;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Bar { pub struct Bar {
pub position:usize, pub position:i32,
pub color:color::Color, pub color:color::Color
} }
impl Bar{ impl Bar{
pub fn new(position:usize, hsl_color:f32) -> Self{ pub fn new(position:i32, hsl_color:f32) -> Self{
Bar{ Bar{
position, position,
color: color::hsl_to_rgb((hsl_color as f32) , 1.0, 0.5), color: color::hsl_to_rgb((hsl_color as f32) , 1.0, 0.5),
} }
} }
} }

View file

@ -1,9 +1,10 @@
use std::borrow::{Borrow, BorrowMut};
use std::ops::Add;
use std::path::Iter;
use async_trait::async_trait; use async_trait::async_trait;
use macroquad::audio::{play_sound_once, Sound, play_sound, PlaySoundParams};
use macroquad::color::{BROWN, WHITE}; use macroquad::color::{BROWN, WHITE};
use macroquad::{hash, time}; use macroquad::hash;
use macroquad::prelude::{clear_background, Vec2, BLACK}; use macroquad::prelude::{clear_background, Vec2, BLACK};
use macroquad::rand::ChooseRandom; use macroquad::rand::ChooseRandom;
use macroquad::shapes::draw_rectangle; use macroquad::shapes::draw_rectangle;
@ -12,8 +13,7 @@ use macroquad::time::{get_frame_time, get_fps};
use macroquad::ui::root_ui; use macroquad::ui::root_ui;
use macroquad::window::{next_frame, screen_height, screen_width}; use macroquad::window::{next_frame, screen_height, screen_width};
use crate::BarPlugin::Bar; use crate::BarPlugin::Bar;
use crate::soundGenerator; use crate::Algorithm::Algorithm;
@ -29,14 +29,13 @@ pub struct GuiVec{
delay:f32, delay:f32,
pub done:bool, pub done:bool,
renderSkip:i32, renderSkip:i32,
skipped:i32, skipped:i32
lastTouched:Vec<usize>,
lastPlayed:f64,
} }
#[async_trait] #[async_trait]
pub trait SortingList{ pub trait SortingList{
async fn new(length:usize, delay:f32) -> Self; fn new(length:i32, delay:f32) -> Self;
fn len(&self) -> usize; fn len(&self) -> usize;
@ -53,7 +52,7 @@ pub trait SortingList{
fn lessThan(&mut self, a:usize, b:usize) -> bool; fn lessThan(&mut self, a:usize, b:usize) -> bool;
fn lessThanEqual(&mut self, a:usize, b:usize) -> bool; fn lessThanEqual(&mut self, a:usize, b:i32) -> bool;
fn isSorted(&mut self) -> bool; fn isSorted(&mut self) -> bool;
@ -66,18 +65,12 @@ pub trait SortingList{
#[async_trait] #[async_trait]
impl SortingList for GuiVec{ impl SortingList for GuiVec{
async fn new(length:usize, delay:f32) -> Self { fn new(length:i32, delay:f32) -> Self {
let colorStep = 360./length as f32; let colorStep = 360./length as f32;
let mut list:Vec<Bar> = vec!(); let mut list:Vec<Bar> = vec!();
let freqStep = 50. + ((2000.-50.)/length as f32);
for i in 1..length+1 { for i in 1..length+1 {
let frequency = i as f32 * freqStep;
list.push(Bar::new(i, (colorStep*i as f32)/360.)); list.push(Bar::new(i, (colorStep*i as f32)/360.));
} }
GuiVec{ GuiVec{
list, list,
initialSize:length as usize, initialSize:length as usize,
@ -89,9 +82,7 @@ impl SortingList for GuiVec{
delay, delay,
done:false, done:false,
renderSkip:1, renderSkip:1,
skipped:0, skipped:0
lastTouched:Vec::with_capacity(2),
lastPlayed:0.,
} }
} }
@ -102,28 +93,29 @@ impl SortingList for GuiVec{
loop { loop {
/*
self.checkPaused();
if self.isPaused{
break;
}
*/
if self.skipped >= self.renderSkip{ if self.skipped >= self.renderSkip{
clear_background(WHITE); clear_background(WHITE);
for (count,bar) in self.list.iter().enumerate(){ for (count,bar) in self.list.iter().enumerate(){
let mut color = bar.color; draw_rectangle(screen_width() * ((count as f32)/(self.initialSize as f32)),screen_height() - (screen_height()/((self.len()) as f32))*bar.position as f32 , screen_width()/((self.len()) as f32), (screen_height()/((self.len()) as f32))*bar.position as f32, bar.color);
if self.lastTouched.contains(&count){
color = BLACK;
}
draw_rectangle(screen_width() * ((count as f32)/(self.initialSize as f32)),screen_height() - (screen_height()/((self.len()) as f32))*bar.position as f32 , screen_width()/((self.len()) as f32), (screen_height()/((self.len()) as f32))*bar.position as f32, color);
} }
draw_text(&format!("FPS: {}", get_fps()), screen_width()*0.01 + 40., 80.0, 20.0, BLACK);
draw_text(&format!("Array reads: {}", self.reads), screen_width()*0.01 + 40., 110.0, 20.0, BLACK);
draw_text(&format!("Array writes: {}", self.writes), screen_width()*0.01 + 40., 140.0, 20.0, BLACK);
draw_text(&format!("Comparisons: {}", self.comps), screen_width()*0.01 + 40., 170.0, 20.0, BLACK);
root_ui().window(hash!(),Vec2::new(screen_width()*0.01, 5.), Vec2::new(800.0, 50.), |ui|{ root_ui().window(hash!(),Vec2::new(screen_width()*0.01, 5.), Vec2::new(800.0, 50.), |ui|{
ui.input_text(hash!(), "Delay (ms)", &mut delayText); ui.input_text(hash!(), "Delay (ms)", &mut delayText);
ui.input_text(hash!(), "StepsPrFrame (How many steps of the algorithm pr frame)", &mut renderSkipText); ui.input_text(hash!(), "StepsPrFrame (How many steps of the algorithm pr frame)", &mut renderSkipText);
draw_text(&format!("FPS: {}", get_fps()), screen_width()*0.01 + 40., 80.0, 20.0, BLACK);
draw_text(&format!("Array reads: {}", self.reads), screen_width()*0.01 + 40., 110.0, 20.0, BLACK);
draw_text(&format!("Array writes: {}", self.writes), screen_width()*0.01 + 40., 140.0, 20.0, BLACK);
draw_text(&format!("Comparisons: {}", self.comps), screen_width()*0.01 + 40., 170.0, 20.0, BLACK);
}); });
@ -170,15 +162,7 @@ impl SortingList for GuiVec{
self.writes += 2; self.writes += 2;
self.reads += 2; self.reads += 2;
self.list.swap(index1, index2); self.list.swap(index1, index2);
self.lastTouched.clear();
self.lastTouched.push(index1);
self.lastTouched.push(index2);
self.draw().await; self.draw().await;
self.done self.done
} }
fn randomize(&mut self){ fn randomize(&mut self){
@ -191,16 +175,13 @@ impl SortingList for GuiVec{
fn get(&mut self, i:usize)-> &Bar{ fn get(&mut self, i:usize)-> &Bar{
self.reads += 1; self.reads += 1;
self.lastTouched.clear();
self.lastTouched.push(i);
self.list.get(i).unwrap() self.list.get(i).unwrap()
} }
fn lessThan(&mut self, a:usize, b:usize) -> bool{ fn lessThan(&mut self, a:usize, b:usize) -> bool{
self.comps += 1; self.comps += 1;
return self.get(a).position < self.get(b).position return self.get(a).position < self.get(b).position
} }
fn lessThanEqual(&mut self, a:usize, b:usize) -> bool{ fn lessThanEqual(&mut self, a:usize, b:i32) -> bool{
self.comps += 1; self.comps += 1;
return self.get(a).position <= b return self.get(a).position <= b
} }
@ -222,12 +203,6 @@ impl SortingList for GuiVec{
self.reads += 1; self.reads += 1;
self.list[i] = elem; self.list[i] = elem;
self.draw().await; self.draw().await;
if time::get_time() + 0.1 >= self.lastPlayed{
self.lastPlayed = time::get_time()+0.1;
}
self.lastTouched.clear();
self.lastTouched.push(i);
self.done self.done
} }
@ -247,16 +222,16 @@ impl SortingList for GuiVec{
} }
pub struct NonGuiVec{ struct NonGuiVec{
pub list: Vec<Bar>, pub list: Vec<Bar>,
} }
#[async_trait] #[async_trait]
impl SortingList for NonGuiVec{ impl SortingList for NonGuiVec{
async fn new(length:usize, delay:f32) -> Self{ fn new(length:i32, delay:f32) -> Self{
let mut list = Vec::new(); let mut list = Vec::new();
for i in 0..(length as usize){ for i in 0..(length as usize){
list.push(Bar::new(i, i as f32)) list.push(Bar::new(i as i32, i as f32))
} }
NonGuiVec { list: list } NonGuiVec { list: list }
} }
@ -290,7 +265,7 @@ impl SortingList for NonGuiVec{
return self.get(a).position < self.get(b).position return self.get(a).position < self.get(b).position
} }
fn lessThanEqual(&mut self, a:usize, b:usize) -> bool{ fn lessThanEqual(&mut self, a:usize, b:i32) -> bool{
return self.get(a).position <= b return self.get(a).position <= b
} }
fn isSorted(&mut self) -> bool{ fn isSorted(&mut self) -> bool{
@ -308,7 +283,6 @@ impl SortingList for NonGuiVec{
self.list[i] = elem; self.list[i] = elem;
self.draw().await; self.draw().await;
false false
} }

View file

@ -1,64 +0,0 @@
mod radixSort;
mod insertSort;
mod bubbleSort;
mod binaryHeap;
mod coctailShaker;
mod quickSort;
mod bogoSort;
mod radixSortLSD;
use crate::GuiHookVec::GuiVec;
use crate::GuiHookVec::SortingList;
#[derive(Debug, Clone)]
pub struct Algorithm{
algorithms:Vec<String>
}
impl Algorithm{
pub fn new() -> Self{
Algorithm { algorithms: vec![
"insertSort".to_string(),
"bubbleSort".to_string(),
"bogoSort".to_string(),
"cocktailShaker".to_string(),
"binaryHeap".to_string(),
"quickSort".to_string(),
"radixSortMSD".to_string(),
"radixSortLSD".to_string()
] }
}
pub async fn run(length:usize, delay:f32, functionName:String){
let mut list:GuiVec = SortingList::new(length, delay).await;
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,
"radixSortMSD" => radixSort::radixSort(&mut list).await,
"radixSortLSD" => radixSortLSD::radixSort(&mut list).await,
_ => panic!("No algorithm with that name implemented!")
}
if !list.done{
list.show().await
}
}
pub fn getAlgorithms(&self) -> &Vec<String>{
&self.algorithms
}
}

View file

@ -1,47 +0,0 @@
use std::collections::{HashMap, BinaryHeap};
use crate::GuiHookVec::SortingList;
pub async fn binaryHeap(list:&mut impl SortingList){
let mut indexMap:HashMap<usize, usize> = HashMap::new();
let mut binHeap:BinaryHeap<usize> = 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 = aw!(SortingList::new(1000,0.0));
aw!(binaryHeap(&mut list));
assert_eq!( list.isSorted(), true);
}
}

View file

@ -1,33 +0,0 @@
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 = aw!(SortingList::new(5,0.0));
aw!(bogoSort(&mut list));
assert_eq!( list.isSorted(), true);
}
}

View file

@ -1,34 +0,0 @@
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 = aw!(SortingList::new(1000,0.0));
aw!(bubbleSort(&mut list));
assert_eq!( list.isSorted(), true);
}
}

View file

@ -1,53 +0,0 @@
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, i+1).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 = aw!(SortingList::new(1000,0.0));
aw!(cocktailShaker(&mut list));
assert_eq!( list.isSorted(), true);
}
}

View file

@ -1,33 +0,0 @@
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 = aw!(SortingList::new(1000,0.0));
aw!(insertSort(&mut list));
assert_eq!( list.isSorted(), true);
}
}

View file

@ -1,69 +0,0 @@
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:usize) -> 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 = aw!(SortingList::new(1000,0.0));
aw!(quickSort(&mut list));
assert_eq!( list.isSorted(), true);
}
}

View file

@ -1,117 +0,0 @@
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| format!("{:b}",x.position)){
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
}
}
stack = stack2.clone();
stack2.clear();
}
}
async fn radix(list:&mut impl SortingList, radix:usize, mut minBoundry:usize, mut maxBoundry:usize) -> Option<(usize,usize,usize)>{
let initialMin = minBoundry.clone();
let initialMax = maxBoundry.clone();
loop{
if maxBoundry == minBoundry{
break
}
let currentBit = get_bit_at(list.get(minBoundry).position, radix);
if currentBit{
if list.swap(minBoundry, maxBoundry-1).await {return None};
maxBoundry -= 1;
}else{
if list.swap(minBoundry, minBoundry).await {return None};
minBoundry += 1;
}
}
Some((initialMin, minBoundry, initialMax))
}
fn get_bit_at(input: usize, 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);
}
}

View file

@ -1,94 +0,0 @@
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| format!("{:b}",x.position)){
if max < i.len(){
max = i.len();
}
}
for i in 0..(max){
if radix(list, i).await {return};
}
}
pub async fn radix(list:&mut impl SortingList, radix:usize) -> bool{
let mut bucket = vec![vec![];2];
for (i, bar) in list.elements().enumerate(){
let cur = if get_bit_at(bar.position, 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(){
if list.set(count, listClone[i]).await {return true};
count += 1;
}
false
}
fn get_bit_at(input: usize, 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);
}
}

View file

@ -1,63 +0,0 @@
use macroquad::hash;
use macroquad::{ui::root_ui, window::screen_width, prelude::Vec2};
enum Status{
Open,
Closed
}
pub struct ButtonDropDown{
selected:String,
elements:Vec<String>,
status:Status
}
impl ButtonDropDown{
pub fn new(elements:&Vec<String>) -> Self{
ButtonDropDown{
selected:elements.get(0).unwrap().clone(),
elements:elements.clone(),
status:Status::Closed
}
}
pub fn render(&mut self) -> String{
let mut algo = "";
let location = Vec2::new((screen_width() / 2.) - 150., 200.);
match self.status{
Status::Open => {
let size = Vec2::new(300., (self.elements.len() as f32*25.0) + 20.0);
root_ui().window(hash!(), location, size, |ui|{
let mut position = Vec2::new(10.0, 10.);
for i in self.elements.iter(){
let label = format!("{}{}", i[0..1].to_string().to_uppercase(), i[1..i.len()].to_string());
if ui.button(position, label.as_str()){
self.selected = i.clone();
self.status = Status::Closed;
}
position.y += 25.0;
}
});
}
Status::Closed => {
root_ui().window(hash!(), location, Vec2::new(300., 50.), |ui|{
let uppercasedSelected = format!("{}{}", self.selected[0..1].to_string().to_uppercase(), self.selected[1..self.selected.len()].to_string());
ui.label(Vec2::new(10.0, 0.0), format!("Curent chosen algorithm: {}", uppercasedSelected).as_str());
if ui.button(Vec2::new(10.0, 20.0), "Open Menu!"){
self.status = Status::Open;
}
if ui.button(Vec2::new(200.0, 20.0), "RUN!"){
algo = self.selected.as_str();
}
});
},
}
algo.to_string()
}
}

View file

@ -1,60 +1,71 @@
mod BarPlugin; mod BarPlugin;
mod GuiHookVec; mod GuiHookVec;
mod algorithm; mod Algorithm;
mod dropdown;
mod soundGenerator;
use std::f32::consts::PI;
use std::fs::File;
use std::path::Path;
use dropdown::ButtonDropDown;
use macroquad::prelude::*; use macroquad::prelude::*;
use macroquad::prelude::scene::clear;
use crate::BarPlugin::Bar;
use crate::GuiHookVec::GuiVec;
use macroquad::hash; use macroquad::hash;
use macroquad::ui::root_ui; use macroquad::ui::root_ui;
#[macroquad::main("BeepSort")] #[macroquad::main("BeepSort")]
async fn main() { async fn main() {
let mut length = 1_usize; let mut length = 1;
let mut lengthString = "100".to_owned(); let mut lengthString = "100".to_owned();
let mut delay = 0.;
let mut delayText = "1".to_owned(); let mut delayText = "1".to_owned();
let mut algorithm = algorithm::Algorithm::new();
let mut buttonDropDown = ButtonDropDown::new(&algorithm.getAlgorithms());
loop{ loop{
clear_background(WHITE); clear_background(WHITE);
length = match lengthString.parse::<usize>(){
delay = match delayText.parse::<f64>(){
Ok(a) => a/1000.,
Err(error)=> {0.1}
};
length = match lengthString.parse::<i32>(){
Ok(a) => a, Ok(a) => a,
Err(_)=> {100} Err(error)=> {100}
}; };
let mut centerX = screen_width()/2.0; draw_text("Sorting!", screen_width()*0.3, screen_height()*0.1, 100.0, GREEN);
draw_text(format!("Length: {}", length.to_string()).as_str(), screen_width()*0.83, 30., 20.0, BLACK);
draw_text(&get_fps().to_string(), screen_width()*0.7, 30.0, 20.0, BLACK);
draw_text("Sorting! Made by Polsevev", centerX-170.0, screen_height()*0.1, 100.0, BLACK); root_ui().window(hash!(), Vec2::new(screen_width()*0.01, 45.), Vec2::new(250., 50.), |ui|{
draw_text(&get_fps().to_string(), centerX + 300., 30.0, 20.0, BLACK);
root_ui().window(hash!(), Vec2::new(centerX - 150.0, 150.), Vec2::new(300., 45.), |ui|{
ui.input_text(hash!(), "Delay (ms)", &mut delayText); ui.input_text(hash!(), "Delay (ms)", &mut delayText);
ui.input_text(hash!(), "Length Of Array!", &mut lengthString); ui.input_text(hash!(), "Length Of Array!", &mut lengthString);
}); });
let mut algo = "";
let mut algo = buttonDropDown.render(); if root_ui().button(Vec2::new(screen_width()*0.01, 100.), "Run InsertSort!"){
algo = "insertSort";
}
if root_ui().button(Vec2::new(screen_width()*0.01, 130.), "Run BubbleSort!"){
algo = "bubbleSort";
}
if root_ui().button(Vec2::new(screen_width()*0.01, 160.), "Run BinaryHeapSort!"){
algo = "binaryHeap";
}
if root_ui().button(Vec2::new(screen_width()*0.01, 190.), "Run CoctailShakerSort!"){
algo = "cocktailShaker";
}
if root_ui().button(Vec2::new(screen_width()*0.01, 220.), "Run BogoSort!"){
algo = "bogoSort";
}
if root_ui().button(Vec2::new(screen_width()*0.01, 250.), "Run QuickSort!"){
algo = "quickSort";
}
if root_ui().button(Vec2::new(screen_width()*0.01, 280.), "Run RadixSort!"){
algo = "radixSort";
}
if algo != ""{ 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 next_frame().await
} }

View file

@ -1,99 +0,0 @@
use std::{f32::consts::PI};
use macroquad::{audio::{Sound, load_sound_from_bytes, play_sound_once}, window::{next_frame, screen_width, screen_height, clear_background}, text::draw_text, prelude::{BLACK, WHITE}};
const CHUNK_ID:&str = "RIFF";
const CHUNK_SIZE:&str = "----";
const FORMAT:&str = "WAVE";
//FMT sub-chunk
const SUBCHUNK_1_ID:&str = "fmt ";
const SUBCHUNK_1_SIZE:i32 = 16;
const AUDIO_FORMAT:i16 = 1;
const NUM_CHANNELS:i16 = 1;
const SAMPLE_RATE:i32 = 44100;
const BYTE_RATE:i32 = SAMPLE_RATE * NUM_CHANNELS as i32 * (SUBCHUNK_1_SIZE / 8);
const BLOACK_ALIGN:i16 = NUM_CHANNELS * (SUBCHUNK_1_SIZE / 8) as i16;
const BITS_PR_SAMPLE:i16 = 16;
//Data sub-chunk
const SUBCHUNK_2_ID:&str = "data";
const SUBCHUNK_2_SIZE:&str = "----";
const MAX_AMPLITUDE:usize = 32760;
pub async fn generateTone(frequency: f32, duration:f32) -> Sound{
// const CHUNK_ID:&str = "RIFF";
// const CHUNK_SIZE:&str = "----";
// const FORMAT:&str = "WAVE";
// //FMT sub-chunk
// const SUBCHUNK_1_ID:&str = "fmt ";
// const SUBCHUNK_1_SIZE:u32 = 16;
// const AUDIO_FORMAT:u16 = 1;
// const NUM_CHANNELS:u16 = 1;
// const SAMPLE_RATE:u32 = 44100;
// const BYTE_RATE:u32 = SAMPLE_RATE * NUM_CHANNELS as u32 * (SUBCHUNK_1_SIZE / 8);
// const BLOACK_ALIGN:u16 = NUM_CHANNELS * (SUBCHUNK_1_SIZE / 8) as u16;
// const BITS_PR_SAMPLE:u16 = 16;
// //Data sub-chunk
// const SUBCHUNK_2_ID:&str = "data";
// const SUBCHUNK_2_SIZE:&str = "----";
// const MAX_AMPLITUDE:usize = 32760;
let mut soundFileBytes = [
CHUNK_ID.as_bytes(),
CHUNK_SIZE.as_bytes(),
FORMAT.as_bytes(),
SUBCHUNK_1_ID.as_bytes(),
&SUBCHUNK_1_SIZE.to_le_bytes(),
&AUDIO_FORMAT.to_le_bytes(),
&NUM_CHANNELS.to_le_bytes(),
&SAMPLE_RATE.to_le_bytes(),
&BYTE_RATE.to_le_bytes(),
&BLOACK_ALIGN.to_le_bytes(),
&BITS_PR_SAMPLE.to_le_bytes(),
SUBCHUNK_2_ID.as_bytes(),
SUBCHUNK_2_SIZE.as_bytes()
].concat();
let startAudio = soundFileBytes.len();
let lim = ((SAMPLE_RATE as f32 * duration) as usize);
for i in 0..((SAMPLE_RATE as f32 * duration) as usize){
let amplitude = 500. * f32::sin((i as f32 - 300.) / 1200.);
let value = f32::sin((2. * PI * (i as f32) * (frequency as f32)) / SAMPLE_RATE as f32);
let channel = (amplitude * if i+100 > lim {0.} else {value});
soundFileBytes.append(&mut (channel as i16).to_le_bytes().to_vec());
}
let endAudio = soundFileBytes.len() as u32;
for (i, elem) in (endAudio-startAudio as u32).to_le_bytes().into_iter().enumerate(){
soundFileBytes[(startAudio-4)+i] = elem;
}
for (i, elem) in (36+endAudio-startAudio as u32).to_be_bytes().into_iter().enumerate(){
soundFileBytes[4+i] = elem;
}
load_sound_from_bytes(&soundFileBytes).await.expect("Failed to load")
}