nil_core/infrastructure/
mine.rs1use crate::error::{Error, Result};
5use crate::infrastructure::building::{Building, BuildingLevel, MineId};
6use derive_more::{Deref, Into};
7use nil_num::growth::growth;
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10
11pub trait Mine: Building {
12 fn mine_id(&self) -> MineId;
13
14 fn production(&self, stats: &MineStatsTable) -> Result<MineProduction>;
16 fn min_production(&self) -> MineProduction;
18 fn max_production(&self) -> MineProduction;
20}
21
22#[derive(Clone, Debug, Deserialize, Serialize)]
23#[serde(rename_all = "camelCase")]
24pub struct MineStats {
25 pub level: BuildingLevel,
26 pub production: MineProduction,
27}
28
29#[derive(Clone, Debug, Deserialize, Serialize)]
30#[serde(rename_all = "camelCase")]
31pub struct MineStatsTable {
32 id: MineId,
33 table: HashMap<BuildingLevel, MineStats>,
34}
35
36impl MineStatsTable {
37 pub(crate) fn new(mine: &dyn Mine) -> Self {
38 let max_level = *mine.max_level();
39 let mut table = HashMap::with_capacity((max_level).into());
40
41 let mut production = f64::from(mine.min_production());
42 let production_growth = growth()
43 .floor(production)
44 .ceil(mine.max_production())
45 .max_level(max_level)
46 .call();
47
48 for level in 1..=max_level {
49 let level = BuildingLevel::new(level);
50 table.insert(
51 level,
52 MineStats {
53 level,
54 production: MineProduction::from(production.round()),
55 },
56 );
57
58 debug_assert!(production.is_normal());
59
60 production += production * production_growth;
61 }
62
63 table.shrink_to_fit();
64
65 Self { id: mine.mine_id(), table }
66 }
67
68 #[inline]
69 pub fn id(&self) -> MineId {
70 self.id
71 }
72
73 #[inline]
74 pub fn get(&self, level: BuildingLevel) -> Result<&MineStats> {
75 self
76 .table
77 .get(&level)
78 .ok_or(Error::MineStatsNotFoundForLevel(self.id, level))
79 }
80}
81
82#[derive(Clone, Copy, Debug, Deref, Into, Deserialize, Serialize)]
84#[into(u32, f64)]
85pub struct MineProduction(u32);
86
87impl MineProduction {
88 #[inline]
89 pub const fn new(value: u32) -> Self {
90 Self(value)
91 }
92}
93
94impl From<f64> for MineProduction {
95 fn from(value: f64) -> Self {
96 Self::new(value as u32)
97 }
98}