added convert support (#12)
* added taiko conversion * finished converts * made clippy happy * optimized allocations for patterns * taiko convert fixes * added mode methods for osu calculators * from CRLF back to LF * updated changelog * updated readme * undo normal hitsound change * added edge_sounds to changelog
This commit is contained in:
@@ -1,111 +0,0 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::iter::{Cycle, Skip, Take};
|
||||
use std::ops::Index;
|
||||
use std::slice::Iter;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct LimitedQueue<T> {
|
||||
queue: Vec<T>,
|
||||
start: usize,
|
||||
end: usize,
|
||||
}
|
||||
|
||||
impl<T> LimitedQueue<T> {
|
||||
#[inline]
|
||||
pub(crate) fn new(capacity: usize) -> Self {
|
||||
Self {
|
||||
end: capacity - 1,
|
||||
start: 0,
|
||||
queue: Vec::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn push(&mut self, elem: T) {
|
||||
let capacity = self.queue.capacity();
|
||||
self.end = (self.end + 1) % capacity;
|
||||
|
||||
if self.queue.len() == capacity {
|
||||
self.start = (self.start + 1) % capacity;
|
||||
self.queue[self.end] = elem;
|
||||
} else {
|
||||
self.queue.push(elem);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
self.queue.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn last(&self) -> Option<&T> {
|
||||
self.queue.get(self.end)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn clear(&mut self) {
|
||||
self.start = 0;
|
||||
self.end = self.queue.capacity() - 1;
|
||||
self.queue.clear();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn full(&self) -> bool {
|
||||
self.queue.len() == self.queue.capacity()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn iter(&self) -> LimitedQueueIter<'_, T> {
|
||||
let iter = self
|
||||
.queue
|
||||
.iter()
|
||||
.cycle()
|
||||
.skip(self.start)
|
||||
.take(self.queue.len());
|
||||
|
||||
LimitedQueueIter { iter }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialOrd> LimitedQueue<T> {
|
||||
pub(crate) fn min(&self) -> Option<&T> {
|
||||
self.queue
|
||||
.iter()
|
||||
.reduce(|min, next| match min.partial_cmp(next) {
|
||||
Some(Ordering::Less) => min,
|
||||
Some(Ordering::Equal) => min,
|
||||
Some(Ordering::Greater) => next,
|
||||
None => min,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Index<usize> for LimitedQueue<T> {
|
||||
type Output = T;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, idx: usize) -> &Self::Output {
|
||||
&self.queue[(self.start + idx) % self.queue.capacity()]
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct LimitedQueueIter<'a, T> {
|
||||
iter: Take<Skip<Cycle<Iter<'a, T>>>>,
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for LimitedQueueIter<'a, T> {
|
||||
type Item = &'a T;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> ExactSizeIterator for LimitedQueueIter<'a, T> {}
|
||||
+24
-5
@@ -2,7 +2,6 @@ mod difficulty_object;
|
||||
mod gradual_difficulty;
|
||||
mod gradual_performance;
|
||||
mod hitobject_rhythm;
|
||||
mod limited_queue;
|
||||
mod pp;
|
||||
mod rim;
|
||||
mod skill;
|
||||
@@ -14,7 +13,6 @@ use difficulty_object::DifficultyObject;
|
||||
pub use gradual_difficulty::*;
|
||||
pub use gradual_performance::*;
|
||||
use hitobject_rhythm::{closest_rhythm, HitObjectRhythm};
|
||||
use limited_queue::LimitedQueue;
|
||||
pub use pp::*;
|
||||
use rim::Rim;
|
||||
use skill_kind::SkillKind;
|
||||
@@ -22,8 +20,9 @@ use stamina_cheese::StaminaCheeseDetector;
|
||||
use taiko_object::IntoTaikoObjectIter;
|
||||
|
||||
use crate::taiko::skill::Skills;
|
||||
use crate::{Beatmap, Mods, Strains};
|
||||
use crate::{Beatmap, GameMode, Mods, OsuStars, Strains};
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::Ordering;
|
||||
use std::f64::consts::PI;
|
||||
|
||||
@@ -53,7 +52,7 @@ const STAMINA_SKILL_MULTIPLIER: f64 = 0.02;
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TaikoStars<'map> {
|
||||
map: &'map Beatmap,
|
||||
map: Cow<'map, Beatmap>,
|
||||
mods: u32,
|
||||
passed_objects: Option<usize>,
|
||||
clock_rate: Option<f64>,
|
||||
@@ -64,7 +63,7 @@ impl<'map> TaikoStars<'map> {
|
||||
#[inline]
|
||||
pub fn new(map: &'map Beatmap) -> Self {
|
||||
Self {
|
||||
map,
|
||||
map: Cow::Borrowed(map),
|
||||
mods: 0,
|
||||
passed_objects: None,
|
||||
clock_rate: None,
|
||||
@@ -331,7 +330,27 @@ impl TaikoPerformanceAttributes {
|
||||
}
|
||||
|
||||
impl From<TaikoPerformanceAttributes> for TaikoDifficultyAttributes {
|
||||
#[inline]
|
||||
fn from(attributes: TaikoPerformanceAttributes) -> Self {
|
||||
attributes.difficulty
|
||||
}
|
||||
}
|
||||
|
||||
impl<'map> From<OsuStars<'map>> for TaikoStars<'map> {
|
||||
#[inline]
|
||||
fn from(osu: OsuStars<'map>) -> Self {
|
||||
let OsuStars {
|
||||
map,
|
||||
mods,
|
||||
passed_objects,
|
||||
clock_rate,
|
||||
} = osu;
|
||||
|
||||
Self {
|
||||
map: map.convert_mode(GameMode::TKO),
|
||||
mods,
|
||||
passed_objects,
|
||||
clock_rate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+38
-5
@@ -1,5 +1,7 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use super::{TaikoDifficultyAttributes, TaikoPerformanceAttributes, TaikoScoreState, TaikoStars};
|
||||
use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
||||
use crate::{Beatmap, DifficultyAttributes, GameMode, Mods, OsuPP, PerformanceAttributes};
|
||||
|
||||
/// Performance calculator on osu!taiko maps.
|
||||
///
|
||||
@@ -33,7 +35,7 @@ use crate::{Beatmap, DifficultyAttributes, Mods, PerformanceAttributes};
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub struct TaikoPP<'map> {
|
||||
map: &'map Beatmap,
|
||||
map: Cow<'map, Beatmap>,
|
||||
attributes: Option<TaikoDifficultyAttributes>,
|
||||
mods: u32,
|
||||
combo: Option<usize>,
|
||||
@@ -51,7 +53,7 @@ impl<'map> TaikoPP<'map> {
|
||||
#[inline]
|
||||
pub fn new(map: &'map Beatmap) -> Self {
|
||||
Self {
|
||||
map,
|
||||
map: Cow::Borrowed(map),
|
||||
attributes: None,
|
||||
mods: 0,
|
||||
combo: None,
|
||||
@@ -171,7 +173,7 @@ impl<'map> TaikoPP<'map> {
|
||||
/// Calculate all performance related values, including pp and stars.
|
||||
pub fn calculate(mut self) -> TaikoPerformanceAttributes {
|
||||
let attributes = self.attributes.take().unwrap_or_else(|| {
|
||||
let mut calculator = TaikoStars::new(self.map).mods(self.mods);
|
||||
let mut calculator = TaikoStars::new(self.map.as_ref()).mods(self.mods);
|
||||
|
||||
if let Some(passed_objects) = self.passed_objects {
|
||||
calculator = calculator.passed_objects(passed_objects);
|
||||
@@ -205,7 +207,7 @@ impl<'map> TaikoPP<'map> {
|
||||
}
|
||||
|
||||
let inner = TaikoPPInner {
|
||||
map: self.map,
|
||||
map: self.map.as_ref(),
|
||||
attributes,
|
||||
mods: self.mods,
|
||||
acc: self.acc,
|
||||
@@ -302,6 +304,37 @@ fn difficulty_range_od(od: f64) -> f64 {
|
||||
crate::difficulty_range(od, 20.0, 35.0, 50.0)
|
||||
}
|
||||
|
||||
impl<'map> From<OsuPP<'map>> for TaikoPP<'map> {
|
||||
#[inline]
|
||||
fn from(osu: OsuPP<'map>) -> Self {
|
||||
let OsuPP {
|
||||
map,
|
||||
mods,
|
||||
acc,
|
||||
combo,
|
||||
n300,
|
||||
n100,
|
||||
n_misses,
|
||||
passed_objects,
|
||||
clock_rate,
|
||||
..
|
||||
} = osu;
|
||||
|
||||
Self {
|
||||
map: map.convert_mode(GameMode::TKO),
|
||||
attributes: None,
|
||||
mods,
|
||||
combo,
|
||||
acc: acc.unwrap_or(1.0),
|
||||
passed_objects,
|
||||
clock_rate,
|
||||
n300,
|
||||
n100,
|
||||
n_misses,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Abstract type to provide flexibility when passing difficulty attributes to a performance calculation.
|
||||
pub trait TaikoAttributeProvider {
|
||||
/// Provide the actual difficulty attributes.
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use super::{DifficultyObject, HitObjectRhythm, LimitedQueue, Rim};
|
||||
use crate::limited_queue::LimitedQueue;
|
||||
|
||||
use super::{DifficultyObject, HitObjectRhythm, Rim};
|
||||
|
||||
use std::ops::Index;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::{LimitedQueue, Rim};
|
||||
use crate::Beatmap;
|
||||
use super::Rim;
|
||||
use crate::{limited_queue::LimitedQueue, Beatmap};
|
||||
|
||||
const ROLL_MIN_REPETITIONS: usize = 12;
|
||||
const TL_MIN_REPETITIONS: isize = 16;
|
||||
|
||||
Reference in New Issue
Block a user