From cba47f82020b6c283e3b01c341c41949d5fb88da Mon Sep 17 00:00:00 2001 From: vun Date: Tue, 28 Jun 2022 10:38:58 +0800 Subject: [PATCH] [WIP] Colour evaluator for new colour encoding --- .../Difficulty/Evaluators/ColourEvaluator.cs | 14 +++++++++-- .../Difficulty/Evaluators/StaminaEvaluator.cs | 5 ++-- .../Preprocessing/ColourEncoding.cs | 17 ++++++++++--- .../Preprocessing/TaikoDifficultyHitObject.cs | 15 +++-------- .../TaikoDifficultyHitObjectColour.cs | 19 ++++++-------- .../Difficulty/Skills/Colour.cs | 25 +++++++++++++------ .../Difficulty/Skills/Peaks.cs | 9 +++---- 7 files changed, 61 insertions(+), 43 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 1627833e8a..60898fe92d 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -12,9 +12,19 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators return Math.Tanh(Math.E * -(val - center) / width); } - public static double EvaluateDifficultyOf(TaikoDifficultyHitObjectColour colour) + public static double EvaluateDifficultyOf(TaikoDifficultyHitObjectColour? colour) { - return 1; + if (colour == null) return 0; + + double difficulty = 7.5 * Math.Log(colour.Encoding.Payload.Length + 1, 10); + // foreach (ColourEncoding encoding in colour.Encoding.Payload) + // { + // difficulty += sigmoid(encoding.MonoRunLength, 1, 1) * 0.4 + 0.6; + // } + difficulty *= -sigmoid(colour.RepetitionInterval, 1, 7); + // difficulty *= -sigmoid(colour.RepetitionInterval, 2, 2) * 0.5 + 0.5; + + return difficulty; } public static double EvaluateDifficultyOf(DifficultyHitObject current) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index be1514891c..9ebdc90eb8 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -16,7 +16,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// The interval between the current and previous note hit using the same key. private static double speedBonus(double interval) { - return Math.Pow(0.8, interval / 1000); + // return 10 / Math.Pow(interval, 0.6); + return Math.Pow(0.1, interval / 1000); } /// @@ -40,7 +41,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators return 0.0; } - double objectStrain = 0.85; + double objectStrain = 1; objectStrain *= speedBonus(taikoCurrent.StartTime - keyPrevious.StartTime); return objectStrain; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/ColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/ColourEncoding.cs index e2ac40170e..c090e7aada 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/ColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/ColourEncoding.cs @@ -14,7 +14,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// Amount of consecutive encoding with the same /// public int EncodingRunLength = 1; - + + /// + /// How many notes are encoded with this encoding + /// + public int NoteLength => MonoRunLength + EncodingRunLength; + /// /// Beginning index in the data that this encodes /// @@ -27,7 +32,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing public static List Encode(List data) { - // Encoding mono lengths + // Compute mono lengths List firstPass = new List(); ColourEncoding? lastEncoded = null; for (int i = 0; i < data.Count; i++) @@ -36,7 +41,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing // This ignores all non-note objects, which may or may not be the desired behaviour TaikoDifficultyHitObject previousObject = (TaikoDifficultyHitObject)taikoObject.PreviousNote(0); - if (previousObject == null || lastEncoded == null || taikoObject.HitType != previousObject.HitType) + if ( + previousObject == null || + lastEncoded == null || + taikoObject.HitType != previousObject.HitType || + taikoObject.Rhythm.Ratio > 1.9) // Reset colour after a slow down of 2x (set as 1.9x for margin of error) { lastEncoded = new ColourEncoding(); lastEncoded.StartIndex = i; @@ -47,7 +56,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing lastEncoded.MonoRunLength += 1; } - // Encode encoding lengths + // Compute encoding lengths List secondPass = new List(); lastEncoded = null; for (int i = 0; i < firstPass.Count; i++) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index 1ee905d94c..7c9188b100 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -19,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public class TaikoDifficultyHitObject : DifficultyHitObject { - private readonly IReadOnlyList monoDifficultyHitObjects; + private readonly IReadOnlyList? monoDifficultyHitObjects; public readonly int MonoIndex; private readonly IReadOnlyList noteObjects; public readonly int NoteIndex; @@ -34,7 +32,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// by other skills in the future. /// This need to be writeable by TaikoDifficultyHitObjectColour so that it can assign potentially reused instances /// - public TaikoDifficultyHitObjectColour Colour; + public TaikoDifficultyHitObjectColour? Colour; /// /// The hit type of this hit object. @@ -65,14 +63,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing centreObjects, rimObjects, noteObjects, difficultyHitObjects.Count) ); } - - List colours = TaikoDifficultyHitObjectColour.EncodeAndAssign(difficultyHitObjects); - - // Pre-evaluate colours - for (int i = 0; i < colours.Count; i++) - { - colours[i].EvaluatedDifficulty = ColourEvaluator.EvaluateDifficultyOf(colours[i]); - } + TaikoDifficultyHitObjectColour.EncodeAndAssign(difficultyHitObjects); return difficultyHitObjects; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs index 6bd99550be..7e18332fab 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs @@ -5,12 +5,11 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing { /// - /// Stores colour compression information for a . + /// Stores colour compression information for a . This is only present for the + /// first in a chunk. /// public class TaikoDifficultyHitObjectColour { - public CoupledColourEncoding Encoding { get; private set; } - private const int max_repetition_interval = 16; /// @@ -21,11 +20,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing public int RepetitionInterval { get; private set; } = max_repetition_interval + 1; /// - /// Evaluated colour difficulty is cached here, as difficulty don't need to be calculated per-note. + /// Encoding information of . /// - /// TODO: Consider having all evaluated difficulty cached in TaikoDifficultyHitObject instead, since we may be - /// reusing evaluator results in the future. - public double EvaluatedDifficulty = 0; + public CoupledColourEncoding Encoding { get; private set; } public TaikoDifficultyHitObjectColour? Previous { get; private set; } = null; @@ -60,8 +57,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing } /// - /// Finds the closest previous that has the identical delta value - /// and run length with the current instance, and returns the amount of notes between them. + /// Finds the closest previous that has the identical . + /// Interval is defined as the amount of chunks between the current and repeated encoding. /// public void FindRepetitionInterval() { @@ -72,7 +69,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing } TaikoDifficultyHitObjectColour? other = Previous.Previous; - int interval = this.Encoding.StartIndex - other.Encoding.EndIndex; + int interval = 2; while (interval < max_repetition_interval) { if (Encoding.hasIdenticalPayload(other.Encoding)) @@ -84,7 +81,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing other = other.Previous; if (other == null) break; - interval = this.Encoding.StartIndex - other.Encoding.EndIndex; + ++interval; } RepetitionInterval = max_repetition_interval + 1; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index bf359f0d64..c0dafc73b5 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs @@ -1,12 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { @@ -18,6 +18,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills protected override double SkillMultiplier => 1; protected override double StrainDecayBase => 0.4; + /// + /// Applies a speed bonus dependent on the time since the last hit. + /// + /// The interval between the current and previous note hit using the same key. + private static double speedBonus(double interval) + { + return Math.Pow(0.4, interval / 1000); + } + public Colour(Mod[] mods) : base(mods) { @@ -25,18 +34,20 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills protected override double StrainValueOf(DifficultyHitObject current) { - TaikoDifficultyHitObjectColour colour = ((TaikoDifficultyHitObject)current).Colour; - double difficulty = colour == null ? 0 : colour.EvaluatedDifficulty; - // if (current != null && colour != null) + double difficulty = ColourEvaluator.EvaluateDifficultyOf(current); + // difficulty *= speedBonus(current.DeltaTime); + // TaikoDifficultyHitObject? taikoCurrent = (TaikoDifficultyHitObject)current; + // TaikoDifficultyHitObjectColour? colour = taikoCurrent?.Colour; + // if (taikoCurrent != null && colour != null) // { // ColourEncoding[] payload = colour.Encoding.Payload; // string payloadDisplay = ""; // for (int i = 0; i < payload.Length; ++i) // { - // payloadDisplay += $",({payload[i].MonoRunLength},{payload[i].EncodingRunLength})"; + // payloadDisplay += $",({payload[i].MonoRunLength}|{payload[i].EncodingRunLength})"; // } - // System.Console.WriteLine($"{current.StartTime},{colour.RepetitionInterval},{colour.Encoding.RunLength}{payloadDisplay}"); + // System.Console.WriteLine($"{current.StartTime},{difficulty},{colour.RepetitionInterval},{colour.Encoding.RunLength}{payloadDisplay}"); // } return difficulty; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs index ebbe027f9e..7b6fb7d102 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs @@ -4,17 +4,16 @@ using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { public class Peaks : Skill { - private const double rhythm_skill_multiplier = 0.32 * final_multiplier; - private const double colour_skill_multiplier = 0.33 * final_multiplier; - private const double stamina_skill_multiplier = 0.4 * final_multiplier; + private const double rhythm_skill_multiplier = 0.3 * final_multiplier; + private const double colour_skill_multiplier = 0.39 * final_multiplier; + private const double stamina_skill_multiplier = 0.33 * final_multiplier; - private const double final_multiplier = 0.047; + private const double final_multiplier = 0.06; private readonly Rhythm rhythm; private readonly Colour colour;