2020-11-27 14:41:35 +08:00
|
|
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
|
|
// See the LICENCE file in the repository root for full licence text.
|
|
|
|
|
2020-11-30 17:46:28 +08:00
|
|
|
using System;
|
|
|
|
|
2020-11-27 14:41:35 +08:00
|
|
|
namespace osu.Game.Utils
|
|
|
|
{
|
2020-11-30 17:07:37 +08:00
|
|
|
/// <summary>
|
2020-11-27 14:41:35 +08:00
|
|
|
/// Provides a fast stateless function that can be used in randomly-looking visual elements.
|
2020-11-30 17:07:37 +08:00
|
|
|
/// </summary>
|
2020-11-27 14:41:35 +08:00
|
|
|
public static class StatelessRNG
|
|
|
|
{
|
|
|
|
private static ulong mix(ulong x)
|
|
|
|
{
|
|
|
|
unchecked
|
|
|
|
{
|
|
|
|
x ^= x >> 33;
|
|
|
|
x *= 0xff51afd7ed558ccd;
|
|
|
|
x ^= x >> 33;
|
|
|
|
x *= 0xc4ceb9fe1a85ec53;
|
|
|
|
x ^= x >> 33;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-30 17:07:37 +08:00
|
|
|
/// <summary>
|
2020-11-30 17:46:28 +08:00
|
|
|
/// Generate a random 64-bit unsigned integer from given seed.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="seed">
|
|
|
|
/// The seed value of this random number generator.
|
|
|
|
/// </param>
|
|
|
|
/// <param name="series">
|
|
|
|
/// The series number.
|
|
|
|
/// Different values are computed for the same seed in different series.
|
|
|
|
/// </param>
|
2020-12-02 11:59:45 +08:00
|
|
|
public static ulong NextULong(int seed, int series = 0)
|
2020-11-30 17:46:28 +08:00
|
|
|
{
|
|
|
|
unchecked
|
|
|
|
{
|
2021-10-27 12:04:41 +08:00
|
|
|
ulong combined = ((ulong)(uint)series << 32) | (uint)seed;
|
2020-11-30 17:46:28 +08:00
|
|
|
// The xor operation is to not map (0, 0) to 0.
|
|
|
|
return mix(combined ^ 0x12345678);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Generate a random integer in range [0, maxValue) from given seed.
|
2020-11-30 17:07:37 +08:00
|
|
|
/// </summary>
|
2020-11-30 17:46:28 +08:00
|
|
|
/// <param name="maxValue">
|
|
|
|
/// The number of possible results.
|
|
|
|
/// </param>
|
2020-11-27 14:41:35 +08:00
|
|
|
/// <param name="seed">
|
|
|
|
/// The seed value of this random number generator.
|
|
|
|
/// </param>
|
|
|
|
/// <param name="series">
|
|
|
|
/// The series number.
|
|
|
|
/// Different values are computed for the same seed in different series.
|
|
|
|
/// </param>
|
2020-11-30 17:46:28 +08:00
|
|
|
public static int NextInt(int maxValue, int seed, int series = 0)
|
|
|
|
{
|
|
|
|
if (maxValue <= 0) throw new ArgumentOutOfRangeException(nameof(maxValue));
|
|
|
|
|
2020-12-02 11:59:45 +08:00
|
|
|
return (int)(NextULong(seed, series) % (ulong)maxValue);
|
2020-11-30 17:46:28 +08:00
|
|
|
}
|
2020-11-27 14:41:35 +08:00
|
|
|
|
2020-11-30 17:07:37 +08:00
|
|
|
/// <summary>
|
2020-11-30 17:46:28 +08:00
|
|
|
/// Compute a random floating point value between 0 and 1 (excluding 1) from given seed and series number.
|
2020-11-30 17:07:37 +08:00
|
|
|
/// </summary>
|
2020-11-27 14:41:35 +08:00
|
|
|
/// <param name="seed">
|
|
|
|
/// The seed value of this random number generator.
|
|
|
|
/// </param>
|
|
|
|
/// <param name="series">
|
|
|
|
/// The series number.
|
|
|
|
/// Different values are computed for the same seed in different series.
|
|
|
|
/// </param>
|
2020-11-30 17:46:28 +08:00
|
|
|
public static float NextSingle(int seed, int series = 0) =>
|
2020-12-02 11:59:45 +08:00
|
|
|
(float)(NextULong(seed, series) & ((1 << 24) - 1)) / (1 << 24); // float has 24-bit precision
|
2021-06-04 18:52:12 +08:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Compute a random floating point value between <paramref name="min"/> and <paramref name="max"/> from given seed and series number.
|
|
|
|
/// </summary>
|
|
|
|
public static float NextSingle(float min, float max, int seed, int series = 0) => min + NextSingle(seed, series) * (max - min);
|
2020-11-27 14:41:35 +08:00
|
|
|
}
|
|
|
|
}
|