This commit is contained in:
Rolf Martin Glomsrud 2025-05-01 20:57:47 +02:00
parent 8928401233
commit ccaf8c1f0b
11 changed files with 611 additions and 39 deletions

View file

@ -0,0 +1,53 @@
use crate::drawableVec::DrawableVec;
use std::collections::{HashMap, BinaryHeap};
use color_eyre::Result;
pub async fn sort(list: &mut DrawableVec) -> Result<()>{
let mut indexMap:HashMap<u32, usize> = HashMap::new();
let mut binHeap:BinaryHeap<u32> = BinaryHeap::new();
let mut ind = 0;
for bar in list.elements(){
binHeap.push(*bar);
indexMap.insert(*bar, ind);
ind += 1;
}
for i in (0..list.len()).rev(){
let bar = binHeap.pop().unwrap();
let barIndex = *indexMap.get(&bar).unwrap();
list.swap(i, barIndex).await?;
let temp = list.get(barIndex);
indexMap.insert(temp, barIndex);
}
Ok(())
}
/*
#[cfg(test)]
#[allow(non_snake_case)]
mod tests {
use crate::GuiHookVec::NonGuiVec;
use super::*;
macro_rules! aw {
($e:expr) => {
tokio_test::block_on($e)
};
}
#[test]
fn binartHeap_correct() {
let mut list:NonGuiVec = aw!(SortingList::new(1000,0.0));
aw!(binaryHeap(&mut list));
assert_eq!( list.isSorted(), true);
}
}
*/

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

@ -0,0 +1,40 @@
use crate::drawableVec::DrawableVec;
use color_eyre::Result;
pub async fn sort(list: &mut DrawableVec) -> Result<()>{
loop{
list.swap(0,0).await?;
if list.isSorted() {
break;
}
list.randomize();
}
Ok(())
}
/*
#[cfg(test)]
#[allow(non_snake_case)]
mod tests {
use crate::GuiHookVec::NonGuiVec;
use super::*;
macro_rules! aw {
($e:expr) => {
tokio_test::block_on($e)
};
}
#[test]
fn bogoSort_correct_this_is_a_meme() {
let mut list:NonGuiVec = aw!(SortingList::new(5,0.0));
aw!(bogoSort(&mut list));
assert_eq!( list.isSorted(), true);
}
}
*/

View file

@ -0,0 +1,41 @@
use crate::drawableVec::DrawableVec;
use color_eyre::Result;
pub async fn sort(list:&mut DrawableVec) -> Result<()>{
let n = list.len();
for i in 0..n {
for j in 0..(n - i - 1) {
if list.lessThan(j + 1, j) {
list.swap(j, j + 1).await?;
}
}
}
Ok(())
}
/*
#[cfg(test)]
#[allow(non_snake_case)]
mod tests {
use crate::GuiHookVec::NonGuiVec;
use super::*;
macro_rules! aw {
($e:expr) => {
tokio_test::block_on($e)
};
}
#[test]
fn bubblesort_correct() {
let mut list:NonGuiVec = aw!(SortingList::new(1000,0.0));
aw!(bubbleSort(&mut list));
assert_eq!( list.isSorted(), true);
}
}
*/

View file

@ -0,0 +1,58 @@
use crate::drawableVec::DrawableVec;
use color_eyre::Result;
pub async fn sort(list:&mut DrawableVec) -> Result<()>{
let mut lowerBound = 0;
let mut upperBound = list.len()-1;
let mut swapped = true;
while swapped{
swapped = false;
for i in lowerBound..upperBound {
if list.lessThan(i+1, i) {
list.swap(i, i+1).await?;
swapped = true;
}
}
if !swapped{
break;
}
swapped = false;
upperBound = upperBound-1;
for i in ((lowerBound)..(upperBound)).rev() {
if list.lessThan(i+1, i) {
list.swap(i+1, i).await?;
swapped = true;
}
}
lowerBound = lowerBound+1;
}
Ok(())
}
/*
#[cfg(test)]
#[allow(non_snake_case)]
mod tests {
use crate::GuiHookVec::NonGuiVec;
use super::*;
macro_rules! aw {
($e:expr) => {
tokio_test::block_on($e)
};
}
#[test]
fn coctailshakersort_correct() {
let mut list:NonGuiVec = aw!(SortingList::new(1000,0.0));
aw!(cocktailShaker(&mut list));
assert_eq!( list.isSorted(), true);
}
}
*/

