From 7c5f059ecb5fbef9a6c3e6f4601790cc662fd151 Mon Sep 17 00:00:00 2001 From: Simon G <45692977+jeenyuhs@users.noreply.github.com> Date: Mon, 22 Jul 2024 19:40:04 +0000 Subject: [PATCH] count strain difficulty --- src/osu/attributes.rs | 4 ++++ src/osu/difficulty/gradual.rs | 3 +++ src/osu/difficulty/mod.rs | 4 ++++ src/osu/difficulty/skills/aim.rs | 18 ++++++++++++++++++ src/osu/difficulty/skills/speed.rs | 13 +++++++++++++ src/osu/performance/mod.rs | 5 +++-- src/taiko/difficulty/mod.rs | 1 - tests/difficulty.rs | 29 +++++++++++++++++++++++++++++ 8 files changed, 74 insertions(+), 3 deletions(-) diff --git a/src/osu/attributes.rs b/src/osu/attributes.rs index c968d8e2..b9498ecc 100644 --- a/src/osu/attributes.rs +++ b/src/osu/attributes.rs @@ -5,8 +5,12 @@ use crate::osu::performance::OsuPerformance; pub struct OsuDifficultyAttributes { /// The difficulty of the aim skill. pub aim: f64, + /// The difficulty strain of the aim skill. + pub aim_strain_difficulty: f64, /// The difficulty of the speed skill. pub speed: f64, + /// The difficulty strain of the aim skill. + pub speed_strain_difficulty: f64, /// The difficulty of the flashlight skill. pub flashlight: f64, /// The ratio of the aim strain with and without considering sliders diff --git a/src/osu/difficulty/gradual.rs b/src/osu/difficulty/gradual.rs index 3a5392b4..acbd8670 100644 --- a/src/osu/difficulty/gradual.rs +++ b/src/osu/difficulty/gradual.rs @@ -187,6 +187,9 @@ impl Iterator for OsuGradualDifficulty { flashlight_difficulty_value, ); + attrs.aim_strain_difficulty = Skill::new(&mut self.skills.aim, &self.diff_objects).count_difficult_strains(); + attrs.speed_strain_difficulty = Skill::new(&mut self.skills.speed, &self.diff_objects).count_difficult_strains(); + Some(attrs) } diff --git a/src/osu/difficulty/mod.rs b/src/osu/difficulty/mod.rs index da56660a..b9bbc710 100644 --- a/src/osu/difficulty/mod.rs +++ b/src/osu/difficulty/mod.rs @@ -39,6 +39,7 @@ pub fn difficulty(difficulty: &Difficulty, converted: &OsuBeatmap<'_>) -> OsuDif } = DifficultyValues::calculate(difficulty, converted); let aim_difficulty_value = aim.difficulty_value(); + let aim_no_sliders_difficulty_value = aim_no_sliders.difficulty_value(); let speed_relevant_note_count = speed.relevant_note_count(); let speed_difficulty_value = speed.difficulty_value(); @@ -138,6 +139,9 @@ impl DifficultyValues { speed.process(hit_object); flashlight.process(hit_object); } + + attrs.aim_strain_difficulty = aim.count_difficult_strains(); + attrs.speed_strain_difficulty = speed.count_difficult_strains(); } Self { skills, attrs } diff --git a/src/osu/difficulty/skills/aim.rs b/src/osu/difficulty/skills/aim.rs index 2ceff6f6..7eecc2a7 100644 --- a/src/osu/difficulty/skills/aim.rs +++ b/src/osu/difficulty/skills/aim.rs @@ -18,6 +18,7 @@ const STRAIN_DECAY_BASE: f64 = 0.15; pub struct Aim { with_sliders: bool, curr_strain: f64, + object_strains: Vec, inner: OsuStrainSkill, } @@ -26,6 +27,7 @@ impl Aim { Self { with_sliders, curr_strain: 0.0, + object_strains: vec![], inner: OsuStrainSkill::default(), } } @@ -106,8 +108,24 @@ impl<'a> Skill<'a, Aim> { AimEvaluator::evaluate_diff_of(curr, self.diff_objects, self.inner.with_sliders) * SKILL_MULTIPLIER; + self.inner.object_strains.push(self.inner.curr_strain); + self.inner.curr_strain } + + pub fn count_difficult_strains(&self) -> f64 { + let difficulty = self.inner.as_difficulty_value(); + + if difficulty == 0.0 { + 0.0 + } else { + println!("object strains: {:?}", self.inner.object_strains); + self.inner.object_strains + .iter() + .map(|&strain| 1.1 / (1.0 + ((-10.0 * (strain / (difficulty - 10.0) - 0.88)) as f64).exp())) + .sum() + } + } } struct AimEvaluator; diff --git a/src/osu/difficulty/skills/speed.rs b/src/osu/difficulty/skills/speed.rs index 7b4260e0..8670bed7 100644 --- a/src/osu/difficulty/skills/speed.rs +++ b/src/osu/difficulty/skills/speed.rs @@ -135,6 +135,19 @@ impl<'a> Skill<'a, Speed> { total_strain } + + pub fn count_difficult_strains(&self) -> f64 { + let difficulty = self.inner.as_difficulty_value(); + + if difficulty == 0.0 { + 0.0 + } else { + self.inner.object_strains + .iter() + .map(|&strain| 1.1 / (1.0 + ((-10.0 * (strain / (difficulty - 10.0) - 0.88)) as f64).exp())) + .sum() + } + } } struct SpeedEvaluator; diff --git a/src/osu/performance/mod.rs b/src/osu/performance/mod.rs index aaf73aa0..8d9b397a 100644 --- a/src/osu/performance/mod.rs +++ b/src/osu/performance/mod.rs @@ -609,7 +609,7 @@ impl OsuPerformanceInner { // In the "remove combo scaling" rework, they assume // the scores misses, are done at the hardest parts of the map. // https://github.com/ppy/osu/blob/c25e1bdeb586db8a2def47232632be61b4d4242e/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs#L261-L264 - aim_value *= 0.96 / ((self.effective_miss_count / (4.0 * self.attrs.aim.log10().powf(0.94))) + 1.0); + aim_value *= 0.96 / ((self.effective_miss_count / (4.0 * self.attrs.aim_strain_difficulty.log10().max(0.0).powf(0.94))) + 1.0); } @@ -674,11 +674,12 @@ impl OsuPerformanceInner { // * Penalize misses by assessing # of misses relative to the total # of objects. // * Default a 3% reduction for any # of misses. + println!("{}", self.attrs.speed_strain_difficulty); if self.effective_miss_count > 0.0 { // In the "remove combo scaling" rework, they assume // the scores misses, are done at the hardest parts of the map. // https://github.com/ppy/osu/blob/c25e1bdeb586db8a2def47232632be61b4d4242e/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs#L261-L264 - speed_value *= 0.96 / ((self.effective_miss_count / (4.0 * self.attrs.speed.log10().powf(0.94))) + 1.0); + speed_value *= 0.96 / ((self.effective_miss_count / (4.0 * self.attrs.speed_strain_difficulty.log10().max(0.0).powf(0.94))) + 1.0); } let ar_factor = if self.attrs.ar > 10.33 { diff --git a/src/taiko/difficulty/mod.rs b/src/taiko/difficulty/mod.rs index 6060e848..fc22d474 100644 --- a/src/taiko/difficulty/mod.rs +++ b/src/taiko/difficulty/mod.rs @@ -54,7 +54,6 @@ pub fn difficulty( peaks.rhythm_difficulty_value() }; - println!("{}", color_rating); let stamina_rating = peaks.stamina_difficulty_value(); let combined_rating = peaks.difficulty_value(); diff --git a/tests/difficulty.rs b/tests/difficulty.rs index a6cc1a3a..6cb38f9d 100644 --- a/tests/difficulty.rs +++ b/tests/difficulty.rs @@ -31,7 +31,9 @@ macro_rules! test_cases { }; ( @Osu { aim: $aim:literal, + aim_strain_difficulty: $aim_strain_difficulty:literal, speed: $speed:literal, + speed_strain_difficulty: $speed_strain_difficulty:literal, flashlight: $flashlight:literal, slider_factor: $slider_factor:literal, speed_note_count: $speed_note_count:literal, @@ -46,6 +48,8 @@ macro_rules! test_cases { }) => { OsuDifficultyAttributes { aim: $aim, + aim_strain_difficulty: $aim_strain_difficulty, + speed_strain_difficulty: $speed_strain_difficulty, speed: $speed, flashlight: $flashlight, slider_factor: $slider_factor, @@ -122,7 +126,9 @@ fn basic_osu() { Osu: OSU { NM => { aim: 2.8693628443424104, + aim_strain_difficulty: 0.0, speed: 2.533869745015772, + speed_strain_difficulty: 0.0, flashlight: 2.288770487900865, slider_factor: 0.9803052946037858, speed_note_count: 210.36373973116545, @@ -137,7 +143,9 @@ fn basic_osu() { }; HD => { aim: 2.8693628443424104, + aim_strain_difficulty: 0.0, speed: 2.533869745015772, + speed_strain_difficulty: 0.0, flashlight: 2.606877929965889, slider_factor: 0.9803052946037858, speed_note_count: 210.36373973116545, @@ -152,7 +160,9 @@ fn basic_osu() { }; HR => { aim: 3.2385394176190507, + aim_strain_difficulty: 0.0, speed: 2.7009854505234308, + speed_strain_difficulty: 0.0, flashlight: 2.8549217213059936, slider_factor: 0.9690667605258665, speed_note_count: 184.01205359079387, @@ -167,7 +177,9 @@ fn basic_osu() { }; DT => { aim: 4.041442573946681, + aim_strain_difficulty: 0.0, speed: 3.6784866216272474, + speed_strain_difficulty: 0.0, flashlight: 3.319522943625448, slider_factor: 0.9776943279272041, speed_note_count: 214.80421464205617, @@ -182,7 +194,9 @@ fn basic_osu() { }; FL => { aim: 2.8693628443424104, + aim_strain_difficulty: 0.0, speed: 2.533869745015772, + speed_strain_difficulty: 0.0, flashlight: 2.288770487900865, slider_factor: 0.9803052946037858, speed_note_count: 210.36373973116545, @@ -197,7 +211,9 @@ fn basic_osu() { }; HD FL => { aim: 2.8693628443424104, + aim_strain_difficulty: 0.0, speed: 2.533869745015772, + speed_strain_difficulty: 0.0, flashlight: 2.606877929965889, slider_factor: 0.9803052946037858, speed_note_count: 210.36373973116545, @@ -217,7 +233,9 @@ fn basic_osu() { Osu: OSU { NM => { aim: 2.8693628443424104, + aim_strain_difficulty: 0.0, speed: 2.533869745015772, + speed_strain_difficulty: 0.0, flashlight: 2.288770487900865, slider_factor: 0.9803052946037858, speed_note_count: 210.36373973116545, @@ -232,7 +250,9 @@ fn basic_osu() { }; HD => { aim: 2.8693628443424104, + aim_strain_difficulty: 0.0, speed: 2.533869745015772, + speed_strain_difficulty: 0.0, flashlight: 2.606877929965889, slider_factor: 0.9803052946037858, speed_note_count: 210.36373973116545, @@ -247,7 +267,9 @@ fn basic_osu() { }; HR => { aim: 3.2385394176190507, + aim_strain_difficulty: 0.0, speed: 2.7009854505234308, + speed_strain_difficulty: 0.0, flashlight: 2.8549217213059936, slider_factor: 0.9690667605258665, speed_note_count: 184.01205359079387, @@ -262,7 +284,9 @@ fn basic_osu() { }; DT => { aim: 4.041442573946681, + aim_strain_difficulty: 0.0, speed: 3.6784866216272474, + speed_strain_difficulty: 0.0, flashlight: 3.319522943625448, slider_factor: 0.9776943279272041, speed_note_count: 214.80421464205617, @@ -277,7 +301,9 @@ fn basic_osu() { }; FL => { aim: 2.8693628443424104, + aim_strain_difficulty: 0.0, speed: 2.533869745015772, + speed_strain_difficulty: 0.0, flashlight: 2.288770487900865, slider_factor: 0.9803052946037858, speed_note_count: 210.36373973116545, @@ -292,7 +318,9 @@ fn basic_osu() { }; HD FL => { aim: 2.8693628443424104, + aim_strain_difficulty: 0.0, speed: 2.533869745015772, + speed_strain_difficulty: 0.0, flashlight: 2.606877929965889, slider_factor: 0.9803052946037858, speed_note_count: 210.36373973116545, @@ -521,6 +549,7 @@ where impl AssertEq for OsuDifficultyAttributes { fn assert_eq(&self, expected: &Self) { + println!("{} - {}", self.aim_strain_difficulty, expected.aim); assert_eq_float(self.aim, expected.aim); assert_eq_float(self.speed, expected.speed); assert_eq_float(self.flashlight, expected.flashlight);