Compare commits

..

35 commits
dev ... master

Author SHA1 Message Date
0969366e27 Added kubernetes config 2023-11-29 21:02:19 +01:00
a4946f0117 lol 2023-11-23 20:53:49 +01:00
0ed1802b18 Made a small change to headline 2023-11-23 20:52:26 +01:00
Rolf Martin Glomsrud
dce6caf88e
Update main.yml 2023-11-23 20:39:43 +01:00
Rolf Martin Glomsrud
e1993b416f
Update main.yml 2023-11-23 20:39:08 +01:00
Rolf Martin Glomsrud
bf2e695e38
Update main.yml 2023-11-23 19:55:36 +01:00
a5a1db2889 fixed audio 2023-03-06 22:00:57 +01:00
937ac30517 mby faster audio generation 2023-03-06 15:48:25 +01:00
483af34fa7 Audio speed up 2023-03-06 15:35:54 +01:00
49b0e69299 maybe fixed audio issues 2023-03-05 04:16:59 +01:00
44c04dbdc2 small sound improvement 2023-03-05 04:13:02 +01:00
8b89189902 Audio cleanup and fix audio playing for swap on algorithm side 2023-03-05 03:58:25 +01:00
db8debb31a SOUND! 2023-03-05 01:51:07 +01:00
2df3d0a005 sound absolutely fixed 2023-03-05 00:23:18 +01:00
c3ef0c4b7b sound fixed! 2023-03-05 00:21:12 +01:00
b39a778b2d added a smoother intro the each sound 2023-03-04 23:39:26 +01:00
b9c6fd24d7 Audio sucks 2023-03-04 23:36:25 +01:00
d81a1a5167 Added processing screen 2023-03-04 23:29:56 +01:00
58aaf78f5a fixed audio, still needs to do static removal 2023-03-04 23:27:01 +01:00
b6c438ae0f added sound generation, this is currently very broken! 2023-03-04 23:11:05 +01:00
67090986bb sound test wasm 2023-03-04 21:47:37 +01:00
3e013192d0 Added MSB and LSB radix sort algorithms 2023-03-04 04:32:52 +01:00
fb40910c10 added a indicator to what element the algorithm is evaluating 2023-03-04 04:00:49 +01:00
7324861472 centered UI 2023-03-04 03:33:39 +01:00
caf515b14f Added dropdown for algorithm choice 2023-03-04 03:14:03 +01:00
8ebad48659 fixed bitwise radix sort 2023-03-04 02:27:27 +01:00
25e4183e7a borked radix sort 2023-03-04 01:52:39 +01:00
79dc592a40 tests fucked, skip on build 2023-03-04 00:14:47 +01:00
913c516713 fixed dependencies 2023-03-04 00:10:31 +01:00
c01a58ef14 workflow fix 2023-03-04 00:08:49 +01:00
3a05b90f09 restructured algorithms, added tests and tests in actions 2023-03-03 23:56:56 +01:00
63e8214974 testing github action 2023-03-03 20:06:40 +01:00
427e5586d7 added testing 2023-03-03 01:37:09 +01:00
0b68bb773f merge? 2023-03-03 01:20:12 +01:00
3dc71499ac added contributing to ReadMe 2023-03-01 00:10:00 +01:00
24 changed files with 1039 additions and 325 deletions

View file

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

View file

@ -0,0 +1,13 @@
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

@ -0,0 +1,21 @@
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

@ -0,0 +1,21 @@
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

@ -0,0 +1,14 @@
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,6 +8,7 @@ version = "0.1.0"
dependencies = [
"async-trait",
"macroquad",
"tokio-test",
]
[[package]]
@ -27,6 +28,28 @@ dependencies = [
"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]]
name = "async-trait"
version = "0.1.64"
@ -86,6 +109,12 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -142,6 +171,12 @@ dependencies = [
"ttf-parser",
]
[[package]]
name = "futures-core"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608"
[[package]]
name = "getrandom"
version = "0.2.8"
@ -323,6 +358,12 @@ version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "pin-project-lite"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
[[package]]
name = "png"
version = "0.17.7"
@ -401,6 +442,41 @@ dependencies = [
"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]]
name = "ttf-parser"
version = "0.15.2"
@ -446,3 +522,69 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]
macroquad = "0.3.25"
async-trait = "0.1.64"
[toolchain]
channel = "nightly"
tokio-test = "*"
[profile.release]
opt-level=3

3
Dockerfile Normal file
View file

@ -0,0 +1,3 @@
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,3 +13,17 @@ WebAssembly version can be found here [beepsort.polsevev.dev](https://beepsort.p
- Clean up user interface, perhaps move to JS?
- Add more visualization modes (circle, points etc)
- 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!!!!!

View file

@ -1,246 +0,0 @@
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,20 +1,28 @@
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_u8;
use macroquad::rand;
use crate::soundGenerator;
#[derive(Debug, Clone, Copy)]
pub struct Bar {
pub position:i32,
pub color:color::Color
pub position:usize,
pub color:color::Color,
}
impl Bar{
pub fn new(position:i32, hsl_color:f32) -> Self{
pub fn new(position:usize, hsl_color:f32) -> Self{
Bar{
position,
color: color::hsl_to_rgb((hsl_color as f32) , 1.0, 0.5),
}
}
}

View file

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

64
src/algorithm.rs Normal file
View file

@ -0,0 +1,64 @@
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

@ -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<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);
}
}

33
src/algorithm/bogoSort.rs Normal file
View file

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

View file

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

View file

@ -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, 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

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

View file

@ -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: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);
}
}

117
src/algorithm/radixSort.rs Normal file
View file

@ -0,0 +1,117 @@
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

@ -0,0 +1,94 @@
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);
}
}

63
src/dropdown.rs Normal file
View file

@ -0,0 +1,63 @@
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,71 +1,60 @@
mod BarPlugin;
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::scene::clear;
use crate::BarPlugin::Bar;
use crate::GuiHookVec::GuiVec;
use macroquad::hash;
use macroquad::ui::root_ui;
#[macroquad::main("BeepSort")]
async fn main() {
let mut length = 1;
let mut length = 1_usize;
let mut lengthString = "100".to_owned();
let mut delay = 0.;
let mut delayText = "1".to_owned();
let mut algorithm = algorithm::Algorithm::new();
let mut buttonDropDown = ButtonDropDown::new(&algorithm.getAlgorithms());
loop{
clear_background(WHITE);
delay = match delayText.parse::<f64>(){
Ok(a) => a/1000.,
Err(error)=> {0.1}
};
length = match lengthString.parse::<i32>(){
length = match lengthString.parse::<usize>(){
Ok(a) => a,
Err(error)=> {100}
Err(_)=> {100}
};
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);
root_ui().window(hash!(), Vec2::new(screen_width()*0.01, 45.), Vec2::new(250., 50.), |ui|{
let mut centerX = screen_width()/2.0;
draw_text("Sorting! Made by Polsevev", centerX-170.0, screen_height()*0.1, 100.0, BLACK);
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!(), "Length Of Array!", &mut lengthString);
});
let mut algo = "";
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";
}
let mut algo = buttonDropDown.render();
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
}

99
src/soundGenerator.rs Normal file
View file

@ -0,0 +1,99 @@
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")
}