43 lines
1.7 KiB
C#
43 lines
1.7 KiB
C#
using ProjectQuint.Core.Charts;
|
|
|
|
namespace ProjectQuint.Probes;
|
|
|
|
public readonly record struct ReplayInput(double Time, int Lane, bool Pressed);
|
|
|
|
public sealed record SyntheticWorkload(PlayableNote[] Notes, ReplayInput[] Events, uint Seed)
|
|
{
|
|
public static SyntheticWorkload Create(int noteCount, uint seed)
|
|
{
|
|
if (noteCount < 1 || noteCount > 100_000)
|
|
throw new ArgumentOutOfRangeException(nameof(noteCount), "Use 1 to 100000 notes.");
|
|
var notes = new PlayableNote[noteCount];
|
|
var events = new List<ReplayInput>(noteCount * 2);
|
|
var state = seed;
|
|
for (var index = 0; index < noteCount; index++)
|
|
{
|
|
// Explicit integer PRNG makes the workload independent of System.Random versions.
|
|
state = unchecked(state * 1664525u + 1013904223u);
|
|
var time = 1.0 + index * 0.125;
|
|
var longNote = index % 11 == 0;
|
|
var note = new PlayableNote
|
|
{
|
|
Id = index + 1,
|
|
Lane = index % 4,
|
|
StartTime = time,
|
|
EndTime = time + (longNote ? 0.375 : 0),
|
|
};
|
|
notes[index] = note;
|
|
// Deliberate misses and early releases exercise failure as well as perfect play.
|
|
if (index % 17 == 0)
|
|
continue;
|
|
var pressTime = time + ((int)(state % 7) - 3) * 0.01;
|
|
events.Add(new ReplayInput(pressTime, note.Lane, true));
|
|
events.Add(new ReplayInput(longNote
|
|
? note.EndTime - (index % 23 == 0 ? 0.2 : 0)
|
|
: pressTime + 0.02, note.Lane, false));
|
|
}
|
|
return new SyntheticWorkload(notes, events.OrderBy(e => e.Time)
|
|
.ThenBy(e => e.Pressed).ThenBy(e => e.Lane).ToArray(), seed);
|
|
}
|
|
}
|