2025-01-21 15:58:33 +00:00
|
|
|
// 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.Collections.Generic;
|
|
|
|
using osu.Framework.Utils;
|
|
|
|
|
2025-01-22 13:24:30 +00:00
|
|
|
namespace osu.Game.Rulesets.Taiko.Difficulty.Utils
|
2025-01-21 15:58:33 +00:00
|
|
|
{
|
|
|
|
public static class IntervalGroupingUtils
|
|
|
|
{
|
2025-02-05 15:41:31 +09:00
|
|
|
public static List<List<T>> GroupByInterval<T>(IReadOnlyList<T> objects) where T : IHasInterval
|
2025-01-21 15:58:33 +00:00
|
|
|
{
|
|
|
|
var groups = new List<List<T>>();
|
|
|
|
|
|
|
|
int i = 0;
|
2025-02-05 15:41:31 +09:00
|
|
|
while (i < objects.Count)
|
|
|
|
groups.Add(createNextGroup(objects, ref i));
|
2025-01-21 15:58:33 +00:00
|
|
|
|
|
|
|
return groups;
|
|
|
|
}
|
|
|
|
|
2025-02-05 15:41:31 +09:00
|
|
|
private static List<T> createNextGroup<T>(IReadOnlyList<T> objects, ref int i) where T : IHasInterval
|
2025-01-21 15:58:33 +00:00
|
|
|
{
|
2025-02-05 15:41:31 +09:00
|
|
|
const double margin_of_error = 5;
|
|
|
|
|
2025-02-10 17:57:01 +09:00
|
|
|
// This never compares the first two elements in the group.
|
|
|
|
// This sounds wrong but is apparently "as intended" (https://github.com/ppy/osu/pull/31636#discussion_r1942673329)
|
2025-02-05 15:41:31 +09:00
|
|
|
var groupedObjects = new List<T> { objects[i] };
|
2025-01-21 15:58:33 +00:00
|
|
|
i++;
|
|
|
|
|
2025-02-05 15:41:31 +09:00
|
|
|
for (; i < objects.Count - 1; i++)
|
2025-01-21 15:58:33 +00:00
|
|
|
{
|
2025-02-05 15:41:31 +09:00
|
|
|
if (!Precision.AlmostEquals(objects[i].Interval, objects[i + 1].Interval, margin_of_error))
|
2025-01-21 15:58:33 +00:00
|
|
|
{
|
2025-02-05 18:48:48 +09:00
|
|
|
// When an interval change occurs, include the object with the differing interval in the case it increased
|
|
|
|
// See https://github.com/ppy/osu/pull/31636#discussion_r1942368372 for rationale.
|
2025-02-05 15:41:31 +09:00
|
|
|
if (objects[i + 1].Interval > objects[i].Interval + margin_of_error)
|
2025-01-21 15:58:33 +00:00
|
|
|
{
|
2025-02-05 15:41:31 +09:00
|
|
|
groupedObjects.Add(objects[i]);
|
2025-01-21 15:58:33 +00:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2025-02-05 15:41:31 +09:00
|
|
|
return groupedObjects;
|
2025-01-21 15:58:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// No interval change occurred
|
2025-02-05 15:41:31 +09:00
|
|
|
groupedObjects.Add(objects[i]);
|
2025-01-21 15:58:33 +00:00
|
|
|
}
|
|
|
|
|
2025-02-05 15:41:31 +09:00
|
|
|
// Check if the last two objects in the object form a "flat" rhythm pattern within the specified margin of error.
|
2025-01-21 15:58:33 +00:00
|
|
|
// If true, add the current object to the group and increment the index to process the next object.
|
2025-02-05 15:41:31 +09:00
|
|
|
if (objects.Count > 2 && i < objects.Count && Precision.AlmostEquals(objects[^1].Interval, objects[^2].Interval, margin_of_error))
|
2025-01-21 15:58:33 +00:00
|
|
|
{
|
2025-02-05 15:41:31 +09:00
|
|
|
groupedObjects.Add(objects[i]);
|
2025-01-21 15:58:33 +00:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2025-02-05 15:41:31 +09:00
|
|
|
return groupedObjects;
|
2025-01-21 15:58:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|