@cloudglides/nox 1.1.3 → 1.1.5

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.
@@ -28,15 +28,17 @@ export class RNG {
28
28
  }
29
29
 
30
30
  int(min, max) {
31
- if (typeof min !== 'number' || typeof max !== 'number') {
32
- throw new TypeError('int() requires two number arguments');
33
- }
34
- if (!Number.isInteger(min) || !Number.isInteger(max)) {
35
- throw new TypeError('int() arguments must be integers');
36
- }
37
- if (min > max) [min, max] = [max, min];
38
- return Math.floor(this.nextFloat() * (max - min + 1)) + min;
39
- }
31
+ if (typeof min !== 'number' || typeof max !== 'number') {
32
+ throw new TypeError('int() requires two number arguments');
33
+ }
34
+ if (!Number.isInteger(min) || !Number.isInteger(max)) {
35
+ throw new TypeError('int() arguments must be integers');
36
+ }
37
+ if (min > max) [min, max] = [max, min];
38
+ const range = max - min + 1;
39
+ let val = Math.floor(this.nextFloat() * range);
40
+ return val + min;
41
+ }
40
42
 
41
43
  bool(probability = 0.5) {
42
44
  if (typeof probability !== 'number') {
@@ -68,74 +70,78 @@ export class RNG {
68
70
  }
69
71
 
70
72
  choice(arr) {
71
- if (!Array.isArray(arr) || arr.length === 0) {
72
- throw new TypeError('choice() requires non-empty array');
73
- }
74
- return arr[this.nextInt(arr.length)];
75
- }
73
+ if (!Array.isArray(arr)) {
74
+ throw new TypeError('choice() requires array');
75
+ }
76
+ const len = arr.length;
77
+ if (len === 0) {
78
+ throw new TypeError('choice() requires non-empty array');
79
+ }
80
+ return arr[this.nextInt(len)];
81
+ }
76
82
 
77
83
  batch(count, fn) {
78
- if (typeof count !== 'number' || !Number.isInteger(count)) {
79
- throw new TypeError('count must be an integer');
80
- }
81
- if (count < 0) {
82
- throw new RangeError('count must be non-negative');
83
- }
84
- if (typeof fn !== 'function') {
85
- throw new TypeError('fn must be a function');
86
- }
87
-
88
- const result = [];
89
- for (let i = 0; i < count; i++) {
90
- result.push(fn(this, i));
91
- }
92
- return result;
93
- }
94
-
95
- floats(count) {
96
- if (typeof count !== 'number' || !Number.isInteger(count)) {
97
- throw new TypeError('count must be an integer');
98
- }
99
- if (count < 0) {
100
- throw new RangeError('count must be non-negative');
101
- }
102
-
103
- const result = new Array(count);
104
- for (let i = 0; i < count; i++) {
105
- result[i] = this.nextFloat();
106
- }
107
- return result;
108
- }
109
-
110
- ints(count, max = 2147483647) {
111
- if (typeof count !== 'number' || !Number.isInteger(count)) {
112
- throw new TypeError('count must be an integer');
113
- }
114
- if (count < 0) {
115
- throw new RangeError('count must be non-negative');
116
- }
117
-
118
- const result = new Array(count);
119
- for (let i = 0; i < count; i++) {
120
- result[i] = this.nextInt(max);
121
- }
122
- return result;
123
- }
124
-
125
- bools(count, probability = 0.5) {
126
- if (typeof count !== 'number' || !Number.isInteger(count)) {
127
- throw new TypeError('count must be an integer');
128
- }
129
- if (count < 0) {
130
- throw new RangeError('count must be non-negative');
131
- }
132
-
133
- const result = new Array(count);
134
- for (let i = 0; i < count; i++) {
135
- result[i] = this.bool(probability);
136
- }
137
- return result;
138
- }
84
+ if (typeof count !== 'number' || !Number.isInteger(count)) {
85
+ throw new TypeError('count must be an integer');
86
+ }
87
+ if (count <= 0) {
88
+ return [];
89
+ }
90
+ if (typeof fn !== 'function') {
91
+ throw new TypeError('fn must be a function');
92
+ }
93
+
94
+ const result = new Array(count);
95
+ for (let i = 0; i < count; i++) {
96
+ result[i] = fn(this, i);
97
+ }
98
+ return result;
99
+ }
100
+
101
+ floats(count) {
102
+ if (typeof count !== 'number' || !Number.isInteger(count)) {
103
+ throw new TypeError('count must be an integer');
104
+ }
105
+ if (count <= 0) {
106
+ return [];
107
+ }
108
+
109
+ const result = new Array(count);
110
+ for (let i = 0; i < count; i++) {
111
+ result[i] = this.nextFloat();
112
+ }
113
+ return result;
114
+ }
115
+
116
+ ints(count, max = 2147483647) {
117
+ if (typeof count !== 'number' || !Number.isInteger(count)) {
118
+ throw new TypeError('count must be an integer');
119
+ }
120
+ if (count <= 0) {
121
+ return [];
122
+ }
123
+
124
+ const result = new Array(count);
125
+ for (let i = 0; i < count; i++) {
126
+ result[i] = this.nextInt(max);
127
+ }
128
+ return result;
129
+ }
130
+
131
+ bools(count, probability = 0.5) {
132
+ if (typeof count !== 'number' || !Number.isInteger(count)) {
133
+ throw new TypeError('count must be an integer');
134
+ }
135
+ if (count <= 0) {
136
+ return [];
137
+ }
138
+
139
+ const result = new Array(count);
140
+ for (let i = 0; i < count; i++) {
141
+ result[i] = this.bool(probability);
142
+ }
143
+ return result;
144
+ }
139
145
  }
