toosoon-prng 1.1.0 → 1.2.1
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/README.md +192 -35
- package/lib/controllers.d.ts +13 -13
- package/lib/controllers.js +38 -44
- package/lib/index.d.ts +1 -2
- package/lib/index.js +2 -25
- package/lib/prng.d.ts +96 -6
- package/lib/prng.js +117 -30
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/utils.d.ts +11 -4
- package/lib/utils.js +27 -20
- package/package.json +7 -3
- package/src/controllers.ts +14 -14
- package/src/index.ts +1 -2
- package/src/prng.ts +110 -20
- package/src/utils.ts +23 -7
- package/tsconfig.json +2 -1
package/src/prng.ts
CHANGED
|
@@ -1,80 +1,163 @@
|
|
|
1
1
|
import { PRNGController } from './controllers';
|
|
2
|
-
import { cyrb128, jsf32, mulberry32, sfc32, xoshiro128ss } from './utils';
|
|
2
|
+
import { cyrb128, jsf32, mulberry32, sfc32, splitmix32, xoshiro128ss } from './utils';
|
|
3
3
|
|
|
4
|
-
export enum
|
|
4
|
+
export enum Algorithm {
|
|
5
5
|
jsf32 = 'jsf32',
|
|
6
6
|
mulberry32 = 'mulberry32',
|
|
7
7
|
sfc32 = 'sfc32',
|
|
8
|
+
splitmix32 = 'splitmix32', // Default
|
|
8
9
|
xoshiro128ss = 'xoshiro128**'
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
/**
|
|
13
|
+
* PRNG class
|
|
14
|
+
*
|
|
15
|
+
* @class PRNG
|
|
16
|
+
*/
|
|
11
17
|
class PRNG {
|
|
12
18
|
public seed: string = '';
|
|
13
|
-
public
|
|
19
|
+
public algorithm: Algorithm = Algorithm.splitmix32;
|
|
14
20
|
public controllers: PRNGController[] = [];
|
|
15
21
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Add a controller to this PRNG
|
|
24
|
+
*
|
|
25
|
+
* @param {PRNGController} controller
|
|
26
|
+
*/
|
|
27
|
+
public addController(controller: PRNGController): void {
|
|
21
28
|
this.controllers.push(controller);
|
|
22
29
|
}
|
|
23
30
|
|
|
24
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Remove a controller from this PRNG
|
|
33
|
+
*
|
|
34
|
+
* @param {PRNGController} controller
|
|
35
|
+
*/
|
|
36
|
+
public removeController(controller: PRNGController): void {
|
|
25
37
|
const index = this.controllers.indexOf(controller);
|
|
26
38
|
this.controllers.splice(index, 1);
|
|
27
39
|
}
|
|
28
40
|
|
|
29
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Set this PRNG seed
|
|
43
|
+
*
|
|
44
|
+
* @param {string} seed
|
|
45
|
+
*/
|
|
46
|
+
public setSeed(seed: string): void {
|
|
30
47
|
if (this.seed === seed) return;
|
|
31
48
|
this.seed = seed;
|
|
32
49
|
this.controllers.forEach((controller) => controller.getValue());
|
|
33
50
|
}
|
|
34
51
|
|
|
35
|
-
|
|
36
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Set this PRNG algorithm for generating pseudo-random values
|
|
54
|
+
*
|
|
55
|
+
* @param {Algorithm} algorithm Algorithm name
|
|
56
|
+
*/
|
|
57
|
+
public setAlgorithm(algorithm: Algorithm): void {
|
|
58
|
+
this.algorithm = algorithm;
|
|
59
|
+
this.controllers.forEach((controller) => controller.getValue());
|
|
37
60
|
}
|
|
38
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Generate a pseudo-random number in the interval [0, 1]
|
|
64
|
+
* PRNG equivalent of `Math.random()`
|
|
65
|
+
*
|
|
66
|
+
* @param {string} seed
|
|
67
|
+
* @returns {number}
|
|
68
|
+
*/
|
|
39
69
|
public random(seed: string): number {
|
|
40
70
|
const hashes = cyrb128(this.seed + seed);
|
|
41
|
-
switch (this.
|
|
42
|
-
case
|
|
71
|
+
switch (this.algorithm) {
|
|
72
|
+
case Algorithm.splitmix32:
|
|
73
|
+
return splitmix32(hashes[0]);
|
|
74
|
+
case Algorithm.jsf32:
|
|
43
75
|
return jsf32(hashes[0], hashes[1], hashes[2], hashes[3]);
|
|
44
|
-
case
|
|
76
|
+
case Algorithm.mulberry32:
|
|
45
77
|
return mulberry32(hashes[0]);
|
|
46
|
-
case
|
|
78
|
+
case Algorithm.sfc32:
|
|
47
79
|
return sfc32(hashes[0], hashes[1], hashes[2], hashes[3]);
|
|
48
|
-
case
|
|
80
|
+
case Algorithm.xoshiro128ss:
|
|
49
81
|
return xoshiro128ss(hashes[0], hashes[1], hashes[2], hashes[3]);
|
|
50
82
|
}
|
|
51
83
|
}
|
|
52
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Generate a pseudo-random boolean (true or false)
|
|
87
|
+
*
|
|
88
|
+
* @param {string} seed
|
|
89
|
+
* @param {number} [probability=0.5] Probability to get `true`
|
|
90
|
+
* @returns {boolean} Either `true` or `false`
|
|
91
|
+
*/
|
|
53
92
|
public randomBoolean(seed: string, probability: number = 0.5): boolean {
|
|
54
93
|
return this.random(seed) < probability;
|
|
55
94
|
}
|
|
56
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Generate a pseudo-random sign (1 or -1)
|
|
98
|
+
*
|
|
99
|
+
* @param {string} seed
|
|
100
|
+
* @param {number} [probability=0.5] Probability to get 1
|
|
101
|
+
* @returns {number} Either 1 or -1
|
|
102
|
+
*/
|
|
57
103
|
public randomSign(seed: string, probability: number = 0.5): number {
|
|
58
104
|
return this.randomBoolean(seed, probability) ? 1 : -1;
|
|
59
105
|
}
|
|
60
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Generate a pseudo-random floating-point number within a specified range
|
|
109
|
+
*
|
|
110
|
+
* @param {string} seed
|
|
111
|
+
* @param {number} [min=0] Minimum boundary
|
|
112
|
+
* @param {number} [max=1] Maximum boundary
|
|
113
|
+
* @param {number} [precision=2] Number of digits after the decimal point
|
|
114
|
+
* @returns {number} Generated float
|
|
115
|
+
*/
|
|
61
116
|
public randomFloat(seed: string, min: number = 0, max: number = 1, precision: number = 2): number {
|
|
62
117
|
return parseFloat(Math.min(min + this.random(seed) * (max - min), max).toFixed(precision));
|
|
63
118
|
}
|
|
64
119
|
|
|
65
|
-
|
|
120
|
+
/**
|
|
121
|
+
* Generate a pseudo-random integer number within a specified range
|
|
122
|
+
*
|
|
123
|
+
* @param {string} seed
|
|
124
|
+
* @param {number} min Minimum boundary
|
|
125
|
+
* @param {number} max Maximum boundary
|
|
126
|
+
* @returns {number} Generated integer
|
|
127
|
+
*/
|
|
128
|
+
public randomInt(seed: string, min: number, max: number): number {
|
|
66
129
|
return Math.floor(this.random(seed) * (max - min + 1) + min);
|
|
67
130
|
}
|
|
68
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Generate a pseudo-random hexadecimal color
|
|
134
|
+
*
|
|
135
|
+
* @param {string} seed
|
|
136
|
+
* @returns {string} Generated hexadecimal color
|
|
137
|
+
*/
|
|
69
138
|
public randomHexColor(seed: string): string {
|
|
70
139
|
return '#' + ('00000' + ((this.random(seed) * (1 << 24)) | 0).toString(16)).slice(-6);
|
|
71
140
|
}
|
|
72
141
|
|
|
73
|
-
|
|
142
|
+
/**
|
|
143
|
+
* Pick a pseudo-random item from a given array
|
|
144
|
+
*
|
|
145
|
+
* @param {string} seed
|
|
146
|
+
* @param {T[]} array Array to pick the item from
|
|
147
|
+
* @returns {T|undefined} Random item picked
|
|
148
|
+
*/
|
|
149
|
+
public randomItem<T = unknown>(seed: string, array: T[]): T | undefined {
|
|
74
150
|
if (array.length === 0) return undefined;
|
|
75
151
|
return array[this.randomInt(seed, 0, array.length - 1)];
|
|
76
152
|
}
|
|
77
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Pick a pseudo-random property value from a given object
|
|
156
|
+
*
|
|
157
|
+
* @param {string} seed
|
|
158
|
+
* @param {object} object Object to pick the property from
|
|
159
|
+
* @returns {T|undefined} Random item picked
|
|
160
|
+
*/
|
|
78
161
|
public randomObjectProperty<T = unknown>(seed: string, object: { [key: string]: T }): T | undefined {
|
|
79
162
|
const keys = Object.keys(object);
|
|
80
163
|
const key = this.randomItem(seed, keys);
|
|
@@ -83,7 +166,14 @@ class PRNG {
|
|
|
83
166
|
}
|
|
84
167
|
}
|
|
85
168
|
|
|
86
|
-
|
|
169
|
+
/**
|
|
170
|
+
* Select a pseudo-random index from an array of weighted items
|
|
171
|
+
*
|
|
172
|
+
* @param {string} seed
|
|
173
|
+
* @param {number[]} weights Array of weights
|
|
174
|
+
* @returns {number} Random index based on weights
|
|
175
|
+
*/
|
|
176
|
+
public randomIndex(seed: string, weights: number[]): number {
|
|
87
177
|
if (weights.length === 0) return -1;
|
|
88
178
|
|
|
89
179
|
let totalWeight = 0;
|
package/src/utils.ts
CHANGED
|
@@ -26,9 +26,9 @@ export function cyrb128(seed: string): number[] {
|
|
|
26
26
|
return [(h1 ^ h2 ^ h3 ^ h4) >>> 0, (h2 ^ h1) >>> 0, (h3 ^ h1) >>> 0, (h4 ^ h1) >>> 0];
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
29
|
+
// *********************
|
|
30
|
+
// Algorithms
|
|
31
|
+
// *********************
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Simple Fast Counter, Generator with a 128-bit state
|
|
@@ -37,7 +37,7 @@ export function cyrb128(seed: string): number[] {
|
|
|
37
37
|
* @param {number} b
|
|
38
38
|
* @param {number} c
|
|
39
39
|
* @param {number} d
|
|
40
|
-
* @return {
|
|
40
|
+
* @return {number}
|
|
41
41
|
*/
|
|
42
42
|
export function sfc32(a: number, b: number, c: number, d: number): number {
|
|
43
43
|
a >>>= 0;
|
|
@@ -54,11 +54,27 @@ export function sfc32(a: number, b: number, c: number, d: number): number {
|
|
|
54
54
|
return (t >>> 0) / 4294967296;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* SplitMix32, Generator with a 32-bit state
|
|
59
|
+
*
|
|
60
|
+
* @param {number} a
|
|
61
|
+
* @returns {number}
|
|
62
|
+
*/
|
|
63
|
+
export function splitmix32(a: number): number {
|
|
64
|
+
a |= 0;
|
|
65
|
+
a = (a + 0x9e3779b9) | 0;
|
|
66
|
+
var t = a ^ (a >>> 16);
|
|
67
|
+
t = Math.imul(t, 0x21f0aaad);
|
|
68
|
+
t = t ^ (t >>> 15);
|
|
69
|
+
t = Math.imul(t, 0x735a2d97);
|
|
70
|
+
return ((t = t ^ (t >>> 15)) >>> 0) / 4294967296;
|
|
71
|
+
}
|
|
72
|
+
|
|
57
73
|
/**
|
|
58
74
|
* Mulberry32, Generator with a 32-bit state
|
|
59
75
|
*
|
|
60
76
|
* @param {number} a
|
|
61
|
-
* @return {
|
|
77
|
+
* @return {number}
|
|
62
78
|
*/
|
|
63
79
|
export function mulberry32(a: number): number {
|
|
64
80
|
let t = (a += 0x6d2b79f5);
|
|
@@ -71,7 +87,7 @@ export function mulberry32(a: number): number {
|
|
|
71
87
|
* Jenkins' Small Fast, Generator with a 32-bit state
|
|
72
88
|
*
|
|
73
89
|
* @param {number} a
|
|
74
|
-
* @
|
|
90
|
+
* @returns {number}
|
|
75
91
|
*/
|
|
76
92
|
export function jsf32(a: number, b: number, c: number, d: number): number {
|
|
77
93
|
a |= 0;
|
|
@@ -90,7 +106,7 @@ export function jsf32(a: number, b: number, c: number, d: number): number {
|
|
|
90
106
|
* xoshiro128**, Generator with a 128-bit state
|
|
91
107
|
*
|
|
92
108
|
* @param {number} a
|
|
93
|
-
* @
|
|
109
|
+
* @returns {number}
|
|
94
110
|
*/
|
|
95
111
|
export function xoshiro128ss(a: number, b: number, c: number, d: number): number {
|
|
96
112
|
let t = b << 9;
|