View file

@ -1,3 +1,29 @@
use crate::drawableVec::DrawableVec; use crate::drawableVec::DrawableVec;
pub mod insertSort; mod radixSort;
mod insertSort;
mod bubbleSort;
mod binaryHeap;
mod coctailShaker;
mod quickSort;
mod bogoSort;
mod radixSortLSD;
use color_eyre::{eyre::Ok, Result};
pub async fn sort(algo: String, list: &mut DrawableVec) -> Result<()> {
match algo.as_str() {
"insertSort" => insertSort::sort(list).await?,
"bubbleSort" => bubbleSort::sort(list).await?,
"bogoSort" => bogoSort::sort(list).await?,
"cocktailShaker" => coctailShaker::sort(list).await?,
"binaryHeap" => binaryHeap::sort(list).await?,
"quickSort" => quickSort::sort(list).await?,
"radixSortMSD" => radixSort::sort(list).await?,
"radixSortLSD" => radixSortLSD::sort(list).await?,
_ => panic!("No algorithm with that name implemented!")
}
Ok(())
}

View file

@ -0,0 +1,74 @@
use crate::drawableVec::DrawableVec;
use color_eyre::Result;
pub async fn sort(list:&mut DrawableVec) -> Result<()> {
let mut stack:Vec<(usize,usize)> = Vec::new();
let start = 0;
let end = list.len()-1;
stack.push((start,end));
while stack.len() > 0{
let (start,end) = stack.pop().unwrap();
let p = list.get(end);
let temp = partition(list, start, end, p).await?;
let pivot = if temp >= 0 {temp} else {break;};
if pivot != 0 && pivot as usize -1 > start{
stack.push((start,pivot as usize-1));
}
if pivot as usize + 1 < end{
stack.push((pivot as usize +1, end))
}
}
Ok(())
}
async fn partition(list:&mut DrawableVec, low:usize, high:usize, p:u32) -> Result<i32>{
let mut pIndex = low;
for i in low..high{
if list.lessThanEqual(i, p){
list.swap(i, pIndex).await?;
pIndex += 1;
}
}
list.swap(pIndex, high).await?;
return Ok(pIndex as i32)
}
/*
#[cfg(test)]
#[allow(non_snake_case)]
mod tests {
use crate::GuiHookVec::NonGuiVec;
use super::*;
macro_rules! aw {
($e:expr) => {
tokio_test::block_on($e)
};
}
#[test]
fn quicksort_correct() {
let mut list:NonGuiVec = aw!(SortingList::new(1000,0.0));
aw!(quickSort(&mut list));
assert_eq!( list.isSorted(), true);
}
}
*/

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

@ -0,0 +1,124 @@
use crate::drawableVec::DrawableVec;
use color_eyre::{eyre::Ok, Result};
pub async fn sort(list:&mut DrawableVec) -> Result<()> {
let mut max = usize::MIN;
for i in list.getListClone().into_iter().map(|x| format!("{:b}",x)){
if max < i.len(){
max = i.len();
}
}
let mut stack:Vec<(usize, usize)> = Vec::new();
let mut stack2:Vec<(usize,usize)> = Vec::new();
stack.push((0, list.len()));
for i in (0..(max)).rev(){
while stack.len() > 0{
let cur = stack.pop().unwrap();
match radix(list, i, cur.0, cur.1).await?{
Some((initial, switch, max)) => {
if initial < switch{
stack2.push((initial, switch));
}
if switch < max{
stack2.push((switch, max));
}
},
None => return Ok(())
}
}
stack = stack2.clone();
stack2.clear();
}
Ok(())
}
async fn radix(list:&mut DrawableVec, radix:usize, mut minBoundry:usize, mut maxBoundry:usize) -> Result<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), radix);
if currentBit{
list.swap(minBoundry, maxBoundry-1).await?;
maxBoundry -= 1;
}else{
list.swap(minBoundry, minBoundry).await?;
minBoundry += 1;
}
}
Ok(Some((initialMin, minBoundry, initialMax)))
}
fn get_bit_at(input: u32, n: usize) -> bool {
if format!("{:b}", input).len() <= n{
false
}else{
input & (1 << n) != 0
}
}
/*
#[cfg(test)]
#[allow(non_snake_case)]
mod tests {
use crate::GuiHookVec::NonGuiVec;
use super::*;
macro_rules! aw {
($e:expr) => {
tokio_test::block_on($e)
};
}
#[test]
fn radixsort_correct() {
let mut list:NonGuiVec = aw!(SortingList::new(1000,0.0));
aw!(radixSort(&mut list));
assert_eq!( list.isSorted(), true);
}
#[test]
fn get_bit_at_test(){
let num = 0b0001;
let othernum = 2;
assert_eq!(get_bit_at(num, 0), true);
assert_eq!(get_bit_at(num, 1), false);
assert_eq!(get_bit_at(othernum, 1), true);
assert_eq!(get_bit_at(othernum, 2), false);
assert_eq!(get_bit_at(othernum, 3), false);
}
}
*/