140
146
 
141
147
  export const rng = () => new RNG();
package/src/rng.js CHANGED
@@ -28,15 +28,17 @@ export class RNG {
28
28
  }
29
29
 
30
30
  int(min, max) {
31
- if (typeof min !== 'number' || typeof max !== 'number') {
32
- throw new TypeError('int() requires two number arguments');
33
- }
34
- if (!Number.isInteger(min) || !Number.isInteger(max)) {
35
- throw new TypeError('int() arguments must be integers');
36
- }
37
- if (min > max) [min, max] = [max, min];
38
- return Math.floor(this.nextFloat() * (max - min + 1)) + min;
39
- }
31
+ if (typeof min !== 'number' || typeof max !== 'number') {
32
+ throw new TypeError('int() requires two number arguments');
33
+ }
34
+ if (!Number.isInteger(min) || !Number.isInteger(max)) {
35
+ throw new TypeError('int() arguments must be integers');
36
+ }
37
+ if (min > max) [min, max] = [max, min];
38
+ const range = max - min + 1;
39
+ let val = Math.floor(this.nextFloat() * range);
40
+ return val + min;
41
+ }
40
42
 
41
43
  bool(probability = 0.5) {
42
44
  if (typeof probability !== 'number') {
@@ -68,74 +70,78 @@ export class RNG {
68
70
  }
69
71
 
70
72
  choice(arr) {
71
- if (!Array.isArray(arr) || arr.length === 0) {
72
- throw new TypeError('choice() requires non-empty array');
73
- }
74
- return arr[this.nextInt(arr.length)];
75
- }
73
+ if (!Array.isArray(arr)) {
74
+ throw new TypeError('choice() requires array');
75
+ }
76
+ const len = arr.length;
77
+ if (len === 0) {
78
+ throw new TypeError('choice() requires non-empty array');
79
+ }
80
+ return arr[this.nextInt(len)];
81
+ }
76
82
 
77
83
  batch(count, fn) {
78
- if (typeof count !== 'number' || !Number.isInteger(count)) {
79
- throw new TypeError('count must be an integer');
80
- }
81
- if (count < 0) {
82
- throw new RangeError('count must be non-negative');
83
- }
84
- if (typeof fn !== 'function') {
85
- throw new TypeError('fn must be a function');
86
- }
87
-
88
- const result = [];
89
- for (let i = 0; i < count; i++) {
90
- result.push(fn(this, i));
91
- }
92
- return result;
93
- }
84
+ if (typeof count !== 'number' || !Number.isInteger(count)) {
85
+ throw new TypeError('count must be an integer');
86
+ }
87
+ if (count <= 0) {
88
+ return [];
89
+ }
90
+ if (typeof fn !== 'function') {
91
+ throw new TypeError('fn must be a function');
92
+ }
93
+
94
+ const result = new Array(count);
95
+ for (let i = 0; i < count; i++) {
96
+ result[i] = fn(this, i);
97
+ }
98
+ return result;
99
+ }
94
100
 
