mirror of
https://github.com/osukey/osukey.git
synced 2025-05-09 23:57:18 +09:00
Implement new colour encoding
This commit is contained in:
parent
f42aac9954
commit
15372267e1
@ -14,21 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
|
|||||||
|
|
||||||
public static double EvaluateDifficultyOf(TaikoDifficultyHitObjectColour colour)
|
public static double EvaluateDifficultyOf(TaikoDifficultyHitObjectColour colour)
|
||||||
{
|
{
|
||||||
if (colour == null) return 0;
|
return 1;
|
||||||
|
|
||||||
double objectStrain = 1.85;
|
|
||||||
|
|
||||||
if (colour.Delta)
|
|
||||||
{
|
|
||||||
objectStrain *= sigmoid(colour.DeltaRunLength, 3, 3) * 0.5 + 0.5;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
objectStrain *= sigmoid(colour.DeltaRunLength, 2, 2) * 0.5 + 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
objectStrain *= -sigmoid(colour.RepetitionInterval, 1, 8);
|
|
||||||
return objectStrain;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double EvaluateDifficultyOf(DifficultyHitObject current)
|
public static double EvaluateDifficultyOf(DifficultyHitObject current)
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
|
||||||
|
{
|
||||||
|
public class ColourEncoding
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Amount consecutive notes of the same colour
|
||||||
|
/// </summary>
|
||||||
|
public int MonoRunLength = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Amount of consecutive encoding with the same <see cref="MonoRunLength" />
|
||||||
|
/// </summary>
|
||||||
|
public int EncodingRunLength = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Beginning index in the data that this encodes
|
||||||
|
/// </summary>
|
||||||
|
public int StartIndex = 0;
|
||||||
|
|
||||||
|
public bool isIdenticalTo(ColourEncoding other)
|
||||||
|
{
|
||||||
|
return other.MonoRunLength == MonoRunLength && other.EncodingRunLength == EncodingRunLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<ColourEncoding> Encode(List<DifficultyHitObject> data)
|
||||||
|
{
|
||||||
|
// Encoding mono lengths
|
||||||
|
List<ColourEncoding> firstPass = new List<ColourEncoding>();
|
||||||
|
ColourEncoding? lastEncoded = null;
|
||||||
|
for (int i = 0; i < data.Count; i++)
|
||||||
|
{
|
||||||
|
TaikoDifficultyHitObject taikoObject = (TaikoDifficultyHitObject)data[i];
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
lastEncoded = new ColourEncoding();
|
||||||
|
lastEncoded.StartIndex = i;
|
||||||
|
firstPass.Add(lastEncoded);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastEncoded.MonoRunLength += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode encoding lengths
|
||||||
|
List<ColourEncoding> secondPass = new List<ColourEncoding>();
|
||||||
|
lastEncoded = null;
|
||||||
|
for (int i = 0; i < firstPass.Count; i++)
|
||||||
|
{
|
||||||
|
if (i == 0 || lastEncoded == null || firstPass[i].MonoRunLength != firstPass[i - 1].MonoRunLength)
|
||||||
|
{
|
||||||
|
lastEncoded = firstPass[i];
|
||||||
|
secondPass.Add(firstPass[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastEncoded.EncodingRunLength += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return secondPass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
|
||||||
|
{
|
||||||
|
public class CoupledColourEncoding
|
||||||
|
{
|
||||||
|
public int RunLength = 1;
|
||||||
|
|
||||||
|
public ColourEncoding[] Payload;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Beginning index in the data that this encodes
|
||||||
|
/// </summary>
|
||||||
|
public int StartIndex { get; private set; } = 0;
|
||||||
|
|
||||||
|
public int EndIndex { get; private set; } = 0;
|
||||||
|
|
||||||
|
private CoupledColourEncoding(ColourEncoding[] payload)
|
||||||
|
{
|
||||||
|
Payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<CoupledColourEncoding> Encode(List<ColourEncoding> data)
|
||||||
|
{
|
||||||
|
List<CoupledColourEncoding> encoded = new List<CoupledColourEncoding>();
|
||||||
|
|
||||||
|
CoupledColourEncoding? lastEncoded = null;
|
||||||
|
for (int i = 0; i < data.Count; i++)
|
||||||
|
{
|
||||||
|
if (lastEncoded != null) lastEncoded.EndIndex = data[i].StartIndex - 1;
|
||||||
|
|
||||||
|
if (i >= data.Count - 2 || !data[i].isIdenticalTo(data[i + 2]))
|
||||||
|
{
|
||||||
|
lastEncoded = new CoupledColourEncoding(new ColourEncoding[] { data[i] });
|
||||||
|
lastEncoded.StartIndex = data[i].StartIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastEncoded = new CoupledColourEncoding(new ColourEncoding[] { data[i], data[i + 1] });
|
||||||
|
lastEncoded.StartIndex = data[i].StartIndex;
|
||||||
|
lastEncoded.RunLength = 3;
|
||||||
|
i++;
|
||||||
|
|
||||||
|
// Peek 2 indices ahead
|
||||||
|
while (i < data.Count - 2 && data[i].isIdenticalTo(data[i + 2]))
|
||||||
|
{
|
||||||
|
lastEncoded.RunLength += 1;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip over peeked data
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
encoded.Add(lastEncoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool hasIdenticalPayload(CoupledColourEncoding other)
|
||||||
|
{
|
||||||
|
if (this.Payload.Length != other.Payload.Length) return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < this.Payload.Length; i++)
|
||||||
|
{
|
||||||
|
if (!this.Payload[i].isIdenticalTo(other.Payload[i])) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -52,21 +52,21 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
|
|||||||
/// <param name="clockRate">The rate at which the gameplay clock is run at.</param>
|
/// <param name="clockRate">The rate at which the gameplay clock is run at.</param>
|
||||||
public static List<DifficultyHitObject> Create(IBeatmap beatmap, double clockRate)
|
public static List<DifficultyHitObject> Create(IBeatmap beatmap, double clockRate)
|
||||||
{
|
{
|
||||||
List<DifficultyHitObject> difficultyHitObject = new List<DifficultyHitObject>();
|
List<DifficultyHitObject> difficultyHitObjects = new List<DifficultyHitObject>();
|
||||||
List<TaikoDifficultyHitObject> centreObjects = new List<TaikoDifficultyHitObject>();
|
List<TaikoDifficultyHitObject> centreObjects = new List<TaikoDifficultyHitObject>();
|
||||||
List<TaikoDifficultyHitObject> rimObjects = new List<TaikoDifficultyHitObject>();
|
List<TaikoDifficultyHitObject> rimObjects = new List<TaikoDifficultyHitObject>();
|
||||||
List<TaikoDifficultyHitObject> noteObjects = new List<TaikoDifficultyHitObject>();
|
List<TaikoDifficultyHitObject> noteObjects = new List<TaikoDifficultyHitObject>();
|
||||||
|
|
||||||
for (int i = 2; i < beatmap.HitObjects.Count; i++)
|
for (int i = 2; i < beatmap.HitObjects.Count; i++)
|
||||||
{
|
{
|
||||||
difficultyHitObject.Add(
|
difficultyHitObjects.Add(
|
||||||
new TaikoDifficultyHitObject(
|
new TaikoDifficultyHitObject(
|
||||||
beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], clockRate, difficultyHitObject,
|
beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], clockRate, difficultyHitObjects,
|
||||||
centreObjects, rimObjects, noteObjects, difficultyHitObject.Count)
|
centreObjects, rimObjects, noteObjects, difficultyHitObjects.Count)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<TaikoDifficultyHitObjectColour> colours = TaikoDifficultyHitObjectColour.CreateColoursFor(difficultyHitObject);
|
List<TaikoDifficultyHitObjectColour> colours = TaikoDifficultyHitObjectColour.EncodeAndAssign(difficultyHitObjects);
|
||||||
|
|
||||||
// Pre-evaluate colours
|
// Pre-evaluate colours
|
||||||
for (int i = 0; i < colours.Count; i++)
|
for (int i = 0; i < colours.Count; i++)
|
||||||
@ -74,7 +74,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
|
|||||||
colours[i].EvaluatedDifficulty = ColourEvaluator.EvaluateDifficultyOf(colours[i]);
|
colours[i].EvaluatedDifficulty = ColourEvaluator.EvaluateDifficultyOf(colours[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return difficultyHitObject;
|
return difficultyHitObjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||||
@ -11,72 +9,51 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class TaikoDifficultyHitObjectColour
|
public class TaikoDifficultyHitObjectColour
|
||||||
{
|
{
|
||||||
|
public CoupledColourEncoding Encoding { get; private set; }
|
||||||
|
|
||||||
private const int max_repetition_interval = 16;
|
private const int max_repetition_interval = 16;
|
||||||
|
|
||||||
public TaikoDifficultyHitObjectColour Previous { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// True if the current colour is different from the previous colour.
|
|
||||||
/// </summary>
|
|
||||||
public bool Delta { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// How many notes are Delta repeated
|
|
||||||
/// </summary>
|
|
||||||
public int DeltaRunLength { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How many notes between the current and previous identical <see cref="TaikoDifficultyHitObjectColour"/>.
|
/// How many notes between the current and previous identical <see cref="TaikoDifficultyHitObjectColour"/>.
|
||||||
/// Negative number means that there is no repetition in range.
|
/// Negative number means that there is no repetition in range.
|
||||||
/// If no repetition is found this will have a value of <see cref="max_repetition_interval"/> + 1.
|
/// If no repetition is found this will have a value of <see cref="max_repetition_interval"/> + 1.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int RepetitionInterval { get; private set; }
|
public int RepetitionInterval { get; private set; } = max_repetition_interval + 1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Evaluated colour difficulty is cached here, as difficulty don't need to be calculated per-note.
|
/// Evaluated colour difficulty is cached here, as difficulty don't need to be calculated per-note.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// TODO: Consider having all evaluated difficulty cached in TaikoDifficultyHitObject instead, since we may be
|
/// TODO: Consider having all evaluated difficulty cached in TaikoDifficultyHitObject instead, since we may be
|
||||||
/// reusing evaluator results in the future.
|
/// reusing evaluator results in the future.
|
||||||
public double EvaluatedDifficulty;
|
public double EvaluatedDifficulty = 0;
|
||||||
|
|
||||||
public TaikoDifficultyHitObjectColour repeatedColour { get; private set; }
|
public TaikoDifficultyHitObjectColour? Previous { get; private set; } = null;
|
||||||
|
|
||||||
/// <summary>
|
public TaikoDifficultyHitObjectColour? repeatedColour { get; private set; } = null;
|
||||||
/// 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.
|
public TaikoDifficultyHitObjectColour(CoupledColourEncoding encoding)
|
||||||
/// </summary>
|
{
|
||||||
public static List<TaikoDifficultyHitObjectColour> CreateColoursFor(List<DifficultyHitObject> hitObjects)
|
Encoding = encoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<TaikoDifficultyHitObjectColour> EncodeAndAssign(List<DifficultyHitObject> hitObjects)
|
||||||
{
|
{
|
||||||
List<TaikoDifficultyHitObjectColour> colours = new List<TaikoDifficultyHitObjectColour>();
|
List<TaikoDifficultyHitObjectColour> colours = new List<TaikoDifficultyHitObjectColour>();
|
||||||
|
List<CoupledColourEncoding> encodings = CoupledColourEncoding.Encode(ColourEncoding.Encode(hitObjects));
|
||||||
for (int i = 0; i < hitObjects.Count; i++)
|
TaikoDifficultyHitObjectColour? lastColour = null;
|
||||||
|
for (int i = 0; i < encodings.Count; i++)
|
||||||
{
|
{
|
||||||
TaikoDifficultyHitObject hitObject = (TaikoDifficultyHitObject)hitObjects[i];
|
lastColour = new TaikoDifficultyHitObjectColour(encodings[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;
|
Previous = lastColour
|
||||||
hitObject.Colour = previous;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
TaikoDifficultyHitObjectColour colour = new TaikoDifficultyHitObjectColour()
|
|
||||||
{
|
|
||||||
Delta = delta,
|
|
||||||
DeltaRunLength = 1,
|
|
||||||
RepetitionInterval = max_repetition_interval + 1,
|
|
||||||
Previous = previous
|
|
||||||
};
|
};
|
||||||
hitObject.Colour = colour;
|
colours.Add(lastColour);
|
||||||
colours.Add(colour);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < colours.Count; i++)
|
foreach (TaikoDifficultyHitObjectColour colour in colours)
|
||||||
{
|
{
|
||||||
colours[i].FindRepetitionInterval();
|
colour.FindRepetitionInterval();
|
||||||
|
((TaikoDifficultyHitObject)hitObjects[colour.Encoding.StartIndex]).Colour = colour;
|
||||||
}
|
}
|
||||||
|
|
||||||
return colours;
|
return colours;
|
||||||
@ -94,23 +71,23 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int interval = Previous.DeltaRunLength;
|
TaikoDifficultyHitObjectColour? other = Previous.Previous;
|
||||||
TaikoDifficultyHitObjectColour other = Previous.Previous;
|
int interval = this.Encoding.StartIndex - other.Encoding.EndIndex;
|
||||||
|
while (interval < max_repetition_interval)
|
||||||
while (other != null && interval < max_repetition_interval)
|
|
||||||
{
|
{
|
||||||
if (other.Delta == Delta && other.DeltaRunLength == DeltaRunLength)
|
if (Encoding.hasIdenticalPayload(other.Encoding))
|
||||||
{
|
{
|
||||||
RepetitionInterval = Math.Min(interval, max_repetition_interval);
|
RepetitionInterval = Math.Min(interval, max_repetition_interval);
|
||||||
repeatedColour = other;
|
repeatedColour = other;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
interval += other.DeltaRunLength;
|
|
||||||
other = other.Previous;
|
other = other.Previous;
|
||||||
|
if (other == null) break;
|
||||||
|
interval = this.Encoding.StartIndex - other.Encoding.EndIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
RepetitionInterval = max_repetition_interval + 1;
|
RepetitionInterval = max_repetition_interval + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,10 +27,17 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
|
|||||||
{
|
{
|
||||||
TaikoDifficultyHitObjectColour colour = ((TaikoDifficultyHitObject)current).Colour;
|
TaikoDifficultyHitObjectColour colour = ((TaikoDifficultyHitObject)current).Colour;
|
||||||
double difficulty = colour == null ? 0 : colour.EvaluatedDifficulty;
|
double difficulty = colour == null ? 0 : colour.EvaluatedDifficulty;
|
||||||
// if (current != null && colour != null)
|
if (current != null && colour != null)
|
||||||
// {
|
{
|
||||||
// System.Console.WriteLine($"{current.StartTime},{colour.Delta},{colour.RepetitionInterval},{difficulty}");
|
ColourEncoding[] payload = colour.Encoding.Payload;
|
||||||
// }
|
string payloadDisplay = "";
|
||||||
|
for (int i = 0; i < payload.Length; ++i)
|
||||||
|
{
|
||||||
|
payloadDisplay += $",({payload[i].MonoRunLength},{payload[i].EncodingRunLength})";
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Console.WriteLine($"{current.StartTime},{colour.RepetitionInterval},{colour.Encoding.RunLength}{payloadDisplay}");
|
||||||
|
}
|
||||||
|
|
||||||
return difficulty;
|
return difficulty;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user