View file

@ -0,0 +1,100 @@
use crate::drawableVec::DrawableVec;
use color_eyre::Result;
pub async fn sort(list:&mut DrawableVec) -> Result<()> {
let mut max = usize::MIN;
for i in list.getListClone().into_iter().map(|x| format!("{:b}",x)){
if max < i.len(){
max = i.len();
}
}
for i in 0..(max){
radix(list, i).await?;
}
Ok(())
}
pub async fn radix(list:&mut DrawableVec, radix:usize) -> Result<()>{
let mut bucket = vec![vec![];2];
for (i, bar) in list.elements().enumerate(){
let cur = if get_bit_at(*bar, radix) {1} else {0};
bucket[cur].push(i);
}
let mut sortedIndexes = Vec::new();
for elements in bucket.into_iter(){
for i in elements{
sortedIndexes.push(i);
}
}
let mut listClone = list.getListClone();
let mut count = 0;
for i in sortedIndexes.clone(){
list.set(count, listClone[i]).await?;
count += 1;
}
Ok(())
}
fn get_bit_at(input: u32, n: usize) -> bool {
if format!("{:b}", input).len() <= n{
false
}else{
input & (1 << n) != 0
}
}
/*
#[cfg(test)]
#[allow(non_snake_case)]
mod tests {
use crate::GuiHookVec::NonGuiVec;
use super::*;
macro_rules! aw {
($e:expr) => {
tokio_test::block_on($e)
};
}
#[test]
fn radixsort_correct() {
let mut list:NonGuiVec = aw!(SortingList::new(1000,0.0));
aw!(radixSort(&mut list));
assert_eq!( list.isSorted(), true);
}
#[test]
fn get_bit_at_test(){
let num = 0b0001;
let othernum = 2;
assert_eq!(get_bit_at(num, 0), true);
assert_eq!(get_bit_at(num, 1), false);
assert_eq!(get_bit_at(othernum, 1), true);
assert_eq!(get_bit_at(othernum, 2), false);
assert_eq!(get_bit_at(othernum, 3), false);
}
}
*/

View file