95
101
  floats(count) {
96
- if (typeof count !== 'number' || !Number.isInteger(count)) {
97
- throw new TypeError('count must be an integer');
98
- }
99
- if (count < 0) {
100
- throw new RangeError('count must be non-negative');
101
- }
102
-
103
- const result = new Array(count);
104
- for (let i = 0; i < count; i++) {
105
- result[i] = this.nextFloat();
106
- }
107
- return result;
108
- }
109
-
110
- ints(count, max = 2147483647) {
111
- if (typeof count !== 'number' || !Number.isInteger(count)) {
112
- throw new TypeError('count must be an integer');
113
- }
114
- if (count < 0) {
115
- throw new RangeError('count must be non-negative');
116
- }
117
-
118
- const result = new Array(count);
119
- for (let i = 0; i < count; i++) {
120
- result[i] = this.nextInt(max);
121
- }
122
- return result;
123
- }
124
-
125
- bools(count, probability = 0.5) {
126
- if (typeof count !== 'number' || !Number.isInteger(count)) {
127
- throw new TypeError('count must be an integer');
128
- }
129
- if (count < 0) {
130
- throw new RangeError('count must be non-negative');
131
- }
132
-
133
- const result = new Array(count);
134
- for (let i = 0; i < count; i++) {
135
- result[i] = this.bool(probability);
136
- }
137
- return result;
138
- }
102
+ if (typeof count !== 'number' || !Number.isInteger(count)) {
103
+ throw new TypeError('count must be an integer');
104
+ }
105
+ if (count <= 0) {
106
+ return [];
107
+ }
108
+
109
+ const result = new Array(count);
110
+ for (let i = 0; i < count; i++) {
111
+ result[i] = this.nextFloat();
112
+ }
113
+ return result;
114
+ }
115
+
116
+ ints(count, max = 2147483647) {
117
+ if (typeof count !== 'number' || !Number.isInteger(count)) {
118
+ throw new TypeError('count must be an integer');
119
+ }
120
+ if (count <= 0) {
121
+ return [];
122
+ }
123
+
124
+ const result = new Array(count);
125
+ for (let i = 0; i < count; i++) {
126
+ result[i] = this.nextInt(max);
127
+ }
128
+ return result;
129
+ }
130
+
131
+ bools(count, probability = 0.5) {
132
+ if (typeof count !== 'number' || !Number.isInteger(count)) {
133
+ throw new TypeError('count must be an integer');
134
+ }
135
+ if (count <= 0) {
136
+ return [];
137
+ }
138
+
139
+ const result = new Array(count);
140
+ for (let i = 0; i < count; i++) {
141
+ result[i] = this.bool(probability);
142
+ }
143
+ return result;
144
+ }
139
145
  }
140
146
 
141
147
  export const rng = () => new RNG();
@@ -1,23 +1,25 @@
1
+ const TWO_PI = 2 * Math.PI;
2
+
1
3
  export const normal = (rng, mean = 0, stddev = 1) => {
2
- if (!rng || typeof rng.nextFloat !== 'function') {
3
- throw new TypeError('First argument must be RNG instance');
4
- }
5
- if (typeof mean !== 'number' || typeof stddev !== 'number') {
6
- throw new TypeError('mean and stddev must be numbers');
7
- }
8
- if (stddev <= 0) {
9
- throw new Error('stddev must be positive');
10
- }
11
-
12
- let u1, u2;
13
- do {
14
- u1 = rng.nextFloat();
15
- u2 = rng.nextFloat();
16
- } while (u1 <= 0 || u2 <= 0);
17
-
18
- const z0 = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
19
- return z0 * stddev + mean;
20
- };
4
+ if (!rng || typeof rng.nextFloat !== 'function') {
5
+ throw new TypeError('First argument must be RNG instance');
6
+ }
7
+ if (typeof mean !== 'number' || typeof stddev !== 'number') {
8
+ throw new TypeError('mean and stddev must be numbers');
9
+ }
10
+ if (stddev <= 0) {
11
+ throw new Error('stddev must be positive');
12
+ }
13
+
14
+ let u1, u2;
15
+ do {
16
+ u1 = rng.nextFloat();
17
+ u2 = rng.nextFloat();
18
+ } while (u1 <= 0 || u2 <= 0);
19
+
20
+ const z0 = Math.sqrt(-2 * Math.log(u1)) * Math.cos(TWO_PI * u2);
21
+ return z0 * stddev + mean;
22
+ };
21
23
 
