1use serde::Serialize;
2
3use crate::Rng;
4
5use super::{Drop, DropSet, DropTable};
6
7#[derive(Default, PartialEq, Eq, Hash, Serialize, Debug)]
9pub struct DropAnalysis {
10 pub seeds: u32,
12
13 pub nothing: u32,
14 pub small_energy: u32,
15 pub big_energy: u32,
16 pub missile: u32,
17 pub super_missile: u32,
18 pub power_bomb: u32,
19}
20
21impl DropAnalysis {
22 fn update(&mut self, drop: Drop) {
23 match drop {
24 Drop::Nothing => self.nothing += 1,
25 Drop::SmallEnergy => self.small_energy += 1,
26 Drop::BigEnergy => self.big_energy += 1,
27 Drop::Missile => self.missile += 1,
28 Drop::SuperMissile => self.super_missile += 1,
29 Drop::PowerBomb => self.power_bomb += 1,
30 }
31 }
32}
33
34pub fn analyze_correlated(
37 table: &DropTable,
38 possible_drops: &DropSet,
39 n: u32,
40 rng: Rng,
41 seeds: impl IntoIterator<Item = u16>,
42) -> DropAnalysis {
43 let mut analysis = DropAnalysis::default();
44
45 for seed in seeds {
46 let mut rng = rng.with_seed(seed);
47 for drop in table.roll_multiple(&mut rng, possible_drops, n) {
48 analysis.update(drop);
49 }
50
51 analysis.seeds += 1;
52 }
53 analysis
54}
55
56pub fn analyze_uncorrelated<S: IntoIterator<Item = u16>>(
59 table: &DropTable,
60 possible_drops: &DropSet,
61 n: u32,
62 seeds: S,
63) -> DropAnalysis
64where
65 S::IntoIter: ExactSizeIterator + Clone,
66{
67 let mut analysis = DropAnalysis::default();
68 let seeds = seeds.into_iter();
69 let num_seeds = seeds.len() as u32;
70 analysis.seeds = num_seeds;
71
72 let drop_count = table.count.unwrap_or(1) + table.extra.as_ref().map(|_| 1).unwrap_or(0);
73
74 seeds
75 .cycle()
76 .take((num_seeds * drop_count * n) as usize)
77 .map(|seed| Rng::RESET.with_seed(seed))
78 .for_each(|mut rng| analysis.update(table.roll_one(&mut rng, possible_drops)));
79
80 analysis
81}