store taiko strain peaks in CompactZerosVec
This commit is contained in:
+3
-3
@@ -181,9 +181,9 @@ impl<'map> TaikoStars<'map> {
|
|||||||
|
|
||||||
TaikoStrains {
|
TaikoStrains {
|
||||||
section_len: SECTION_LEN,
|
section_len: SECTION_LEN,
|
||||||
color: colour,
|
color: colour.to_vec(),
|
||||||
rhythm,
|
rhythm: rhythm.to_vec(),
|
||||||
stamina,
|
stamina: stamina.to_vec(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,12 @@ use std::{
|
|||||||
rc::{Rc, Weak},
|
rc::{Rc, Weak},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::taiko::{
|
use crate::{
|
||||||
colours::{AlternatingMonoPattern, MonoStreak, RepeatingHitPatterns},
|
taiko::{
|
||||||
difficulty_object::{ObjectLists, TaikoDifficultyObject},
|
colours::{AlternatingMonoPattern, MonoStreak, RepeatingHitPatterns},
|
||||||
|
difficulty_object::{ObjectLists, TaikoDifficultyObject},
|
||||||
|
},
|
||||||
|
util::CompactZerosVec,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Skill, StrainDecaySkill, StrainSkill};
|
use super::{Skill, StrainDecaySkill, StrainSkill};
|
||||||
@@ -15,7 +18,7 @@ pub(crate) struct Colour {
|
|||||||
curr_strain: f64,
|
curr_strain: f64,
|
||||||
curr_section_peak: f64,
|
curr_section_peak: f64,
|
||||||
curr_section_end: f64,
|
curr_section_end: f64,
|
||||||
pub(crate) strain_peaks: Vec<f64>,
|
pub(crate) strain_peaks: CompactZerosVec,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Colour {
|
impl Colour {
|
||||||
@@ -24,7 +27,7 @@ impl Colour {
|
|||||||
curr_strain: 0.0,
|
curr_strain: 0.0,
|
||||||
curr_section_peak: 0.0,
|
curr_section_peak: 0.0,
|
||||||
curr_section_end: 0.0,
|
curr_section_end: 0.0,
|
||||||
strain_peaks: Vec::new(),
|
strain_peaks: CompactZerosVec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,7 +46,7 @@ impl Skill for Colour {
|
|||||||
|
|
||||||
impl StrainSkill for Colour {
|
impl StrainSkill for Colour {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn strain_peaks_mut(&mut self) -> &mut Vec<f64> {
|
fn strain_peaks_mut(&mut self) -> &mut CompactZerosVec {
|
||||||
&mut self.strain_peaks
|
&mut self.strain_peaks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use crate::taiko::difficulty_object::{ObjectLists, TaikoDifficultyObject};
|
use crate::{
|
||||||
|
taiko::difficulty_object::{ObjectLists, TaikoDifficultyObject},
|
||||||
|
util::CompactZerosVec,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{colour::Colour, rhythm::Rhythm, stamina::Stamina, Skill, StrainSkill};
|
use super::{colour::Colour, rhythm::Rhythm, stamina::Stamina, Skill, StrainSkill};
|
||||||
|
|
||||||
@@ -74,9 +77,9 @@ impl Skill for Peaks {
|
|||||||
let stamina_peaks = self.stamina.get_curr_strain_peaks();
|
let stamina_peaks = self.stamina.get_curr_strain_peaks();
|
||||||
|
|
||||||
let zip = colour_peaks
|
let zip = colour_peaks
|
||||||
.into_iter()
|
.iter()
|
||||||
.zip(rhythm_peaks)
|
.zip(rhythm_peaks.iter())
|
||||||
.zip(stamina_peaks);
|
.zip(stamina_peaks.iter());
|
||||||
|
|
||||||
for ((mut colour_peak, mut rhythm_peak), mut stamina_peak) in zip {
|
for ((mut colour_peak, mut rhythm_peak), mut stamina_peak) in zip {
|
||||||
colour_peak *= Self::COLOUR_SKILL_MULTIPLIER;
|
colour_peak *= Self::COLOUR_SKILL_MULTIPLIER;
|
||||||
@@ -116,7 +119,7 @@ pub(crate) struct PeaksDifficultyValues {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct PeaksRaw {
|
pub(crate) struct PeaksRaw {
|
||||||
pub(crate) colour: Vec<f64>,
|
pub(crate) colour: CompactZerosVec,
|
||||||
pub(crate) rhythm: Vec<f64>,
|
pub(crate) rhythm: CompactZerosVec,
|
||||||
pub(crate) stamina: Vec<f64>,
|
pub(crate) stamina: CompactZerosVec,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
taiko::difficulty_object::{HitObjectRhythm, ObjectLists, TaikoDifficultyObject},
|
taiko::difficulty_object::{HitObjectRhythm, ObjectLists, TaikoDifficultyObject},
|
||||||
util::LimitedQueue,
|
util::{CompactZerosVec, LimitedQueue},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Skill, StrainDecaySkill, StrainSkill};
|
use super::{Skill, StrainDecaySkill, StrainSkill};
|
||||||
@@ -17,7 +17,7 @@ pub(crate) struct Rhythm {
|
|||||||
history: LimitedQueue<HistoryElement, HISTORY_MAX_LEN>,
|
history: LimitedQueue<HistoryElement, HISTORY_MAX_LEN>,
|
||||||
curr_section_peak: f64,
|
curr_section_peak: f64,
|
||||||
curr_section_end: f64,
|
curr_section_end: f64,
|
||||||
pub(crate) strain_peaks: Vec<f64>,
|
pub(crate) strain_peaks: CompactZerosVec,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rhythm {
|
impl Rhythm {
|
||||||
@@ -31,7 +31,7 @@ impl Rhythm {
|
|||||||
history: LimitedQueue::new(),
|
history: LimitedQueue::new(),
|
||||||
curr_section_peak: 0.0,
|
curr_section_peak: 0.0,
|
||||||
curr_section_end: 0.0,
|
curr_section_end: 0.0,
|
||||||
strain_peaks: Vec::new(),
|
strain_peaks: CompactZerosVec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ impl Skill for Rhythm {
|
|||||||
|
|
||||||
impl StrainSkill for Rhythm {
|
impl StrainSkill for Rhythm {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn strain_peaks_mut(&mut self) -> &mut Vec<f64> {
|
fn strain_peaks_mut(&mut self) -> &mut CompactZerosVec {
|
||||||
&mut self.strain_peaks
|
&mut self.strain_peaks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use crate::taiko::difficulty_object::{ObjectLists, TaikoDifficultyObject};
|
use crate::{
|
||||||
|
taiko::difficulty_object::{ObjectLists, TaikoDifficultyObject},
|
||||||
|
util::CompactZerosVec,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{Skill, StrainDecaySkill, StrainSkill};
|
use super::{Skill, StrainDecaySkill, StrainSkill};
|
||||||
|
|
||||||
@@ -7,7 +10,7 @@ pub(crate) struct Stamina {
|
|||||||
curr_strain: f64,
|
curr_strain: f64,
|
||||||
curr_section_peak: f64,
|
curr_section_peak: f64,
|
||||||
curr_section_end: f64,
|
curr_section_end: f64,
|
||||||
pub(crate) strain_peaks: Vec<f64>,
|
pub(crate) strain_peaks: CompactZerosVec,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stamina {
|
impl Stamina {
|
||||||
@@ -16,7 +19,7 @@ impl Stamina {
|
|||||||
curr_strain: 0.0,
|
curr_strain: 0.0,
|
||||||
curr_section_peak: 0.0,
|
curr_section_peak: 0.0,
|
||||||
curr_section_end: 0.0,
|
curr_section_end: 0.0,
|
||||||
strain_peaks: Vec::new(),
|
strain_peaks: CompactZerosVec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,7 +38,7 @@ impl Skill for Stamina {
|
|||||||
|
|
||||||
impl StrainSkill for Stamina {
|
impl StrainSkill for Stamina {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn strain_peaks_mut(&mut self) -> &mut Vec<f64> {
|
fn strain_peaks_mut(&mut self) -> &mut CompactZerosVec {
|
||||||
&mut self.strain_peaks
|
&mut self.strain_peaks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
use std::{cmp::Ordering, mem};
|
use std::{cmp::Ordering, mem};
|
||||||
|
|
||||||
use crate::taiko::{
|
use crate::{
|
||||||
difficulty_object::{ObjectLists, TaikoDifficultyObject},
|
taiko::{
|
||||||
SECTION_LEN,
|
difficulty_object::{ObjectLists, TaikoDifficultyObject},
|
||||||
|
SECTION_LEN,
|
||||||
|
},
|
||||||
|
util::CompactZerosVec,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) trait Skill: Sized {
|
pub(crate) trait Skill: Sized {
|
||||||
@@ -13,7 +16,7 @@ pub(crate) trait Skill: Sized {
|
|||||||
pub(crate) trait StrainSkill: Skill {
|
pub(crate) trait StrainSkill: Skill {
|
||||||
const DECAY_WEIGHT: f64 = 0.9;
|
const DECAY_WEIGHT: f64 = 0.9;
|
||||||
|
|
||||||
fn strain_peaks_mut(&mut self) -> &mut Vec<f64>;
|
fn strain_peaks_mut(&mut self) -> &mut CompactZerosVec;
|
||||||
fn curr_section_peak(&mut self) -> &mut f64;
|
fn curr_section_peak(&mut self) -> &mut f64;
|
||||||
fn curr_section_end(&mut self) -> &mut f64;
|
fn curr_section_end(&mut self) -> &mut f64;
|
||||||
|
|
||||||
@@ -76,9 +79,7 @@ pub(crate) trait StrainSkill: Skill {
|
|||||||
|
|
||||||
// * Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871).
|
// * Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871).
|
||||||
// * These sections will not contribute to the difficulty.
|
// * These sections will not contribute to the difficulty.
|
||||||
let mut peaks = self.get_curr_strain_peaks();
|
let mut peaks = self.get_curr_strain_peaks().to_non_zeros();
|
||||||
|
|
||||||
peaks.retain(|&peak| peak > 0.0);
|
|
||||||
peaks.sort_unstable_by(|a, b| b.partial_cmp(a).unwrap_or(Ordering::Equal));
|
peaks.sort_unstable_by(|a, b| b.partial_cmp(a).unwrap_or(Ordering::Equal));
|
||||||
|
|
||||||
// * Difficulty is the weighted sum of the highest strains from every section.
|
// * Difficulty is the weighted sum of the highest strains from every section.
|
||||||
@@ -92,7 +93,7 @@ pub(crate) trait StrainSkill: Skill {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_curr_strain_peaks(mut self) -> Vec<f64> {
|
fn get_curr_strain_peaks(mut self) -> CompactZerosVec {
|
||||||
let curr_peak = *self.curr_section_peak();
|
let curr_peak = *self.curr_section_peak();
|
||||||
let mut strain_peaks = mem::take(self.strain_peaks_mut());
|
let mut strain_peaks = mem::take(self.strain_peaks_mut());
|
||||||
strain_peaks.push(curr_peak);
|
strain_peaks.push(curr_peak);
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
use std::{
|
||||||
|
iter::{self, Copied},
|
||||||
|
slice,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub(crate) struct CompactZerosVec {
|
||||||
|
inner: Vec<Number>,
|
||||||
|
non_zero_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompactZerosVec {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn push(&mut self, num: f64) {
|
||||||
|
if num.abs() > f64::EPSILON {
|
||||||
|
self.inner.push(Number::NonZero(num));
|
||||||
|
self.non_zero_count += 1;
|
||||||
|
} else {
|
||||||
|
self.push_n_zeros(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn push_n_zeros(&mut self, n: usize) {
|
||||||
|
match self.inner.last_mut() {
|
||||||
|
Some(Number::NonZero(_)) | None => self.inner.push(Number::Zeros(n)),
|
||||||
|
Some(Number::Zeros(zeros)) => *zeros += n,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_non_zeros(&self) -> Vec<f64> {
|
||||||
|
let mut non_zeros = Vec::with_capacity(self.non_zero_count);
|
||||||
|
|
||||||
|
let iter = self.inner.iter().filter_map(|num| match num {
|
||||||
|
Number::NonZero(n) => Some(*n),
|
||||||
|
Number::Zeros(_) => None,
|
||||||
|
});
|
||||||
|
|
||||||
|
non_zeros.extend(iter);
|
||||||
|
|
||||||
|
non_zeros
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn iter(&self) -> Iter<'_> {
|
||||||
|
Iter::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_vec(&self) -> Vec<f64> {
|
||||||
|
let mut nums = Vec::with_capacity(self.inner.len() * 2);
|
||||||
|
|
||||||
|
for &num in self.inner.iter() {
|
||||||
|
match num {
|
||||||
|
Number::NonZero(num) => nums.push(num),
|
||||||
|
Number::Zeros(zeros) => nums.extend(iter::repeat(0.0).take(zeros)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nums
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
enum Number {
|
||||||
|
NonZero(f64),
|
||||||
|
Zeros(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct Iter<'a> {
|
||||||
|
iter: Copied<slice::Iter<'a, Number>>,
|
||||||
|
curr: Option<Number>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iter<'a> {
|
||||||
|
fn new(compact_zeros: &'a CompactZerosVec) -> Self {
|
||||||
|
let mut iter = compact_zeros.inner.iter().copied();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
curr: iter.next(),
|
||||||
|
iter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for Iter<'_> {
|
||||||
|
type Item = f64;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match self.curr.as_mut()? {
|
||||||
|
Number::NonZero(n) => {
|
||||||
|
let n = *n;
|
||||||
|
self.curr = self.iter.next();
|
||||||
|
|
||||||
|
Some(n)
|
||||||
|
}
|
||||||
|
Number::Zeros(zeros @ 1..) => {
|
||||||
|
*zeros -= 1;
|
||||||
|
|
||||||
|
Some(0.0)
|
||||||
|
}
|
||||||
|
Number::Zeros(_) => {
|
||||||
|
self.curr = self.iter.next();
|
||||||
|
|
||||||
|
self.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-2
@@ -1,4 +1,5 @@
|
|||||||
mod byte_hasher;
|
mod byte_hasher;
|
||||||
|
mod compact_zeros;
|
||||||
mod float_ext;
|
mod float_ext;
|
||||||
mod limited_queue;
|
mod limited_queue;
|
||||||
mod sorted_vec;
|
mod sorted_vec;
|
||||||
@@ -7,6 +8,6 @@ mod tandem_sort;
|
|||||||
pub use self::sorted_vec::SortedVec;
|
pub use self::sorted_vec::SortedVec;
|
||||||
|
|
||||||
pub(crate) use self::{
|
pub(crate) use self::{
|
||||||
byte_hasher::ByteHasher, float_ext::FloatExt, limited_queue::LimitedQueue,
|
byte_hasher::ByteHasher, compact_zeros::CompactZerosVec, float_ext::FloatExt,
|
||||||
tandem_sort::TandemSorter,
|
limited_queue::LimitedQueue, tandem_sort::TandemSorter,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user