@ -1,6 +1,7 @@
use std::time::Duration; use std::time::Duration;
use color_eyre::{eyre::Ok, Result}; use color_eyre::{eyre::Ok, Result};
use rand::seq::SliceRandom;
use ratatui::{ use ratatui::{
DefaultTerminal, Frame, DefaultTerminal, Frame,
crossterm::event::{self, Event, KeyCode, KeyEventKind}, crossterm::event::{self, Event, KeyCode, KeyEventKind},
@ -12,8 +13,8 @@ use ratatui::{
use tokio::{sync::mpsc::{UnboundedReceiver, UnboundedSender}, time::sleep}; use tokio::{sync::mpsc::{UnboundedReceiver, UnboundedSender}, time::sleep};
use crate::{ use crate::{
algorithm::{self, insertSort::{self, sort}}, algorithm::{self},
graphics::{self, vertical_barchart}, tui::{self, Message}, tui::Message,
}; };
pub enum SortingMessage{ pub enum SortingMessage{
@ -23,7 +24,8 @@ pub enum SortingMessage{
pub struct DrawableVec { pub struct DrawableVec {
vec: Vec<u32>, vec: Vec<u32>,
event_rx: UnboundedReceiver<SortingMessage>, event_rx: UnboundedReceiver<SortingMessage>,
event_tx: UnboundedSender<Message> event_tx: UnboundedSender<Message>,
algo: String
} }
impl DrawableVec { impl DrawableVec {
@ -31,12 +33,13 @@ impl DrawableVec {
return DrawableVec { return DrawableVec {
vec, vec,
event_rx, event_rx,
event_tx: event_tx.clone() event_tx: event_tx.clone(),
algo: "radixSortMSD".to_string(),
}; };
} }
pub async fn run(mut self) -> Result<()> { pub async fn run(mut self) -> Result<()> {
insertSort::sort(&mut self).await?; algorithm::sort(self.algo.clone(), &mut self).await?;
sleep(Duration::from_secs(100000)).await; sleep(Duration::from_secs(100000)).await;
Ok(()) Ok(())
} }
@ -53,7 +56,47 @@ impl DrawableVec {
Ok(()) Ok(())
} }
pub async fn set(&mut self, i:usize, elem:u32) -> Result<()>{
self.vec[i] = elem;
self.event_tx.send(Message::SetEvent(i, elem))?;
self.event_rx.recv().await;
Ok(())
}
pub fn lessThan(&self, a: usize, b: usize) -> bool { pub fn lessThan(&self, a: usize, b: usize) -> bool {
self.vec[a] < self.vec[b] self.vec[a] < self.vec[b]
} }
pub fn elements(&mut self) -> std::slice::Iter<'_, u32> {
self.vec.iter()
}
pub fn get(&mut self, i:usize)-> u32{
*self.vec.get(i).unwrap()
}
pub fn randomize(&mut self){
self.vec.shuffle(&mut rand::rng());
}
pub fn isSorted(&mut self) -> bool{
let mut prev:u32 = 0;
for bar in self.elements() {
if *bar < prev{
return false;
}else{
prev = *bar;
}
}
true
}
pub fn lessThanEqual(&mut self, a:usize, b:u32) -> bool{
return self.get(a) <= b
}
pub fn getListClone(&self) -> Vec<u32>{
self.vec.clone()
}
} }

View file

@ -13,11 +13,9 @@ pub fn vertical_barchart(temperatures: &[u32]) -> BarChart {
.enumerate() .enumerate()
.map(|(hour, value)| vertical_bar(hour, value)) .map(|(hour, value)| vertical_bar(hour, value))
.collect(); .collect();
let title = Line::from("Weather (Vertical)").centered();
BarChart::default() BarChart::default()
.data(BarGroup::default().bars(&bars)) .data(BarGroup::default().bars(&bars))
.block(Block::new().title(title)) .bar_width(1)
.bar_width(5)
} }
pub fn vertical_bar(hour: usize, temperature: &u32) -> Bar { pub fn vertical_bar(hour: usize, temperature: &u32) -> Bar {

View file

@ -1,19 +1,29 @@
use std::{time::Duration}; use std::time::Duration;
use color_eyre::{Result, eyre::Ok};
use crossterm::event::{Event, KeyCode, KeyEventKind, MouseEventKind}; use crossterm::event::{Event, KeyCode, KeyEventKind, MouseEventKind};
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use ratatui::{layout::{Constraint, Layout}, prelude::CrosstermBackend, style::Stylize, Terminal}; use ratatui::{
use tokio::{sync::mpsc::{self, UnboundedReceiver, UnboundedSender}, task::JoinHandle, time}; Terminal,
use color_eyre::{eyre::Ok, Result}; layout::{Constraint, Layout},
prelude::CrosstermBackend,
style::Stylize,
};
use tokio::{
sync::mpsc::{self, UnboundedReceiver, UnboundedSender},
task::JoinHandle,
time,
};
pub enum Message { pub enum Message {
Quit, Quit,
Tick, Tick,
Render, Render,
StartSimulation, StartSimulation,
SwapEvent(usize, usize) SwapEvent(usize, usize),
SetEvent(usize, u32),
} }
pub struct Tui{ pub struct Tui {
terminal: Terminal<CrosstermBackend<std::io::Stdout>>, terminal: Terminal<CrosstermBackend<std::io::Stdout>>,
tick_rate: f64, tick_rate: f64,
frame_rate: f64, frame_rate: f64,
@ -23,8 +33,10 @@ pub struct Tui{
should_exit: bool, should_exit: bool,
vec: Vec<u32>, vec: Vec<u32>,
} }
use crate::{drawableVec::{self, DrawableVec, SortingMessage}, graphics::vertical_barchart}; use crate::{
drawableVec::{self, DrawableVec, SortingMessage},
graphics::vertical_barchart,
};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum UpdateCommand { pub enum UpdateCommand {
@ -32,22 +44,22 @@ pub enum UpdateCommand {
Quit, Quit,
} }
impl Tui{ impl Tui {
pub fn new() -> Result<Self>{ pub fn new() -> Result<Self> {
let terminal = ratatui::init(); let terminal = ratatui::init();
let (event_tx, event_rx):(UnboundedSender<Message>,UnboundedReceiver<Message>) = mpsc::unbounded_channel(); let (event_tx, event_rx): (UnboundedSender<Message>, UnboundedReceiver<Message>) =
mpsc::unbounded_channel();
let (sorting_tx, sorting_rx) = mpsc::unbounded_channel(); let (sorting_tx, sorting_rx) = mpsc::unbounded_channel();
let mut vec = (Vec::from_iter(1..100)); let mut vec = (Vec::from_iter(1..100));
vec.shuffle(&mut rand::rng()); vec.shuffle(&mut rand::rng());
let drawableVec = DrawableVec::new(event_tx.clone(),sorting_rx, vec.clone()); let drawableVec = DrawableVec::new(event_tx.clone(), sorting_rx, vec.clone());
let sorter = tokio::spawn(drawableVec.run()); let sorter = tokio::spawn(drawableVec.run());
Ok(Self {
Ok(Self{
terminal, terminal,
tick_rate: 10., tick_rate: 20.,
frame_rate: 60., frame_rate: 120.,
event_rx, event_rx,
event_tx, event_tx,
sorting_tx, sorting_tx,
@ -56,7 +68,7 @@ impl Tui{
}) })
} }
pub async fn run(&mut self) -> Result<()>{ pub async fn run(&mut self) -> Result<()> {
let tick_rate = Duration::from_secs_f64(1.0 / self.tick_rate); let tick_rate = Duration::from_secs_f64(1.0 / self.tick_rate);
let frame_rate = Duration::from_secs_f64(1.0 / self.frame_rate); let frame_rate = Duration::from_secs_f64(1.0 / self.frame_rate);
let mut tick_interval = time::interval(tick_rate); let mut tick_interval = time::interval(tick_rate);
@ -96,18 +108,22 @@ impl Tui{
async fn update(&mut self, message: Message) -> Result<UpdateCommand> { async fn update(&mut self, message: Message) -> Result<UpdateCommand> {
match message { match message {
Message::Quit => Ok(UpdateCommand::Quit), Message::Quit => Ok(UpdateCommand::Quit),
Message::Tick => { Message::Tick => Ok(UpdateCommand::None),
Ok(UpdateCommand::None)
}
Message::Render => { Message::Render => {
self.view()?; self.view()?;
Ok(UpdateCommand::None) Ok(UpdateCommand::None)
} }
Message::StartSimulation => todo!(), Message::StartSimulation => todo!(),
Message::SwapEvent(a,b) => {self.vec.swap(a, b); Ok(UpdateCommand::None)}, Message::SwapEvent(a, b) => {
self.vec.swap(a, b);
Ok(UpdateCommand::None)
}
Message::SetEvent(i, e) => {
self.vec.insert(i, e);
Ok(UpdateCommand::None)
}
} }
} }
fn view(&mut self) -> Result<()> { fn view(&mut self) -> Result<()> {
self.terminal.draw(|frame| { self.terminal.draw(|frame| {
@ -130,7 +146,7 @@ impl Tui{
Event::Key(key) => { Event::Key(key) => {
if key.kind == KeyEventKind::Press && key.code == KeyCode::Esc { if key.kind == KeyEventKind::Press && key.code == KeyCode::Esc {
self.event_tx.send(Message::Quit)?; self.event_tx.send(Message::Quit)?;
}else if key.kind == KeyEventKind::Press && key.code == KeyCode:: Enter { } else if key.kind == KeyEventKind::Press && key.code == KeyCode::Enter {
self.event_tx.send(Message::StartSimulation)?; self.event_tx.send(Message::StartSimulation)?;
} }
} }
@ -138,5 +154,4 @@ impl Tui{
} }
Ok(()) Ok(())
} }
} }