com.wallstop-studios.unity-helpers 2.0.0-rc07 → 2.0.0-rc08
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/Extension/DirectionExtensions.cs +5 -2
- package/Runtime/Core/Extension/IEnumerableExtensions.cs +19 -6
- package/Runtime/Core/Extension/RandomExtensions.cs +9 -87
- package/Runtime/Core/Extension/UnityExtensions.cs +2 -2
- package/Runtime/Core/Random/AbstractRandom.cs +82 -128
- package/Runtime/Core/Random/IRandom.cs +26 -7
- package/Runtime/Core/Random/PerlinNoise.cs +369 -0
- package/Runtime/Core/Random/PerlinNoise.cs.meta +3 -0
- package/Tests/Runtime/Extensions/RandomExtensionTests.cs +27 -0
- package/Tests/Runtime/Extensions/RandomExtensionTests.cs.meta +3 -0
- package/Tests/Runtime/Random/RandomTestBase.cs +300 -4
- package/Tests/Runtime/Random/SquirrelRandomTests.cs +1 -1
- package/package.json +1 -1
|
@@ -4,14 +4,30 @@
|
|
|
4
4
|
using System.Collections.Generic;
|
|
5
5
|
using System.Linq;
|
|
6
6
|
using System.Runtime.CompilerServices;
|
|
7
|
+
using Core.DataStructure.Adapters;
|
|
7
8
|
using Core.Extension;
|
|
8
9
|
using Core.Serialization;
|
|
9
10
|
using NUnit.Framework;
|
|
10
11
|
using UnityHelpers.Core.Random;
|
|
11
12
|
|
|
13
|
+
public enum TestValues
|
|
14
|
+
{
|
|
15
|
+
Value0,
|
|
16
|
+
Value1,
|
|
17
|
+
Value2,
|
|
18
|
+
Value3,
|
|
19
|
+
Value4,
|
|
20
|
+
Value5,
|
|
21
|
+
Value6,
|
|
22
|
+
Value7,
|
|
23
|
+
Value8,
|
|
24
|
+
Value9,
|
|
25
|
+
}
|
|
26
|
+
|
|
12
27
|
public abstract class RandomTestBase
|
|
13
28
|
{
|
|
14
29
|
private const int NumGeneratorChecks = 1_000;
|
|
30
|
+
private const int NormalIterations = 1_000;
|
|
15
31
|
private const int SampleCount = 12_750_000;
|
|
16
32
|
|
|
17
33
|
private readonly int[] _samples = new int[1_000];
|
|
@@ -34,7 +50,10 @@
|
|
|
34
50
|
[Parallelizable]
|
|
35
51
|
public void Bool()
|
|
36
52
|
{
|
|
37
|
-
TestAndVerify(
|
|
53
|
+
TestAndVerify(
|
|
54
|
+
random => Math.Min(_samples.Length - 1, Convert.ToInt32(random.NextBool())),
|
|
55
|
+
maxLength: Math.Min(2, _samples.Length)
|
|
56
|
+
);
|
|
38
57
|
}
|
|
39
58
|
|
|
40
59
|
[Test]
|
|
@@ -44,6 +63,16 @@
|
|
|
44
63
|
TestAndVerify(random => random.Next(0, _samples.Length));
|
|
45
64
|
}
|
|
46
65
|
|
|
66
|
+
[Test]
|
|
67
|
+
[Parallelizable]
|
|
68
|
+
public void IntRaw()
|
|
69
|
+
{
|
|
70
|
+
int sampleLength = GetSampleLength();
|
|
71
|
+
TestAndVerify(random =>
|
|
72
|
+
(int)((1.0 * random.Next()) / (1.0 * int.MaxValue) * sampleLength)
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
47
76
|
[Test]
|
|
48
77
|
[Parallelizable]
|
|
49
78
|
public void IntRange()
|
|
@@ -119,6 +148,17 @@
|
|
|
119
148
|
);
|
|
120
149
|
}
|
|
121
150
|
|
|
151
|
+
[Test]
|
|
152
|
+
[Parallelizable]
|
|
153
|
+
public void ShortRaw()
|
|
154
|
+
{
|
|
155
|
+
int sampleLength = GetSampleLength(short.MaxValue);
|
|
156
|
+
TestAndVerify(
|
|
157
|
+
random => (int)((1.0 * random.NextShort()) / (1.0 * short.MaxValue) * sampleLength),
|
|
158
|
+
maxLength: short.MaxValue
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
122
162
|
[Test]
|
|
123
163
|
[Parallelizable]
|
|
124
164
|
public void ShortRange()
|
|
@@ -156,6 +196,17 @@
|
|
|
156
196
|
);
|
|
157
197
|
}
|
|
158
198
|
|
|
199
|
+
[Test]
|
|
200
|
+
[Parallelizable]
|
|
201
|
+
public void ByteRaw()
|
|
202
|
+
{
|
|
203
|
+
int sampleLength = GetSampleLength(byte.MaxValue);
|
|
204
|
+
TestAndVerify(
|
|
205
|
+
random => (int)((1.0 * random.NextByte()) / (1.0 * byte.MaxValue) * sampleLength),
|
|
206
|
+
maxLength: byte.MaxValue
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
159
210
|
[Test]
|
|
160
211
|
[Parallelizable]
|
|
161
212
|
public void ByteRange()
|
|
@@ -292,6 +343,16 @@
|
|
|
292
343
|
TestAndVerify(random => (int)random.NextLong(0, _samples.Length));
|
|
293
344
|
}
|
|
294
345
|
|
|
346
|
+
[Test]
|
|
347
|
+
[Parallelizable]
|
|
348
|
+
public void LongRaw()
|
|
349
|
+
{
|
|
350
|
+
int sampleLength = GetSampleLength();
|
|
351
|
+
TestAndVerify(random =>
|
|
352
|
+
(int)(1.0 * random.NextLong() / (1.0 * long.MaxValue) * sampleLength)
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
|
|
295
356
|
[Test]
|
|
296
357
|
[Parallelizable]
|
|
297
358
|
public void LongRange()
|
|
@@ -319,6 +380,16 @@
|
|
|
319
380
|
TestAndVerify(random => (int)random.NextUlong(0, (ulong)_samples.Length));
|
|
320
381
|
}
|
|
321
382
|
|
|
383
|
+
[Test]
|
|
384
|
+
[Parallelizable]
|
|
385
|
+
public void UlongRaw()
|
|
386
|
+
{
|
|
387
|
+
int sampleLength = GetSampleLength();
|
|
388
|
+
TestAndVerify(random =>
|
|
389
|
+
(int)(1.0 * random.NextUlong() / (1.0 * ulong.MaxValue) * sampleLength)
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
|
|
322
393
|
[Test]
|
|
323
394
|
[Parallelizable]
|
|
324
395
|
public void UlongRange()
|
|
@@ -339,6 +410,78 @@
|
|
|
339
410
|
);
|
|
340
411
|
}
|
|
341
412
|
|
|
413
|
+
[Test]
|
|
414
|
+
[Parallelizable]
|
|
415
|
+
public void NextBytes()
|
|
416
|
+
{
|
|
417
|
+
IRandom random = NewRandom();
|
|
418
|
+
HashSet<byte> seen = new();
|
|
419
|
+
int total = 0;
|
|
420
|
+
for (int i = 0; i < NormalIterations; ++i)
|
|
421
|
+
{
|
|
422
|
+
int size = random.Next(1, 40);
|
|
423
|
+
total += size;
|
|
424
|
+
byte[] buffer = new byte[size];
|
|
425
|
+
random.NextBytes(buffer);
|
|
426
|
+
foreach (byte value in buffer)
|
|
427
|
+
{
|
|
428
|
+
seen.Add(value);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
double seenTargetMin = Math.Min(total, byte.MaxValue) * 0.9;
|
|
433
|
+
double seenTargetMax = Math.Min(total, byte.MaxValue) * 1.1;
|
|
434
|
+
Assert.LessOrEqual(seenTargetMin, seen.Count);
|
|
435
|
+
Assert.GreaterOrEqual(seenTargetMax, seen.Count);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
[Test]
|
|
439
|
+
[Parallelizable]
|
|
440
|
+
public void NextGaussian()
|
|
441
|
+
{
|
|
442
|
+
IRandom random = NewRandom();
|
|
443
|
+
List<double> values = new();
|
|
444
|
+
for (int i = 0; i < NormalIterations; ++i)
|
|
445
|
+
{
|
|
446
|
+
double value = random.NextGaussian();
|
|
447
|
+
values.Add(value);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
Assert.IsTrue(CheckApproximateNormality(values));
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
[Test]
|
|
454
|
+
[Parallelizable]
|
|
455
|
+
public void NextGuid()
|
|
456
|
+
{
|
|
457
|
+
IRandom random = NewRandom();
|
|
458
|
+
|
|
459
|
+
HashSet<Guid> seen = new();
|
|
460
|
+
for (int i = 0; i < NormalIterations; ++i)
|
|
461
|
+
{
|
|
462
|
+
Guid value = random.NextGuid();
|
|
463
|
+
seen.Add(value);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
Assert.LessOrEqual(NormalIterations * 0.9, seen.Count);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
[Test]
|
|
470
|
+
[Parallelizable]
|
|
471
|
+
public void NextKGuid()
|
|
472
|
+
{
|
|
473
|
+
IRandom random = NewRandom();
|
|
474
|
+
|
|
475
|
+
HashSet<KGuid> seen = new();
|
|
476
|
+
for (int i = 0; i < NormalIterations; ++i)
|
|
477
|
+
{
|
|
478
|
+
KGuid value = random.NextKGuid();
|
|
479
|
+
seen.Add(value);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
Assert.LessOrEqual(NormalIterations * 0.9, seen.Count);
|
|
483
|
+
}
|
|
484
|
+
|
|
342
485
|
[Test]
|
|
343
486
|
[Parallelizable]
|
|
344
487
|
public void Copy()
|
|
@@ -388,11 +531,164 @@
|
|
|
388
531
|
}
|
|
389
532
|
}
|
|
390
533
|
|
|
391
|
-
|
|
534
|
+
[Test]
|
|
535
|
+
[Parallelizable]
|
|
536
|
+
public void NextEnumerable()
|
|
537
|
+
{
|
|
538
|
+
IRandom random = NewRandom();
|
|
539
|
+
for (int i = 0; i < NormalIterations; ++i)
|
|
540
|
+
{
|
|
541
|
+
HashSet<TestValues> selected = Enum.GetValues(typeof(TestValues))
|
|
542
|
+
.OfType<TestValues>()
|
|
543
|
+
.Shuffled(random)
|
|
544
|
+
.Skip(3)
|
|
545
|
+
.ToHashSet();
|
|
546
|
+
|
|
547
|
+
TestValues value = random.NextOf(selected.Shuffled(random));
|
|
548
|
+
Assert.IsTrue(selected.Contains(value));
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
[Test]
|
|
553
|
+
[Parallelizable]
|
|
554
|
+
public void NextArray()
|
|
555
|
+
{
|
|
556
|
+
IRandom random = NewRandom();
|
|
557
|
+
for (int i = 0; i < NormalIterations; ++i)
|
|
558
|
+
{
|
|
559
|
+
TestValues[] values = Enum.GetValues(typeof(TestValues))
|
|
560
|
+
.OfType<TestValues>()
|
|
561
|
+
.Shuffled(random)
|
|
562
|
+
.Skip(3)
|
|
563
|
+
.ToArray();
|
|
564
|
+
|
|
565
|
+
TestValues value = random.NextOf(values);
|
|
566
|
+
Assert.IsTrue(values.Contains(value));
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
[Test]
|
|
571
|
+
[Parallelizable]
|
|
572
|
+
public void NextList()
|
|
573
|
+
{
|
|
574
|
+
IRandom random = NewRandom();
|
|
575
|
+
for (int i = 0; i < NormalIterations; ++i)
|
|
576
|
+
{
|
|
577
|
+
List<TestValues> values = Enum.GetValues(typeof(TestValues))
|
|
578
|
+
.OfType<TestValues>()
|
|
579
|
+
.Shuffled(random)
|
|
580
|
+
.Skip(3)
|
|
581
|
+
.ToList();
|
|
582
|
+
|
|
583
|
+
TestValues value = random.NextOf(values);
|
|
584
|
+
Assert.IsTrue(values.Contains(value));
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
[Test]
|
|
589
|
+
[Parallelizable]
|
|
590
|
+
public void NextHashSet()
|
|
591
|
+
{
|
|
592
|
+
IRandom random = NewRandom();
|
|
593
|
+
for (int i = 0; i < NormalIterations; ++i)
|
|
594
|
+
{
|
|
595
|
+
HashSet<TestValues> values = Enum.GetValues(typeof(TestValues))
|
|
596
|
+
.OfType<TestValues>()
|
|
597
|
+
.Shuffled(random)
|
|
598
|
+
.Skip(3)
|
|
599
|
+
.ToHashSet();
|
|
600
|
+
|
|
601
|
+
TestValues value = random.NextOf(values);
|
|
602
|
+
Assert.IsTrue(values.Contains(value));
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
[Test]
|
|
607
|
+
[Parallelizable]
|
|
608
|
+
public void NextLinkedList()
|
|
609
|
+
{
|
|
610
|
+
IRandom random = NewRandom();
|
|
611
|
+
for (int i = 0; i < NormalIterations; ++i)
|
|
612
|
+
{
|
|
613
|
+
LinkedList<TestValues> values = Enum.GetValues(typeof(TestValues))
|
|
614
|
+
.OfType<TestValues>()
|
|
615
|
+
.Shuffled(random)
|
|
616
|
+
.Skip(3)
|
|
617
|
+
.ToLinkedList();
|
|
618
|
+
|
|
619
|
+
TestValues value = random.NextOf(values);
|
|
620
|
+
Assert.IsTrue(values.Contains(value));
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
[Test]
|
|
625
|
+
[Parallelizable]
|
|
626
|
+
public void NextEnum()
|
|
627
|
+
{
|
|
628
|
+
IRandom random = NewRandom();
|
|
629
|
+
HashSet<TestValues> seenEnums = new();
|
|
630
|
+
for (int i = 0; i < NormalIterations; ++i)
|
|
631
|
+
{
|
|
632
|
+
TestValues value = random.NextEnum<TestValues>();
|
|
633
|
+
_ = seenEnums.Add(value);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
Assert.AreEqual(Enum.GetValues(typeof(TestValues)).Length, seenEnums.Count);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
[Test]
|
|
640
|
+
[Parallelizable]
|
|
641
|
+
public void NextNoiseMap()
|
|
642
|
+
{
|
|
643
|
+
IRandom random = NewRandom();
|
|
644
|
+
for (int i = 0; i < NormalIterations; ++i)
|
|
645
|
+
{
|
|
646
|
+
int width = random.Next(1, 75);
|
|
647
|
+
int height = random.Next(1, 75);
|
|
648
|
+
float[,] noise = random.NextNoiseMap(width, height);
|
|
649
|
+
Assert.IsNotNull(noise);
|
|
650
|
+
Assert.AreEqual(width * height, noise.Length);
|
|
651
|
+
foreach (float value in noise)
|
|
652
|
+
{
|
|
653
|
+
Assert.LessOrEqual(0f, value);
|
|
654
|
+
Assert.GreaterOrEqual(1.1f, value);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
protected virtual double GetDeviationFor(string caller)
|
|
392
660
|
{
|
|
393
661
|
return 0.0625;
|
|
394
662
|
}
|
|
395
663
|
|
|
664
|
+
private static bool CheckApproximateNormality(IEnumerable<double> data)
|
|
665
|
+
{
|
|
666
|
+
IReadOnlyList<double> input = data as IReadOnlyList<double> ?? data.ToArray();
|
|
667
|
+
int n = input.Count;
|
|
668
|
+
if (n < 3)
|
|
669
|
+
{
|
|
670
|
+
return true;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
double mean = input.Average();
|
|
674
|
+
double variance = input.Sum(x => Math.Pow(x - mean, 2)) / n;
|
|
675
|
+
double stdDev = Math.Sqrt(variance);
|
|
676
|
+
|
|
677
|
+
double skewness = input.Sum(x => Math.Pow((x - mean) / stdDev, 3)) / n;
|
|
678
|
+
double kurtosis = input.Sum(x => Math.Pow((x - mean) / stdDev, 4)) / n - 3; // Excess kurtosis
|
|
679
|
+
|
|
680
|
+
// Thresholds can be defined based on empirical rules or domain-specific values
|
|
681
|
+
const double skewnessThreshold = 0.5;
|
|
682
|
+
const double kurtosisThreshold = 1.0;
|
|
683
|
+
|
|
684
|
+
return Math.Abs(skewness) < skewnessThreshold && Math.Abs(kurtosis) < kurtosisThreshold;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
protected int GetSampleLength(int? sampleLength = null)
|
|
688
|
+
{
|
|
689
|
+
return Math.Min(_samples.Length, sampleLength ?? _samples.Length);
|
|
690
|
+
}
|
|
691
|
+
|
|
396
692
|
private void TestAndVerify(
|
|
397
693
|
Func<IRandom, int> sample,
|
|
398
694
|
int? maxLength = null,
|
|
@@ -414,9 +710,9 @@
|
|
|
414
710
|
}
|
|
415
711
|
}
|
|
416
712
|
|
|
417
|
-
sampleLength =
|
|
713
|
+
sampleLength = GetSampleLength(maxLength);
|
|
418
714
|
double average = SampleCount * 1.0 / sampleLength;
|
|
419
|
-
double deviationAllowed = average *
|
|
715
|
+
double deviationAllowed = average * GetDeviationFor(caller);
|
|
420
716
|
List<int> zeroCountIndexes = new();
|
|
421
717
|
List<int> outsideRange = new();
|
|
422
718
|
for (int i = 0; i < sampleLength; i++)
|