Compare commits
35 commits
Author | SHA1 | Date | |
---|---|---|---|
0969366e27 | |||
a4946f0117 | |||
0ed1802b18 | |||
![]() |
dce6caf88e | ||
![]() |
e1993b416f | ||
![]() |
bf2e695e38 | ||
a5a1db2889 | |||
937ac30517 | |||
483af34fa7 | |||
49b0e69299 | |||
44c04dbdc2 | |||
8b89189902 | |||
db8debb31a | |||
2df3d0a005 | |||
c3ef0c4b7b | |||
b39a778b2d | |||
b9c6fd24d7 | |||
d81a1a5167 | |||
58aaf78f5a | |||
b6c438ae0f | |||
67090986bb | |||
3e013192d0 | |||
fb40910c10 | |||
7324861472 | |||
caf515b14f | |||
8ebad48659 | |||
25e4183e7a | |||
79dc592a40 | |||
913c516713 | |||
c01a58ef14 | |||
3a05b90f09 | |||
63e8214974 | |||
427e5586d7 | |||
0b68bb773f | |||
3dc71499ac |
24 changed files with 1039 additions and 325 deletions
5
.github/workflows/main.yml
vendored
5
.github/workflows/main.yml
vendored
|
@ -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:
|
||||
|
|
13
.kubernetes/beepsort-cert.yml
Normal file
13
.kubernetes/beepsort-cert.yml
Normal 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"
|
||||
|
21
.kubernetes/beepsort-deploy.yml
Normal file
21
.kubernetes/beepsort-deploy.yml
Normal 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
|
21
.kubernetes/beepsort-ingress.yml
Normal file
21
.kubernetes/beepsort-ingress.yml
Normal 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
|
14
.kubernetes/beepsort-service.yml
Normal file
14
.kubernetes/beepsort-service.yml
Normal 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
142
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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
3
Dockerfile
Normal 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/
|
14
README.md
14
README.md
|
@ -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!!!!!
|
246
src/Algorithm.rs
246
src/Algorithm.rs
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
64
src/algorithm.rs
Normal 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
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
47
src/algorithm/binaryHeap.rs
Normal file
47
src/algorithm/binaryHeap.rs
Normal 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
33
src/algorithm/bogoSort.rs
Normal 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);
|
||||
}
|
||||
}
|
34
src/algorithm/bubbleSort.rs
Normal file
34
src/algorithm/bubbleSort.rs
Normal 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);
|
||||
}
|
||||
}
|
53
src/algorithm/coctailShaker.rs
Normal file
53
src/algorithm/coctailShaker.rs
Normal 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);
|
||||
}
|
||||
}
|
33
src/algorithm/insertSort.rs
Normal file
33
src/algorithm/insertSort.rs
Normal 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);
|
||||
}
|
||||
}
|
69
src/algorithm/quickSort.rs
Normal file
69
src/algorithm/quickSort.rs
Normal 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
117
src/algorithm/radixSort.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
|
94
src/algorithm/radixSortLSD.rs
Normal file
94
src/algorithm/radixSortLSD.rs
Normal 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
63
src/dropdown.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
|
75
src/main.rs
75
src/main.rs
|
@ -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
99
src/soundGenerator.rs
Normal 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")
|
||||
|
||||
}
|
Loading…
Reference in a new issue