1use crate::effective::TypeEffectiveness;
2use scarlet_queen_core::{
3 each_individual::{EachCrateIndividual, FitnessIndividualTrait, Individual},
4 pokemon_type::{PokemonTypeAll, PokemonTypeTrait},
5};
6use std::{ops::Deref, rc::Rc};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct FitnessPokemonType<P>
10where
11 P: PokemonTypeTrait,
12{
13 pokemon_type: Rc<Individual<P>>,
14}
15
16impl<P> FitnessPokemonType<P>
17where
18 P: PokemonTypeTrait,
19{
20 fn attack_effectiveness(&self, defense: &Self) -> TypeEffectiveness {
21 TypeEffectiveness::from_effective_array(self, defense)
22 }
23}
24
25impl<P> EachCrateIndividual for FitnessPokemonType<P>
26where
27 P: PokemonTypeTrait,
28{
29 type Item = P;
30
31 fn new(pokemon_type: &Rc<Individual<P>>) -> FitnessPokemonType<P> {
32 FitnessPokemonType {
33 pokemon_type: Rc::clone(pokemon_type),
34 }
35 }
36
37 fn get_individual(&self) -> &Individual<P> {
38 &self.pokemon_type
39 }
40}
41
42impl<P> FitnessIndividualTrait for FitnessPokemonType<P>
43where
44 P: PokemonTypeTrait,
45{
46 fn fitness(&self, other: &Self) -> usize {
47 self.attack_effectiveness(other).point()
48 }
49}
50
51impl<P> From<FitnessPokemonType<P>> for usize
52where
53 P: PokemonTypeTrait,
54{
55 fn from(val: FitnessPokemonType<P>) -> Self {
56 usize::from(&val)
57 }
58}
59
60impl<P> From<&FitnessPokemonType<P>> for usize
61where
62 P: PokemonTypeTrait,
63{
64 fn from(val: &FitnessPokemonType<P>) -> Self {
65 match <P as Into<PokemonTypeAll>>::into(val.pokemon_type.deref().get_value().clone()) {
66 PokemonTypeAll::None => 0,
67 PokemonTypeAll::Normal => 1,
68 PokemonTypeAll::Fire => 2,
69 PokemonTypeAll::Water => 3,
70 PokemonTypeAll::Electric => 4,
71 PokemonTypeAll::Grass => 5,
72 PokemonTypeAll::Ice => 6,
73 PokemonTypeAll::Fighting => 7,
74 PokemonTypeAll::Poison => 8,
75 PokemonTypeAll::Ground => 9,
76 PokemonTypeAll::Flying => 10,
77 PokemonTypeAll::Psychic => 11,
78 PokemonTypeAll::Bug => 12,
79 PokemonTypeAll::Rock => 13,
80 PokemonTypeAll::Ghost => 14,
81 PokemonTypeAll::Dragon => 15,
82 PokemonTypeAll::Dark => 16,
83 PokemonTypeAll::Steel => 17,
84 PokemonTypeAll::Fairy => 18,
85 }
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use std::rc::Rc;
92
93 use scarlet_queen_core::{
94 each_individual::{EachCrateIndividual, FitnessIndividualTrait, Individual},
95 pokemon_type::PokemonTypeAll,
96 };
97
98 use crate::{effective::TypeEffectiveness, pokemon_type::FitnessPokemonType};
99
100 #[test]
101 fn test_fitnesspokemontype_attackeffectiveness() {
102 let testcases = vec![
103 (
104 (
105 FitnessPokemonType {
106 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::None)),
107 },
108 FitnessPokemonType {
109 pokemon_type: Rc::new(Individual::new_with_id(1, PokemonTypeAll::Dragon)),
110 },
111 ),
112 TypeEffectiveness::Normal,
113 ),
114 (
115 (
116 FitnessPokemonType {
117 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Steel)),
118 },
119 FitnessPokemonType {
120 pokemon_type: Rc::new(Individual::new_with_id(1, PokemonTypeAll::None)),
121 },
122 ),
123 TypeEffectiveness::Normal,
124 ),
125 (
126 (
127 FitnessPokemonType {
128 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Fire)),
129 },
130 FitnessPokemonType {
131 pokemon_type: Rc::new(Individual::new_with_id(1, PokemonTypeAll::Grass)),
132 },
133 ),
134 TypeEffectiveness::SuperEffective,
135 ),
136 (
137 (
138 FitnessPokemonType {
139 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Fire)),
140 },
141 FitnessPokemonType {
142 pokemon_type: Rc::new(Individual::new_with_id(1, PokemonTypeAll::Water)),
143 },
144 ),
145 TypeEffectiveness::NotVeryEffective,
146 ),
147 (
148 (
149 FitnessPokemonType {
150 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Rock)),
151 },
152 FitnessPokemonType {
153 pokemon_type: Rc::new(Individual::new_with_id(1, PokemonTypeAll::Rock)),
154 },
155 ),
156 TypeEffectiveness::Normal,
157 ),
158 (
159 (
160 FitnessPokemonType {
161 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Fighting)),
162 },
163 FitnessPokemonType {
164 pokemon_type: Rc::new(Individual::new_with_id(1, PokemonTypeAll::Ghost)),
165 },
166 ),
167 TypeEffectiveness::NoEffect,
168 ),
169 ];
170 for ((arg_1, arg_2), result) in testcases.into_iter() {
171 assert_eq!(
172 FitnessPokemonType::<PokemonTypeAll>::attack_effectiveness(&arg_1, &arg_2),
173 result
174 );
175 }
176 }
177
178 #[test]
179 fn test_fitnesspokemontype_eachcrateindividual_new() {
180 let testcases: Vec<(
181 Rc<Individual<PokemonTypeAll>>,
182 FitnessPokemonType<PokemonTypeAll>,
183 )> = vec![
184 (
185 Rc::new(Individual::new_with_id(0, PokemonTypeAll::None)),
186 FitnessPokemonType {
187 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::None)),
188 },
189 ),
190 (
191 Rc::new(Individual::new_with_id(1, PokemonTypeAll::Fire)),
192 FitnessPokemonType {
193 pokemon_type: Rc::new(Individual::new_with_id(1, PokemonTypeAll::Fire)),
194 },
195 ),
196 (
197 Rc::new(Individual::new_with_id(0, PokemonTypeAll::Dragon)),
198 FitnessPokemonType {
199 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Dragon)),
200 },
201 ),
202 ];
203 for (arg, result) in testcases.into_iter() {
204 assert_eq!(FitnessPokemonType::<PokemonTypeAll>::new(&arg), result);
205 }
206 }
207
208 #[test]
209 fn test_fitnesspokemontype_fitnessindividual_fitness() {
210 let testcases = vec![
211 (
212 (
213 FitnessPokemonType {
214 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::None)),
215 },
216 FitnessPokemonType {
217 pokemon_type: Rc::new(Individual::new_with_id(1, PokemonTypeAll::Dragon)),
218 },
219 ),
220 2,
221 ),
222 (
223 (
224 FitnessPokemonType {
225 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Steel)),
226 },
227 FitnessPokemonType {
228 pokemon_type: Rc::new(Individual::new_with_id(1, PokemonTypeAll::None)),
229 },
230 ),
231 2,
232 ),
233 (
234 (
235 FitnessPokemonType {
236 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Fire)),
237 },
238 FitnessPokemonType {
239 pokemon_type: Rc::new(Individual::new_with_id(1, PokemonTypeAll::Grass)),
240 },
241 ),
242 3,
243 ),
244 (
245 (
246 FitnessPokemonType {
247 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Fire)),
248 },
249 FitnessPokemonType {
250 pokemon_type: Rc::new(Individual::new_with_id(1, PokemonTypeAll::Water)),
251 },
252 ),
253 1,
254 ),
255 (
256 (
257 FitnessPokemonType {
258 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Rock)),
259 },
260 FitnessPokemonType {
261 pokemon_type: Rc::new(Individual::new_with_id(1, PokemonTypeAll::Rock)),
262 },
263 ),
264 2,
265 ),
266 (
267 (
268 FitnessPokemonType {
269 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Fighting)),
270 },
271 FitnessPokemonType {
272 pokemon_type: Rc::new(Individual::new_with_id(1, PokemonTypeAll::Ghost)),
273 },
274 ),
275 0,
276 ),
277 ];
278 for ((arg_1, arg_2), result) in testcases.into_iter() {
279 assert_eq!(
280 FitnessPokemonType::<PokemonTypeAll>::fitness(&arg_1, &arg_2),
281 result
282 );
283 }
284 }
285
286 #[test]
287 fn test_fitnesspokemontype_intousize_into() {
288 let testcases: Vec<(FitnessPokemonType<PokemonTypeAll>, usize)> = vec![
289 (
290 FitnessPokemonType {
291 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::None)),
292 },
293 0,
294 ),
295 (
296 FitnessPokemonType {
297 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Normal)),
298 },
299 1,
300 ),
301 (
302 FitnessPokemonType {
303 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Fire)),
304 },
305 2,
306 ),
307 (
308 FitnessPokemonType {
309 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Water)),
310 },
311 3,
312 ),
313 (
314 FitnessPokemonType {
315 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Electric)),
316 },
317 4,
318 ),
319 (
320 FitnessPokemonType {
321 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Grass)),
322 },
323 5,
324 ),
325 (
326 FitnessPokemonType {
327 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Ice)),
328 },
329 6,
330 ),
331 (
332 FitnessPokemonType {
333 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Fighting)),
334 },
335 7,
336 ),
337 (
338 FitnessPokemonType {
339 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Poison)),
340 },
341 8,
342 ),
343 (
344 FitnessPokemonType {
345 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Ground)),
346 },
347 9,
348 ),
349 (
350 FitnessPokemonType {
351 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Flying)),
352 },
353 10,
354 ),
355 (
356 FitnessPokemonType {
357 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Psychic)),
358 },
359 11,
360 ),
361 (
362 FitnessPokemonType {
363 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Bug)),
364 },
365 12,
366 ),
367 (
368 FitnessPokemonType {
369 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Rock)),
370 },
371 13,
372 ),
373 (
374 FitnessPokemonType {
375 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Ghost)),
376 },
377 14,
378 ),
379 (
380 FitnessPokemonType {
381 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Dragon)),
382 },
383 15,
384 ),
385 (
386 FitnessPokemonType {
387 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Dark)),
388 },
389 16,
390 ),
391 (
392 FitnessPokemonType {
393 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Steel)),
394 },
395 17,
396 ),
397 (
398 FitnessPokemonType {
399 pokemon_type: Rc::new(Individual::new_with_id(0, PokemonTypeAll::Fairy)),
400 },
401 18,
402 ),
403 ];
404 for (arg, result) in testcases.into_iter() {
405 assert_eq!(usize::from(&arg), result);
406 assert_eq!(usize::from(arg), result);
407 }
408 }
409}