diff --git a/proptest-regressions/osu/performance/mod.txt b/proptest-regressions/osu/performance/mod.txt index 6b101f0b..9e6597b7 100644 --- a/proptest-regressions/osu/performance/mod.txt +++ b/proptest-regressions/osu/performance/mod.txt @@ -12,3 +12,5 @@ cc e5a861f6c665dd09e46423e71d7596edf98897d4130d3144aa6f5be580f31a8b # shrinks to cc 2cd5c105bcca0b4255afccc15bee3894b06bd20ac3f5c5d3b785f7e0ef99df46 # shrinks to acc = 0.0, combo = None, n300 = Some(0), n100 = None, n50 = Some(479), n_misses = Some(123), best_case = false cc 2cba8a76243aac7233e9207a3162aaa1f08f933c0cb3a2ac79580ece3a7329fc # shrinks to acc = 0.0, n300 = Some(0), n100 = Some(0), n50 = Some(0), n_misses = None, best_case = false cc e93787ad8a849ec6d05750c8d09494b8f5a9fa785f843d9a8e2db986c0b32645 # shrinks to acc = 0.0, n300 = None, n100 = None, n50 = None, n_misses = Some(602), best_case = false +cc a53cb48861126aa63be54606f9a770db5eae95242c9a9d75cf1fd101cfb21729 # shrinks to lazer = true, acc = 0.5679586776392227, n_slider_ticks = None, n_slider_ends = None, n300 = None, n100 = None, n50 = Some(0), n_misses = None, best_case = false +cc cacb94cb2a61cf05e7083e332b378290a6267a499bf30821228bc0ae4dfe46f6 # shrinks to lazer = true, acc = 0.5270982297689498, n_slider_ticks = None, n_slider_ends = None, n300 = Some(70), n100 = None, n50 = None, n_misses = None, best_case = false diff --git a/src/any/score_state.rs b/src/any/score_state.rs index 08c50731..94e8c904 100644 --- a/src/any/score_state.rs +++ b/src/any/score_state.rs @@ -15,6 +15,14 @@ pub struct ScoreState { /// /// Irrelevant for osu!mania. pub max_combo: u32, + /// Amount of successfully hit slider ticks and repeats. + /// + /// Only relevant for osu!standard in lazer. + pub slider_tick_hits: u32, + /// Amount of successfully hit slider ends. + /// + /// Only relevant for osu!standard in lazer. + pub slider_end_hits: u32, /// Amount of current gekis (n320 for osu!mania). pub n_geki: u32, /// Amount of current katus (tiny droplet misses for osu!catch / n200 for @@ -35,6 +43,8 @@ impl ScoreState { pub const fn new() -> Self { Self { max_combo: 0, + slider_tick_hits: 0, + slider_end_hits: 0, n_geki: 0, n_katu: 0, n300: 0, @@ -66,6 +76,8 @@ impl From for OsuScoreState { fn from(state: ScoreState) -> Self { Self { max_combo: state.max_combo, + slider_tick_hits: state.slider_tick_hits, + slider_end_hits: state.slider_end_hits, n300: state.n300, n100: state.n100, n50: state.n50, @@ -115,6 +127,8 @@ impl From for ScoreState { fn from(state: OsuScoreState) -> Self { Self { max_combo: state.max_combo, + slider_tick_hits: state.slider_tick_hits, + slider_end_hits: state.slider_end_hits, n_geki: 0, n_katu: 0, n300: state.n300, @@ -129,6 +143,8 @@ impl From for ScoreState { fn from(state: TaikoScoreState) -> Self { Self { max_combo: state.max_combo, + slider_tick_hits: 0, + slider_end_hits: 0, n_geki: 0, n_katu: 0, n300: state.n300, @@ -143,6 +159,8 @@ impl From for ScoreState { fn from(state: CatchScoreState) -> Self { Self { max_combo: state.max_combo, + slider_tick_hits: 0, + slider_end_hits: 0, n_geki: 0, n_katu: state.tiny_droplet_misses, n300: state.fruits, @@ -157,6 +175,8 @@ impl From for ScoreState { fn from(state: ManiaScoreState) -> Self { Self { max_combo: 0, + slider_tick_hits: 0, + slider_end_hits: 0, n_geki: state.n320, n_katu: state.n200, n300: state.n300, diff --git a/src/catch/performance/mod.rs b/src/catch/performance/mod.rs index b9c097c3..8ceb4ac6 100644 --- a/src/catch/performance/mod.rs +++ b/src/catch/performance/mod.rs @@ -474,6 +474,8 @@ impl<'map> TryFrom> for CatchPerformance<'map> { difficulty, acc, combo, + slider_tick_hits: _, + slider_end_hits: _, n300, n100, n50, diff --git a/src/mania/performance/mod.rs b/src/mania/performance/mod.rs index 5f66023d..3e8f0112 100644 --- a/src/mania/performance/mod.rs +++ b/src/mania/performance/mod.rs @@ -827,6 +827,8 @@ impl<'map> TryFrom> for ManiaPerformance<'map> { difficulty, acc, combo: _, + slider_tick_hits: _, + slider_end_hits: _, n300, n100, n50, diff --git a/src/osu/attributes.rs b/src/osu/attributes.rs index 68715cf5..281e8c2f 100644 --- a/src/osu/attributes.rs +++ b/src/osu/attributes.rs @@ -27,6 +27,8 @@ pub struct OsuDifficultyAttributes { pub n_circles: u32, /// The amount of sliders. pub n_sliders: u32, + /// The amount of slider ticks and repeat points. + pub n_slider_ticks: u32, /// The amount of spinners. pub n_spinners: u32, /// The final star rating diff --git a/src/osu/convert.rs b/src/osu/convert.rs index 19de59d8..a3227f57 100644 --- a/src/osu/convert.rs +++ b/src/osu/convert.rs @@ -56,6 +56,17 @@ pub fn convert_objects( OsuObjectKind::Slider(ref slider) => { attrs.n_sliders += 1; attrs.max_combo += slider.nested_objects.len() as u32; + + attrs.n_slider_ticks += slider + .nested_objects + .iter() + .filter(|nested| { + matches!( + nested.kind, + NestedSliderObjectKind::Tick | NestedSliderObjectKind::Repeat + ) + }) + .count() as u32; } OsuObjectKind::Spinner(_) => attrs.n_spinners += 1, } diff --git a/src/osu/performance/mod.rs b/src/osu/performance/mod.rs index c7d68323..47228420 100644 --- a/src/osu/performance/mod.rs +++ b/src/osu/performance/mod.rs @@ -28,6 +28,8 @@ pub struct OsuPerformance<'map> { pub(crate) difficulty: Difficulty, pub(crate) acc: Option, pub(crate) combo: Option, + pub(crate) slider_tick_hits: Option, + pub(crate) slider_end_hits: Option, pub(crate) n300: Option, pub(crate) n100: Option, pub(crate) n50: Option, @@ -166,6 +168,24 @@ impl<'map> OsuPerformance<'map> { self } + /// Specify the amount of hit slider ticks. + /// + /// Only relevant for osu!lazer. + pub const fn n_slider_ticks(mut self, n_slider_ticks: u32) -> Self { + self.slider_tick_hits = Some(n_slider_ticks); + + self + } + + /// Specify the amount of hit slider ends. + /// + /// Only relevant for osu!lazer. + pub const fn n_slider_ends(mut self, n_slider_ends: u32) -> Self { + self.slider_end_hits = Some(n_slider_ends); + + self + } + /// Specify the amount of 300s of a play. pub const fn n300(mut self, n300: u32) -> Self { self.n300 = Some(n300); @@ -293,6 +313,8 @@ impl<'map> OsuPerformance<'map> { pub const fn state(mut self, state: OsuScoreState) -> Self { let OsuScoreState { max_combo, + slider_tick_hits, + slider_end_hits, n300, n100, n50, @@ -300,6 +322,8 @@ impl<'map> OsuPerformance<'map> { } = state; self.combo = Some(max_combo); + self.slider_tick_hits = Some(slider_tick_hits); + self.slider_end_hits = Some(slider_end_hits); self.n300 = Some(n300); self.n100 = Some(n100); self.n50 = Some(n50); @@ -342,8 +366,29 @@ impl<'map> OsuPerformance<'map> { let mut n100 = self.n100.map_or(0, |n| cmp::min(n, n_remaining)); let mut n50 = self.n50.map_or(0, |n| cmp::min(n, n_remaining)); + let lazer = self.lazer.unwrap_or(true); + + let (n_slider_ends, n_slider_ticks, max_slider_ends, max_slider_ticks) = if lazer { + let n_slider_ends = self + .slider_end_hits + .map_or(attrs.n_sliders, |n| cmp::min(n, attrs.n_sliders)); + let n_slider_ticks = self + .slider_tick_hits + .map_or(attrs.n_slider_ticks, |n| cmp::min(n, attrs.n_slider_ticks)); + + ( + n_slider_ends, + n_slider_ticks, + attrs.n_sliders, + attrs.n_slider_ticks, + ) + } else { + (0, 0, 0, 0) + }; + if let Some(acc) = self.acc { - let target_total = acc * f64::from(6 * n_objects); + let target_total = + acc * f64::from(30 * n_objects + 15 * max_slider_ends + 3 * max_slider_ticks); match (self.n300, self.n100, self.n50) { (Some(_), Some(_), Some(_)) => { @@ -363,13 +408,28 @@ impl<'map> OsuPerformance<'map> { n300 = cmp::min(n300, n_remaining); let n_remaining = n_remaining - n300; - let raw_n100 = target_total - f64::from(n_remaining + 6 * n300); + let raw_n100 = (target_total + - f64::from( + 5 * n_remaining + 30 * n300 + 15 * n_slider_ends + 3 * n_slider_ticks, + )) + / 5.0; let min_n100 = cmp::min(n_remaining, raw_n100.floor() as u32); let max_n100 = cmp::min(n_remaining, raw_n100.ceil() as u32); for new100 in min_n100..=max_n100 { let new50 = n_remaining - new100; - let dist = (acc - accuracy(n300, new100, new50, misses)).abs(); + let dist = (acc + - accuracy( + n_slider_ticks, + n_slider_ends, + n300, + new100, + new50, + misses, + max_slider_ticks, + max_slider_ends, + )) + .abs(); if dist < best_dist { best_dist = dist; @@ -384,13 +444,28 @@ impl<'map> OsuPerformance<'map> { n100 = cmp::min(n100, n_remaining); let n_remaining = n_remaining - n100; - let raw_n300 = (target_total - f64::from(n_remaining + 2 * n100)) / 5.0; + let raw_n300 = (target_total + - f64::from( + 5 * n_remaining + 10 * n100 + 15 * n_slider_ends + 3 * n_slider_ticks, + )) + / 25.0; let min_n300 = cmp::min(n_remaining, raw_n300.floor() as u32); let max_n300 = cmp::min(n_remaining, raw_n300.ceil() as u32); for new300 in min_n300..=max_n300 { let new50 = n_remaining - new300; - let curr_dist = (acc - accuracy(new300, n100, new50, misses)).abs(); + let curr_dist = (acc + - accuracy( + n_slider_ticks, + n_slider_ends, + new300, + n100, + new50, + misses, + max_slider_ticks, + max_slider_ends, + )) + .abs(); if curr_dist < best_dist { best_dist = curr_dist; @@ -405,16 +480,27 @@ impl<'map> OsuPerformance<'map> { n50 = cmp::min(n50, n_remaining); let n_remaining = n_remaining - n50; - let raw_n300 = (target_total + f64::from(2 * misses + n50) - - f64::from(2 * n_objects)) - / 4.0; + let raw_n300 = (target_total + f64::from(10 * misses + 5 * n50) + - f64::from(10 * n_objects + 15 * n_slider_ends + 3 * n_slider_ticks)) + / 20.0; let min_n300 = cmp::min(n_remaining, raw_n300.floor() as u32); let max_n300 = cmp::min(n_remaining, raw_n300.ceil() as u32); for new300 in min_n300..=max_n300 { let new100 = n_remaining - new300; - let curr_dist = (acc - accuracy(new300, new100, n50, misses)).abs(); + let curr_dist = (acc + - accuracy( + n_slider_ticks, + n_slider_ends, + new300, + new100, + n50, + misses, + max_slider_ticks, + max_slider_ends, + )) + .abs(); if curr_dist < best_dist { best_dist = curr_dist; @@ -426,18 +512,38 @@ impl<'map> OsuPerformance<'map> { (None, None, None) => { let mut best_dist = f64::MAX; - let raw_n300 = (target_total - f64::from(n_remaining)) / 5.0; + let raw_n300 = (target_total + - f64::from(5 * n_remaining + 15 * n_slider_ends + 3 * n_slider_ticks)) + / 25.0; let min_n300 = cmp::min(n_remaining, raw_n300.floor() as u32); let max_n300 = cmp::min(n_remaining, raw_n300.ceil() as u32); for new300 in min_n300..=max_n300 { - let raw_n100 = target_total - f64::from(n_remaining + 5 * new300); + let raw_n100 = (target_total + - f64::from( + 5 * n_remaining + + 25 * new300 + + 15 * n_slider_ends + + 3 * n_slider_ticks, + )) + / 5.0; let min_n100 = cmp::min(raw_n100.floor() as u32, n_remaining - new300); let max_n100 = cmp::min(raw_n100.ceil() as u32, n_remaining - new300); for new100 in min_n100..=max_n100 { let new50 = n_remaining - new300 - new100; - let curr_dist = (acc - accuracy(new300, new100, new50, misses)).abs(); + let curr_dist = (acc + - accuracy( + n_slider_ticks, + n_slider_ends, + new300, + new100, + new50, + misses, + max_slider_ticks, + max_slider_ends, + )) + .abs(); if curr_dist < best_dist { best_dist = curr_dist; @@ -492,6 +598,8 @@ impl<'map> OsuPerformance<'map> { }); self.combo = Some(max_combo); + self.slider_end_hits = Some(n_slider_ends); + self.slider_tick_hits = Some(n_slider_ticks); self.n300 = Some(n300); self.n100 = Some(n100); self.n50 = Some(n50); @@ -499,6 +607,8 @@ impl<'map> OsuPerformance<'map> { OsuScoreState { max_combo, + slider_tick_hits: n_slider_ticks, + slider_end_hits: n_slider_ends, n300, n100, n50, @@ -517,13 +627,21 @@ impl<'map> OsuPerformance<'map> { let effective_miss_count = calculate_effective_misses(&attrs, &state); + let lazer = self.lazer.unwrap_or(true); + + let (n_slider_ends, n_slider_ticks) = if lazer { + (attrs.n_sliders, attrs.n_slider_ticks) + } else { + (0, 0) + }; + let inner = OsuPerformanceInner { attrs, mods: self.difficulty.get_mods(), - acc: state.accuracy(), + acc: state.accuracy(n_slider_ticks, n_slider_ends), state, effective_miss_count, - lazer: self.lazer.unwrap_or(true), + lazer, }; inner.calculate() @@ -535,6 +653,8 @@ impl<'map> OsuPerformance<'map> { difficulty: Difficulty::new(), acc: None, combo: None, + slider_tick_hits: None, + slider_end_hits: None, n300: None, n100: None, n50: None, @@ -894,13 +1014,24 @@ fn calculate_effective_misses(attrs: &OsuDifficultyAttributes, state: &OsuScoreS combo_based_miss_count.max(f64::from(state.misses)) } -fn accuracy(n300: u32, n100: u32, n50: u32, misses: u32) -> f64 { - if n300 + n100 + n50 + misses == 0 { +fn accuracy( + n_slider_ticks: u32, + n_slider_ends: u32, + n300: u32, + n100: u32, + n50: u32, + misses: u32, + max_slider_ticks: u32, + max_slider_ends: u32, +) -> f64 { + if n_slider_ticks + n_slider_ends + n300 + n100 + n50 + misses == 0 { return 0.0; } - let numerator = 6 * n300 + 2 * n100 + n50; - let denominator = 6 * (n300 + n100 + n50 + misses); + let numerator = 300 * n300 + 100 * n100 + 50 * n50 + 150 * n_slider_ends + 30 * n_slider_ticks; + + let denominator = + 300 * (n300 + n100 + n50 + misses) + 150 * max_slider_ends + 30 * max_slider_ticks; f64::from(numerator) / f64::from(denominator) } @@ -922,6 +1053,8 @@ mod test { static ATTRS: OnceLock = OnceLock::new(); const N_OBJECTS: u32 = 601; + const N_SLIDERS: u32 = 293; + const N_SLIDER_TICKS: u32 = 15; fn beatmap() -> Beatmap { Beatmap::from_path("./resources/2785319.osu").unwrap() @@ -941,6 +1074,8 @@ mod test { attrs.n_circles + attrs.n_sliders + attrs.n_spinners, N_OBJECTS, ); + assert_eq!(attrs.n_sliders, N_SLIDERS); + assert_eq!(attrs.n_slider_ticks, N_SLIDER_TICKS); attrs }) @@ -952,7 +1087,10 @@ mod test { /// /// Very slow but accurate. fn brute_force_best( + lazer: bool, acc: f64, + n_slider_ticks: Option, + n_slider_ends: Option, n300: Option, n100: Option, n50: Option, @@ -961,8 +1099,20 @@ mod test { ) -> OsuScoreState { let misses = cmp::min(misses, N_OBJECTS); + let (n_slider_ends, n_slider_ticks, max_slider_ends, max_slider_ticks) = if lazer { + let n_slider_ends = n_slider_ends.map_or(N_SLIDERS, |n| cmp::min(n, N_SLIDERS)); + let n_slider_ticks = + n_slider_ticks.map_or(N_SLIDER_TICKS, |n| cmp::min(n, N_SLIDER_TICKS)); + + (n_slider_ends, n_slider_ticks, N_SLIDERS, N_SLIDER_TICKS) + } else { + (0, 0, 0, 0) + }; + let mut best_state = OsuScoreState { misses, + slider_end_hits: n_slider_ends, + slider_tick_hits: n_slider_ticks, ..Default::default() }; @@ -998,7 +1148,16 @@ mod test { None => n_remaining.saturating_sub(new300 + new100), }; - let curr_acc = accuracy(new300, new100, new50, misses); + let curr_acc = accuracy( + n_slider_ticks, + n_slider_ends, + new300, + new100, + new50, + misses, + max_slider_ticks, + max_slider_ends, + ); let curr_dist = (acc - curr_acc).abs(); if curr_dist < best_dist { @@ -1042,10 +1201,13 @@ mod test { #[test] fn hitresults( - acc in 0.0..=1.0, - n300 in prop::option::weighted(0.10, 0_u32..=N_OBJECTS + 10), - n100 in prop::option::weighted(0.10, 0_u32..=N_OBJECTS + 10), - n50 in prop::option::weighted(0.10, 0_u32..=N_OBJECTS + 10), + lazer in prop::bool::ANY, + acc in 0.0_f64..=1.0, + n_slider_ticks in prop::option::weighted(0.1, 0_u32..=N_SLIDER_TICKS + 10), + n_slider_ends in prop::option::weighted(0.1, 0_u32..=N_SLIDERS + 10), + n300 in prop::option::weighted(0.1, 0_u32..=N_OBJECTS + 10), + n100 in prop::option::weighted(0.1, 0_u32..=N_OBJECTS + 10), + n50 in prop::option::weighted(0.1, 0_u32..=N_OBJECTS + 10), n_misses in prop::option::weighted(0.15, 0_u32..=N_OBJECTS + 10), best_case in prop::bool::ANY, ) { @@ -1060,8 +1222,17 @@ mod test { let mut state = OsuPerformance::from(attrs) .accuracy(acc * 100.0) + .lazer(lazer) .hitresult_priority(priority); + if let Some(n_slider_ticks) = n_slider_ticks { + state = state.n_slider_ticks(n_slider_ticks); + } + + if let Some(n_slider_ends) = n_slider_ends { + state = state.n_slider_ends(n_slider_ends); + } + if let Some(n300) = n300 { state = state.n300(n300); } @@ -1083,7 +1254,10 @@ mod test { assert_eq!(first, state); let mut expected = brute_force_best( + lazer, acc, + n_slider_ticks, + n_slider_ends, n300, n100, n50, @@ -1100,6 +1274,7 @@ mod test { fn hitresults_n300_n100_misses_best() { let state = OsuPerformance::from(attrs()) .combo(500) + .lazer(true) .n300(300) .n100(20) .misses(2) @@ -1108,6 +1283,8 @@ mod test { let expected = OsuScoreState { max_combo: 500, + slider_tick_hits: N_SLIDER_TICKS, + slider_end_hits: N_SLIDERS, n300: 300, n100: 20, n50: 279, @@ -1120,6 +1297,7 @@ mod test { #[test] fn hitresults_n300_n50_misses_best() { let state = OsuPerformance::from(attrs()) + .lazer(false) .combo(500) .n300(300) .n50(10) @@ -1129,6 +1307,8 @@ mod test { let expected = OsuScoreState { max_combo: 500, + slider_tick_hits: 0, + slider_end_hits: 0, n300: 300, n100: 289, n50: 10, @@ -1141,6 +1321,7 @@ mod test { #[test] fn hitresults_n50_misses_worst() { let state = OsuPerformance::from(attrs()) + .lazer(true) .combo(500) .n50(10) .misses(2) @@ -1149,6 +1330,8 @@ mod test { let expected = OsuScoreState { max_combo: 500, + slider_tick_hits: N_SLIDER_TICKS, + slider_end_hits: N_SLIDERS, n300: 0, n100: 589, n50: 10, @@ -1161,6 +1344,7 @@ mod test { #[test] fn hitresults_n300_n100_n50_misses_worst() { let state = OsuPerformance::from(attrs()) + .lazer(false) .combo(500) .n300(300) .n100(50) @@ -1171,6 +1355,8 @@ mod test { let expected = OsuScoreState { max_combo: 500, + slider_tick_hits: 0, + slider_end_hits: 0, n300: 300, n100: 50, n50: 249, diff --git a/src/osu/score_state.rs b/src/osu/score_state.rs index 2305ebe6..e5a54ea6 100644 --- a/src/osu/score_state.rs +++ b/src/osu/score_state.rs @@ -1,9 +1,17 @@ /// Aggregation for a score's current state. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct OsuScoreState { - /// Maximum combo that the score has had so far. - /// **Not** the maximum possible combo of the map so far. + /// Maximum combo that the score has had so far. **Not** the maximum + /// possible combo of the map so far. pub max_combo: u32, + /// Amount of successfully hit slider ticks and repeat. + /// + /// Only relevant for osu!lazer. + pub slider_tick_hits: u32, + /// Amount of successfully hit slider ends. + /// + /// Only relevant for osu!lazer. + pub slider_end_hits: u32, /// Amount of current 300s. pub n300: u32, /// Amount of current 100s. @@ -19,6 +27,8 @@ impl OsuScoreState { pub const fn new() -> Self { Self { max_combo: 0, + slider_tick_hits: 0, + slider_end_hits: 0, n300: 0, n100: 0, n50: 0, @@ -32,15 +42,35 @@ impl OsuScoreState { } /// Calculate the accuracy between `0.0` and `1.0` for this state. - pub fn accuracy(&self) -> f64 { - let total_hits = self.total_hits(); - - if total_hits == 0 { + /// + /// `max_slider_ticks` and `max_slider_ends` are only relevant for + /// `osu!lazer` scores. Otherwise, they may be `0`. + pub fn accuracy(&self, max_slider_ticks: u32, max_slider_ends: u32) -> f64 { + if self.total_hits() + self.slider_tick_hits + self.slider_end_hits == 0 { return 0.0; } - let numerator = 6 * self.n300 + 2 * self.n100 + self.n50; - let denominator = 6 * total_hits; + debug_assert!( + self.slider_end_hits <= max_slider_ends, + "`self.slider_end_hits` must not be greater than `max_slider_ends`" + ); + debug_assert!( + self.slider_tick_hits <= max_slider_ticks, + "`self.slider_tick_hits` must not be greater than `max_slider_ticks`" + ); + + let numerator = 300 * self.n300 + + 100 * self.n100 + + 50 * self.n50 + + 150 * self.slider_end_hits + + 30 * self.slider_tick_hits; + + let denominator = 300 * self.n300 + + 300 * self.n100 + + 300 * self.n50 + + 300 * self.misses + + 150 * max_slider_ends + + 30 * max_slider_ticks; f64::from(numerator) / f64::from(denominator) } diff --git a/src/taiko/performance/mod.rs b/src/taiko/performance/mod.rs index 6a8ac6e1..95e1ce81 100644 --- a/src/taiko/performance/mod.rs +++ b/src/taiko/performance/mod.rs @@ -364,6 +364,8 @@ impl<'map> TryFrom> for TaikoPerformance<'map> { difficulty, acc, combo, + slider_tick_hits: _, + slider_end_hits: _, n300, n100, n50: _, diff --git a/tests/difficulty.rs b/tests/difficulty.rs index 552a0707..8f3e735a 100644 --- a/tests/difficulty.rs +++ b/tests/difficulty.rs @@ -42,6 +42,7 @@ macro_rules! test_cases { hp: $hp:literal, n_circles: $n_circles:literal, n_sliders: $n_sliders:literal, + n_slider_ticks: $n_slider_ticks:literal, n_spinners: $n_spinners:literal, stars: $stars:literal, max_combo: $max_combo:literal, @@ -59,6 +60,7 @@ macro_rules! test_cases { hp: $hp, n_circles: $n_circles, n_sliders: $n_sliders, + n_slider_ticks: $n_slider_ticks, n_spinners: $n_spinners, stars: $stars, max_combo: $max_combo, @@ -139,6 +141,7 @@ fn basic_osu() { hp: 5.0, n_circles: 307, n_sliders: 293, + n_slider_ticks: 15, n_spinners: 1, stars: 5.643619989739299, max_combo: 909, @@ -156,6 +159,7 @@ fn basic_osu() { hp: 5.0, n_circles: 307, n_sliders: 293, + n_slider_ticks: 15, n_spinners: 1, stars: 5.643619989739299, max_combo: 909, @@ -173,6 +177,7 @@ fn basic_osu() { hp: 7.0, n_circles: 307, n_sliders: 293, + n_slider_ticks: 15, n_spinners: 1, stars: 6.243301253337941, max_combo: 909, @@ -190,6 +195,7 @@ fn basic_osu() { hp: 5.0, n_circles: 307, n_sliders: 293, + n_slider_ticks: 15, n_spinners: 1, stars: 8.030649319285482, max_combo: 909, @@ -207,6 +213,7 @@ fn basic_osu() { hp: 5.0, n_circles: 307, n_sliders: 293, + n_slider_ticks: 15, n_spinners: 1, stars: 6.858771801534423, max_combo: 909, @@ -224,6 +231,7 @@ fn basic_osu() { hp: 5.0, n_circles: 307, n_sliders: 293, + n_slider_ticks: 15, n_spinners: 1, stars: 7.167932950561898, max_combo: 909, diff --git a/tests/performance.rs b/tests/performance.rs index ee06a660..ec6fbcce 100644 --- a/tests/performance.rs +++ b/tests/performance.rs @@ -39,7 +39,7 @@ macro_rules! test_cases { effective_miss_count: $effective_miss_count:expr, }) => { ( - OsuPerformance::from($map.as_owned()).lazer(false), + OsuPerformance::from($map.as_owned()).lazer(true), OsuPerformanceAttributes { pp: $pp, pp_acc: $pp_acc,