use crate::error::{Error, Result};
use crate::infrastructure::building::{Building, BuildingLevel, MineId};
use crate::world::config::WorldConfig;
use derive_more::{Deref, Into};
use nil_num::growth::growth;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
pub trait Mine: Building {
fn mine_id(&self) -> MineId;
fn production(&self, stats: &MineStatsTable) -> Result<MineProduction>;
fn min_production(&self) -> MineProduction;
fn max_production(&self) -> MineProduction;
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MineStats {
pub level: BuildingLevel,
pub production: MineProduction,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MineStatsTable {
id: MineId,
table: HashMap<BuildingLevel, MineStats>,
}
impl MineStatsTable {
pub(crate) fn new(config: &WorldConfig, mine: &dyn Mine) -> Self {
let max_level = *mine.max_level();
let mut table = HashMap::with_capacity((max_level).into());
let speed = f64::from(config.speed());
let mut production = mine.min_production() * speed;
let production_growth = growth()
.floor(production)
.ceil(mine.max_production() * speed)
.max_level(max_level)
.call();
for level in 1..=max_level {
let level = BuildingLevel::new(level);
table.insert(
level,
MineStats {
level,
production: MineProduction::from(production.round()),
},
);
debug_assert!(production.is_normal());
production += production * production_growth;
}
table.shrink_to_fit();
Self { id: mine.mine_id(), table }
}
#[inline]
pub fn id(&self) -> MineId {
self.id
}
#[inline]
pub fn get(&self, level: BuildingLevel) -> Result<&MineStats> {
self
.table
.get(&level)
.ok_or(Error::MineStatsNotFoundForLevel(self.id, level))
}
}
#[derive(Clone, Copy, Debug, Deref, Into, Deserialize, Serialize, nil_num::F64Ops)]
#[into(u32, f64)]
pub struct MineProduction(u32);
impl MineProduction {
#[inline]
pub const fn new(value: u32) -> Self {
Self(value)
}
}
impl From<f64> for MineProduction {
fn from(value: f64) -> Self {
Self::new(value as u32)
}
}