use std::collections::HashMap;
use std::cmp::Ordering;
use std::fmt::{self, Display, Formatter};
use std::hash::{Hash, Hasher};
use rand::Rng;
pub struct Stock<'a> {
id: i64,
initial_value: i64,
name: &'a str,
value: i64,
variation: i64,
}
impl<'a> Stock<'a> {
pub fn new(id: i64, name: &'a str, value: i64, variation: i64) -> Self {
Self { id, initial_value: value, name, value, variation }
}
pub fn value(&self) -> i64 { self.value }
pub fn name(&self) -> &str { self.name }
pub fn id(&self) -> i64 { self.id }
pub fn vary(&mut self) -> i64 {
let variation = self.variation;
let vary = rand::thread_rng().gen_range(-variation..variation);
self.value += vary;
vary
}
pub fn reset(&mut self) { self.value = self.initial_value; }
}
impl<'a> Hash for Stock<'a> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
self.name.hash(state);
}
}
impl<'a> Ord for Stock<'a> {
fn cmp(&self, other: &Self) -> Ordering {
self.id.cmp(&other.id)
}
}
impl<'a> PartialOrd for Stock<'a> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<'a> PartialEq for Stock<'a> {
fn eq(&self, other: &Self) -> bool {
(self.id == other.id) && (self.name == other.name)
}
}
impl<'a> Eq for Stock<'a> {}
impl<'a> Display for Stock<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}, Value: {}", self.name, self.value)
}
}
pub struct Player {
balance: i64,
income: i64,
stock_balances: HashMap<i64, i64>,
}
impl Player {
pub fn new(balance: i64, income: i64) -> Self {
Self { balance, income, stock_balances: HashMap::new() }
}
pub fn balance(&self) -> i64 { self.balance }
pub fn stock_balance(&self, stock: &Stock) -> i64 {
if let Some(b) = self.stock_balances.get(&stock.id()) {
return *b;
} else {
return 0;
}
}
pub fn buy_stock(&mut self, stock: &Stock, amount: i64) -> Result<(), ()> {
let cost = stock.value() * amount;
if i64::from(self.balance) < cost { return Err(()) }
self.balance -= cost;
let stock_balance = self.stock_balance(stock);
self.stock_balances.insert(stock.id(), stock_balance + amount);
Ok(())
}
pub fn sell_stock(&mut self, stock: &Stock, amount: i64) -> Result<(), ()> {
let bal = self.stock_balance(stock);
if bal < amount { return Err(()) }
self.stock_balances.insert(stock.id(), bal - amount);
self.balance += stock.value() * amount;
Ok(())
}
pub fn reset_stock(&mut self, stock: &Stock) {
self.stock_balances.insert(stock.id(), 0);
}
pub fn collect_income(&mut self) { self.balance += self.income }
pub fn net_worth(&self, stocks: &[Stock]) -> i64 {
let mut result = self.balance;
for s in stocks { result += s.value() * self.stock_balance(s) }
result
}
}