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/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 PRNGMethod {
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 method: PRNGMethod = PRNGMethod.sfc32;
19
+ public algorithm: Algorithm = Algorithm.splitmix32;
14
20
  public controllers: PRNGController[] = [];
15
21
 
16
- constructor(seed: string = '') {
17
- this.setSeed(seed);
18
- }
19
-
20
- public addController(controller: PRNGController) {
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
- public removeController(controller: PRNGController) {
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
- public setSeed(seed: string) {
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
- public setMethod(method: PRNGMethod) {
36
- this.method = method;
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.method) {
42
- case PRNGMethod.jsf32:
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 PRNGMethod.mulberry32:
76
+ case Algorithm.mulberry32:
45
77
  return mulberry32(hashes[0]);
46
- case PRNGMethod.sfc32:
78
+ case Algorithm.sfc32:
47
79
  return sfc32(hashes[0], hashes[1], hashes[2], hashes[3]);
48
- case PRNGMethod.xoshiro128ss:
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
- public randomInt(seed: string, min: number, max: number) {
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
- public randomItem<T = unknown>(seed: string, array: T[] = []): T | undefined {
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
- public randomIndex(seed: string, weights: number[] = []): number {
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
- // Pseudo-random Number Generator
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 {Function}
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 {Function}
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
- * @return {Function}
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
- * @return {Function}
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;
package/tsconfig.json CHANGED
@@ -5,7 +5,8 @@
5
5
  "baseUrl": ".",
6
6
  "outDir": "lib",
7
7
  "target": "ES5",
8
- "module": "NodeNext",
8
+ "module": "ESNext",
9
+ "moduleResolution": "Bundler",
9
10
  "lib": ["DOM", "ESNext"],
10
11
  "allowJs": true,
11
12
  "allowSyntheticDefaultImports": true,