added example for gradual calculation to readme
This commit is contained in:
@@ -73,6 +73,87 @@ let result = map.pp()
|
|||||||
println!("PP: {}", result.pp());
|
println!("PP: {}", result.pp());
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Gradual calculation
|
||||||
|
Sometimes you might want to calculate the difficulty of a map or performance of a score after each hit object.
|
||||||
|
This could be done by using `passed_objects` as the amount of objects that were passed so far.
|
||||||
|
However, this requires to recalculate the beginning again and again, we can be more efficient than that.
|
||||||
|
|
||||||
|
Instead, you should use `GradualDifficultyAttributes` and `GradualPerformanceAttributes`:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rosu_pp::{
|
||||||
|
Beatmap, BeatmapExt, GradualPerformanceAttributes, ScoreState, taiko::TaikoScoreState,
|
||||||
|
};
|
||||||
|
|
||||||
|
let map = match Beatmap::from_path("/path/to/file.osu") {
|
||||||
|
Ok(map) => map,
|
||||||
|
Err(why) => panic!("Error while parsing map: {}", why),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mods = 8 + 64; // HDDT
|
||||||
|
|
||||||
|
// If you're only interested in the star rating or other difficulty value,
|
||||||
|
// use `GradualDifficultyAttribtes`, either through its function `new`
|
||||||
|
// or through the method `BeatmapExt::gradual_difficulty`.
|
||||||
|
let gradual_difficulty = map.gradual_difficulty(mods);
|
||||||
|
|
||||||
|
// Since `GradualDifficultyAttributes` implements `Iterator`, you can use
|
||||||
|
// any iterate function on it, use it in loops, collect them into a `Vec`, ...
|
||||||
|
for (i, difficulty) in gradual_difficulty.enumerate() {
|
||||||
|
println!("Stars after object {}: {}", i, difficulty.stars());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gradually calculating performance values does the same as calculating
|
||||||
|
// difficulty attributes but it goes the extra step and also evaluates
|
||||||
|
// the state of a score for these difficulty attributes.
|
||||||
|
let mut gradual_performance = map.gradual_performance(mods);
|
||||||
|
|
||||||
|
// The default score state is kinda chunky because it considers all modes.
|
||||||
|
let state = ScoreState {
|
||||||
|
max_combo: 1,
|
||||||
|
n_katu: 0, // only relevant for ctb
|
||||||
|
n300: 1,
|
||||||
|
n100: 0,
|
||||||
|
n50: 0,
|
||||||
|
misses: 0,
|
||||||
|
score: 300, // only relevant for mania
|
||||||
|
};
|
||||||
|
|
||||||
|
// Process the score state after the first object
|
||||||
|
let curr_performance = match gradual_performance.process_next_object(state) {
|
||||||
|
Some(perf) => perf,
|
||||||
|
None => panic!("the map has no hit objects"),
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("PP after the first object: {}", curr_performance.pp());
|
||||||
|
|
||||||
|
// If you're only interested in maps of a specific mode, consider
|
||||||
|
// using the mode's gradual calculator instead of the general one.
|
||||||
|
// Let's assume it's a taiko map.
|
||||||
|
// Instead of starting off with `BeatmapExt::gradual_performance` one could have
|
||||||
|
// created the struct via `TaikoGradualPerformanceAttributes::new`.
|
||||||
|
let mut gradual_performance = match gradual_performance {
|
||||||
|
GradualPerformanceAttributes::Taiko(gradual) => gradual,
|
||||||
|
_ => panic!("the map was not taiko but {:?}", map.mode),
|
||||||
|
};
|
||||||
|
|
||||||
|
// A little simpler than the general score state.
|
||||||
|
let state = TaikoScoreState {
|
||||||
|
max_combo: 11,
|
||||||
|
n300: 9,
|
||||||
|
n100: 1,
|
||||||
|
misses: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Process the next 10 objects in one go
|
||||||
|
let curr_performance = match gradual_performance.process_next_n_objects(state, 10) {
|
||||||
|
Some(perf) => perf,
|
||||||
|
None => panic!("the last `process_next_object` already processed the last object"),
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("PP after the first 11 objects: {}", curr_performance.pp());
|
||||||
|
```
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
| Flag | Description |
|
| Flag | Description |
|
||||||
|
|||||||
+1
-1
@@ -139,7 +139,7 @@ impl<'map> FruitsPP<'map> {
|
|||||||
///
|
///
|
||||||
/// If you want to calculate the performance after every few objects, instead of
|
/// If you want to calculate the performance after every few objects, instead of
|
||||||
/// using [`FruitsPP`] multiple times with different `passed_objects`, you should use
|
/// using [`FruitsPP`] multiple times with different `passed_objects`, you should use
|
||||||
/// [`FruitsGradualPerformanceAttributes`](crate::fuits::FruitsGradualPerformanceAttributes).
|
/// [`FruitsGradualPerformanceAttributes`](crate::fruits::FruitsGradualPerformanceAttributes).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn passed_objects(mut self, passed_objects: usize) -> Self {
|
pub fn passed_objects(mut self, passed_objects: usize) -> Self {
|
||||||
self.passed_objects.replace(passed_objects);
|
self.passed_objects.replace(passed_objects);
|
||||||
|
|||||||
+1
-1
@@ -112,7 +112,7 @@ impl Iterator for GradualDifficultyAttributes<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Aggregation for a score's current state i.e. what wa
|
/// Aggregation for a score's current state i.e. what is
|
||||||
/// the maximum combo so far, what are the current
|
/// the maximum combo so far, what are the current
|
||||||
/// hitresults and what is the current score.
|
/// hitresults and what is the current score.
|
||||||
///
|
///
|
||||||
|
|||||||
+82
@@ -73,6 +73,88 @@
|
|||||||
//! println!("PP: {}", result.pp());
|
//! println!("PP: {}", result.pp());
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
//! ## Gradual calculation
|
||||||
|
//! Sometimes you might want to calculate the difficulty of a map or performance of a score after each hit object.
|
||||||
|
//! This could be done by using `passed_objects` as the amount of objects that were passed so far.
|
||||||
|
//! However, this requires to recalculate the beginning again and again, we can be more efficient than that.
|
||||||
|
//!
|
||||||
|
//! Instead, you should use `GradualDifficultyAttributes` and `GradualPerformanceAttributes`:
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! use rosu_pp::{
|
||||||
|
//! Beatmap, BeatmapExt, GradualPerformanceAttributes, ScoreState,
|
||||||
|
//! taiko::TaikoScoreState,
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! let map = match Beatmap::from_path("/path/to/file.osu") {
|
||||||
|
//! Ok(map) => map,
|
||||||
|
//! Err(why) => panic!("Error while parsing map: {}", why),
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! let mods = 8 + 64; // HDDT
|
||||||
|
//!
|
||||||
|
//! // If you're only interested in the star rating or other difficulty value,
|
||||||
|
//! // use `GradualDifficultyAttribtes`, either through its function `new`
|
||||||
|
//! // or through the method `BeatmapExt::gradual_difficulty`.
|
||||||
|
//! let gradual_difficulty = map.gradual_difficulty(mods);
|
||||||
|
//!
|
||||||
|
//! // Since `GradualDifficultyAttributes` implements `Iterator`, you can use
|
||||||
|
//! // any iterate function on it, use it in loops, collect them into a `Vec`, ...
|
||||||
|
//! for (i, difficulty) in gradual_difficulty.enumerate() {
|
||||||
|
//! println!("Stars after object {}: {}", i, difficulty.stars());
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // Gradually calculating performance values does the same as calculating
|
||||||
|
//! // difficulty attributes but it goes the extra step and also evaluates
|
||||||
|
//! // the state of a score for these difficulty attributes.
|
||||||
|
//! let mut gradual_performance = map.gradual_performance(mods);
|
||||||
|
//!
|
||||||
|
//! // The default score state is kinda chunky because it considers all modes.
|
||||||
|
//! let state = ScoreState {
|
||||||
|
//! max_combo: 1,
|
||||||
|
//! n_katu: 0, // only relevant for ctb
|
||||||
|
//! n300: 1,
|
||||||
|
//! n100: 0,
|
||||||
|
//! n50: 0,
|
||||||
|
//! misses: 0,
|
||||||
|
//! score: 300, // only relevant for mania
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! // Process the score state after the first object
|
||||||
|
//! let curr_performance = match gradual_performance.process_next_object(state) {
|
||||||
|
//! Some(perf) => perf,
|
||||||
|
//! None => panic!("the map has no hit objects"),
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! println!("PP after the first object: {}", curr_performance.pp());
|
||||||
|
//!
|
||||||
|
//! // If you're only interested in maps of a specific mode, consider
|
||||||
|
//! // using the mode's gradual calculator instead of the general one.
|
||||||
|
//! // Let's assume it's a taiko map.
|
||||||
|
//! // Instead of starting off with `BeatmapExt::gradual_performance` one could have
|
||||||
|
//! // created the struct via `TaikoGradualPerformanceAttributes::new`.
|
||||||
|
//! let mut gradual_performance = match gradual_performance {
|
||||||
|
//! GradualPerformanceAttributes::Taiko(gradual) => gradual,
|
||||||
|
//! _ => panic!("the map was not taiko but {:?}", map.mode),
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! // A little simpler than the general score state.
|
||||||
|
//! let state = TaikoScoreState {
|
||||||
|
//! max_combo: 11,
|
||||||
|
//! n300: 9,
|
||||||
|
//! n100: 1,
|
||||||
|
//! misses: 1,
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! // Process the next 10 objects in one go
|
||||||
|
//! let curr_performance = match gradual_performance.process_next_n_objects(state, 10) {
|
||||||
|
//! Some(perf) => perf,
|
||||||
|
//! None => panic!("the last `process_next_object` already processed the last object"),
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! println!("PP after the first 11 objects: {}", curr_performance.pp());
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
//! ## Features
|
//! ## Features
|
||||||
//!
|
//!
|
||||||
//! | Flag | Description |
|
//! | Flag | Description |
|
||||||
|
|||||||
Reference in New Issue
Block a user