improved osu hitresult generation

This commit is contained in:
MaxOhn
2022-10-15 11:36:41 +02:00
parent fa91703a2a
commit d83217f5d0
8 changed files with 303 additions and 294 deletions
+20 -5
View File
@@ -20,16 +20,31 @@ pub struct ManiaScoreState {
}
impl ManiaScoreState {
/// Create a new empty score state.
#[inline]
pub fn new() -> Self {
Self::default()
}
/// Return the total amount of hits by adding everything up.
#[inline]
pub fn total_hits(&self) -> usize {
self.n320 + self.n300 + self.n200 + self.n100 + self.n50 + self.n_misses
}
}
impl ManiaScoreState {
/// Create a new empty score state.
pub fn new() -> Self {
Self::default()
/// Calculate the accuracy between `0.0` and `1.0` for this state.
#[inline]
pub fn accuracy(&self) -> f64 {
let total_hits = self.total_hits();
if total_hits == 0 {
return 0.0;
}
let numerator = 6 * (self.n320 + self.n300) + 4 * self.n200 + 2 * self.n100 + self.n50;
let denominator = 6 * total_hits;
numerator as f64 / denominator as f64
}
}
+15 -28
View File
@@ -1,7 +1,9 @@
use std::borrow::Cow;
use super::{ManiaDifficultyAttributes, ManiaPerformanceAttributes, ManiaScoreState, ManiaStars};
use crate::{Beatmap, DifficultyAttributes, GameMode, Mods, OsuPP, PerformanceAttributes};
use crate::{
Beatmap, DifficultyAttributes, GameMode, HitResultPriority, Mods, OsuPP, PerformanceAttributes,
};
// TODO: update
/// Performance calculator on osu!mania maps.
@@ -48,7 +50,7 @@ pub struct ManiaPP<'map> {
pub(crate) n_misses: Option<usize>,
acc: Option<f64>,
hitresult_priority: Option<ManiaHitResultPriority>,
hitresult_priority: Option<HitResultPriority>,
}
impl<'map> ManiaPP<'map> {
@@ -120,7 +122,7 @@ impl<'map> ManiaPP<'map> {
self
}
/// Specify the accuracy of a play.
/// Specify the accuracy of a play between `0` and `100`.
/// This will be used to generate matching hitresults.
#[inline]
pub fn accuracy(mut self, acc: f64) -> Self {
@@ -131,9 +133,9 @@ impl<'map> ManiaPP<'map> {
/// Specify how hitresults should be generated.
///
/// Defauls to [`ManiaHitResultPriority::BestCase`].
/// Defauls to [`HitResultPriority::BestCase`].
#[inline]
pub fn hitresult_priority(mut self, priority: ManiaHitResultPriority) -> Self {
pub fn hitresult_priority(mut self, priority: HitResultPriority) -> Self {
self.hitresult_priority = Some(priority);
self
@@ -237,7 +239,7 @@ impl<'map> ManiaPP<'map> {
}
fn generate_hitresults(&self) -> ManiaScoreState {
let n_objects = self.map.hit_objects.len();
let n_objects = self.passed_objects.unwrap_or(self.map.hit_objects.len());
let priority = self.hitresult_priority.unwrap_or_default();
let mut state = ManiaScoreState {
@@ -250,6 +252,7 @@ impl<'map> ManiaPP<'map> {
};
if let Some(acc) = self.acc {
// TODO: test
let target_total = (acc * (n_objects * 6) as f64).round() as usize;
let mut delta = target_total.saturating_sub(n_objects.saturating_sub(state.n_misses));
@@ -274,7 +277,7 @@ impl<'map> ManiaPP<'map> {
state.n50 += n_objects.saturating_sub(state.total_hits() - state.n50);
if let ManiaHitResultPriority::BestCase = priority {
if let HitResultPriority::BestCase = priority {
// Shift n50 to n200
if self.n320.or(self.n300).or(self.n200).or(self.n50).is_none() {
let n = (state.n320 + state.n300).min(state.n50 / 2);
@@ -309,7 +312,7 @@ impl<'map> ManiaPP<'map> {
let remaining = n_objects.saturating_sub(state.total_hits());
match priority {
ManiaHitResultPriority::BestCase => {
HitResultPriority::BestCase => {
if self.n320.is_none() {
state.n320 = remaining;
} else if self.n300.is_none() {
@@ -324,7 +327,7 @@ impl<'map> ManiaPP<'map> {
state.n320 = remaining;
}
}
ManiaHitResultPriority::WorstCase => {
HitResultPriority::WorstCase => {
if self.n50.is_none() {
state.n50 = remaining;
} else if self.n100.is_none() {
@@ -405,26 +408,10 @@ impl ManiaPpInner {
return 0.0;
}
let numerator = *n320 * 320 + *n300 * 300 + *n200 * 200 + *n100 * 100 + *n50 * 50;
let denominator = total_hits as f64 * 320.0;
let numerator = *n320 * 32 + *n300 * 30 + *n200 * 20 + *n100 * 10 + *n50 * 5;
let denominator = total_hits * 32;
numerator as f64 / denominator
}
}
/// While generating hitresults that weren't specific, decide how they should be distributed.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ManiaHitResultPriority {
/// Prioritize good hitresults over bad ones
BestCase,
/// Prioritize bad hitresults over good ones
WorstCase,
}
impl Default for ManiaHitResultPriority {
#[inline]
fn default() -> Self {
Self::BestCase
numerator as f64 / denominator as f64
}
}