diff --git a/src/es04_rational_traits.rs b/src/es04_rational_traits.rs index f7387e0..4f7f545 100644 --- a/src/es04_rational_traits.rs +++ b/src/es04_rational_traits.rs @@ -1,10 +1,9 @@ #![allow(dead_code)] +use super::es02_rational::Rational; use std::ops::Add; use std::ops::Mul; -use super::es02_rational::Rational; - /** Es.4 * Per la struttura dei numeri razionali implementare i traits Add e Mul sia per fare * somma e moltiplicazione di numeri razionali che per fare somma e moltiplicazione di un numero razionale e un intero (i32). diff --git a/src/es05_bank.rs b/src/es05_bank.rs index 3de3343..516af66 100644 --- a/src/es05_bank.rs +++ b/src/es05_bank.rs @@ -1,8 +1,7 @@ #![allow(dead_code)] -use std::{fmt::Debug, rc::Rc}; - use self::states::AccountState; +use std::{fmt::Debug, rc::Rc}; /** * Dovete implementare un ContoBancario che ha come informazioni diff --git a/src/es07_list_generic.rs b/src/es07_list_generic.rs index dcadd37..cc8fbd4 100644 --- a/src/es07_list_generic.rs +++ b/src/es07_list_generic.rs @@ -160,7 +160,6 @@ impl LinkedList { None } - pub fn get(&mut self, n: i32) -> Option { if self.size == 0 { return None; diff --git a/src/es08_folds.rs b/src/es08_folds.rs index ab415fe..5802499 100644 --- a/src/es08_folds.rs +++ b/src/es08_folds.rs @@ -28,16 +28,16 @@ pub struct NumVocali { u: i32, } impl NumVocali { - pub fn new(a:i32, e:i32, i:i32, o:i32, u:i32) -> Self { - Self {a, e, i, o, u} + pub fn new(a: i32, e: i32, i: i32, o: i32, u: i32) -> Self { + Self { a, e, i, o, u } } } #[derive(Debug, PartialEq, Default)] pub struct TuplaVocali(i32, i32, i32, i32, i32); impl TuplaVocali { - pub fn new(a:i32, e:i32, i:i32, o:i32, u:i32) -> Self { - Self (a, e, i, o, u) + pub fn new(a: i32, e: i32, i: i32, o: i32, u: i32) -> Self { + Self(a, e, i, o, u) } } diff --git a/src/es09_auction.rs b/src/es09_auction.rs index b00379d..7642268 100644 --- a/src/es09_auction.rs +++ b/src/es09_auction.rs @@ -1,15 +1,18 @@ #![allow(unused)] +use rand::{Rng, SeedableRng}; +use rand_pcg::Pcg32; use std::{ - collections::HashMap, + collections::{HashMap, HashSet, VecDeque}, rc::Rc, sync::{ mpsc::{self, Receiver, Sender}, - Arc, + Arc, Mutex, }, thread, time::Duration, }; + /** * Implementare il protocollo English Auction. * Un banditore attende n partecipanti ad un’asta per un prodotto che ha un prezzo iniziale ed un prezzo di @@ -37,109 +40,220 @@ pub struct Product { name: String, price: f32, reserve: f32, - owner: Option, } #[derive(Clone, Debug)] enum AuctionRequest { - NewProduct(String, f32), + AuctionStart(String, f32), + AuctionOver(Arc), UpdatedPrice(f32), - YouWon, - EndProduct(Arc), - AuctionOver, + YouAreWinning(f32), + YouWon(Product), + Stop, } #[derive(Clone, Debug)] enum AuctionResponse { - NotInterested, + NotInterested(String), WantForPrice(String, f32), } +type SendRequest = Sender; +type ReciveRequest = Receiver; +type SendResponse = Sender; +type ReciveResponse = Receiver; + #[derive(Debug)] struct Auctioneer { - products: Vec, - sender: HashMap>, - recive: Receiver, + products: VecDeque, + currents: HashSet, + participants: HashMap, + recive: ReciveResponse, } #[derive(Debug)] struct Participant { name: String, money: f32, + rng: Arc>, products_won: Vec, - sender: Sender, - recive: Receiver, + sender: SendResponse, + recive: ReciveRequest, } #[derive(Debug)] -struct Auction { +pub struct Auction { auctioneer: Auctioneer, participants: Vec, - sender: Sender, + sender: SendResponse, + rng: Arc>, +} + +impl Product { + pub fn new(name: &str, price: f32, reserve: f32) -> Self { + Self { + name: name.to_string(), + price, + reserve, + } + } } impl Participant { - pub fn get_next_move(&self, price:f32) { - let diff = 10.0_f32.min(price - self.money); - if diff > 0.0 { - + pub fn auction_loop(&mut self) { + while let Ok(result) = self.recive.recv() { + match result { + AuctionRequest::AuctionStart(_, price) => self.updated_price(price), + AuctionRequest::UpdatedPrice(price) => self.updated_price(price), + AuctionRequest::YouAreWinning(price) => self.winning_for(price), + AuctionRequest::YouWon(prod) => self.won_product(prod), + AuctionRequest::AuctionOver(prod) => println!( + "Participant {:?} money:{:?}, won: {:?}", + self.name, self.money, self.products_won + ), + AuctionRequest::Stop => return, + } } } + + fn updated_price(&self, price: f32) { + let name = self.name.clone(); + let response = if price <= self.money { + let up = self.rng.lock().unwrap().gen_range(price..self.money); + AuctionResponse::WantForPrice(name, up) + } else { + AuctionResponse::NotInterested(name) + }; + + self.sender.send(response); + } + fn winning_for(&self, price: f32) { + self.sender + .send(AuctionResponse::WantForPrice(self.name.clone(), price)); + } + fn won_product(&mut self, product: Product) { + self.money -= product.price; + self.products_won.push(product); + } } impl Auctioneer { - fn send(&self, message: AuctionRequest) { - for (_, channel) in &self.sender { - channel.send(message.clone()); - } - } + pub fn auction_loop(&mut self) { + while let Some(mut product) = self.products.pop_front() { + self.new_product(product.name.clone(), product.price); + let mut winner = None; - pub fn new_product(&self, name: String, price:f32) { - self.send(AuctionRequest::NewProduct(name, price)); - } - pub fn update_price(&self, price:f32) { - self.send(AuctionRequest::UpdatedPrice(price)); - } - pub fn end_product(&self, product: Arc) { - self.send(AuctionRequest::EndProduct(product)); - } - pub fn end_auction(&self) { - self.send(AuctionRequest::AuctionOver); - } - pub fn wait_for_responses(&self, timeout: u64) -> Option<(String, f32)> { - let mut price = None; - loop { - let timeout = Duration::from_millis(timeout); - match self.recive.recv_timeout(timeout) { - Ok(AuctionResponse::WantForPrice(name, proposed)) => { - if let Some((n, p)) = &price { - if proposed > *p { - price = Some((name, proposed)) - } - } else { - price = Some((name, proposed)) - } + loop { + let response = self.wait_for_responses(); + if response.len() > 1 { + let (name, price) = response + .iter() + .reduce(|acc, curr| if curr.1 > acc.1 { curr } else { acc }) + .unwrap(); + + winner = Some(name.clone()); + product.price = *price; + self.update_price(name.clone(), *price); + } else { + break; } - Ok(AuctionResponse::NotInterested) => (), - _ => break, - }; + } + + if product.price < product.reserve { + winner = None + } + + self.end_product(winner, product); } - price + self.end_auction(); + } + + fn new_product(&mut self, name: String, price: f32) { + let iter = self.participants.keys().map(|part| part.clone()); + self.currents.clear(); + self.currents.extend(iter); + self.send(false, AuctionRequest::AuctionStart(name, price)); + } + fn update_price(&mut self, owner: String, price: f32) { + self.currents.remove(&owner); + self.send_only(&owner, AuctionRequest::YouAreWinning(price)); + self.send(false, AuctionRequest::UpdatedPrice(price)); + self.currents.insert(owner); + } + fn end_product(&mut self, winner: Option, product: Product) { + if let Some(winner) = winner { + self.currents.remove(&winner); + self.send_only(&winner, AuctionRequest::YouWon(product.clone())); + } + self.send(true, AuctionRequest::AuctionOver(Arc::new(product))); + } + fn end_auction(&self) { + self.send(true, AuctionRequest::Stop); + } + fn wait_for_responses(&mut self) -> Vec<(String, f32)> { + let mut responses = vec![]; + let mut count = 0; + let total = self.currents.len(); + while count < total { + if let Some(response) = self.recive() { + responses.push(response); + } + count += 1; + } + + responses + } + + fn recive(&mut self) -> Option<(String, f32)> { + match self.recive.recv() { + Ok(response) => { + println!("Response -> {:?}", response); + match response { + AuctionResponse::NotInterested(name) => { + self.currents.remove(&name); + None + } + AuctionResponse::WantForPrice(name, price) => Some((name, price)), + } + } + Err(err) => panic!("Channel with the partecipants is interrupted!\n{}", err), + } + } + fn send(&self, all: bool, message: AuctionRequest) { + let recipients: Vec<&String> = if all { + self.participants.iter().map(|(k, v)| k).collect() + } else { + self.currents.iter().map(|x| x).collect() + }; + + let mut count = 0; + for recipient in recipients { + self.send_only(recipient, message.clone()); + count += 1; + } + } + fn send_only(&self, recipient: &String, message: AuctionRequest) { + if let Some(channel) = self.participants.get(recipient) { + println!("Sending to {:?} -> {:?}", recipient, message); + channel.send(message); + } } } impl Auction { - pub fn new(products: Vec) -> Self { + pub fn new(products: VecDeque, seed: u64) -> Self { let channel_participant = mpsc::channel(); let auctioneer = Auctioneer { products, - sender: HashMap::new(), + currents: HashSet::new(), + participants: HashMap::new(), recive: channel_participant.1, }; Self { auctioneer, + rng: Arc::new(Mutex::new(Pcg32::seed_from_u64(seed))), participants: vec![], sender: channel_participant.0, } @@ -150,12 +264,13 @@ impl Auction { let participant = Participant { name: name.clone(), money, + rng: self.rng.clone(), products_won: vec![], sender: self.sender.clone(), recive: channel.1, }; - self.auctioneer.sender.insert(name, channel.0); + self.auctioneer.participants.insert(name, channel.0); self.participants.push(participant); } @@ -169,40 +284,12 @@ impl Auction { fn start_participant(participant: Participant) { thread::spawn(|| { let mut part = participant; - - while let Ok(result) = part.recive.recv() { - match result { - AuctionRequest::NewProduct(_, price) => (), - AuctionRequest::UpdatedPrice(_) => todo!(), - AuctionRequest::EndProduct(_) => todo!(), - AuctionRequest::YouWon => todo!(), - AuctionRequest::AuctionOver => return - } - } + part.auction_loop(); }); } fn start_auctioneer(auctioneer: Auctioneer) { - thread::spawn(|| { - let mut auct = auctioneer; - while let Some(mut product) = auct.products.pop() { - auct.new_product(product.name.clone(), product.price); - - while let Some(response) = auct.wait_for_responses(300) { - let (name, price) = response; - auct.update_price(price); - product.owner = Some(name); - product.price = price; - } - - if product.price < product.reserve { - product.owner = None - } - - auct.end_product(Arc::new(product)); - } - - auct.end_auction(); - }); + let mut auct = auctioneer; + auct.auction_loop(); } } diff --git a/src/lib.rs b/src/lib.rs index 5550ca2..23ff734 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,4 +7,3 @@ pub mod es06_list; pub mod es07_list_generic; pub mod es08_folds; pub mod es09_auction; - diff --git a/tests/es09_auction.rs b/tests/es09_auction.rs new file mode 100644 index 0000000..ea842e6 --- /dev/null +++ b/tests/es09_auction.rs @@ -0,0 +1,19 @@ +use esercizi::es09_auction::{Auction, Product}; +use std::collections::VecDeque; + +#[test] +fn test_auction() { + let products = VecDeque::from([ + Product::new("bau", 10.0, 1000.0), + Product::new("woof", 321.0, 18554.0), + Product::new("woof2", 31.0, 1854.0), + ]); + let mut auction = Auction::new(products, 0); + + auction.add_participant("th1".to_string(), 4520.0); + auction.add_participant("th2".to_string(), 6500.0); + auction.add_participant("th3".to_string(), 15020.0); + auction.add_participant("th4".to_string(), 8520.0); + + auction.start(); +}