22
24
  export const exponential = (rng, lambda = 1) => {
23
25
  if (!rng || typeof rng.nextFloat !== 'function') {
@@ -34,38 +34,43 @@ export const weightedPick = (arr, weights, rng) => {
34
34
  };
35
35
 
36
36
  export const weightedSample = (arr, weights, count, rng) => {
37
- if (!Array.isArray(arr) || arr.length === 0) {
38
- throw new TypeError('arr must be a non-empty array');
39
- }
40
- if (!Array.isArray(weights) || weights.length === 0) {
41
- throw new TypeError('weights must be a non-empty array');
42
- }
43
- if (arr.length !== weights.length) {
44
- throw new Error('arr and weights must have same length');
45
- }
46
- if (typeof count !== 'number' || !Number.isInteger(count)) {
47
- throw new TypeError('count must be an integer');
48
- }
49
- if (count < 0) {
50
- throw new RangeError('count must be non-negative');
51
- }
52
- if (!rng || typeof rng.nextFloat !== 'function') {
53
- throw new TypeError('rng must be an RNG instance');
54
- }
55
-
56
- const result = [];
57
- const remaining = [...arr];
58
- const remainingWeights = [...weights];
59
-
60
- for (let i = 0; i < count && remaining.length > 0; i++) {
61
- const idx = weightedPickIndex(remainingWeights, rng);
62
- result.push(remaining[idx]);
63
- remaining.splice(idx, 1);
64
- remainingWeights.splice(idx, 1);
65
- }
66
-
67
- return result;
68
- };
37
+ if (!Array.isArray(arr) || arr.length === 0) {
38
+ throw new TypeError('arr must be a non-empty array');
39
+ }
40
+ if (!Array.isArray(weights) || weights.length === 0) {
41
+ throw new TypeError('weights must be a non-empty array');
42
+ }
43
+ if (arr.length !== weights.length) {
44
+ throw new Error('arr and weights must have same length');
45
+ }
46
+ if (typeof count !== 'number' || !Number.isInteger(count)) {
47
+ throw new TypeError('count must be an integer');
48
+ }
49
+ if (count <= 0) {
50
+ return [];
51
+ }
52
+ if (!rng || typeof rng.nextFloat !== 'function') {
53
+ throw new TypeError('rng must be an RNG instance');
54
+ }
55
+
56
+ const result = [];
57
+ const len = arr.length;
58
+ if (count >= len) {
59
+ return [...arr];
60
+ }
61
+
62
+ const remaining = [...arr];
63
+ const remainingWeights = [...weights];
64
+
65
+ for (let i = 0; i < count && remaining.length > 0; i++) {
66
+ const idx = weightedPickIndex(remainingWeights, rng);
67
+ result.push(remaining[idx]);
68
+ remaining.splice(idx, 1);
69
+ remainingWeights.splice(idx, 1);
70
+ }
71
+
72
+ return result;
73
+ };
69
74
 
70
75
  const weightedPickIndex = (weights, rng) => {
71
76
  const total = weights.reduce((a, b) => a + b, 0);
@@ -80,27 +85,30 @@ const weightedPickIndex = (weights, rng) => {
80
85
  };
81
86
 
82
87
  export const reservoirSample = (stream, k, rng) => {
83
- if (!Array.isArray(stream) || stream.length === 0) {
84
- throw new TypeError('stream must be a non-empty array');
85
- }
86
- if (typeof k !== 'number' || !Number.isInteger(k)) {
87
- throw new TypeError('k must be an integer');
88
- }
89
- if (k <= 0) {
90
- throw new RangeError('k must be positive');
91
- }
92
- if (!rng || typeof rng.nextInt !== 'function') {
93
- throw new TypeError('rng must be an RNG instance');
94
- }
95
-
96
- const reservoir = stream.slice(0, Math.min(k, stream.length));
97
-
98
- for (let i = k; i < stream.length; i++) {
99
- const j = rng.nextInt(i + 1);
100
- if (j < k) {
101
- reservoir[j] = stream[i];
102
- }
103
- }
104
-
105
- return reservoir;
106
- };
88
+ if (!Array.isArray(stream) || stream.length === 0) {
89
+ throw new TypeError('stream must be a non-empty array');
90
+ }
91
+ if (typeof k !== 'number' || !Number.isInteger(k)) {
92
+ throw new TypeError('k must be an integer');
93
+ }
94
+ if (k <= 0) {
95
+ throw new RangeError('k must be positive');
96
+ }
97
+ if (k > stream.length) {
98
+ throw new RangeError('k cannot exceed stream length');
99
+ }
100
+ if (!rng || typeof rng.nextInt !== 'function') {
101
+ throw new TypeError('rng must be an RNG instance');
102
+ }
103
+
104
+ const reservoir = stream.slice(0, k);
105
+
106
+ for (let i = k; i < stream.length; i++) {
107
+ const j = rng.nextInt(i + 1);
108
+ if (j < k) {
109
+ reservoir[j] = stream[i];
110
+ }
111
+ }
112
+
113
+ return reservoir;
114
+ };
@@ -1,21 +1,23 @@
1
1
  export const shuffle = (arr, rng, inPlace = false) => {
2
- if (!Array.isArray(arr)) {
3
- throw new TypeError('First argument must be array');
4
- }
5
- if (!rng || typeof rng.nextInt !== 'function') {
6
- throw new TypeError('RNG instance required');
7
- }
8
- if (typeof inPlace !== 'boolean') {
9
- throw new TypeError('inPlace must be boolean');
10
- }
11
-
12
- const target = inPlace ? arr : [...arr];
13
- for (let i = target.length - 1; i > 0; i--) {
14
- const j = rng.nextInt(i + 1);
15
- [target[i], target[j]] = [target[j], target[i]];
16
- }
17
- return target;
18
- };
2
+ if (!Array.isArray(arr)) {
3
+ throw new TypeError('First argument must be array');
4
+ }
5
+ if (!rng || typeof rng.nextInt !== 'function') {
6
+ throw new TypeError('RNG instance required');
7
+ }
8
+
9
+ const target = inPlace ? arr : [...arr];
10
+ const len = target.length;
11
+ for (let i = len - 1; i > 0; i--) {
12
+ const j = rng.nextInt(i + 1);
13
+ if (i !== j) {
14
+ const temp = target[i];
15
+ target[i] = target[j];
16
+ target[j] = temp;
17
+ }
18
+ }
19
+ return target;
20
+ };
19
21
 
