apply proper sorting for catch objects
This commit is contained in:
+11
-2
@@ -8,7 +8,7 @@ use crate::{
|
|||||||
hit_object::{HitObject, HitObjectKind, HoldNote, Spinner},
|
hit_object::{HitObject, HitObjectKind, HoldNote, Spinner},
|
||||||
mode::ConvertStatus,
|
mode::ConvertStatus,
|
||||||
},
|
},
|
||||||
util::{float_ext::FloatExt, random::Random, sort},
|
util::{float_ext::FloatExt, random::Random, sort::TandemSorter},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@@ -75,12 +75,21 @@ pub fn convert_objects(
|
|||||||
palpable_objects.extend(new_objects);
|
palpable_objects.extend(new_objects);
|
||||||
}
|
}
|
||||||
|
|
||||||
sort::csharp(&mut palpable_objects, |a, b| {
|
// Initializing hyper dashes requires objects to be sorted by C#'s unstable
|
||||||
|
// sort. After that, we unsort the objects again and then apply a stable
|
||||||
|
// sort to have the correct order for generating difficulty objects.
|
||||||
|
// Required e.g. due to map /b/102923.
|
||||||
|
let mut sorter = TandemSorter::new_unstable(&mut palpable_objects, |a, b| {
|
||||||
a.start_time.total_cmp(&b.start_time)
|
a.start_time.total_cmp(&b.start_time)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sorter.sort(&mut palpable_objects);
|
||||||
|
|
||||||
initialize_hyper_dash(cs, &mut palpable_objects);
|
initialize_hyper_dash(cs, &mut palpable_objects);
|
||||||
|
|
||||||
|
sorter.unsort(&mut palpable_objects);
|
||||||
|
palpable_objects.sort_by(|a, b| a.start_time.total_cmp(&b.start_time));
|
||||||
|
|
||||||
palpable_objects
|
palpable_objects
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -282,11 +282,9 @@ impl From<BeatmapState> for Beatmap {
|
|||||||
slider_tick_rate,
|
slider_tick_rate,
|
||||||
} = state.difficulty.into();
|
} = state.difficulty.into();
|
||||||
|
|
||||||
let mut sorter = sort::TandemSorter::new(
|
let mut sorter = sort::TandemSorter::new_stable(&state.hit_objects, |a, b| {
|
||||||
&state.hit_objects,
|
a.start_time.total_cmp(&b.start_time)
|
||||||
|a, b| a.start_time.total_cmp(&b.start_time),
|
});
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
sorter.sort(&mut state.hit_objects);
|
sorter.sort(&mut state.hit_objects);
|
||||||
sorter.sort(&mut state.hit_sounds);
|
sorter.sort(&mut state.hit_sounds);
|
||||||
|
|||||||
@@ -103,11 +103,9 @@ fn convert(map: &mut Beatmap) {
|
|||||||
// We only convert osu! to taiko so we don't need to remove objects
|
// We only convert osu! to taiko so we don't need to remove objects
|
||||||
// with the same timestamp that would appear only in mania
|
// with the same timestamp that would appear only in mania
|
||||||
|
|
||||||
let mut sorter = TandemSorter::new(
|
let mut sorter = TandemSorter::new_stable(&map.hit_objects, |a, b| {
|
||||||
&map.hit_objects,
|
a.start_time.total_cmp(&b.start_time)
|
||||||
|a, b| a.start_time.total_cmp(&b.start_time),
|
});
|
||||||
true,
|
|
||||||
);
|
|
||||||
sorter.sort(&mut map.hit_objects);
|
sorter.sort(&mut map.hit_objects);
|
||||||
sorter.sort(&mut map.hit_sounds);
|
sorter.sort(&mut map.hit_sounds);
|
||||||
|
|
||||||
|
|||||||
+50
-22
@@ -7,27 +7,26 @@ pub struct TandemSorter {
|
|||||||
should_reset: bool,
|
should_reset: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! new_fn {
|
||||||
|
( $fn:ident: $sort:expr ) => {
|
||||||
|
/// Sort indices based on the given slice.
|
||||||
|
///
|
||||||
|
/// Note that this does **not** sort the given slice.
|
||||||
|
pub fn $fn<T>(slice: &[T], cmp: fn(&T, &T) -> Ordering) -> Self {
|
||||||
|
let mut indices: Box<[usize]> = (0..slice.len()).collect();
|
||||||
|
$sort(&mut indices, |&i, &j| cmp(&slice[i], &slice[j]));
|
||||||
|
|
||||||
|
Self {
|
||||||
|
indices,
|
||||||
|
should_reset: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
impl TandemSorter {
|
impl TandemSorter {
|
||||||
/// Sort indices based on the given slice.
|
new_fn!(new_stable: <[_]>::sort_by);
|
||||||
///
|
new_fn!(new_unstable: super::csharp);
|
||||||
/// Note that this does **not** sort the given slice.
|
|
||||||
pub fn new<T>(slice: &[T], cmp: fn(&T, &T) -> Ordering, stable: bool) -> Self {
|
|
||||||
let mut indices: Box<[usize]> = (0..slice.len()).collect();
|
|
||||||
let sort_by = |&i: &usize, &j: &usize| cmp(&slice[i], &slice[j]);
|
|
||||||
|
|
||||||
if stable {
|
|
||||||
indices.sort_by(sort_by);
|
|
||||||
} else {
|
|
||||||
// When sorting integers, the order of elements with equal values
|
|
||||||
// does not matter so we can use rust's sort instead of C#'s.
|
|
||||||
indices.sort_unstable_by(sort_by);
|
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
|
||||||
indices,
|
|
||||||
should_reset: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sort the given slice based on the internal ordering.
|
/// Sort the given slice based on the internal ordering.
|
||||||
pub fn sort<T>(&mut self, slice: &mut [T]) {
|
pub fn sort<T>(&mut self, slice: &mut [T]) {
|
||||||
@@ -60,6 +59,35 @@ impl TandemSorter {
|
|||||||
self.should_reset = true;
|
self.should_reset = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unsort the given slice based on the internal ordering.
|
||||||
|
pub fn unsort<T>(mut self, slice: &mut [T]) {
|
||||||
|
if self.should_reset {
|
||||||
|
self.toggle_marks();
|
||||||
|
self.should_reset = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..self.indices.len() {
|
||||||
|
let i_idx = self.indices[i];
|
||||||
|
|
||||||
|
if Self::idx_is_marked(i_idx) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut j = i;
|
||||||
|
let mut j_idx = i_idx;
|
||||||
|
|
||||||
|
while j != j_idx {
|
||||||
|
self.indices[j] = Self::toggle_mark_idx(j_idx);
|
||||||
|
self.indices.swap(j, j_idx);
|
||||||
|
slice.swap(j, j_idx);
|
||||||
|
j = self.indices[j];
|
||||||
|
j_idx = self.indices[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
self.indices[j] = Self::toggle_mark_idx(j_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn toggle_marks(&mut self) {
|
fn toggle_marks(&mut self) {
|
||||||
for idx in self.indices.iter_mut() {
|
for idx in self.indices.iter_mut() {
|
||||||
*idx = Self::toggle_mark_idx(*idx);
|
*idx = Self::toggle_mark_idx(*idx);
|
||||||
@@ -85,12 +113,12 @@ mod tests {
|
|||||||
fn sort() {
|
fn sort() {
|
||||||
let mut base = vec![9, 7, 8, 1, 4, 3, 5, 2];
|
let mut base = vec![9, 7, 8, 1, 4, 3, 5, 2];
|
||||||
let mut other = "hello World".chars().collect::<Vec<_>>();
|
let mut other = "hello World".chars().collect::<Vec<_>>();
|
||||||
let mut sorter = TandemSorter::new(&base, u8::cmp, false);
|
let mut sorter = TandemSorter::new_stable(&base, u8::cmp);
|
||||||
|
|
||||||
sorter.sort(&mut base);
|
sorter.sort(&mut base);
|
||||||
assert_eq!(base, vec![1, 2, 3, 4, 5, 7, 8, 9]);
|
assert_eq!(base, vec![1, 2, 3, 4, 5, 7, 8, 9]);
|
||||||
|
|
||||||
sorter.sort(&mut other);
|
sorter.sort(&mut other);
|
||||||
assert_eq!(other, "lo oWelhrld".chars().collect::<Vec<_>>());
|
assert_eq!(other.iter().collect::<String>(), "lo oWelhrld");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user