com.wallstop-studios.unity-helpers 2.0.0-rc05 → 2.0.0-rc07
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Runtime/Core/DataStructure/TimedCache.cs +4 -3
- package/Runtime/Core/Extension/IListExtensions.cs +2 -2
- package/Runtime/Core/Extension/RandomExtensions.cs +23 -4
- package/Runtime/Core/Extension/UnityExtensions.cs +278 -90
- package/Runtime/Core/Helper/ArrayConverter.cs +39 -0
- package/Runtime/Core/Helper/ArrayConverter.cs.meta +3 -0
- package/Runtime/Core/Helper/Helpers.cs +133 -563
- package/Runtime/Core/Helper/Partials/LogHelpers.cs +13 -0
- package/Runtime/Core/Helper/Partials/LogHelpers.cs.meta +3 -0
- package/Runtime/Core/Helper/Partials/MathHelpers.cs +30 -0
- package/Runtime/Core/Helper/Partials/MathHelpers.cs.meta +3 -0
- package/Runtime/Core/Helper/Partials/ObjectHelpers.cs +388 -0
- package/Runtime/Core/Helper/Partials/ObjectHelpers.cs.meta +3 -0
- package/Runtime/Core/Helper/Partials/TransformHelpers.cs +167 -0
- package/Runtime/Core/Helper/Partials/TransformHelpers.cs.meta +3 -0
- package/Runtime/Core/Helper/Partials.meta +3 -0
- package/Runtime/Core/Helper/WallMath.cs +85 -22
- package/Runtime/Core/Random/AbstractRandom.cs +208 -162
- package/Runtime/Core/Random/DotNetRandom.cs +3 -5
- package/Runtime/Core/Random/PRNG.cs +7 -0
- package/Runtime/Core/Random/PRNG.cs.meta +3 -0
- package/Runtime/Core/Random/PcgRandom.cs +4 -6
- package/Runtime/Core/Random/RandomState.cs +31 -3
- package/Runtime/Core/Random/SquirrelRandom.cs +12 -15
- package/Runtime/Core/Random/SystemRandom.cs +92 -46
- package/Runtime/Core/Random/ThreadLocalRandom.cs +2 -1
- package/Runtime/Core/Random/UnityRandom.cs +2 -4
- package/Runtime/Core/Random/WyRandom.cs +2 -4
- package/Runtime/Core/Random/XorShiftRandom.cs +3 -5
- package/Runtime/Core/Serialization/Serializer.cs +36 -14
- package/Runtime/Utils/CircleLineRenderer.cs +17 -5
- package/Tests/Runtime/DataStructures/SpatialTreeTests.cs +34 -10
- package/Tests/Runtime/Helper/ArrayConverterTests.cs +19 -0
- package/Tests/Runtime/Helper/ArrayConverterTests.cs.meta +3 -0
- package/Tests/Runtime/Helper/ObjectHelperTests.cs +402 -0
- package/Tests/Runtime/Helper/ObjectHelperTests.cs.meta +3 -0
- package/Tests/Runtime/Helper/WallMathTests.cs +221 -0
- package/Tests/Runtime/Helper/WallMathTests.cs.meta +3 -0
- package/Tests/Runtime/Helper.meta +3 -0
- package/Tests/Runtime/Performance/RandomPerformanceTests.cs +58 -3
- package/Tests/Runtime/Performance/SpatialTreePerformanceTest.cs +47 -34
- package/Tests/Runtime/Random/RandomTestBase.cs +284 -9
- package/Tests/Runtime/Random/SquirrelRandomTests.cs +5 -0
- package/Tests/Runtime/Serialization/JsonSerializationTest.cs +24 -11
- package/Tests/Runtime/Utils/SpriteRendererMetadataTests.cs +21 -17
- package/package.json +1 -1
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
public static double BoundedDouble(double max, double value)
|
|
16
16
|
{
|
|
17
|
-
return value < max
|
|
17
|
+
return value < max
|
|
18
|
+
? value
|
|
19
|
+
: BitConverter.Int64BitsToDouble(BitConverter.DoubleToInt64Bits(value) - 1);
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
public static float BoundedFloat(float max, float value)
|
|
@@ -22,52 +24,113 @@
|
|
|
22
24
|
return value < max
|
|
23
25
|
? value
|
|
24
26
|
: BitConverter.ToSingle(
|
|
25
|
-
BitConverter.GetBytes(
|
|
27
|
+
BitConverter.GetBytes(
|
|
28
|
+
BitConverter.ToInt32(BitConverter.GetBytes(value), 0) - 1
|
|
29
|
+
),
|
|
30
|
+
0
|
|
31
|
+
);
|
|
26
32
|
}
|
|
27
33
|
|
|
28
|
-
public static int WrappedAdd(int value, int increment, int max)
|
|
34
|
+
public static int WrappedAdd(this int value, int increment, int max)
|
|
29
35
|
{
|
|
30
36
|
WrappedAdd(ref value, increment, max);
|
|
31
37
|
return value;
|
|
32
38
|
}
|
|
33
39
|
|
|
34
|
-
public static
|
|
40
|
+
public static int WrappedAdd(ref int value, int increment, int max)
|
|
35
41
|
{
|
|
36
|
-
value
|
|
42
|
+
value += increment;
|
|
37
43
|
if (value < max)
|
|
38
44
|
{
|
|
39
|
-
return;
|
|
45
|
+
return value;
|
|
40
46
|
}
|
|
41
|
-
value %= max;
|
|
47
|
+
return value %= max;
|
|
42
48
|
}
|
|
43
49
|
|
|
44
|
-
public static int WrappedIncrement(int value, int max)
|
|
50
|
+
public static int WrappedIncrement(this int value, int max)
|
|
45
51
|
{
|
|
46
52
|
return WrappedAdd(value, 1, max);
|
|
47
53
|
}
|
|
48
54
|
|
|
49
|
-
public static
|
|
55
|
+
public static int WrappedIncrement(ref int value, int max)
|
|
56
|
+
{
|
|
57
|
+
return WrappedAdd(ref value, 1, max);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public static T Clamp<T>(this T value, T min, T max)
|
|
61
|
+
where T : IComparable<T>
|
|
62
|
+
{
|
|
63
|
+
if (value.CompareTo(min) < 0)
|
|
64
|
+
{
|
|
65
|
+
return min;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return max.CompareTo(value) < 0 ? max : value;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public static Vector2 Clamp(this Rect bounds, Vector2 point)
|
|
50
72
|
{
|
|
51
|
-
|
|
73
|
+
return Clamp(bounds, ref point);
|
|
52
74
|
}
|
|
53
75
|
|
|
54
|
-
public static
|
|
76
|
+
public static Vector2 Clamp(this Rect bounds, ref Vector2 point)
|
|
55
77
|
{
|
|
56
|
-
if (
|
|
78
|
+
if (bounds.Contains(point))
|
|
79
|
+
{
|
|
80
|
+
return point;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
Vector2 center = bounds.center;
|
|
84
|
+
Vector2 direction = point - center;
|
|
85
|
+
|
|
86
|
+
if (direction == Vector2.zero)
|
|
87
|
+
{
|
|
88
|
+
return center;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
float tMax = float.MaxValue;
|
|
92
|
+
Vector2 min = bounds.min;
|
|
93
|
+
Vector2 max = bounds.max;
|
|
94
|
+
|
|
95
|
+
if (direction.x != 0)
|
|
96
|
+
{
|
|
97
|
+
if (0 < direction.x)
|
|
98
|
+
{
|
|
99
|
+
float t2 = (max.x - center.x) / direction.x;
|
|
100
|
+
tMax = Math.Min(tMax, t2);
|
|
101
|
+
}
|
|
102
|
+
else
|
|
103
|
+
{
|
|
104
|
+
float t1 = (min.x - center.x) / direction.x;
|
|
105
|
+
tMax = Math.Min(tMax, t1);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (direction.y != 0)
|
|
57
110
|
{
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
111
|
+
if (direction.y > 0)
|
|
112
|
+
{
|
|
113
|
+
float t2 = (max.y - center.y) / direction.y;
|
|
114
|
+
tMax = Math.Min(tMax, t2);
|
|
115
|
+
}
|
|
116
|
+
else
|
|
117
|
+
{
|
|
118
|
+
float t1 = (min.y - center.y) / direction.y;
|
|
119
|
+
tMax = Math.Min(tMax, t1);
|
|
120
|
+
}
|
|
67
121
|
}
|
|
122
|
+
|
|
123
|
+
tMax = Mathf.Clamp01(tMax);
|
|
124
|
+
|
|
125
|
+
point = center + direction * tMax;
|
|
126
|
+
point = new Vector2(
|
|
127
|
+
Mathf.Clamp(point.x, min.x, max.x),
|
|
128
|
+
Mathf.Clamp(point.y, min.y, max.y)
|
|
129
|
+
);
|
|
130
|
+
return point;
|
|
68
131
|
}
|
|
69
132
|
|
|
70
|
-
public static bool Approximately(float lhs, float rhs, float tolerance = 0.045f)
|
|
133
|
+
public static bool Approximately(this float lhs, float rhs, float tolerance = 0.045f)
|
|
71
134
|
{
|
|
72
135
|
return Math.Abs(lhs - rhs) <= tolerance;
|
|
73
136
|
}
|
|
@@ -15,25 +15,16 @@
|
|
|
15
15
|
private static readonly ConcurrentDictionary<Type, Array> EnumTypeCache = new();
|
|
16
16
|
|
|
17
17
|
protected const uint HalfwayUint = uint.MaxValue / 2;
|
|
18
|
-
protected const double MagicDouble = 4.6566128752458E-10;
|
|
19
18
|
protected const float MagicFloat = 5.960465E-008F;
|
|
20
19
|
|
|
21
20
|
protected double? _cachedGaussian;
|
|
22
21
|
|
|
23
|
-
protected AbstractRandom() { }
|
|
24
|
-
|
|
25
22
|
public abstract RandomState InternalState { get; }
|
|
26
23
|
|
|
27
|
-
public int Next()
|
|
24
|
+
public virtual int Next()
|
|
28
25
|
{
|
|
29
|
-
int
|
|
30
|
-
|
|
31
|
-
{
|
|
32
|
-
result = unchecked((int)NextUint());
|
|
33
|
-
}
|
|
34
|
-
while (result < 0);
|
|
35
|
-
|
|
36
|
-
return result;
|
|
26
|
+
// Mask out the MSB to ensure the value is within [0, int.MaxValue]
|
|
27
|
+
return unchecked((int)NextUint() & 0x7FFFFFFF);
|
|
37
28
|
}
|
|
38
29
|
|
|
39
30
|
public int Next(int max)
|
|
@@ -50,40 +41,136 @@
|
|
|
50
41
|
{
|
|
51
42
|
if (max <= min)
|
|
52
43
|
{
|
|
53
|
-
throw new ArgumentException(
|
|
44
|
+
throw new ArgumentException(
|
|
45
|
+
$"Min {min} cannot be larger-than or equal-to max {max}"
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
uint range = (uint)(max - min);
|
|
50
|
+
if (range == 0)
|
|
51
|
+
{
|
|
52
|
+
return unchecked((int)NextUint());
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
return unchecked((int)NextUint(range)) + min;
|
|
55
|
+
return unchecked((int)(min + NextUint(range)));
|
|
58
56
|
}
|
|
59
57
|
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
public T Next<T>(IEnumerable<T> enumerable)
|
|
59
|
+
{
|
|
60
|
+
if (enumerable is ICollection<T> collection)
|
|
61
|
+
{
|
|
62
|
+
return Next(collection);
|
|
63
|
+
}
|
|
62
64
|
|
|
63
|
-
|
|
65
|
+
return Next((IReadOnlyList<T>)enumerable.ToList());
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public T Next<T>(ICollection<T> collection)
|
|
64
69
|
{
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
int count = collection.Count;
|
|
71
|
+
if (count <= 0)
|
|
72
|
+
{
|
|
73
|
+
throw new ArgumentException("Collection size cannot be less-than or equal-to 0");
|
|
74
|
+
}
|
|
67
75
|
|
|
68
|
-
|
|
69
|
-
Generates a uniform random number within the bound, avoiding modulo bias
|
|
70
|
-
*/
|
|
71
|
-
uint threshold = unchecked((uint)((0x100000000UL - max) % max));
|
|
72
|
-
while (true)
|
|
76
|
+
switch (collection)
|
|
73
77
|
{
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
case IList<T> list:
|
|
79
|
+
return Next(list);
|
|
80
|
+
case IReadOnlyList<T> readOnlyList:
|
|
81
|
+
return Next(readOnlyList);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
int index = Next(count);
|
|
85
|
+
int i = 0;
|
|
86
|
+
foreach (T element in collection)
|
|
87
|
+
{
|
|
88
|
+
if (i++ == index)
|
|
76
89
|
{
|
|
77
|
-
return
|
|
90
|
+
return element;
|
|
78
91
|
}
|
|
79
92
|
}
|
|
93
|
+
|
|
94
|
+
// Should never happen
|
|
95
|
+
return default;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public T Next<T>(IList<T> list)
|
|
99
|
+
{
|
|
100
|
+
if (ReferenceEquals(list, null))
|
|
101
|
+
{
|
|
102
|
+
throw new ArgumentNullException(nameof(list));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/*
|
|
106
|
+
For small lists, it's much more efficient to simply return one of their elements
|
|
107
|
+
instead of trying to generate a random number within bounds (which is implemented as a while(true) loop)
|
|
108
|
+
*/
|
|
109
|
+
switch (list.Count)
|
|
110
|
+
{
|
|
111
|
+
case 1:
|
|
112
|
+
return list[0];
|
|
113
|
+
case 2:
|
|
114
|
+
return NextBool() ? list[0] : list[1];
|
|
115
|
+
default:
|
|
116
|
+
return list[Next(list.Count)];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private T Next<T>(IReadOnlyList<T> list)
|
|
121
|
+
{
|
|
122
|
+
/*
|
|
123
|
+
For small lists, it's much more efficient to simply return one of their elements
|
|
124
|
+
instead of trying to generate a random number within bounds (which is implemented as a while(true) loop)
|
|
125
|
+
*/
|
|
126
|
+
switch (list.Count)
|
|
127
|
+
{
|
|
128
|
+
case 1:
|
|
129
|
+
return list[0];
|
|
130
|
+
case 2:
|
|
131
|
+
return NextBool() ? list[0] : list[1];
|
|
132
|
+
default:
|
|
133
|
+
return list[Next(list.Count)];
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public T Next<T>()
|
|
138
|
+
where T : struct, Enum
|
|
139
|
+
{
|
|
140
|
+
Type enumType = typeof(T);
|
|
141
|
+
T[] enumValues;
|
|
142
|
+
if (EnumTypeCache.TryGetValue(enumType, out Array enumArray))
|
|
143
|
+
{
|
|
144
|
+
enumValues = (T[])enumArray;
|
|
145
|
+
}
|
|
146
|
+
else
|
|
147
|
+
{
|
|
148
|
+
enumValues = (T[])Enum.GetValues(enumType);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return RandomOf(enumValues);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Internal sampler
|
|
155
|
+
public abstract uint NextUint();
|
|
156
|
+
|
|
157
|
+
public uint NextUint(uint max)
|
|
158
|
+
{
|
|
159
|
+
if (max == 0)
|
|
160
|
+
{
|
|
161
|
+
throw new ArgumentException("Max cannot be zero");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return (uint)(NextDouble() * max);
|
|
80
165
|
}
|
|
81
166
|
|
|
82
167
|
public uint NextUint(uint min, uint max)
|
|
83
168
|
{
|
|
84
169
|
if (max <= min)
|
|
85
170
|
{
|
|
86
|
-
throw new ArgumentException(
|
|
171
|
+
throw new ArgumentException(
|
|
172
|
+
$"Min {min} cannot be larger-than or equal-to max {max}"
|
|
173
|
+
);
|
|
87
174
|
}
|
|
88
175
|
|
|
89
176
|
return min + NextUint(max - min);
|
|
@@ -123,12 +210,10 @@
|
|
|
123
210
|
{
|
|
124
211
|
uint upper = NextUint();
|
|
125
212
|
uint lower = NextUint();
|
|
126
|
-
|
|
127
|
-
if (NextBool())
|
|
213
|
+
unchecked
|
|
128
214
|
{
|
|
129
|
-
return
|
|
215
|
+
return (long)((((ulong)upper << 32) | lower) & (0x1UL << 63));
|
|
130
216
|
}
|
|
131
|
-
return unchecked((long)((ulong)lower << 32) | upper);
|
|
132
217
|
}
|
|
133
218
|
|
|
134
219
|
public long NextLong(long max)
|
|
@@ -138,51 +223,52 @@
|
|
|
138
223
|
throw new ArgumentException($"Max {max} cannot be less-than or equal-to 0");
|
|
139
224
|
}
|
|
140
225
|
|
|
141
|
-
|
|
142
|
-
{
|
|
143
|
-
return Next(unchecked((int)max));
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
long withinRange;
|
|
147
|
-
do
|
|
148
|
-
{
|
|
149
|
-
withinRange = NextLong();
|
|
150
|
-
}
|
|
151
|
-
while (withinRange < 0 || max <= withinRange);
|
|
152
|
-
return withinRange;
|
|
226
|
+
return (long)(NextDouble() * max);
|
|
153
227
|
}
|
|
154
228
|
|
|
155
229
|
public long NextLong(long min, long max)
|
|
156
230
|
{
|
|
157
231
|
if (max <= min)
|
|
158
232
|
{
|
|
159
|
-
throw new ArgumentException(
|
|
233
|
+
throw new ArgumentException(
|
|
234
|
+
$"Min {min} cannot be larger-than or equal-to Max {max}"
|
|
235
|
+
);
|
|
160
236
|
}
|
|
161
237
|
|
|
162
|
-
|
|
238
|
+
ulong range = (ulong)(max - min);
|
|
239
|
+
if (range == 0)
|
|
240
|
+
{
|
|
241
|
+
return unchecked((long)NextUlong());
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return unchecked((long)(NextDouble() * range + min));
|
|
163
245
|
}
|
|
164
246
|
|
|
165
247
|
public ulong NextUlong()
|
|
166
248
|
{
|
|
167
|
-
|
|
249
|
+
uint upper = NextUint();
|
|
250
|
+
uint lower = NextUint();
|
|
251
|
+
return ((ulong)upper << 32) | lower;
|
|
168
252
|
}
|
|
169
253
|
|
|
170
254
|
public ulong NextUlong(ulong max)
|
|
171
255
|
{
|
|
172
|
-
return
|
|
256
|
+
return (ulong)(NextDouble() * max);
|
|
173
257
|
}
|
|
174
258
|
|
|
175
259
|
public ulong NextUlong(ulong min, ulong max)
|
|
176
260
|
{
|
|
177
261
|
if (max <= min)
|
|
178
262
|
{
|
|
179
|
-
throw new ArgumentException(
|
|
263
|
+
throw new ArgumentException(
|
|
264
|
+
$"Min {min} cannot be larger-than or equal-to max {max}"
|
|
265
|
+
);
|
|
180
266
|
}
|
|
181
267
|
|
|
182
|
-
return
|
|
268
|
+
return NextUlong(max - min) + min;
|
|
183
269
|
}
|
|
184
270
|
|
|
185
|
-
public bool NextBool()
|
|
271
|
+
public virtual bool NextBool()
|
|
186
272
|
{
|
|
187
273
|
return NextUint() < HalfwayUint;
|
|
188
274
|
}
|
|
@@ -194,7 +280,7 @@
|
|
|
194
280
|
throw new ArgumentException(nameof(buffer));
|
|
195
281
|
}
|
|
196
282
|
|
|
197
|
-
const byte sizeOfInt =
|
|
283
|
+
const byte sizeOfInt = sizeof(int); // May differ on some platforms
|
|
198
284
|
|
|
199
285
|
// See how many ints we can slap into it.
|
|
200
286
|
int chunks = buffer.Length / sizeOfInt;
|
|
@@ -226,9 +312,8 @@
|
|
|
226
312
|
double value;
|
|
227
313
|
do
|
|
228
314
|
{
|
|
229
|
-
value = NextUint() *
|
|
230
|
-
}
|
|
231
|
-
while (value < 0 || 1 <= value);
|
|
315
|
+
value = NextUint() * (1.0 / uint.MaxValue);
|
|
316
|
+
} while (1.0 <= value);
|
|
232
317
|
|
|
233
318
|
return value;
|
|
234
319
|
}
|
|
@@ -247,11 +332,57 @@
|
|
|
247
332
|
{
|
|
248
333
|
if (max <= min)
|
|
249
334
|
{
|
|
250
|
-
throw new ArgumentException(
|
|
335
|
+
throw new ArgumentException(
|
|
336
|
+
$"Min {min} cannot be larger-than or equal-to max {max}"
|
|
337
|
+
);
|
|
251
338
|
}
|
|
252
339
|
|
|
253
340
|
double range = max - min;
|
|
254
|
-
|
|
341
|
+
if (double.IsInfinity(range))
|
|
342
|
+
{
|
|
343
|
+
return NextDoubleWithInfiniteRange(min, max);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return min + (NextDouble() * range);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
protected double NextDoubleWithInfiniteRange(double min, double max)
|
|
350
|
+
{
|
|
351
|
+
double random;
|
|
352
|
+
do
|
|
353
|
+
{
|
|
354
|
+
random = NextDoubleFullRange();
|
|
355
|
+
} while (random < min || max <= random);
|
|
356
|
+
|
|
357
|
+
return random;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
protected double NextDoubleFullRange()
|
|
361
|
+
{
|
|
362
|
+
double value = double.NaN;
|
|
363
|
+
do
|
|
364
|
+
{
|
|
365
|
+
ulong randomBits = NextUlong();
|
|
366
|
+
|
|
367
|
+
// Extract exponent (bits 52-62)
|
|
368
|
+
const ulong exponentMask = 0x7FF0000000000000;
|
|
369
|
+
|
|
370
|
+
ulong exponent = (randomBits & exponentMask) >> 52;
|
|
371
|
+
|
|
372
|
+
// Ensure exponent is not all 1's to avoid Inf and NaN
|
|
373
|
+
if (exponent == 0x7FF)
|
|
374
|
+
{
|
|
375
|
+
continue; // Regenerate
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/*
|
|
379
|
+
For uniform distribution over all finite doubles, no further masking is necessary,
|
|
380
|
+
reassemble the bits
|
|
381
|
+
*/
|
|
382
|
+
value = BitConverter.Int64BitsToDouble(unchecked((long)randomBits));
|
|
383
|
+
} while (double.IsInfinity(value) || double.IsNaN(value));
|
|
384
|
+
|
|
385
|
+
return value;
|
|
255
386
|
}
|
|
256
387
|
|
|
257
388
|
public double NextGaussian(double mean = 0, double stdDev = 1)
|
|
@@ -277,8 +408,7 @@
|
|
|
277
408
|
x = 2 * NextDouble() - 1;
|
|
278
409
|
y = 2 * NextDouble() - 1;
|
|
279
410
|
square = x * x + y * y;
|
|
280
|
-
}
|
|
281
|
-
while (square > 1 || square == 0);
|
|
411
|
+
} while (square == 0 || 1 < square);
|
|
282
412
|
|
|
283
413
|
double fac = Math.Sqrt(-2 * Math.Log(square) / square);
|
|
284
414
|
_cachedGaussian = x * fac;
|
|
@@ -290,10 +420,8 @@
|
|
|
290
420
|
float value;
|
|
291
421
|
do
|
|
292
422
|
{
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
296
|
-
while (value < 0 || 1 <= value);
|
|
423
|
+
value = NextUint() / (1f * uint.MaxValue);
|
|
424
|
+
} while (1f <= value);
|
|
297
425
|
|
|
298
426
|
return value;
|
|
299
427
|
}
|
|
@@ -312,108 +440,22 @@
|
|
|
312
440
|
{
|
|
313
441
|
if (max <= min)
|
|
314
442
|
{
|
|
315
|
-
throw new ArgumentException(
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
return min + NextFloat(max - min);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
public T Next<T>(IEnumerable<T> enumerable)
|
|
322
|
-
{
|
|
323
|
-
if (enumerable is ICollection<T> collection)
|
|
324
|
-
{
|
|
325
|
-
return Next(collection);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
return Next((IReadOnlyList<T>)enumerable.ToList());
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
public T Next<T>(ICollection<T> collection)
|
|
332
|
-
{
|
|
333
|
-
int count = collection.Count;
|
|
334
|
-
if (count <= 0)
|
|
335
|
-
{
|
|
336
|
-
throw new ArgumentException("Collection size cannot be less-than or equal-to 0");
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
switch (collection)
|
|
340
|
-
{
|
|
341
|
-
case IList<T> list:
|
|
342
|
-
return Next(list);
|
|
343
|
-
case IReadOnlyList<T> readOnlyList:
|
|
344
|
-
return Next(readOnlyList);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
int index = Next(count);
|
|
348
|
-
int i = 0;
|
|
349
|
-
foreach (T element in collection)
|
|
350
|
-
{
|
|
351
|
-
if (i++ == index)
|
|
352
|
-
{
|
|
353
|
-
return element;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// Should never happen
|
|
358
|
-
return default;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
public T Next<T>(IList<T> list)
|
|
362
|
-
{
|
|
363
|
-
if (ReferenceEquals(list, null))
|
|
364
|
-
{
|
|
365
|
-
throw new ArgumentNullException(nameof(list));
|
|
443
|
+
throw new ArgumentException(
|
|
444
|
+
$"Min {min} cannot be larger-than or equal-to max {max}"
|
|
445
|
+
);
|
|
366
446
|
}
|
|
367
447
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
instead of trying to generate a random number within bounds (which is implemented as a while(true) loop)
|
|
371
|
-
*/
|
|
372
|
-
switch (list.Count)
|
|
448
|
+
float range = max - min;
|
|
449
|
+
if (float.IsInfinity(range))
|
|
373
450
|
{
|
|
374
|
-
|
|
375
|
-
return list[0];
|
|
376
|
-
case 2:
|
|
377
|
-
return NextBool() ? list[0] : list[1];
|
|
378
|
-
default:
|
|
379
|
-
return list[Next(list.Count)];
|
|
451
|
+
return (float)NextDouble(min, max);
|
|
380
452
|
}
|
|
381
|
-
}
|
|
382
453
|
|
|
383
|
-
|
|
384
|
-
{
|
|
385
|
-
/*
|
|
386
|
-
For small lists, it's much more efficient to simply return one of their elements
|
|
387
|
-
instead of trying to generate a random number within bounds (which is implemented as a while(true) loop)
|
|
388
|
-
*/
|
|
389
|
-
switch (list.Count)
|
|
390
|
-
{
|
|
391
|
-
case 1:
|
|
392
|
-
return list[0];
|
|
393
|
-
case 2:
|
|
394
|
-
return NextBool() ? list[0] : list[1];
|
|
395
|
-
default:
|
|
396
|
-
return list[Next(list.Count)];
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
public T Next<T>() where T : struct, Enum
|
|
401
|
-
{
|
|
402
|
-
Type enumType = typeof(T);
|
|
403
|
-
T[] enumValues;
|
|
404
|
-
if (EnumTypeCache.TryGetValue(enumType, out Array enumArray))
|
|
405
|
-
{
|
|
406
|
-
enumValues = (T[])enumArray;
|
|
407
|
-
}
|
|
408
|
-
else
|
|
409
|
-
{
|
|
410
|
-
enumValues = (T[])Enum.GetValues(enumType);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
return RandomOf(enumValues);
|
|
454
|
+
return min + NextFloat(range);
|
|
414
455
|
}
|
|
415
456
|
|
|
416
|
-
public T NextCachedEnum<T>()
|
|
457
|
+
public T NextCachedEnum<T>()
|
|
458
|
+
where T : struct, Enum
|
|
417
459
|
{
|
|
418
460
|
Type enumType = typeof(T);
|
|
419
461
|
T[] enumValues = (T[])EnumTypeCache.GetOrAdd(enumType, Enum.GetValues);
|
|
@@ -437,7 +479,7 @@
|
|
|
437
479
|
|
|
438
480
|
// Advances the RNG
|
|
439
481
|
// https://code2d.wordpress.com/2020/07/21/perlin-noise/
|
|
440
|
-
public float[,] NextNoiseMap(int width, int height, float scale, int octaves)
|
|
482
|
+
public float[,] NextNoiseMap(int width, int height, float scale = 2.5f, int octaves = 8)
|
|
441
483
|
{
|
|
442
484
|
if (width <= 0)
|
|
443
485
|
{
|
|
@@ -511,7 +553,11 @@
|
|
|
511
553
|
{
|
|
512
554
|
// Returns a value between 0f and 1f based on noiseMap value
|
|
513
555
|
// minNoiseHeight being 0f, and maxNoiseHeight being 1f
|
|
514
|
-
noiseMap[x, y] = Mathf.InverseLerp(
|
|
556
|
+
noiseMap[x, y] = Mathf.InverseLerp(
|
|
557
|
+
minNoiseHeight,
|
|
558
|
+
maxNoiseHeight,
|
|
559
|
+
noiseMap[x, y]
|
|
560
|
+
);
|
|
515
561
|
}
|
|
516
562
|
}
|
|
517
563
|
return noiseMap;
|
|
@@ -534,4 +580,4 @@
|
|
|
534
580
|
|
|
535
581
|
public abstract IRandom Copy();
|
|
536
582
|
}
|
|
537
|
-
}
|
|
583
|
+
}
|
|
@@ -8,8 +8,6 @@
|
|
|
8
8
|
[DataContract]
|
|
9
9
|
public sealed class DotNetRandom : AbstractRandom
|
|
10
10
|
{
|
|
11
|
-
[JsonPropertyName("State")]
|
|
12
|
-
[DataMember(Name = "State")]
|
|
13
11
|
public override RandomState InternalState =>
|
|
14
12
|
new RandomState(unchecked((ulong)_seed), state2: _numberGenerated);
|
|
15
13
|
|
|
@@ -27,12 +25,12 @@
|
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
[JsonConstructor]
|
|
30
|
-
public DotNetRandom(RandomState
|
|
28
|
+
public DotNetRandom(RandomState internalState)
|
|
31
29
|
{
|
|
32
|
-
_seed = unchecked((int)
|
|
30
|
+
_seed = unchecked((int)internalState.State1);
|
|
33
31
|
_random = new Random(_seed);
|
|
34
32
|
_numberGenerated = 0;
|
|
35
|
-
ulong generationCount =
|
|
33
|
+
ulong generationCount = internalState.State2;
|
|
36
34
|
|
|
37
35
|
while (_numberGenerated < generationCount)
|
|
38
36
|
{
|