mirror of
https://github.com/ppy/osu.git
synced 2025-03-14 18:37:28 +08:00
Replace weird IntervalGroupedHitObjects
inheritance layer
This commit is contained in:
parent
1c4bc6dffd
commit
14c68bcc58
@ -1,64 +0,0 @@
|
||||
// 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;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for grouping <see cref="IHasInterval"/>s by their interval. In edges where an interval change
|
||||
/// occurs, the <see cref="IHasInterval"/> is added to the group with the smaller interval.
|
||||
/// </summary>
|
||||
public abstract class IntervalGroupedHitObjects<TChildType>
|
||||
where TChildType : IHasInterval
|
||||
{
|
||||
public IReadOnlyList<TChildType> Children { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="IntervalGroupedHitObjects{TChildType}"/> from a list of <see cref="IHasInterval"/>s, and add
|
||||
/// them to the <see cref="Children"/> list until the end of the group.
|
||||
/// </summary>
|
||||
/// <param name="data">The list of <see cref="IHasInterval"/>s.</param>
|
||||
/// <param name="i">
|
||||
/// Index in <paramref name="data"/> to start adding children. This will be modified and should be passed into
|
||||
/// the next <see cref="IntervalGroupedHitObjects{TChildType}"/>'s constructor.
|
||||
/// </param>
|
||||
/// <param name="marginOfError">
|
||||
/// The margin of error for the interval, within of which no interval change is considered to have occured.
|
||||
/// </param>
|
||||
protected IntervalGroupedHitObjects(List<TChildType> data, ref int i, double marginOfError)
|
||||
{
|
||||
List<TChildType> children = new List<TChildType>();
|
||||
Children = children;
|
||||
children.Add(data[i]);
|
||||
i++;
|
||||
|
||||
for (; i < data.Count - 1; i++)
|
||||
{
|
||||
// An interval change occured, add the current data if the next interval is larger.
|
||||
if (!Precision.AlmostEquals(data[i].Interval, data[i + 1].Interval, marginOfError))
|
||||
{
|
||||
if (data[i + 1].Interval > data[i].Interval + marginOfError)
|
||||
{
|
||||
children.Add(data[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// No interval change occured
|
||||
children.Add(data[i]);
|
||||
}
|
||||
|
||||
// Check if the last two objects in the data form a "flat" rhythm pattern within the specified margin of error.
|
||||
// If true, add the current object to the group and increment the index to process the next object.
|
||||
if (data.Count > 2 && Precision.AlmostEquals(data[^1].Interval, data[^2].Interval, marginOfError))
|
||||
{
|
||||
children.Add(data[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -9,9 +9,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data
|
||||
/// <summary>
|
||||
/// Represents <see cref="SameRhythmGroupedHitObjects"/> grouped by their <see cref="SameRhythmGroupedHitObjects.StartTime"/>'s interval.
|
||||
/// </summary>
|
||||
public class SamePatternsGroupedHitObjects : IntervalGroupedHitObjects<SameRhythmGroupedHitObjects>
|
||||
public class SamePatternsGroupedHitObjects
|
||||
{
|
||||
public SamePatternsGroupedHitObjects? Previous { get; private set; }
|
||||
public IReadOnlyList<SameRhythmGroupedHitObjects> Children { get; }
|
||||
|
||||
public SamePatternsGroupedHitObjects? Previous { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="SameRhythmGroupedHitObjects.Interval"/> between children <see cref="SameRhythmGroupedHitObjects"/> within this group.
|
||||
@ -29,27 +31,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data
|
||||
|
||||
public IEnumerable<TaikoDifficultyHitObject> AllHitObjects => Children.SelectMany(child => child.Children);
|
||||
|
||||
private SamePatternsGroupedHitObjects(SamePatternsGroupedHitObjects? previous, List<SameRhythmGroupedHitObjects> data, ref int i)
|
||||
: base(data, ref i, 5)
|
||||
public SamePatternsGroupedHitObjects(SamePatternsGroupedHitObjects? previous, List<SameRhythmGroupedHitObjects> children)
|
||||
{
|
||||
Previous = previous;
|
||||
|
||||
foreach (TaikoDifficultyHitObject hitObject in AllHitObjects)
|
||||
{
|
||||
hitObject.Rhythm.SamePatternsGroupedHitObjects = this;
|
||||
}
|
||||
}
|
||||
|
||||
public static void GroupPatterns(List<SameRhythmGroupedHitObjects> data)
|
||||
{
|
||||
List<SamePatternsGroupedHitObjects> samePatterns = new List<SamePatternsGroupedHitObjects>();
|
||||
|
||||
// Index does not need to be incremented, as it is handled within the IntervalGroupedHitObjects constructor.
|
||||
for (int i = 0; i < data.Count;)
|
||||
{
|
||||
SamePatternsGroupedHitObjects? previous = samePatterns.Count > 0 ? samePatterns[^1] : null;
|
||||
samePatterns.Add(new SamePatternsGroupedHitObjects(previous, data, ref i));
|
||||
}
|
||||
Children = children;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,17 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty.Utils;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a group of <see cref="TaikoDifficultyHitObject"/>s with no rhythm variation.
|
||||
/// </summary>
|
||||
public class SameRhythmGroupedHitObjects : IntervalGroupedHitObjects<TaikoDifficultyHitObject>, IHasInterval
|
||||
public class SameRhythmGroupedHitObjects : IHasInterval
|
||||
{
|
||||
public List<TaikoDifficultyHitObject> Children { get; private set; }
|
||||
|
||||
public TaikoDifficultyHitObject FirstHitObject => Children[0];
|
||||
|
||||
public SameRhythmGroupedHitObjects? Previous;
|
||||
@ -40,53 +43,21 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data
|
||||
/// <inheritdoc/>
|
||||
public double Interval { get; private set; }
|
||||
|
||||
public SameRhythmGroupedHitObjects(SameRhythmGroupedHitObjects? previous, List<TaikoDifficultyHitObject> data, ref int i)
|
||||
: base(data, ref i, 5)
|
||||
public SameRhythmGroupedHitObjects(SameRhythmGroupedHitObjects? previous, List<TaikoDifficultyHitObject> children)
|
||||
{
|
||||
Previous = previous;
|
||||
Children = children;
|
||||
|
||||
foreach (var hitObject in Children)
|
||||
{
|
||||
hitObject.Rhythm.SameRhythmGroupedHitObjects = this;
|
||||
// Calculate the average interval between hitobjects, or null if there are fewer than two
|
||||
HitObjectInterval = Children.Count < 2 ? null : Duration / (Children.Count - 1);
|
||||
|
||||
// Pass the HitObjectInterval to each child.
|
||||
hitObject.HitObjectInterval = HitObjectInterval;
|
||||
}
|
||||
// Calculate the ratio between this group's interval and the previous group's interval
|
||||
HitObjectIntervalRatio = Previous?.HitObjectInterval != null && HitObjectInterval != null
|
||||
? HitObjectInterval.Value / Previous.HitObjectInterval.Value
|
||||
: 1;
|
||||
|
||||
calculateIntervals();
|
||||
}
|
||||
|
||||
public static List<SameRhythmGroupedHitObjects> GroupHitObjects(List<TaikoDifficultyHitObject> data)
|
||||
{
|
||||
List<SameRhythmGroupedHitObjects> flatPatterns = new List<SameRhythmGroupedHitObjects>();
|
||||
|
||||
// Index does not need to be incremented, as it is handled within IntervalGroupedHitObjects's constructor.
|
||||
for (int i = 0; i < data.Count;)
|
||||
{
|
||||
SameRhythmGroupedHitObjects? previous = flatPatterns.Count > 0 ? flatPatterns[^1] : null;
|
||||
flatPatterns.Add(new SameRhythmGroupedHitObjects(previous, data, ref i));
|
||||
}
|
||||
|
||||
return flatPatterns;
|
||||
}
|
||||
|
||||
private void calculateIntervals()
|
||||
{
|
||||
// Calculate the average interval between hitobjects, or null if there are fewer than two.
|
||||
HitObjectInterval = Children.Count < 2 ? null : (Children[^1].StartTime - Children[0].StartTime) / (Children.Count - 1);
|
||||
|
||||
// If both the current and previous intervals are available, calculate the ratio.
|
||||
if (Previous?.HitObjectInterval != null && HitObjectInterval != null)
|
||||
{
|
||||
HitObjectIntervalRatio = HitObjectInterval.Value / Previous.HitObjectInterval.Value;
|
||||
}
|
||||
|
||||
if (Previous == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Interval = StartTime - Previous.StartTime;
|
||||
// Calculate the interval from the previous group's start time
|
||||
Interval = Previous != null ? StartTime - Previous.StartTime : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,63 @@
|
||||
// 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.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm
|
||||
{
|
||||
public static class TaikoRhythmDifficultyPreprocessor
|
||||
{
|
||||
public static void ProcessAndAssign(List<TaikoDifficultyHitObject> hitObjects)
|
||||
{
|
||||
var rhythmGroups = createSameRhythmGroupedHitObjects(hitObjects);
|
||||
|
||||
foreach (var rhythmGroup in rhythmGroups)
|
||||
{
|
||||
foreach (var hitObject in rhythmGroup.Children)
|
||||
{
|
||||
hitObject.Rhythm.SameRhythmGroupedHitObjects = rhythmGroup;
|
||||
hitObject.HitObjectInterval = rhythmGroup.HitObjectInterval;
|
||||
}
|
||||
}
|
||||
|
||||
var patternGroups = createSamePatternGroupedHitObjects(rhythmGroups);
|
||||
|
||||
foreach (var patternGroup in patternGroups)
|
||||
{
|
||||
foreach (var hitObject in patternGroup.AllHitObjects)
|
||||
{
|
||||
hitObject.Rhythm.SamePatternsGroupedHitObjects = patternGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<SameRhythmGroupedHitObjects> createSameRhythmGroupedHitObjects(List<TaikoDifficultyHitObject> hitObjects)
|
||||
{
|
||||
var rhythmGroups = new List<SameRhythmGroupedHitObjects>();
|
||||
var groups = IntervalGroupingUtils.GroupByInterval(hitObjects);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
var previous = rhythmGroups.Count > 0 ? rhythmGroups[^1] : null;
|
||||
rhythmGroups.Add(new SameRhythmGroupedHitObjects(previous, group));
|
||||
}
|
||||
|
||||
return rhythmGroups;
|
||||
}
|
||||
|
||||
private static List<SamePatternsGroupedHitObjects> createSamePatternGroupedHitObjects(List<SameRhythmGroupedHitObjects> rhythmGroups)
|
||||
{
|
||||
var patternGroups = new List<SamePatternsGroupedHitObjects>();
|
||||
var groups = IntervalGroupingUtils.GroupByInterval(rhythmGroups);
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
var previous = patternGroups.Count > 0 ? patternGroups[^1] : null;
|
||||
patternGroups.Add(new SamePatternsGroupedHitObjects(previous, group));
|
||||
}
|
||||
|
||||
return patternGroups;
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty.Utils;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
|
||||
{
|
||||
|
@ -13,7 +13,7 @@ using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty.Skills;
|
||||
using osu.Game.Rulesets.Taiko.Mods;
|
||||
using osu.Game.Rulesets.Taiko.Scoring;
|
||||
@ -91,9 +91,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
||||
}
|
||||
|
||||
TaikoColourDifficultyPreprocessor.ProcessAndAssign(difficultyHitObjects);
|
||||
|
||||
var groupedHitObjects = SameRhythmGroupedHitObjects.GroupHitObjects(noteObjects);
|
||||
SamePatternsGroupedHitObjects.GroupPatterns(groupedHitObjects);
|
||||
TaikoRhythmDifficultyPreprocessor.ProcessAndAssign(noteObjects);
|
||||
|
||||
return difficultyHitObjects;
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
// 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.
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm
|
||||
namespace osu.Game.Rulesets.Taiko.Difficulty.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// The interface for hitobjects that provide an interval value.
|
||||
/// The interface for objects that provide an interval value.
|
||||
/// </summary>
|
||||
public interface IHasInterval
|
||||
{
|
@ -0,0 +1,64 @@
|
||||
// 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;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty.Utils;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data
|
||||
{
|
||||
public static class IntervalGroupingUtils
|
||||
{
|
||||
public static List<List<T>> GroupByInterval<T>(IReadOnlyList<T> data, double marginOfError = 5) where T : IHasInterval
|
||||
{
|
||||
var groups = new List<List<T>>();
|
||||
if (data.Count == 0)
|
||||
return groups;
|
||||
|
||||
int i = 0;
|
||||
|
||||
while (i < data.Count)
|
||||
{
|
||||
var group = createGroup(data, ref i, marginOfError);
|
||||
groups.Add(group);
|
||||
}
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
private static List<T> createGroup<T>(IReadOnlyList<T> data, ref int i, double marginOfError) where T : IHasInterval
|
||||
{
|
||||
var children = new List<T> { data[i] };
|
||||
i++;
|
||||
|
||||
for (; i < data.Count - 1; i++)
|
||||
{
|
||||
// An interval change occured, add the current data if the next interval is larger.
|
||||
if (!Precision.AlmostEquals(data[i].Interval, data[i + 1].Interval, marginOfError))
|
||||
{
|
||||
if (data[i + 1].Interval > data[i].Interval + marginOfError)
|
||||
{
|
||||
children.Add(data[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
// No interval change occurred
|
||||
children.Add(data[i]);
|
||||
}
|
||||
|
||||
// Check if the last two objects in the data form a "flat" rhythm pattern within the specified margin of error.
|
||||
// If true, add the current object to the group and increment the index to process the next object.
|
||||
if (data.Count > 2 && i < data.Count &&
|
||||
Precision.AlmostEquals(data[^1].Interval, data[^2].Interval, marginOfError))
|
||||
{
|
||||
children.Add(data[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user