Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 4* Special Rate to Sim #2

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ pub enum Pool {
Focus,
Fivestar,
FourstarFocus,
FourstarSpecial,
Fourstar,
Threestar,
}
Expand All @@ -82,8 +83,9 @@ impl TryFrom<u8> for Pool {
0 => Focus,
1 => Fivestar,
2 => FourstarFocus,
3 => Fourstar,
4 => Threestar,
3 => FourstarSpecial,
4 => Fourstar,
5 => Threestar,
_ => return Err(()),
})
}
Expand Down
42 changes: 23 additions & 19 deletions src/sim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use rand::distributions::Distribution;
use rand::rngs::SmallRng;
use rand::{Rng, SeedableRng};

use weighted_choice::{WeightedIndex4, WeightedIndex5};
use weighted_choice::{WeightedIndex4, WeightedIndex6};

use goal::{CustomGoal, GoalKind};

Expand Down Expand Up @@ -38,9 +38,9 @@ pub struct Sim {
/// Precalculated tables for the probabilities of units being randomly chosen.
#[derive(Debug, Copy, Clone, Default)]
struct RandTables {
pool_sizes: [[u8; 4]; 5],
pool_dists: [WeightedIndex5; 26],
color_dists: [WeightedIndex4; 5],
pool_sizes: [[u8; 4]; 6],
pool_dists: [WeightedIndex6; 26],
color_dists: [WeightedIndex4; 6],
}

/// Scratch space for representing the goal in a way that is faster to work with.
Expand Down Expand Up @@ -83,6 +83,7 @@ impl Sim {
[0, 0, 0, 0],
[26, 19, 14, 17],
[0, 0, 0, 0],
[69, 56, 45, 34],
[45, 46, 37, 50],
[45, 46, 37, 50],
];
Expand All @@ -93,13 +94,13 @@ impl Sim {
self.tables.pool_sizes[2][color as usize] = 1;
}

for color in 0..5 {
self.tables.color_dists[color] = WeightedIndex4::new(self.tables.pool_sizes[color]);
for pool in 0..6 {
self.tables.color_dists[pool] = WeightedIndex4::new(self.tables.pool_sizes[pool]);
}

for pity_incr in 0..26 {
self.tables.pool_dists[pity_incr] =
WeightedIndex5::new(self.probabilities(pity_incr as u32));
WeightedIndex6::new(self.probabilities(pity_incr as u32));
}
}

Expand Down Expand Up @@ -220,6 +221,7 @@ impl Sim {
|| sample.0 == Pool::Fourstar
|| sample.0 == Pool::Fivestar
|| (sample.0 == Pool::FourstarFocus && !self.goal_data.is_fourstar_focus)
|| sample.0 == Pool::FourstarSpecial
|| !self.goal_data.color_needed[color as usize]
{
return PullOrbResult {
Expand Down Expand Up @@ -279,7 +281,7 @@ impl Sim {

/// Calculates the actual probabilities of selecting a unit from each of the four
/// possible pools after a certain number of rate increases.
fn probabilities(&self, pity_incr: u32) -> [f32; 5] {
fn probabilities(&self, pity_incr: u32) -> [f32; 6] {
let bases = self.bases();
let pity_pct = if pity_incr >= 25 {
100.0 - bases[Pool::Focus as usize] - bases[1]
Expand All @@ -293,29 +295,31 @@ impl Sim {
probabilities[Pool::Focus as usize] += pity_pct * focus_ratio;
probabilities[Pool::Fivestar as usize] += pity_pct * (1.0 - focus_ratio);

let lower_ratio = bases[Pool::Fourstar as usize]
/ (bases[Pool::Fourstar as usize] + bases[Pool::Threestar as usize]);
probabilities[Pool::Fourstar as usize] -= pity_pct * lower_ratio;
probabilities[Pool::Threestar as usize] -= pity_pct * (1.0 - lower_ratio);
let lower_dem = bases[Pool::FourstarFocus as usize] + bases[Pool::FourstarSpecial as usize]
+ bases[Pool::Fourstar as usize] + bases[Pool::Threestar as usize];
probabilities[Pool::FourstarFocus as usize] -= pity_pct * bases[Pool::FourstarFocus as usize] / lower_dem;
probabilities[Pool::FourstarSpecial as usize] -= pity_pct * bases[Pool::FourstarSpecial as usize] / lower_dem;
probabilities[Pool::Fourstar as usize] -= pity_pct * bases[Pool::Fourstar as usize] / lower_dem;
probabilities[Pool::Threestar as usize] -= pity_pct * bases[Pool::Threestar as usize] / lower_dem;
probabilities
}

/// Gives the base probabilities of selecting a unit from each pool.
fn bases(&self) -> [f32; 5] {
fn bases(&self) -> [f32; 6] {
let (focus, fivestar) = self.banner.starting_rates;
if self.banner.fourstar_focus.is_some() {
[3.0, 3.0, 3.0, 55.0, 36.0]
[3.0, 3.0, 3.0, 3.0, 52.0, 36.0]
} else if (focus, fivestar) == (6, 0) {
// The lower-rarity breakdown on this new banner is different
// for no apparent reason
[6.0, 0.0, 0.0, 60.0, 34.0]
[6.0, 0.0, 0.0, 3.0, 57.0, 34.0]
} else {
let focus = focus as f32;
let fivestar = fivestar as f32;
let fivestar_total = focus + fivestar;
let fourstar = (100.0 - fivestar_total) * 58.0 / 94.0;
let threestar = (100.0 - fivestar_total) * 36.0 / 94.0;
[focus, fivestar, 0.0, fourstar, threestar]
let fivestar_total = focus + fivestar + 3.0;
let fourstar = (100.0 - fivestar_total) * 55.0 / 91.0;
let threestar = (100.0 - fivestar_total) * 36.0 / 91.0;
[focus, fivestar, 0.0, 3.0, fourstar, threestar]
}
}
}
32 changes: 19 additions & 13 deletions src/weighted_choice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,47 +43,53 @@ impl Distribution<usize> for WeightedIndex4 {

/// Optimized version of rand::WeightedIndex for a fixed-size collection of five floats.
#[derive(Copy, Clone, Debug, Default)]
pub struct WeightedIndex5 {
pub struct WeightedIndex6 {
// Cumulative weights stored for faster lookup
values: [f32; 5],
values: [f32; 6],
}

impl WeightedIndex5 {
impl WeightedIndex6 {
/// Constructs a sampler from the given weights. Weights do not need to sum to 1.
pub fn new<T: Into<f32> + Copy>(values: [T; 5]) -> Self {
pub fn new<T: Into<f32> + Copy>(values: [T; 6]) -> Self {
let total = values[0].into()
+ values[1].into()
+ values[2].into()
+ values[3].into()
+ values[4].into();
+ values[4].into()
+ values[5].into();
Self {
values: [
values[0].into() / total,
(values[0].into() + values[1].into()) / total,
(values[0].into() + values[1].into() + values[2].into()) / total,
(values[0].into() + values[1].into() + values[2].into() + values[3].into()) / total,
(values[0].into() + values[1].into() + values[2].into() + values[3].into() + values[4].into()) / total,
1.0,
],
}
}
}

impl Distribution<usize> for WeightedIndex5 {
impl Distribution<usize> for WeightedIndex6 {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
let choice = rng.gen::<f32>();
if choice > self.values[1] {
if choice > self.values[2] {
if choice > self.values[3] {
4
if choice > self.values[2] {
if choice > self.values[3] {
if choice > self.values[4] {
5
} else {
3
4
}
} else {
2
3
}
} else {
if choice > self.values[0] {
1
if choice > self.values[1] {
2
} else {
1
}
} else {
0
}
Expand Down