veloren/world/src/civ/econ.rs

80 lines
2.1 KiB
Rust
Raw Normal View History

2020-03-28 18:16:19 +00:00
use super::GenCtx;
2020-04-17 23:29:01 +00:00
use rand::prelude::*;
2020-03-28 18:16:19 +00:00
pub struct SellOrder {
pub quantity: f32,
pub price: f32,
// The money returned to the seller
pub q_sold: f32,
}
pub struct BuyOrder {
quantity: f32,
max_price: f32,
}
#[derive(Clone, Debug)]
pub struct Belief {
pub price: f32,
pub confidence: f32,
}
impl Belief {
pub fn choose_price(&self, ctx: &mut GenCtx<impl Rng>) -> f32 {
self.price + ctx.rng.gen_range(-1.0, 1.0) * self.confidence
}
pub fn update_buyer(&mut self, years: f32, new_price: f32) {
if (self.price - new_price).abs() < self.confidence {
self.confidence *= 0.8;
} else {
self.price += (new_price - self.price) * 0.5; // TODO: Make this vary with `years`
self.confidence = (self.price - new_price).abs();
}
}
pub fn update_seller(&mut self, proportion: f32) {
self.price *= 1.0 + (proportion - 0.5) * 0.25;
self.confidence /= 1.0 + (proportion - 0.5) * 0.25;
}
}
pub fn buy_units<'a>(
ctx: &mut GenCtx<impl Rng>,
2020-04-17 23:29:01 +00:00
sellers: impl Iterator<Item = &'a mut SellOrder>,
2020-03-28 18:16:19 +00:00
max_quantity: f32,
max_price: f32,
max_spend: f32,
) -> (f32, f32) {
2020-04-17 23:29:01 +00:00
let mut sell_orders = sellers.filter(|so| so.quantity > 0.0).collect::<Vec<_>>();
2020-03-28 18:16:19 +00:00
// Sort sell orders by price, cheapest first
2020-04-17 23:29:01 +00:00
sell_orders.sort_by(|a, b| {
a.price
.partial_cmp(&b.price)
.unwrap_or_else(|| panic!("{} and {}", a.price, b.price))
});
2020-03-28 18:16:19 +00:00
let mut quantity = 0.0;
let mut spent = 0.0;
for order in sell_orders {
2020-04-17 23:29:01 +00:00
if quantity >= max_quantity || // We've purchased enough
2020-03-28 18:16:19 +00:00
spent >= max_spend || // We've spent enough
2020-04-17 23:29:01 +00:00
order.price > max_price
// Price is too high
2020-03-28 18:16:19 +00:00
{
break;
} else {
let q = (max_quantity - quantity)
.min(order.quantity - order.q_sold)
.min((max_spend - spent) / order.price);
order.q_sold += q;
quantity += q;
spent += q * order.price;
}
}
(quantity, spent)
}