20
22
  export const pick = (arr, rng) => {
21
23
  if (!Array.isArray(arr)) {
@@ -32,22 +34,29 @@ export const pick = (arr, rng) => {
32
34
  };
33
35
 
34
36
  export const sample = (arr, count, rng) => {
35
- if (!Array.isArray(arr)) {
36
- throw new TypeError('First argument must be array');
37
- }
38
- if (typeof count !== 'number' || !Number.isInteger(count)) {
39
- throw new TypeError('Sample count must be an integer');
40
- }
41
- if (count <= 0) {
42
- throw new Error('Sample count must be positive');
43
- }
44
- if (count > arr.length) {
45
- throw new Error('Sample count exceeds array length');
46
- }
47
- if (!rng || typeof rng.nextInt !== 'function') {
48
- throw new TypeError('RNG instance required');
49
- }
50
-
51
- const copy = shuffle(arr, rng);
52
- return copy.slice(0, count);
53
- };
37
+ if (!Array.isArray(arr)) {
38
+ throw new TypeError('First argument must be array');
39
+ }
40
+ if (typeof count !== 'number' || !Number.isInteger(count)) {
41
+ throw new TypeError('Sample count must be an integer');
42
+ }
43
+ if (count <= 0) {
44
+ throw new Error('Sample count must be positive');
45
+ }
46
+ if (count > arr.length) {
47
+ throw new Error('Sample count exceeds array length');
48
+ }
49
+ if (!rng || typeof rng.nextInt !== 'function') {
50
+ throw new TypeError('RNG instance required');
51
+ }
52
+
53
+ const copy = [...arr];
54
+ const len = copy.length;
55
+ for (let i = len - 1; i >= len - count; i--) {
56
+ const j = rng.nextInt(i + 1);
57
+ const temp = copy[i];
58
+ copy[i] = copy[j];
59
+ copy[j] = temp;
60
+ }
61
+ return copy.slice(len - count);
62
+ };