Auction
- missing more tests - indented all other exercises
This commit is contained in:
@@ -1,10 +1,9 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use super::es02_rational::Rational;
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
use std::ops::Mul;
|
use std::ops::Mul;
|
||||||
|
|
||||||
use super::es02_rational::Rational;
|
|
||||||
|
|
||||||
/** Es.4
|
/** Es.4
|
||||||
* Per la struttura dei numeri razionali implementare i traits Add e Mul sia per fare
|
* 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).
|
* 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)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::{fmt::Debug, rc::Rc};
|
|
||||||
|
|
||||||
use self::states::AccountState;
|
use self::states::AccountState;
|
||||||
|
use std::{fmt::Debug, rc::Rc};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dovete implementare un ContoBancario che ha come informazioni
|
* Dovete implementare un ContoBancario che ha come informazioni
|
||||||
|
|||||||
@@ -160,7 +160,6 @@ impl<T> LinkedList<T> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn get(&mut self, n: i32) -> Option<T> {
|
pub fn get(&mut self, n: i32) -> Option<T> {
|
||||||
if self.size == 0 {
|
if self.size == 0 {
|
||||||
return None;
|
return None;
|
||||||
|
|||||||
@@ -28,16 +28,16 @@ pub struct NumVocali {
|
|||||||
u: i32,
|
u: i32,
|
||||||
}
|
}
|
||||||
impl NumVocali {
|
impl NumVocali {
|
||||||
pub fn new(a:i32, e:i32, i:i32, o:i32, u:i32) -> Self {
|
pub fn new(a: i32, e: i32, i: i32, o: i32, u: i32) -> Self {
|
||||||
Self {a, e, i, o, u}
|
Self { a, e, i, o, u }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Default)]
|
#[derive(Debug, PartialEq, Default)]
|
||||||
pub struct TuplaVocali(i32, i32, i32, i32, i32);
|
pub struct TuplaVocali(i32, i32, i32, i32, i32);
|
||||||
impl TuplaVocali {
|
impl TuplaVocali {
|
||||||
pub fn new(a:i32, e:i32, i:i32, o:i32, u:i32) -> Self {
|
pub fn new(a: i32, e: i32, i: i32, o: i32, u: i32) -> Self {
|
||||||
Self (a, e, i, o, u)
|
Self(a, e, i, o, u)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
|
|
||||||
|
use rand::{Rng, SeedableRng};
|
||||||
|
use rand_pcg::Pcg32;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::{HashMap, HashSet, VecDeque},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::{
|
sync::{
|
||||||
mpsc::{self, Receiver, Sender},
|
mpsc::{self, Receiver, Sender},
|
||||||
Arc,
|
Arc, Mutex,
|
||||||
},
|
},
|
||||||
thread,
|
thread,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementare il protocollo English Auction.
|
* 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
|
* 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,
|
name: String,
|
||||||
price: f32,
|
price: f32,
|
||||||
reserve: f32,
|
reserve: f32,
|
||||||
owner: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
enum AuctionRequest {
|
enum AuctionRequest {
|
||||||
NewProduct(String, f32),
|
AuctionStart(String, f32),
|
||||||
|
AuctionOver(Arc<Product>),
|
||||||
UpdatedPrice(f32),
|
UpdatedPrice(f32),
|
||||||
YouWon,
|
YouAreWinning(f32),
|
||||||
EndProduct(Arc<Product>),
|
YouWon(Product),
|
||||||
AuctionOver,
|
Stop,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
enum AuctionResponse {
|
enum AuctionResponse {
|
||||||
NotInterested,
|
NotInterested(String),
|
||||||
WantForPrice(String, f32),
|
WantForPrice(String, f32),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SendRequest = Sender<AuctionRequest>;
|
||||||
|
type ReciveRequest = Receiver<AuctionRequest>;
|
||||||
|
type SendResponse = Sender<AuctionResponse>;
|
||||||
|
type ReciveResponse = Receiver<AuctionResponse>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Auctioneer {
|
struct Auctioneer {
|
||||||
products: Vec<Product>,
|
products: VecDeque<Product>,
|
||||||
sender: HashMap<String, Sender<AuctionRequest>>,
|
currents: HashSet<String>,
|
||||||
recive: Receiver<AuctionResponse>,
|
participants: HashMap<String, SendRequest>,
|
||||||
|
recive: ReciveResponse,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Participant {
|
struct Participant {
|
||||||
name: String,
|
name: String,
|
||||||
money: f32,
|
money: f32,
|
||||||
|
rng: Arc<Mutex<Pcg32>>,
|
||||||
products_won: Vec<Product>,
|
products_won: Vec<Product>,
|
||||||
sender: Sender<AuctionResponse>,
|
sender: SendResponse,
|
||||||
recive: Receiver<AuctionRequest>,
|
recive: ReciveRequest,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Auction {
|
pub struct Auction {
|
||||||
auctioneer: Auctioneer,
|
auctioneer: Auctioneer,
|
||||||
participants: Vec<Participant>,
|
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 {
|
impl Participant {
|
||||||
pub fn get_next_move(&self, price:f32) {
|
pub fn auction_loop(&mut self) {
|
||||||
let diff = 10.0_f32.min(price - self.money);
|
while let Ok(result) = self.recive.recv() {
|
||||||
if diff > 0.0 {
|
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 {
|
impl Auctioneer {
|
||||||
fn send(&self, message: AuctionRequest) {
|
pub fn auction_loop(&mut self) {
|
||||||
for (_, channel) in &self.sender {
|
while let Some(mut product) = self.products.pop_front() {
|
||||||
channel.send(message.clone());
|
self.new_product(product.name.clone(), product.price);
|
||||||
}
|
let mut winner = None;
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_product(&self, name: String, price:f32) {
|
loop {
|
||||||
self.send(AuctionRequest::NewProduct(name, price));
|
let response = self.wait_for_responses();
|
||||||
}
|
if response.len() > 1 {
|
||||||
pub fn update_price(&self, price:f32) {
|
let (name, price) = response
|
||||||
self.send(AuctionRequest::UpdatedPrice(price));
|
.iter()
|
||||||
}
|
.reduce(|acc, curr| if curr.1 > acc.1 { curr } else { acc })
|
||||||
pub fn end_product(&self, product: Arc<Product>) {
|
.unwrap();
|
||||||
self.send(AuctionRequest::EndProduct(product));
|
|
||||||
}
|
winner = Some(name.clone());
|
||||||
pub fn end_auction(&self) {
|
product.price = *price;
|
||||||
self.send(AuctionRequest::AuctionOver);
|
self.update_price(name.clone(), *price);
|
||||||
}
|
} else {
|
||||||
pub fn wait_for_responses(&self, timeout: u64) -> Option<(String, f32)> {
|
break;
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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 {
|
impl Auction {
|
||||||
pub fn new(products: Vec<Product>) -> Self {
|
pub fn new(products: VecDeque<Product>, seed: u64) -> Self {
|
||||||
let channel_participant = mpsc::channel();
|
let channel_participant = mpsc::channel();
|
||||||
let auctioneer = Auctioneer {
|
let auctioneer = Auctioneer {
|
||||||
products,
|
products,
|
||||||
sender: HashMap::new(),
|
currents: HashSet::new(),
|
||||||
|
participants: HashMap::new(),
|
||||||
recive: channel_participant.1,
|
recive: channel_participant.1,
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
auctioneer,
|
auctioneer,
|
||||||
|
rng: Arc::new(Mutex::new(Pcg32::seed_from_u64(seed))),
|
||||||
participants: vec![],
|
participants: vec![],
|
||||||
sender: channel_participant.0,
|
sender: channel_participant.0,
|
||||||
}
|
}
|
||||||
@@ -150,12 +264,13 @@ impl Auction {
|
|||||||
let participant = Participant {
|
let participant = Participant {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
money,
|
money,
|
||||||
|
rng: self.rng.clone(),
|
||||||
products_won: vec![],
|
products_won: vec![],
|
||||||
sender: self.sender.clone(),
|
sender: self.sender.clone(),
|
||||||
recive: channel.1,
|
recive: channel.1,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.auctioneer.sender.insert(name, channel.0);
|
self.auctioneer.participants.insert(name, channel.0);
|
||||||
self.participants.push(participant);
|
self.participants.push(participant);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,40 +284,12 @@ impl Auction {
|
|||||||
fn start_participant(participant: Participant) {
|
fn start_participant(participant: Participant) {
|
||||||
thread::spawn(|| {
|
thread::spawn(|| {
|
||||||
let mut part = participant;
|
let mut part = participant;
|
||||||
|
part.auction_loop();
|
||||||
while let Ok(result) = part.recive.recv() {
|
|
||||||
match result {
|
|
||||||
AuctionRequest::NewProduct(_, price) => (),
|
|
||||||
AuctionRequest::UpdatedPrice(_) => todo!(),
|
|
||||||
AuctionRequest::EndProduct(_) => todo!(),
|
|
||||||
AuctionRequest::YouWon => todo!(),
|
|
||||||
AuctionRequest::AuctionOver => return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_auctioneer(auctioneer: Auctioneer) {
|
fn start_auctioneer(auctioneer: Auctioneer) {
|
||||||
thread::spawn(|| {
|
let mut auct = auctioneer;
|
||||||
let mut auct = auctioneer;
|
auct.auction_loop();
|
||||||
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();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,4 +7,3 @@ pub mod es06_list;
|
|||||||
pub mod es07_list_generic;
|
pub mod es07_list_generic;
|
||||||
pub mod es08_folds;
|
pub mod es08_folds;
|
||||||
pub mod es09_auction;
|
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