diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/RhythmEvaluator.cs index 22321a8f6e..8accc6124c 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/RhythmEvaluator.cs @@ -25,32 +25,32 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators double samePattern = 0; double intervalPenalty = 0; - if (rhythm.SameRhythmHitObjects?.FirstHitObject == hitObject) // Difficulty for SameRhythmHitObjects + if (rhythm.SameRhythmGroupedHitObjects?.FirstHitObject == hitObject) // Difficulty for SameRhythmGroupedHitObjects { - sameRhythm += 10.0 * evaluateDifficultyOf(rhythm.SameRhythmHitObjects, hitWindow); - intervalPenalty = repeatedIntervalPenalty(rhythm.SameRhythmHitObjects, hitWindow); + sameRhythm += 10.0 * evaluateDifficultyOf(rhythm.SameRhythmGroupedHitObjects, hitWindow); + intervalPenalty = repeatedIntervalPenalty(rhythm.SameRhythmGroupedHitObjects, hitWindow); } - if (rhythm.SamePatterns?.FirstHitObject == hitObject) // Difficulty for SamePatterns - samePattern += 1.15 * ratioDifficulty(rhythm.SamePatterns.IntervalRatio); + if (rhythm.SamePatternsGroupedHitObjects?.FirstHitObject == hitObject) // Difficulty for SamePatternsGroupedHitObjects + samePattern += 1.15 * ratioDifficulty(rhythm.SamePatternsGroupedHitObjects.IntervalRatio); difficulty += Math.Max(sameRhythm, samePattern) * intervalPenalty; return difficulty; } - private static double evaluateDifficultyOf(SameRhythmHitObjects sameRhythmHitObjects, double hitWindow) + private static double evaluateDifficultyOf(SameRhythmGroupedHitObjects sameRhythmGroupedHitObjects, double hitWindow) { - double intervalDifficulty = ratioDifficulty(sameRhythmHitObjects.HitObjectIntervalRatio); - double? previousInterval = sameRhythmHitObjects.Previous?.HitObjectInterval; + double intervalDifficulty = ratioDifficulty(sameRhythmGroupedHitObjects.HitObjectIntervalRatio); + double? previousInterval = sameRhythmGroupedHitObjects.Previous?.HitObjectInterval; - intervalDifficulty *= repeatedIntervalPenalty(sameRhythmHitObjects, hitWindow); + intervalDifficulty *= repeatedIntervalPenalty(sameRhythmGroupedHitObjects, hitWindow); // If a previous interval exists and there are multiple hit objects in the sequence: - if (previousInterval != null && sameRhythmHitObjects.Children.Count > 1) + if (previousInterval != null && sameRhythmGroupedHitObjects.Children.Count > 1) { - double expectedDurationFromPrevious = (double)previousInterval * sameRhythmHitObjects.Children.Count; - double durationDifference = sameRhythmHitObjects.Duration - expectedDurationFromPrevious; + double expectedDurationFromPrevious = (double)previousInterval * sameRhythmGroupedHitObjects.Children.Count; + double durationDifference = sameRhythmGroupedHitObjects.Duration - expectedDurationFromPrevious; if (durationDifference > 0) { @@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators // Penalise patterns that can be hit within a single hit window. intervalDifficulty *= DifficultyCalculationUtils.Logistic( - sameRhythmHitObjects.Duration / hitWindow, + sameRhythmGroupedHitObjects.Duration / hitWindow, midpointOffset: 0.6, multiplier: 1, maxValue: 1); @@ -75,20 +75,20 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// /// Determines if the changes in hit object intervals is consistent based on a given threshold. /// - private static double repeatedIntervalPenalty(SameRhythmHitObjects sameRhythmHitObjects, double hitWindow, double threshold = 0.1) + private static double repeatedIntervalPenalty(SameRhythmGroupedHitObjects sameRhythmGroupedHitObjects, double hitWindow, double threshold = 0.1) { - double longIntervalPenalty = sameInterval(sameRhythmHitObjects, 3); + double longIntervalPenalty = sameInterval(sameRhythmGroupedHitObjects, 3); - double shortIntervalPenalty = sameRhythmHitObjects.Children.Count < 6 - ? sameInterval(sameRhythmHitObjects, 4) + double shortIntervalPenalty = sameRhythmGroupedHitObjects.Children.Count < 6 + ? sameInterval(sameRhythmGroupedHitObjects, 4) : 1.0; // Returns a non-penalty if there are 6 or more notes within an interval. // The duration penalty is based on hit object duration relative to hitWindow. - double durationPenalty = Math.Max(1 - sameRhythmHitObjects.Duration * 2 / hitWindow, 0.5); + double durationPenalty = Math.Max(1 - sameRhythmGroupedHitObjects.Duration * 2 / hitWindow, 0.5); return Math.Min(longIntervalPenalty, shortIntervalPenalty) * durationPenalty; - double sameInterval(SameRhythmHitObjects startObject, int intervalCount) + double sameInterval(SameRhythmGroupedHitObjects startObject, int intervalCount) { List intervals = new List(); var currentObject = startObject; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythm.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/IntervalGroupedHitObjects.cs similarity index 62% rename from osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythm.cs rename to osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/IntervalGroupedHitObjects.cs index b1ca22595b..930b3fc0e4 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythm.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/IntervalGroupedHitObjects.cs @@ -1,8 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using System.Collections.Generic; +using osu.Framework.Utils; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data { @@ -10,35 +10,26 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data /// A base class for grouping s by their interval. In edges where an interval change /// occurs, the is added to the group with the smaller interval. /// - public abstract class SameRhythm - where ChildType : IHasInterval + public abstract class IntervalGroupedHitObjects + where TChildType : IHasInterval { - public IReadOnlyList Children { get; private set; } + public IReadOnlyList Children { get; private set; } /// - /// Determines if the intervals between two child objects are within a specified margin of error, - /// indicating that the intervals are effectively "flat" or consistent. - /// - private bool isFlat(ChildType current, ChildType previous, double marginOfError) - { - return Math.Abs(current.Interval - previous.Interval) <= marginOfError; - } - - /// - /// Create a new from a list of s, and add + /// Create a new from a list of s, and add /// them to the list until the end of the group. /// /// The list of s. /// /// Index in to start adding children. This will be modified and should be passed into - /// the next 's constructor. + /// the next 's constructor. /// /// /// The margin of error for the interval, within of which no interval change is considered to have occured. /// - protected SameRhythm(List data, ref int i, double marginOfError) + protected IntervalGroupedHitObjects(List data, ref int i, double marginOfError) { - List children = new List(); + List children = new List(); Children = children; children.Add(data[i]); i++; @@ -46,9 +37,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data for (; i < data.Count - 1; i++) { // An interval change occured, add the current data if the next interval is larger. - if (!isFlat(data[i], data[i + 1], marginOfError)) + if (!Precision.AlmostEquals(data[i].Interval, data[i + 1].Interval, marginOfError)) { - if (data[i + 1].Interval > data[i].Interval + marginOfError) + if (Precision.DefinitelyBigger(data[i].Interval, data[i + 1].Interval, marginOfError)) { children.Add(data[i]); i++; @@ -63,7 +54,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data // 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 && isFlat(data[^1], data[^2], marginOfError)) + if (data.Count > 2 && Precision.AlmostEquals(data[^1].Interval, data[^2].Interval, marginOfError)) { children.Add(data[i]); i++; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SamePatterns.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SamePatternsGroupedHitObjects.cs similarity index 50% rename from osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SamePatterns.cs rename to osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SamePatternsGroupedHitObjects.cs index 50839c4561..d4cbc9c1f9 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SamePatterns.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SamePatternsGroupedHitObjects.cs @@ -7,21 +7,21 @@ using System.Linq; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data { /// - /// Represents grouped by their 's interval. + /// Represents grouped by their 's interval. /// - public class SamePatterns : SameRhythm + public class SamePatternsGroupedHitObjects : IntervalGroupedHitObjects { - public SamePatterns? Previous { get; private set; } + public SamePatternsGroupedHitObjects? Previous { get; private set; } /// - /// The between children within this group. - /// If there is only one child, this will have the value of the first child's . + /// The between children within this group. + /// If there is only one child, this will have the value of the first child's . /// public double ChildrenInterval => Children.Count > 1 ? Children[1].Interval : Children[0].Interval; /// - /// The ratio of between this and the previous . In the - /// case where there is no previous , this will have a value of 1. + /// The ratio of between this and the previous . In the + /// case where there is no previous , this will have a value of 1. /// public double IntervalRatio => ChildrenInterval / Previous?.ChildrenInterval ?? 1.0d; @@ -29,26 +29,26 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data public IEnumerable AllHitObjects => Children.SelectMany(child => child.Children); - private SamePatterns(SamePatterns? previous, List data, ref int i) + private SamePatternsGroupedHitObjects(SamePatternsGroupedHitObjects? previous, List data, ref int i) : base(data, ref i, 5) { Previous = previous; foreach (TaikoDifficultyHitObject hitObject in AllHitObjects) { - hitObject.Rhythm.SamePatterns = this; + hitObject.Rhythm.SamePatternsGroupedHitObjects = this; } } - public static void GroupPatterns(List data) + public static void GroupPatterns(List data) { - List samePatterns = new List(); + List samePatterns = new List(); - // Index does not need to be incremented, as it is handled within the SameRhythm constructor. + // Index does not need to be incremented, as it is handled within the IntervalGroupedHitObjects constructor. for (int i = 0; i < data.Count;) { - SamePatterns? previous = samePatterns.Count > 0 ? samePatterns[^1] : null; - samePatterns.Add(new SamePatterns(previous, data, ref i)); + SamePatternsGroupedHitObjects? previous = samePatterns.Count > 0 ? samePatterns[^1] : null; + samePatterns.Add(new SamePatternsGroupedHitObjects(previous, data, ref i)); } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmHitObjects.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmGroupedHitObjects.cs similarity index 70% rename from osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmHitObjects.cs rename to osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmGroupedHitObjects.cs index 0ccc6da026..0b59433a2e 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmHitObjects.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmGroupedHitObjects.cs @@ -9,11 +9,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data /// /// Represents a group of s with no rhythm variation. /// - public class SameRhythmHitObjects : SameRhythm, IHasInterval + public class SameRhythmGroupedHitObjects : IntervalGroupedHitObjects, IHasInterval { public TaikoDifficultyHitObject FirstHitObject => Children[0]; - public SameRhythmHitObjects? Previous; + public SameRhythmGroupedHitObjects? Previous; /// /// of the first hit object. @@ -26,30 +26,28 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data public double Duration => Children[^1].StartTime - Children[0].StartTime; /// - /// The interval in ms of each hit object in this . This is only defined if there is - /// more than two hit objects in this . + /// The interval in ms of each hit object in this . This is only defined if there is + /// more than two hit objects in this . /// public double? HitObjectInterval; /// - /// The ratio of between this and the previous . In the + /// The ratio of between this and the previous . In the /// case where one or both of the is undefined, this will have a value of 1. /// public double HitObjectIntervalRatio = 1; - /// - /// The interval between the of this and the previous . - /// - public double Interval { get; private set; } = double.PositiveInfinity; + /// + public double Interval { get; private set; } - public SameRhythmHitObjects(SameRhythmHitObjects? previous, List data, ref int i) + public SameRhythmGroupedHitObjects(SameRhythmGroupedHitObjects? previous, List data, ref int i) : base(data, ref i, 5) { Previous = previous; foreach (var hitObject in Children) { - hitObject.Rhythm.SameRhythmHitObjects = this; + hitObject.Rhythm.SameRhythmGroupedHitObjects = this; // Pass the HitObjectInterval to each child. hitObject.HitObjectInterval = HitObjectInterval; @@ -58,15 +56,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data calculateIntervals(); } - public static List GroupHitObjects(List data) + public static List GroupHitObjects(List data) { - List flatPatterns = new List(); + List flatPatterns = new List(); - // Index does not need to be incremented, as it is handled within SameRhythm's constructor. + // Index does not need to be incremented, as it is handled within IntervalGroupedHitObjects's constructor. for (int i = 0; i < data.Count;) { - SameRhythmHitObjects? previous = flatPatterns.Count > 0 ? flatPatterns[^1] : null; - flatPatterns.Add(new SameRhythmHitObjects(previous, data, ref i)); + SameRhythmGroupedHitObjects? previous = flatPatterns.Count > 0 ? flatPatterns[^1] : null; + flatPatterns.Add(new SameRhythmGroupedHitObjects(previous, data, ref i)); } return flatPatterns; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/TaikoDifficultyHitObjectRhythm.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/TaikoDifficultyHitObjectRhythm.cs index beb7bfe5f6..351015ae08 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/TaikoDifficultyHitObjectRhythm.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/TaikoDifficultyHitObjectRhythm.cs @@ -15,12 +15,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm /// /// The group of hit objects with consistent rhythm that this object belongs to. /// - public SameRhythmHitObjects? SameRhythmHitObjects; + public SameRhythmGroupedHitObjects? SameRhythmGroupedHitObjects; /// /// The larger pattern of rhythm groups that this object is part of. /// - public SamePatterns? SamePatterns; + public SamePatternsGroupedHitObjects? SamePatternsGroupedHitObjects; /// /// The ratio of current