Auction
- missing more tests - indented all other exercises
This commit is contained in:
@@ -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).
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -160,7 +160,6 @@ impl<T> LinkedList<T> {
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
pub fn get(&mut self, n: i32) -> Option<T> {
|
||||
if self.size == 0 {
|
||||
return None;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum AuctionRequest {
|
||||
NewProduct(String, f32),
|
||||
AuctionStart(String, f32),
|
||||
AuctionOver(Arc<Product>),
|
||||
UpdatedPrice(f32),
|
||||
YouWon,
|
||||
EndProduct(Arc<Product>),
|
||||
AuctionOver,
|
||||
YouAreWinning(f32),
|
||||
YouWon(Product),
|
||||
Stop,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum AuctionResponse {
|
||||
NotInterested,
|
||||
NotInterested(String),
|
||||
WantForPrice(String, f32),
|
||||
}
|
||||
|
||||
type SendRequest = Sender<AuctionRequest>;
|
||||
type ReciveRequest = Receiver<AuctionRequest>;
|
||||
type SendResponse = Sender<AuctionResponse>;
|
||||
type ReciveResponse = Receiver<AuctionResponse>;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Auctioneer {
|
||||
products: Vec<Product>,
|
||||
sender: HashMap<String, Sender<AuctionRequest>>,
|
||||
recive: Receiver<AuctionResponse>,
|
||||
products: VecDeque<Product>,
|
||||
currents: HashSet<String>,
|
||||
participants: HashMap<String, SendRequest>,
|
||||
recive: ReciveResponse,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Participant {
|
||||
name: String,
|
||||
money: f32,
|
||||
rng: Arc<Mutex<Pcg32>>,
|
||||
products_won: Vec<Product>,
|
||||
sender: Sender<AuctionResponse>,
|
||||
recive: Receiver<AuctionRequest>,
|
||||
sender: SendResponse,
|
||||
recive: ReciveRequest,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Auction {
|
||||
pub struct Auction {
|
||||
auctioneer: Auctioneer,
|
||||
participants: Vec<Participant>,
|
||||
sender: Sender<AuctionResponse>,
|
||||
sender: SendResponse,
|
||||
rng: Arc<Mutex<Pcg32>>,
|
||||
}
|
||||
|
||||
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<Product>) {
|
||||
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<String>, 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<Product>) -> Self {
|
||||
pub fn new(products: VecDeque<Product>, 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,4 +7,3 @@ pub mod es06_list;
|
||||
pub mod es07_list_generic;
|
||||
pub mod es08_folds;
|
||||
pub mod es09_auction;
|
||||
|
||||
|
||||
19
tests/es09_auction.rs
Normal file
19
tests/es09_auction.rs
Normal file
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user