TAIKO-6 Pre-evaluate colour to avoid per-note evaluation

This commit is contained in:
vun
2022-06-23 17:10:30 +08:00
parent c5fd48372b
commit f42aac9954
4 changed files with 72 additions and 37 deletions

View File

@ -12,10 +12,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
return Math.Tanh(Math.E * -(val - center) / width);
}
public static double EvaluateDifficultyOf(DifficultyHitObject current)
public static double EvaluateDifficultyOf(TaikoDifficultyHitObjectColour colour)
{
TaikoDifficultyHitObject taikoCurrent = (TaikoDifficultyHitObject)current;
TaikoDifficultyHitObjectColour colour = taikoCurrent.Colour;
if (colour == null) return 0;
double objectStrain = 1.85;
@ -29,9 +27,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
objectStrain *= sigmoid(colour.DeltaRunLength, 2, 2) * 0.5 + 0.5;
}
objectStrain *= -sigmoid(colour.RepetitionInterval, 1, 8); // * 0.5 + 0.5;
// Console.WriteLine($"{current.StartTime},{colour.Delta},{colour.RepetitionInterval},{objectStrain}");
objectStrain *= -sigmoid(colour.RepetitionInterval, 1, 8);
return objectStrain;
}
public static double EvaluateDifficultyOf(DifficultyHitObject current)
{
return EvaluateDifficultyOf(((TaikoDifficultyHitObject)current).Colour);
}
}
}

View File

@ -10,6 +10,7 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Difficulty.Evaluators;
namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
{
@ -29,10 +30,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
public readonly TaikoDifficultyHitObjectRhythm Rhythm;
/// <summary>
/// Colour data for this hit object. This is used by colour evaluator to calculate colour, but can be used
/// differently by other skills in the future.
/// Colour data for this hit object. This is used by colour evaluator to calculate colour difficulty, but can be used
/// by other skills in the future.
/// This need to be writeable by TaikoDifficultyHitObjectColour so that it can assign potentially reused instances
/// </summary>
public readonly TaikoDifficultyHitObjectColour Colour;
public TaikoDifficultyHitObjectColour Colour;
/// <summary>
/// The hit type of this hit object.
@ -64,8 +66,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
);
}
// Find repetition interval for the final TaikoDifficultyHitObjectColour
((TaikoDifficultyHitObject)difficultyHitObject.Last()).Colour?.FindRepetitionInterval();
List<TaikoDifficultyHitObjectColour> colours = TaikoDifficultyHitObjectColour.CreateColoursFor(difficultyHitObject);
// Pre-evaluate colours
for (int i = 0; i < colours.Count; i++)
{
colours[i].EvaluatedDifficulty = ColourEvaluator.EvaluateDifficultyOf(colours[i]);
}
return difficultyHitObject;
}
@ -115,9 +123,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
NoteIndex = noteObjects.Count;
noteObjects.Add(this);
// Need to be done after NoteIndex is set.
Colour = TaikoDifficultyHitObjectColour.GetInstanceFor(this);
}
/// <summary>

View File

@ -1,6 +1,8 @@
#nullable disable
using System;
using System.Collections.Generic;
using osu.Game.Rulesets.Difficulty.Preprocessing;
namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
{
@ -11,7 +13,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
{
private const int max_repetition_interval = 16;
private TaikoDifficultyHitObjectColour previous;
public TaikoDifficultyHitObjectColour Previous { get; private set; }
/// <summary>
/// True if the current colour is different from the previous colour.
@ -30,35 +32,54 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
/// </summary>
public int RepetitionInterval { get; private set; }
/// <summary>
/// Evaluated colour difficulty is cached here, as difficulty don't need to be calculated per-note.
/// </summary>
/// TODO: Consider having all evaluated difficulty cached in TaikoDifficultyHitObject instead, since we may be
/// reusing evaluator results in the future.
public double EvaluatedDifficulty;
public TaikoDifficultyHitObjectColour repeatedColour { get; private set; }
/// <summary>
/// Get the <see cref="TaikoDifficultyHitObjectColour"/> instance for the given hitObject. This is implemented
/// as a static function instead of constructor to allow for reusing existing instances.
/// TODO: findRepetitionInterval needs to be called a final time after all hitObjects have been processed.
/// </summary>
public static TaikoDifficultyHitObjectColour GetInstanceFor(TaikoDifficultyHitObject hitObject)
public static List<TaikoDifficultyHitObjectColour> CreateColoursFor(List<DifficultyHitObject> hitObjects)
{
TaikoDifficultyHitObject lastObject = hitObject.PreviousNote(0);
TaikoDifficultyHitObjectColour previous = lastObject?.Colour;
bool delta = lastObject == null || hitObject.HitType != lastObject.HitType;
List<TaikoDifficultyHitObjectColour> colours = new List<TaikoDifficultyHitObjectColour>();
if (previous != null && delta == previous.Delta)
for (int i = 0; i < hitObjects.Count; i++)
{
previous.DeltaRunLength += 1;
return previous;
TaikoDifficultyHitObject hitObject = (TaikoDifficultyHitObject)hitObjects[i];
TaikoDifficultyHitObject lastObject = hitObject.PreviousNote(0);
TaikoDifficultyHitObjectColour previous = lastObject?.Colour;
bool delta = lastObject == null || hitObject.HitType != lastObject.HitType;
if (previous != null && delta == previous.Delta)
{
previous.DeltaRunLength += 1;
hitObject.Colour = previous;
continue;
}
TaikoDifficultyHitObjectColour colour = new TaikoDifficultyHitObjectColour()
{
Delta = delta,
DeltaRunLength = 1,
RepetitionInterval = max_repetition_interval + 1,
Previous = previous
};
hitObject.Colour = colour;
colours.Add(colour);
}
// Calculate RepetitionInterval for previous
previous?.FindRepetitionInterval();
return new TaikoDifficultyHitObjectColour()
for (int i = 0; i < colours.Count; i++)
{
Delta = delta,
DeltaRunLength = 1,
RepetitionInterval = max_repetition_interval + 1,
previous = previous
};
colours[i].FindRepetitionInterval();
}
return colours;
}
/// <summary>
@ -67,14 +88,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
/// </summary>
public void FindRepetitionInterval()
{
if (previous?.previous == null)
if (Previous?.Previous == null)
{
RepetitionInterval = max_repetition_interval + 1;
return;
}
int interval = previous.DeltaRunLength;
TaikoDifficultyHitObjectColour other = previous.previous;
int interval = Previous.DeltaRunLength;
TaikoDifficultyHitObjectColour other = Previous.Previous;
while (other != null && interval < max_repetition_interval)
{
@ -86,7 +107,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
}
interval += other.DeltaRunLength;
other = other.previous;
other = other.Previous;
}
RepetitionInterval = max_repetition_interval + 1;

View File

@ -6,7 +6,7 @@
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Difficulty.Skills;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.Difficulty.Evaluators;
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing;
namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
{
@ -25,7 +25,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
protected override double StrainValueOf(DifficultyHitObject current)
{
return ColourEvaluator.EvaluateDifficultyOf(current);
TaikoDifficultyHitObjectColour colour = ((TaikoDifficultyHitObject)current).Colour;
double difficulty = colour == null ? 0 : colour.EvaluatedDifficulty;
// if (current != null && colour != null)
// {
// System.Console.WriteLine($"{current.StartTime},{colour.Delta},{colour.RepetitionInterval},{difficulty}");
// }
return difficulty;
}
}
}