td_wavegen/
lib.rs

1/// Simple type to differenciate mobs!
2#[derive(Debug, Clone, PartialEq)]
3pub struct MobType {
4    /// Map the mob types in your game to different indexes!
5    pub index: usize,
6    /// The cost of each instance of this specific mob!
7    cost: usize,
8}
9
10impl MobType {
11    pub fn new(index: usize, cost: usize) -> Self {
12        MobType {
13            index: index,
14            cost: cost,
15        }
16    }
17}
18
19#[derive(Debug, Clone)]
20struct MobCostMap(Vec<(usize, usize)>);
21
22impl From<&Vec<MobType>> for MobCostMap {
23    fn from(mob_types: &Vec<MobType>) -> MobCostMap {
24        let mut map_cost_map_contents = mob_types
25            .iter()
26            .map(|e| (e.cost, e.index))
27            .collect::<Vec<(usize, usize)>>();
28        map_cost_map_contents.sort_by(|a, b| a.0.cmp(&b.0));
29        MobCostMap(map_cost_map_contents)
30    }
31}
32
33/// A single wave, i.e. a set of mobs for a given max cost!
34#[derive(Debug, PartialEq, Clone)]
35pub struct Wave {
36    /// Optional wave nr.!
37    pub wave_number: Option<usize>,
38    /// Total real cost of this wave. Might be a bit lower than the max cost if there is no mob to buy for the leftover budget!
39    pub total_cost: usize,
40    /// List of mobs for this wave!
41    pub mobs: Vec<MobType>,
42}
43
44impl Wave {
45    /// Generate a wave from a given maximum cost. This will "buy" mobs for this wave until it runs out of budget!
46    pub fn gen_from_max_total_cost(mut max_total_cost: usize, mob_types: &Vec<MobType>) -> Wave {
47        let mut mob_cost_map: MobCostMap = MobCostMap::from(mob_types);
48        let mut total_cost: usize = 0;
49        let mut mobs: Vec<MobType> = Vec::new();
50        while max_total_cost > 0 || mob_cost_map.0.len() > 0 {
51            if let Some(mob_cost) = mob_cost_map.0.last() {
52                if max_total_cost >= mob_cost.0 {
53                    max_total_cost -= mob_cost.0;
54                    total_cost += mob_cost.0;
55                    mobs.push(MobType {
56                        index: mob_cost.1,
57                        cost: mob_cost.0,
58                    });
59                } else {
60                    mob_cost_map.0.remove(mob_cost_map.0.len() - 1);
61                }
62            } else {
63                break;
64            }
65        }
66        Wave {
67            wave_number: None,
68            total_cost: total_cost,
69            mobs: mobs,
70        }
71    }
72}
73
74/// Main type to use. Creates multiple waves!
75#[derive(Debug, Clone)]
76pub struct Waves {
77    /// Next wave number!
78    next_wave: usize,
79    /// Function that determines the budget of each wave!
80    cost_function: fn(usize) -> usize,
81    /// Registered mob types that the system can "buy" in a wave!
82    mob_types: Vec<MobType>,
83}
84
85impl Waves {
86    /// Waves builder. Best to use this!
87    pub fn builder() -> WavesBuilder {
88        WavesBuilder {
89            next_wave: 1,
90            mob_types: Vec::new(),
91            cost_function: |wave_nr| wave_nr,
92        }
93    }
94    /// Generates a single wave based on current wave number (and its budget)!
95    /// This wave is generated outside of the Waves iterator and won't have a wave number!
96    pub fn gen_single_current_wave(&self) -> Wave {
97        let max_total_cost: usize = (self.cost_function)(self.get_next_wave_number());
98        let wave: Wave = Wave::gen_from_max_total_cost(max_total_cost, &self.mob_types);
99        wave
100    }
101    /// Returns current wave number [1..]!
102    pub fn get_next_wave_number(&self) -> usize {
103        self.next_wave
104    }
105}
106
107impl Iterator for Waves {
108    type Item = Wave;
109    fn next(&mut self) -> Option<Self::Item> {
110        let max_total_cost: usize = (self.cost_function)(self.next_wave);
111        let mut wave: Wave = Wave::gen_from_max_total_cost(max_total_cost, &self.mob_types);
112        wave.wave_number = Some(self.next_wave);
113        self.next_wave += 1;
114        Some(wave)
115    }
116}
117
118pub struct WavesBuilder {
119    next_wave: usize,
120    mob_types: Vec<MobType>,
121    cost_function: fn(usize) -> usize,
122}
123
124impl WavesBuilder {
125    /// Register a single mob type with the waves builder!
126    pub fn add_mob_type(mut self, mob_type: MobType) -> WavesBuilder {
127        self.mob_types.push(mob_type);
128        self
129    }
130    /// Register a vec of mob types all at once!
131    pub fn add_mob_types(mut self, mut mob_types: Vec<MobType>) -> WavesBuilder {
132        self.mob_types.append(&mut mob_types);
133        self
134    }
135    /// Use an already finished vec of mob types!
136    pub fn with_mob_types(mut self, mob_types: Vec<MobType>) -> WavesBuilder {
137        self.mob_types = mob_types;
138        self
139    }
140    /// Specify cost function for the waves!
141    pub fn with_cost_function(mut self, f: fn(usize) -> usize) -> WavesBuilder {
142        self.cost_function = f;
143        self
144    }
145    /// Usually 1, sets the starting wave!
146    pub fn with_starting_wave(mut self, starting_wave: usize) -> WavesBuilder {
147        self.next_wave = starting_wave;
148        self
149    }
150    /// Creates a waves object and consumes the builder!
151    pub fn build(self) -> Waves {
152        Waves {
153            next_wave: self.next_wave,
154            cost_function: self.cost_function,
155            mob_types: self.mob_types,
156        }
157    }
158}
159
160#[cfg(test)]
161mod tests {
162    use super::*;
163
164    #[test]
165    fn mob_cost_map_length() {
166        let mob_type_a = MobType { index: 1, cost: 1 };
167        let mob_type_b = MobType { index: 2, cost: 2 };
168        let mob_type_c = MobType { index: 3, cost: 3 };
169        let mob_types = vec![mob_type_a, mob_type_c, mob_type_b];
170        let mob_cost_map = MobCostMap::from(&mob_types);
171        println!("{:?}", mob_cost_map);
172        assert_eq!(mob_cost_map.0.len(), 3);
173    }
174
175    #[test]
176    fn gen_wave_from_max_total_cost_7_a() {
177        let mob_type_a = MobType { index: 1, cost: 1 };
178        let mob_type_b = MobType { index: 2, cost: 2 };
179        let mob_type_c = MobType { index: 3, cost: 3 };
180        let mob_types = vec![mob_type_a, mob_type_c, mob_type_b];
181        let wave: Wave = Wave::gen_from_max_total_cost(7, &mob_types);
182        println!("{:?}", wave);
183        assert_eq!(wave.total_cost, 7);
184        assert_eq!(wave.mobs.len(), 3);
185    }
186
187    #[test]
188    fn gen_wave_from_max_total_cost_8() {
189        let mob_type_a = MobType { index: 1, cost: 1 };
190        let mob_type_b = MobType { index: 2, cost: 2 };
191        let mob_type_c = MobType { index: 3, cost: 3 };
192        let mob_types = vec![mob_type_a, mob_type_c, mob_type_b];
193        let wave: Wave = Wave::gen_from_max_total_cost(8, &mob_types);
194        println!("{:?}", wave);
195        assert_eq!(wave.total_cost, 8);
196        assert_eq!(wave.mobs.len(), 3);
197    }
198
199    #[test]
200    fn gen_wave_from_max_total_cost_11() {
201        let mob_type_a = MobType { index: 1, cost: 1 };
202        let mob_type_b = MobType { index: 2, cost: 4 };
203        let mob_types = vec![mob_type_b, mob_type_a];
204        let wave: Wave = Wave::gen_from_max_total_cost(11, &mob_types);
205        println!("{:?}", wave);
206        assert_eq!(wave.total_cost, 11);
207        assert_eq!(wave.mobs.len(), 5);
208    }
209
210    #[test]
211    fn gen_wave_from_max_total_cost_7_b() {
212        let mob_type_a = MobType { index: 1, cost: 2 };
213        let mob_type_b = MobType { index: 2, cost: 4 };
214        let mob_types = vec![mob_type_b, mob_type_a];
215        let wave: Wave = Wave::gen_from_max_total_cost(7, &mob_types);
216        println!("{:?}", wave);
217        assert_eq!(wave.total_cost, 6);
218        assert_eq!(wave.mobs.len(), 2);
219    }
220
221    #[test]
222    fn roundtrip() {
223        let mob_type_a = MobType { index: 1, cost: 1 };
224        let mob_type_b = MobType { index: 2, cost: 3 };
225        let mob_type_c = MobType { index: 3, cost: 5 };
226        let mob_type_d = MobType { index: 4, cost: 7 };
227        let mob_types = vec![mob_type_a, mob_type_c, mob_type_b, mob_type_d];
228
229        let mob_cost_map = MobCostMap::from(&mob_types);
230        assert_eq!(mob_cost_map.0, [(1, 1), (3, 2), (5, 3), (7, 4)]);
231        println!("{:?}", mob_cost_map);
232
233        let mut waves = Waves::builder()
234            .with_mob_types(mob_types)
235            .with_starting_wave(2)
236            .with_cost_function(|wave| wave * 3)
237            .build();
238        println!("{:?}", waves);
239        let wave_1 = waves.next();
240        let wave_2 = waves.next();
241        let wave_3 = waves.next();
242        let wave_4 = waves.next();
243        let wave_5 = waves.next();
244        println!("{:?}", wave_1);
245        println!("{:?}", wave_2);
246        println!("{:?}", wave_3);
247        println!("{:?}", wave_4);
248        println!("{:?}", wave_5);
249        let test_wave_5 = Some(Wave {
250            wave_number: Some(6),
251            total_cost: 18,
252            mobs: vec![
253                MobType { index: 4, cost: 7 },
254                MobType { index: 4, cost: 7 },
255                MobType { index: 2, cost: 3 },
256                MobType { index: 1, cost: 1 },
257            ],
258        });
259        assert_eq!(wave_5, test_wave_5);
260    }
261}