mirror of
https://github.com/ppy/osu.git
synced 2024-12-13 08:32:57 +08:00
Replicate stable's unstable sort
This commit is contained in:
parent
5017c92fe8
commit
306d876d22
@ -1,6 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -10,10 +11,12 @@ using osu.Game.Rulesets.Difficulty.Skills;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Mania.Difficulty.Skills;
|
||||
using osu.Game.Rulesets.Mania.MathUtils;
|
||||
using osu.Game.Rulesets.Mania.Mods;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Scoring;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Difficulty
|
||||
@ -51,10 +54,17 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
||||
|
||||
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
|
||||
{
|
||||
for (int i = 1; i < beatmap.HitObjects.Count; i++)
|
||||
yield return new ManiaDifficultyHitObject(beatmap.HitObjects[i], beatmap.HitObjects[i - 1], clockRate);
|
||||
var sortedObjects = beatmap.HitObjects.ToArray();
|
||||
|
||||
LegacySortHelper<HitObject>.Sort(sortedObjects, Comparer<HitObject>.Create((a, b) => (int)Math.Round(a.StartTime) - (int)Math.Round(b.StartTime)));
|
||||
|
||||
for (int i = 1; i < sortedObjects.Length; i++)
|
||||
yield return new ManiaDifficultyHitObject(sortedObjects[i], sortedObjects[i - 1], clockRate);
|
||||
}
|
||||
|
||||
// Sorting is done in CreateDifficultyHitObjects, since the full list of hitobjects is required.
|
||||
protected override IEnumerable<DifficultyHitObject> SortObjects(IEnumerable<DifficultyHitObject> input) => input;
|
||||
|
||||
protected override Skill[] CreateSkills(IBeatmap beatmap) => new Skill[]
|
||||
{
|
||||
new Strain(((ManiaBeatmap)beatmap).TotalColumns)
|
||||
|
164
osu.Game.Rulesets.Mania/MathUtils/LegacySortHelper.cs
Normal file
164
osu.Game.Rulesets.Mania/MathUtils/LegacySortHelper.cs
Normal file
@ -0,0 +1,164 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.MathUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to .NET4.0 unstable sorting methods.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://referencesource.microsoft.com/#mscorlib/system/collections/generic/arraysorthelper.cs
|
||||
/// </remarks>
|
||||
internal static class LegacySortHelper<T>
|
||||
{
|
||||
private const int quick_sort_depth_threshold = 32;
|
||||
|
||||
public static void Sort(T[] keys, IComparer<T> comparer)
|
||||
{
|
||||
if (keys == null)
|
||||
throw new ArgumentNullException(nameof(keys));
|
||||
|
||||
if (keys.Length == 0)
|
||||
return;
|
||||
|
||||
comparer ??= Comparer<T>.Default;
|
||||
depthLimitedQuickSort(keys, 0, keys.Length - 1, comparer, quick_sort_depth_threshold);
|
||||
}
|
||||
|
||||
private static void depthLimitedQuickSort(T[] keys, int left, int right, IComparer<T> comparer, int depthLimit)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (depthLimit == 0)
|
||||
{
|
||||
heapsort(keys, left, right, comparer);
|
||||
return;
|
||||
}
|
||||
|
||||
int i = left;
|
||||
int j = right;
|
||||
|
||||
// pre-sort the low, middle (pivot), and high values in place.
|
||||
// this improves performance in the face of already sorted data, or
|
||||
// data that is made up of multiple sorted runs appended together.
|
||||
int middle = i + ((j - i) >> 1);
|
||||
swapIfGreater(keys, comparer, i, middle); // swap the low with the mid point
|
||||
swapIfGreater(keys, comparer, i, j); // swap the low with the high
|
||||
swapIfGreater(keys, comparer, middle, j); // swap the middle with the high
|
||||
|
||||
T x = keys[middle];
|
||||
|
||||
do
|
||||
{
|
||||
while (comparer.Compare(keys[i], x) < 0) i++;
|
||||
while (comparer.Compare(x, keys[j]) < 0) j--;
|
||||
Contract.Assert(i >= left && j <= right, "(i>=left && j<=right) Sort failed - Is your IComparer bogus?");
|
||||
if (i > j) break;
|
||||
|
||||
if (i < j)
|
||||
{
|
||||
T key = keys[i];
|
||||
keys[i] = keys[j];
|
||||
keys[j] = key;
|
||||
}
|
||||
|
||||
i++;
|
||||
j--;
|
||||
} while (i <= j);
|
||||
|
||||
// The next iteration of the while loop is to "recursively" sort the larger half of the array and the
|
||||
// following calls recrusively sort the smaller half. So we subtrack one from depthLimit here so
|
||||
// both sorts see the new value.
|
||||
depthLimit--;
|
||||
|
||||
if (j - left <= right - i)
|
||||
{
|
||||
if (left < j) depthLimitedQuickSort(keys, left, j, comparer, depthLimit);
|
||||
left = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i < right) depthLimitedQuickSort(keys, i, right, comparer, depthLimit);
|
||||
right = j;
|
||||
}
|
||||
} while (left < right);
|
||||
}
|
||||
|
||||
private static void heapsort(T[] keys, int lo, int hi, IComparer<T> comparer)
|
||||
{
|
||||
Contract.Requires(keys != null);
|
||||
Contract.Requires(comparer != null);
|
||||
Contract.Requires(lo >= 0);
|
||||
Contract.Requires(hi > lo);
|
||||
Contract.Requires(hi < keys.Length);
|
||||
|
||||
int n = hi - lo + 1;
|
||||
|
||||
for (int i = n / 2; i >= 1; i = i - 1)
|
||||
{
|
||||
downHeap(keys, i, n, lo, comparer);
|
||||
}
|
||||
|
||||
for (int i = n; i > 1; i = i - 1)
|
||||
{
|
||||
swap(keys, lo, lo + i - 1);
|
||||
downHeap(keys, 1, i - 1, lo, comparer);
|
||||
}
|
||||
}
|
||||
|
||||
private static void downHeap(T[] keys, int i, int n, int lo, IComparer<T> comparer)
|
||||
{
|
||||
Contract.Requires(keys != null);
|
||||
Contract.Requires(comparer != null);
|
||||
Contract.Requires(lo >= 0);
|
||||
Contract.Requires(lo < keys.Length);
|
||||
|
||||
T d = keys[lo + i - 1];
|
||||
|
||||
while (i <= n / 2)
|
||||
{
|
||||
var child = 2 * i;
|
||||
|
||||
if (child < n && comparer.Compare(keys[lo + child - 1], keys[lo + child]) < 0)
|
||||
{
|
||||
child++;
|
||||
}
|
||||
|
||||
if (!(comparer.Compare(d, keys[lo + child - 1]) < 0))
|
||||
break;
|
||||
|
||||
keys[lo + i - 1] = keys[lo + child - 1];
|
||||
i = child;
|
||||
}
|
||||
|
||||
keys[lo + i - 1] = d;
|
||||
}
|
||||
|
||||
private static void swap(T[] a, int i, int j)
|
||||
{
|
||||
if (i != j)
|
||||
{
|
||||
T t = a[i];
|
||||
a[i] = a[j];
|
||||
a[j] = t;
|
||||
}
|
||||
}
|
||||
|
||||
private static void swapIfGreater(T[] keys, IComparer<T> comparer, int a, int b)
|
||||
{
|
||||
if (a != b)
|
||||
{
|
||||
if (comparer.Compare(keys[a], keys[b]) > 0)
|
||||
{
|
||||
T key = keys[a];
|
||||
keys[a] = keys[b];
|
||||
keys[b] = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user