use std::collections::HashMap;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::fmt::{self, Display, Formatter};
use rand::Rng;
pub struct Stock {
direction: i64,
id: i64,
initial_value: i64,
name: String,
value: i64,
variation: i64,
}
impl Stock {
pub fn new(id: i64, name: String, value: i64, variation: i64) -> Self {
Self { direction: 0, 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) {
let random = rand::thread_rng().gen_range(-self.variation..=self.variation);
self.direction = ((self.direction * 3)/5) + random;
self.value += self.direction;
}
pub fn reset(&mut self) {
self.value = self.initial_value;
self.direction = 0;
}
}
impl Hash for Stock {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
self.name.hash(state);
}
}
impl Ord for Stock {
fn cmp(&self, other: &Self) -> Ordering {
self.id.cmp(&other.id)
}
}
impl PartialOrd for Stock {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for Stock {
fn eq(&self, other: &Self) -> bool {
(self.id == other.id) && (self.name == other.name)
}
}
impl Eq for Stock {}
pub fn generate_name() -> String {
let first_names = [
"Trading", "Rainbow", "Cake", "Power", "Mining", "Spacecraft", "Cargo", "Crab",
"Dining", "Computer", "Game", "Security", "Block", "Micro", "Time",
];
let last_names = [
"Incorporated", "Enterprise", "Solutions", "Company", "Operations", "Factory",
"Agency", "Firm", "Chain", "Box", "Store", "Market",
];
let first_name = first_names[rand::thread_rng().gen_range(0..first_names.len())];
let last_name = last_names[rand::thread_rng().gen_range(0..last_names.len())];
format!("{} {}", first_name, last_name)
}
pub fn generate_stock(id: i64, min_value: i64, max_value: i64, min_variation: i64,
max_variation: i64, name: String) -> Stock {
let value = rand::thread_rng().gen_range(min_value..=max_value);
let variation = rand::thread_rng().gen_range(min_variation..=max_variation);
Stock::new(id, name, value, variation)
}
impl Display for Stock {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}, Value: {}", self.name, self.value)
}
}
pub struct Player {
balance: i64,
income: i64,
initial_income: i64,
stock_balances: HashMap<i64, i64>,
}
impl Player {
pub fn new(balance: i64, income: i64) -> Self {
Self { balance, income, initial_income: 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 income(&self) -> i64 { self.income }
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 increase_income(&mut self) -> Result<(), ()> {
let cost = self.initial_income * 10;
if cost > self.balance { return Err(()); }
self.income += self.initial_income;
self.balance -= cost;
Ok(())
}
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
}
pub fn withdraw(&mut self, amount: i64) -> Result<(), ()> {
if self.balance < amount { return Err(()); }
self.balance -= amount;
Ok(())
}
pub fn deposit(&mut self, amount: i64) { self.balance += amount; }
}