From 8a6733ad87517135175a127657526b1a65e18227 Mon Sep 17 00:00:00 2001 From: Jay Lawton Date: Thu, 26 Dec 2024 21:16:28 +1000 Subject: [PATCH 1/9] fix colour --- .../Difficulty/Evaluators/ColourEvaluator.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 25428c8b2fd3..3ee9f36cbb68 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -36,18 +36,64 @@ public static double EvaluateDifficultyOf(RepeatingHitPatterns repeatingHitPatte return 2 * (1 - DifficultyCalculationUtils.Logistic(exponent: Math.E * repeatingHitPattern.RepetitionInterval - 2 * Math.E)); } + /// + /// Calculates a consistency penalty based on the number of consecutive consistent intervals, + /// considering the delta time between each colour sequence. + /// + /// The current hitObject to consider. + /// The allowable margin of error for determining whether ratios are consistent. + private static double consistentRatioPenalty(TaikoDifficultyHitObject hitObject, double threshold = 0.01) + { + int consistentRatioCount = 0; + double totalRatioCount = 0.0; + + TaikoDifficultyHitObject current = hitObject; + + while (current.Previous(1) is TaikoDifficultyHitObject previousHitObject) + { + double currentRatio = current.Rhythm.Ratio; + double previousRatio = previousHitObject.Rhythm.Ratio; + + // If there's no valid hit object before the previous one, break the loop. + if (previousHitObject.Previous(1) is not TaikoDifficultyHitObject) + break; + + // A consistent interval is defined as the percentage difference between the two rhythmic ratios with the margin of error. + if (Math.Abs(1 - currentRatio / previousRatio) <= threshold) + { + consistentRatioCount++; + totalRatioCount += currentRatio; + } + + current = previousHitObject; + } + + double ratioPenalty = 1 - totalRatioCount / (consistentRatioCount + 1) * 0.15; + + return 1.0 - (1 - ratioPenalty); + } + + /// + /// Evaluate the difficulty of the first hitobject within a colour streak. + /// public static double EvaluateDifficultyOf(DifficultyHitObject hitObject) { TaikoDifficultyHitObjectColour colour = ((TaikoDifficultyHitObject)hitObject).Colour; + var taikoObject = (TaikoDifficultyHitObject)hitObject; double difficulty = 0.0d; if (colour.MonoStreak?.FirstHitObject == hitObject) // Difficulty for MonoStreak difficulty += EvaluateDifficultyOf(colour.MonoStreak); + if (colour.AlternatingMonoPattern?.FirstHitObject == hitObject) // Difficulty for AlternatingMonoPattern difficulty += EvaluateDifficultyOf(colour.AlternatingMonoPattern); + if (colour.RepeatingHitPattern?.FirstHitObject == hitObject) // Difficulty for RepeatingHitPattern difficulty += EvaluateDifficultyOf(colour.RepeatingHitPattern); + double consistencyPenalty = consistentRatioPenalty(taikoObject); + difficulty *= consistencyPenalty; + return difficulty; } } From 41e052b172a72ad3cc2414aad65a3afbd82f6b80 Mon Sep 17 00:00:00 2001 From: Jay Lawton Date: Thu, 26 Dec 2024 22:14:41 +1000 Subject: [PATCH 2/9] review fix Co-authored-by: StanR --- .../Difficulty/Evaluators/ColourEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 3ee9f36cbb68..de87a52252f2 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -78,8 +78,8 @@ private static double consistentRatioPenalty(TaikoDifficultyHitObject hitObject, /// public static double EvaluateDifficultyOf(DifficultyHitObject hitObject) { - TaikoDifficultyHitObjectColour colour = ((TaikoDifficultyHitObject)hitObject).Colour; var taikoObject = (TaikoDifficultyHitObject)hitObject; + TaikoDifficultyHitObjectColour colour = taikoObject.Colour; double difficulty = 0.0d; if (colour.MonoStreak?.FirstHitObject == hitObject) // Difficulty for MonoStreak From ac1bda06dc4e97418b46577c338a1ed94f5d7cb5 Mon Sep 17 00:00:00 2001 From: Jay Lawton Date: Fri, 27 Dec 2024 20:41:04 +1000 Subject: [PATCH 3/9] remove cancelled out operand --- .../Difficulty/Evaluators/ColourEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index de87a52252f2..1f5f3ce54490 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -70,7 +70,7 @@ private static double consistentRatioPenalty(TaikoDifficultyHitObject hitObject, double ratioPenalty = 1 - totalRatioCount / (consistentRatioCount + 1) * 0.15; - return 1.0 - (1 - ratioPenalty); + return ratioPenalty; } /// From 82fa235e226930e3f0b6b529cf684885dc6344bc Mon Sep 17 00:00:00 2001 From: Jay Lawton Date: Sun, 29 Dec 2024 20:42:15 +1000 Subject: [PATCH 4/9] increase nerf, adjust tests --- .../TaikoDifficultyCalculatorTest.cs | 8 ++++---- .../Difficulty/Evaluators/ColourEvaluator.cs | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs index 09d6540f7266..361d54a9d584 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs @@ -14,13 +14,13 @@ public class TaikoDifficultyCalculatorTest : DifficultyCalculatorTest { protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko"; - [TestCase(3.0920212594351191d, 200, "diffcalc-test")] - [TestCase(3.0920212594351191d, 200, "diffcalc-test-strong")] + [TestCase(2.9028399902546886d, 200, "diffcalc-test")] + [TestCase(2.9028399902546886d, 200, "diffcalc-test-strong")] public void Test(double expectedStarRating, int expectedMaxCombo, string name) => base.Test(expectedStarRating, expectedMaxCombo, name); - [TestCase(4.0789820318081444d, 200, "diffcalc-test")] - [TestCase(4.0789820318081444d, 200, "diffcalc-test-strong")] + [TestCase(3.8741038430570431d, 200, "diffcalc-test")] + [TestCase(3.8741038430570431d, 200, "diffcalc-test-strong")] public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new TaikoModDoubleTime()); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 1f5f3ce54490..e84019f0e8ca 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -1,3 +1,4 @@ + // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. @@ -68,7 +69,7 @@ private static double consistentRatioPenalty(TaikoDifficultyHitObject hitObject, current = previousHitObject; } - double ratioPenalty = 1 - totalRatioCount / (consistentRatioCount + 1) * 0.15; + double ratioPenalty = 1 - totalRatioCount / (consistentRatioCount + 1) * 0.30; return ratioPenalty; } From 33076269006d3102baa6bfd1bcf235cf4c241ccd Mon Sep 17 00:00:00 2001 From: Jay Lawton Date: Tue, 7 Jan 2025 19:00:23 +1000 Subject: [PATCH 5/9] fix automated spacing issues --- osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs | 1 - osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs index ed9f88a34078..361d54a9d584 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs @@ -21,7 +21,6 @@ public void Test(double expectedStarRating, int expectedMaxCombo, string name) [TestCase(3.8741038430570431d, 200, "diffcalc-test")] [TestCase(3.8741038430570431d, 200, "diffcalc-test-strong")] - public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new TaikoModDoubleTime()); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index e84019f0e8ca..ea15eaa66d11 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -1,4 +1,3 @@ - // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. From ffb08c4cd34f496e8f51a62dd9b4b7bd67158edd Mon Sep 17 00:00:00 2001 From: Jay Lawton Date: Tue, 7 Jan 2025 19:02:43 +1000 Subject: [PATCH 6/9] up penalty --- .../Difficulty/Evaluators/ColourEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index ea15eaa66d11..364ed8487786 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -68,7 +68,7 @@ private static double consistentRatioPenalty(TaikoDifficultyHitObject hitObject, current = previousHitObject; } - double ratioPenalty = 1 - totalRatioCount / (consistentRatioCount + 1) * 0.30; + double ratioPenalty = 1 - totalRatioCount / (consistentRatioCount + 1) * 0.40; return ratioPenalty; } From 8522dbd4335323338d889b9287b638be1f422783 Mon Sep 17 00:00:00 2001 From: Jay Lawton Date: Tue, 7 Jan 2025 19:05:52 +1000 Subject: [PATCH 7/9] adjust tests --- .../TaikoDifficultyCalculatorTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs index 361d54a9d584..1a8f4e3f0829 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs @@ -14,13 +14,13 @@ public class TaikoDifficultyCalculatorTest : DifficultyCalculatorTest { protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko"; - [TestCase(2.9028399902546886d, 200, "diffcalc-test")] - [TestCase(2.9028399902546886d, 200, "diffcalc-test-strong")] + [TestCase(2.8492342476337797d, 200, "diffcalc-test")] + [TestCase(2.8492342476337797d, 200, "diffcalc-test-strong")] public void Test(double expectedStarRating, int expectedMaxCombo, string name) => base.Test(expectedStarRating, expectedMaxCombo, name); - [TestCase(3.8741038430570431d, 200, "diffcalc-test")] - [TestCase(3.8741038430570431d, 200, "diffcalc-test-strong")] + [TestCase(3.8179679353183031d, 200, "diffcalc-test")] + [TestCase(3.8179679353183031d, 200, "diffcalc-test-strong")] public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new TaikoModDoubleTime()); From 46ce8b300e847326095c816df0572eff8b403f9b Mon Sep 17 00:00:00 2001 From: Jay Lawton Date: Tue, 7 Jan 2025 20:25:56 +1000 Subject: [PATCH 8/9] apply review changes --- .../TaikoDifficultyCalculatorTest.cs | 8 ++++---- .../Difficulty/Evaluators/ColourEvaluator.cs | 19 +++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs index 1a8f4e3f0829..de3bec5fcf2d 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs @@ -14,13 +14,13 @@ public class TaikoDifficultyCalculatorTest : DifficultyCalculatorTest { protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko"; - [TestCase(2.8492342476337797d, 200, "diffcalc-test")] - [TestCase(2.8492342476337797d, 200, "diffcalc-test-strong")] + [TestCase(2.837609165845338d, 200, "diffcalc-test")] + [TestCase(2.837609165845338d, 200, "diffcalc-test-strong")] public void Test(double expectedStarRating, int expectedMaxCombo, string name) => base.Test(expectedStarRating, expectedMaxCombo, name); - [TestCase(3.8179679353183031d, 200, "diffcalc-test")] - [TestCase(3.8179679353183031d, 200, "diffcalc-test-strong")] + [TestCase(3.8005218640444949, 200, "diffcalc-test")] + [TestCase(3.8005218640444949, 200, "diffcalc-test-strong")] public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new TaikoModDoubleTime()); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 364ed8487786..09d1d2e985a5 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -42,33 +42,36 @@ public static double EvaluateDifficultyOf(RepeatingHitPatterns repeatingHitPatte /// /// The current hitObject to consider. /// The allowable margin of error for determining whether ratios are consistent. - private static double consistentRatioPenalty(TaikoDifficultyHitObject hitObject, double threshold = 0.01) + /// The maximum objects to check per count of consistent ratio. + private static double consistentRatioPenalty(TaikoDifficultyHitObject? hitObject, double threshold = 0.01, int maxObjectsToCheck = 64) { int consistentRatioCount = 0; double totalRatioCount = 0.0; - TaikoDifficultyHitObject current = hitObject; + TaikoDifficultyHitObject? current = hitObject; - while (current.Previous(1) is TaikoDifficultyHitObject previousHitObject) + for (int i = 0; i < maxObjectsToCheck; i++) { + // If there is no previous or current object to check, break the loop. + if (current?.Previous(1) is not TaikoDifficultyHitObject previousHitObject || previousHitObject.Index <= 1) + break; + double currentRatio = current.Rhythm.Ratio; double previousRatio = previousHitObject.Rhythm.Ratio; - // If there's no valid hit object before the previous one, break the loop. - if (previousHitObject.Previous(1) is not TaikoDifficultyHitObject) - break; - // A consistent interval is defined as the percentage difference between the two rhythmic ratios with the margin of error. if (Math.Abs(1 - currentRatio / previousRatio) <= threshold) { consistentRatioCount++; totalRatioCount += currentRatio; + break; } current = previousHitObject; } - double ratioPenalty = 1 - totalRatioCount / (consistentRatioCount + 1) * 0.40; + // Ensure no division by zero + double ratioPenalty = 1 - totalRatioCount / (consistentRatioCount + 1) * 0.80; return ratioPenalty; } From 8fb4b160ff2b8538d57bb758fa5289a48d534242 Mon Sep 17 00:00:00 2001 From: Jay Lawton Date: Tue, 7 Jan 2025 20:55:40 +1000 Subject: [PATCH 9/9] fix nullable hell --- .../Difficulty/Evaluators/ColourEvaluator.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 09d1d2e985a5..3ff5b87fb6cf 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -43,19 +43,21 @@ public static double EvaluateDifficultyOf(RepeatingHitPatterns repeatingHitPatte /// The current hitObject to consider. /// The allowable margin of error for determining whether ratios are consistent. /// The maximum objects to check per count of consistent ratio. - private static double consistentRatioPenalty(TaikoDifficultyHitObject? hitObject, double threshold = 0.01, int maxObjectsToCheck = 64) + private static double consistentRatioPenalty(TaikoDifficultyHitObject hitObject, double threshold = 0.01, int maxObjectsToCheck = 64) { int consistentRatioCount = 0; double totalRatioCount = 0.0; - TaikoDifficultyHitObject? current = hitObject; + TaikoDifficultyHitObject current = hitObject; for (int i = 0; i < maxObjectsToCheck; i++) { - // If there is no previous or current object to check, break the loop. - if (current?.Previous(1) is not TaikoDifficultyHitObject previousHitObject || previousHitObject.Index <= 1) + // Break if there is no valid previous object + if (current.Index <= 1) break; + var previousHitObject = (TaikoDifficultyHitObject)current.Previous(1); + double currentRatio = current.Rhythm.Ratio; double previousRatio = previousHitObject.Rhythm.Ratio; @@ -67,6 +69,7 @@ private static double consistentRatioPenalty(TaikoDifficultyHitObject? hitObject break; } + // Move to the previous object current = previousHitObject; }