novac 2.0.1 → 2.2.0

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.
Files changed (161) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1574 -597
  3. package/bin/novac +468 -171
  4. package/bin/nvc +522 -0
  5. package/bin/nvml +78 -17
  6. package/demo.nv +0 -0
  7. package/demo_builtins.nv +0 -0
  8. package/demo_http.nv +0 -0
  9. package/examples/bf.nv +69 -0
  10. package/examples/math.nv +21 -0
  11. package/kits/birdAPI/kitdef.js +954 -0
  12. package/kits/kitRNG/kitdef.js +740 -0
  13. package/kits/kitSSH/kitdef.js +1272 -0
  14. package/kits/kitadb/kitdef.js +606 -0
  15. package/kits/kitai/kitdef.js +2185 -0
  16. package/kits/kitansi/kitdef.js +1402 -0
  17. package/kits/kitcanvas/kitdef.js +914 -0
  18. package/kits/kitclippy/kitdef.js +925 -0
  19. package/kits/kitformat/kitdef.js +1485 -0
  20. package/kits/kitgps/kitdef.js +1862 -0
  21. package/kits/kitlibproc/kitdef.js +3 -2
  22. package/kits/kitmatrix/ex.js +19 -0
  23. package/kits/kitmatrix/kitdef.js +960 -0
  24. package/kits/kitmorse/kitdef.js +229 -0
  25. package/kits/kitmpatch/kitdef.js +906 -0
  26. package/kits/kitnet/kitdef.js +1401 -0
  27. package/kits/kitnovacweb/README.md +1416 -143
  28. package/kits/kitnovacweb/kitdef.js +92 -2
  29. package/kits/kitnovacweb/nvml/executor.js +578 -176
  30. package/kits/kitnovacweb/nvml/index.js +2 -2
  31. package/kits/kitnovacweb/nvml/lexer.js +72 -69
  32. package/kits/kitnovacweb/nvml/parser.js +328 -159
  33. package/kits/kitnovacweb/nvml/renderer.js +770 -270
  34. package/kits/kitparse/kitdef.js +1688 -0
  35. package/kits/kitproto/kitdef.js +613 -0
  36. package/kits/kitqr/kitdef.js +637 -0
  37. package/kits/kitregex++/kitdef.js +1353 -0
  38. package/kits/kitrequire/kitdef.js +1599 -0
  39. package/kits/kitx11/kitdef.js +1 -0
  40. package/kits/kitx11/kitx11.js +2472 -0
  41. package/kits/kitx11/kitx11_conn.js +948 -0
  42. package/kits/kitx11/kitx11_worker.js +121 -0
  43. package/kits/libtea/kitdef.js +2691 -0
  44. package/kits/libterm/ex.js +285 -0
  45. package/kits/libterm/kitdef.js +1927 -0
  46. package/novac/LICENSE +21 -0
  47. package/novac/README.md +1823 -0
  48. package/novac/bin/novac +950 -0
  49. package/novac/bin/nvc +522 -0
  50. package/novac/bin/nvml +542 -0
  51. package/novac/demo.nv +245 -0
  52. package/novac/demo_builtins.nv +209 -0
  53. package/novac/demo_http.nv +62 -0
  54. package/novac/examples/bf.nv +69 -0
  55. package/novac/examples/math.nv +21 -0
  56. package/novac/kits/kitai/kitdef.js +2185 -0
  57. package/novac/kits/kitansi/kitdef.js +1402 -0
  58. package/novac/kits/kitformat/kitdef.js +1485 -0
  59. package/novac/kits/kitgps/kitdef.js +1862 -0
  60. package/novac/kits/kitlibfs/kitdef.js +231 -0
  61. package/{examples/example-project/nova_modules → novac/kits}/kitlibproc/kitdef.js +3 -2
  62. package/novac/kits/kitmatrix/ex.js +19 -0
  63. package/novac/kits/kitmatrix/kitdef.js +960 -0
  64. package/novac/kits/kitmpatch/kitdef.js +906 -0
  65. package/novac/kits/kitnovacweb/README.md +1572 -0
  66. package/novac/kits/kitnovacweb/demo.nv +12 -0
  67. package/novac/kits/kitnovacweb/demo.nvml +71 -0
  68. package/novac/kits/kitnovacweb/index.nova +12 -0
  69. package/novac/kits/kitnovacweb/kitdef.js +692 -0
  70. package/novac/kits/kitnovacweb/nova.kit.json +8 -0
  71. package/novac/kits/kitnovacweb/nvml/executor.js +739 -0
  72. package/novac/kits/kitnovacweb/nvml/index.js +67 -0
  73. package/novac/kits/kitnovacweb/nvml/lexer.js +263 -0
  74. package/novac/kits/kitnovacweb/nvml/parser.js +508 -0
  75. package/novac/kits/kitnovacweb/nvml/renderer.js +924 -0
  76. package/novac/kits/kitparse/kitdef.js +1688 -0
  77. package/novac/kits/kitregex++/kitdef.js +1353 -0
  78. package/novac/kits/kitrequire/kitdef.js +1599 -0
  79. package/novac/kits/kitx11/kitdef.js +1 -0
  80. package/novac/kits/kitx11/kitx11.js +2472 -0
  81. package/novac/kits/kitx11/kitx11_conn.js +948 -0
  82. package/novac/kits/kitx11/kitx11_worker.js +121 -0
  83. package/novac/kits/libtea/tf.js +2691 -0
  84. package/novac/kits/libterm/ex.js +285 -0
  85. package/novac/kits/libterm/kitdef.js +1927 -0
  86. package/novac/node_modules/chalk/license +9 -0
  87. package/novac/node_modules/chalk/package.json +83 -0
  88. package/novac/node_modules/chalk/readme.md +297 -0
  89. package/novac/node_modules/chalk/source/index.d.ts +325 -0
  90. package/novac/node_modules/chalk/source/index.js +225 -0
  91. package/novac/node_modules/chalk/source/utilities.js +33 -0
  92. package/novac/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
  93. package/novac/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
  94. package/novac/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
  95. package/novac/node_modules/chalk/source/vendor/supports-color/browser.js +34 -0
  96. package/novac/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
  97. package/novac/node_modules/chalk/source/vendor/supports-color/index.js +190 -0
  98. package/novac/node_modules/commander/LICENSE +22 -0
  99. package/novac/node_modules/commander/Readme.md +1176 -0
  100. package/novac/node_modules/commander/esm.mjs +16 -0
  101. package/novac/node_modules/commander/index.js +24 -0
  102. package/novac/node_modules/commander/lib/argument.js +150 -0
  103. package/novac/node_modules/commander/lib/command.js +2777 -0
  104. package/novac/node_modules/commander/lib/error.js +39 -0
  105. package/novac/node_modules/commander/lib/help.js +747 -0
  106. package/novac/node_modules/commander/lib/option.js +380 -0
  107. package/novac/node_modules/commander/lib/suggestSimilar.js +101 -0
  108. package/novac/node_modules/commander/package-support.json +19 -0
  109. package/novac/node_modules/commander/package.json +82 -0
  110. package/novac/node_modules/commander/typings/esm.d.mts +3 -0
  111. package/novac/node_modules/commander/typings/index.d.ts +1113 -0
  112. package/novac/node_modules/node-addon-api/LICENSE.md +9 -0
  113. package/novac/node_modules/node-addon-api/README.md +95 -0
  114. package/novac/node_modules/node-addon-api/common.gypi +21 -0
  115. package/novac/node_modules/node-addon-api/except.gypi +25 -0
  116. package/novac/node_modules/node-addon-api/index.js +14 -0
  117. package/novac/node_modules/node-addon-api/napi-inl.deprecated.h +186 -0
  118. package/novac/node_modules/node-addon-api/napi-inl.h +7165 -0
  119. package/novac/node_modules/node-addon-api/napi.h +3364 -0
  120. package/novac/node_modules/node-addon-api/node_addon_api.gyp +42 -0
  121. package/novac/node_modules/node-addon-api/node_api.gyp +9 -0
  122. package/novac/node_modules/node-addon-api/noexcept.gypi +26 -0
  123. package/novac/node_modules/node-addon-api/package-support.json +21 -0
  124. package/novac/node_modules/node-addon-api/package.json +480 -0
  125. package/novac/node_modules/node-addon-api/tools/README.md +73 -0
  126. package/novac/node_modules/node-addon-api/tools/check-napi.js +99 -0
  127. package/novac/node_modules/node-addon-api/tools/clang-format.js +71 -0
  128. package/novac/node_modules/node-addon-api/tools/conversion.js +301 -0
  129. package/novac/node_modules/serialize-javascript/LICENSE +27 -0
  130. package/novac/node_modules/serialize-javascript/README.md +149 -0
  131. package/novac/node_modules/serialize-javascript/index.js +297 -0
  132. package/novac/node_modules/serialize-javascript/package.json +33 -0
  133. package/novac/package.json +27 -0
  134. package/novac/scripts/update-bin.js +24 -0
  135. package/novac/src/core/bstd.js +1035 -0
  136. package/novac/src/core/config.js +155 -0
  137. package/novac/src/core/describe.js +187 -0
  138. package/novac/src/core/emitter.js +499 -0
  139. package/novac/src/core/error.js +86 -0
  140. package/novac/src/core/executor.js +5606 -0
  141. package/novac/src/core/formatter.js +686 -0
  142. package/novac/src/core/lexer.js +1026 -0
  143. package/novac/src/core/nova_builtins.js +717 -0
  144. package/novac/src/core/nova_thread_worker.js +166 -0
  145. package/novac/src/core/parser.js +2181 -0
  146. package/novac/src/core/types.js +112 -0
  147. package/novac/src/index.js +28 -0
  148. package/novac/src/runtime/stdlib.js +244 -0
  149. package/package.json +6 -3
  150. package/scripts/update-bin.js +0 -0
  151. package/src/core/bstd.js +838 -362
  152. package/src/core/executor.js +2578 -170
  153. package/src/core/lexer.js +502 -54
  154. package/src/core/nova_builtins.js +21 -3
  155. package/src/core/parser.js +413 -72
  156. package/src/core/types.js +30 -2
  157. package/src/index.js +0 -0
  158. package/examples/example-project/README.md +0 -3
  159. package/examples/example-project/src/main.nova +0 -3
  160. package/src/core/environment.js +0 -0
  161. /package/{examples/example-project/bin/example-project.nv → novac/node_modules/node-addon-api/nothing.c} +0 -0
@@ -0,0 +1,740 @@
1
+ // kitdef.js — kitRandom
2
+ // Comprehensive random number generation, sampling, shuffling, weighted
3
+ // selection, seeded RNG, distributions, ID generation, geometry, and more.
4
+
5
+ module.exports = {
6
+ kitdef: {
7
+
8
+ name: "kitRandom",
9
+ version: "1.0.0",
10
+ description: "Comprehensive random utilities: floats, ints, booleans, sampling, shuffling, weighted picks, seeded RNG, distributions, ID generation, geometry, and dice.",
11
+
12
+ // ──────────────────────────────────────────────────────────────────────
13
+ // BASIC FLOATS & INTS
14
+ // ──────────────────────────────────────────────────────────────────────
15
+
16
+ /** Random float in [0, 1) */
17
+ float01() {
18
+ return Math.random();
19
+ },
20
+
21
+ /**
22
+ * Random float in [min, max).
23
+ * If only one argument, returns float in [0, min).
24
+ */
25
+ float(min, max) {
26
+ if (min === undefined) return Math.random();
27
+ if (max === undefined) { max = min; min = 0; }
28
+ return min + Math.random() * (max - min);
29
+ },
30
+
31
+ /** Random float in [min, max], inclusive on both ends. */
32
+ floatInclusive(min, max) {
33
+ return min + Math.random() * (max - min + Number.EPSILON);
34
+ },
35
+
36
+ /**
37
+ * Random integer in [min, max], inclusive on both ends.
38
+ * If only one argument, returns int in [0, min].
39
+ */
40
+ int(min, max) {
41
+ if (max === undefined) { max = min; min = 0; }
42
+ min = Math.ceil(min);
43
+ max = Math.floor(max);
44
+ return Math.floor(Math.random() * (max - min + 1)) + min;
45
+ },
46
+
47
+ /**
48
+ * Random integer in [min, max), exclusive of max.
49
+ */
50
+ intExclusive(min, max) {
51
+ if (max === undefined) { max = min; min = 0; }
52
+ min = Math.ceil(min);
53
+ max = Math.floor(max);
54
+ return Math.floor(Math.random() * (max - min)) + min;
55
+ },
56
+
57
+ /** Random sign: returns 1 or -1. */
58
+ sign() {
59
+ return Math.random() < 0.5 ? 1 : -1;
60
+ },
61
+
62
+ /** Random number rounded to a given number of decimal places. */
63
+ floatRounded(min, max, decimals = 2) {
64
+ const f = this.float(min, max);
65
+ return parseFloat(f.toFixed(decimals));
66
+ },
67
+
68
+ // ──────────────────────────────────────────────────────────────────────
69
+ // BOOLEANS
70
+ // ──────────────────────────────────────────────────────────────────────
71
+
72
+ /** Random boolean, 50/50. */
73
+ bool() {
74
+ return Math.random() < 0.5;
75
+ },
76
+
77
+ /**
78
+ * Random boolean with a given probability of being true.
79
+ * @param {number} p - Probability in [0, 1]. Default 0.5.
80
+ */
81
+ chance(p = 0.5) {
82
+ return Math.random() < p;
83
+ },
84
+
85
+ /** Roll a 1-in-n chance. Returns true if it hits. */
86
+ oneIn(n) {
87
+ return Math.floor(Math.random() * n) === 0;
88
+ },
89
+
90
+ // ──────────────────────────────────────────────────────────────────────
91
+ // ARRAY SAMPLING & SHUFFLING
92
+ // ──────────────────────────────────────────────────────────────────────
93
+
94
+ /**
95
+ * Pick one random item from an array.
96
+ * Returns undefined for empty arrays.
97
+ */
98
+ pick(arr) {
99
+ if (!arr || arr.length === 0) return undefined;
100
+ return arr[Math.floor(Math.random() * arr.length)];
101
+ },
102
+
103
+ /**
104
+ * Pick k unique random items from an array (no replacement).
105
+ * Returns a new array of length min(k, arr.length).
106
+ */
107
+ sample(arr, k) {
108
+ if (!arr || arr.length === 0) return [];
109
+ k = Math.min(k, arr.length);
110
+ const copy = arr.slice();
111
+ const result = [];
112
+ for (let i = 0; i < k; i++) {
113
+ const j = Math.floor(Math.random() * (copy.length - i)) + i;
114
+ [copy[i], copy[j]] = [copy[j], copy[i]];
115
+ result.push(copy[i]);
116
+ }
117
+ return result;
118
+ },
119
+
120
+ /**
121
+ * Pick k items from an array with replacement (duplicates allowed).
122
+ */
123
+ sampleWithReplacement(arr, k) {
124
+ if (!arr || arr.length === 0) return [];
125
+ const result = [];
126
+ for (let i = 0; i < k; i++) {
127
+ result.push(arr[Math.floor(Math.random() * arr.length)]);
128
+ }
129
+ return result;
130
+ },
131
+
132
+ /**
133
+ * Shuffle an array in-place using Fisher-Yates.
134
+ * Returns the same array.
135
+ */
136
+ shuffle(arr) {
137
+ for (let i = arr.length - 1; i > 0; i--) {
138
+ const j = Math.floor(Math.random() * (i + 1));
139
+ [arr[i], arr[j]] = [arr[j], arr[i]];
140
+ }
141
+ return arr;
142
+ },
143
+
144
+ /**
145
+ * Return a shuffled copy of an array without mutating the original.
146
+ */
147
+ shuffled(arr) {
148
+ return this.shuffle(arr.slice());
149
+ },
150
+
151
+ /**
152
+ * Pick a random key from an object.
153
+ */
154
+ pickKey(obj) {
155
+ const keys = Object.keys(obj);
156
+ return keys[Math.floor(Math.random() * keys.length)];
157
+ },
158
+
159
+ /**
160
+ * Pick a random value from an object.
161
+ */
162
+ pickValue(obj) {
163
+ const values = Object.values(obj);
164
+ return values[Math.floor(Math.random() * values.length)];
165
+ },
166
+
167
+ /**
168
+ * Pick a random entry [key, value] from an object.
169
+ */
170
+ pickEntry(obj) {
171
+ const entries = Object.entries(obj);
172
+ return entries[Math.floor(Math.random() * entries.length)];
173
+ },
174
+
175
+ // ──────────────────────────────────────────────────────────────────────
176
+ // WEIGHTED SELECTION
177
+ // ──────────────────────────────────────────────────────────────────────
178
+
179
+ /**
180
+ * Pick an item by weight. Weights do not need to sum to 1.
181
+ * @param {Array} items - Array of items to pick from.
182
+ * @param {Array} weights - Parallel array of numeric weights (>= 0).
183
+ *
184
+ * @example
185
+ * weighted(["common","rare","legendary"], [100, 10, 1])
186
+ */
187
+ weighted(items, weights) {
188
+ if (items.length !== weights.length) throw new Error("items and weights must be the same length");
189
+ const total = weights.reduce((s, w) => s + w, 0);
190
+ if (total <= 0) throw new Error("weights must sum to a positive number");
191
+ let r = Math.random() * total;
192
+ for (let i = 0; i < items.length; i++) {
193
+ r -= weights[i];
194
+ if (r <= 0) return items[i];
195
+ }
196
+ return items[items.length - 1];
197
+ },
198
+
199
+ /**
200
+ * Pick from an array of { item, weight } objects.
201
+ * @example
202
+ * weightedObjects([{ item: "sword", weight: 5 }, { item: "shield", weight: 3 }])
203
+ */
204
+ weightedObjects(entries) {
205
+ return this.weighted(entries.map(e => e.item), entries.map(e => e.weight));
206
+ },
207
+
208
+ /**
209
+ * Pick multiple items by weight, with replacement.
210
+ */
211
+ weightedSample(items, weights, k) {
212
+ const result = [];
213
+ for (let i = 0; i < k; i++) result.push(this.weighted(items, weights));
214
+ return result;
215
+ },
216
+
217
+ // ──────────────────────────────────────────────────────────────────────
218
+ // DISTRIBUTIONS
219
+ // ──────────────────────────────────────────────────────────────────────
220
+
221
+ /**
222
+ * Normal (Gaussian) distribution using Box-Muller transform.
223
+ * @param {number} mean - Default 0.
224
+ * @param {number} stddev - Default 1.
225
+ */
226
+ gaussian(mean = 0, stddev = 1) {
227
+ let u, v;
228
+ do { u = Math.random(); } while (u === 0);
229
+ do { v = Math.random(); } while (v === 0);
230
+ return mean + Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v) * stddev;
231
+ },
232
+
233
+ /**
234
+ * Gaussian clamped to [min, max] by resampling until in range.
235
+ */
236
+ gaussianClamped(mean, stddev, min, max) {
237
+ let v;
238
+ do { v = this.gaussian(mean, stddev); } while (v < min || v > max);
239
+ return v;
240
+ },
241
+
242
+ /**
243
+ * Exponential distribution: models time between events.
244
+ * @param {number} lambda - Rate parameter (default 1). Mean = 1/lambda.
245
+ */
246
+ exponential(lambda = 1) {
247
+ return -Math.log(1 - Math.random()) / lambda;
248
+ },
249
+
250
+ /**
251
+ * Triangular distribution between min and max with a peak at mode.
252
+ * Useful for estimates (optimistic/pessimistic/likely).
253
+ */
254
+ triangular(min, mode, max) {
255
+ const u = Math.random();
256
+ const fc = (mode - min) / (max - min);
257
+ if (u < fc) return min + Math.sqrt(u * (max - min) * (mode - min));
258
+ return max - Math.sqrt((1 - u) * (max - min) * (max - mode));
259
+ },
260
+
261
+ /**
262
+ * Bernoulli trial: returns 1 with probability p, else 0.
263
+ */
264
+ bernoulli(p = 0.5) {
265
+ return Math.random() < p ? 1 : 0;
266
+ },
267
+
268
+ /**
269
+ * Binomial: number of successes in n Bernoulli trials with probability p.
270
+ */
271
+ binomial(n, p) {
272
+ let s = 0;
273
+ for (let i = 0; i < n; i++) if (Math.random() < p) s++;
274
+ return s;
275
+ },
276
+
277
+ /**
278
+ * Poisson distribution: number of events in a fixed interval.
279
+ * @param {number} lambda - Expected number of events (mean).
280
+ */
281
+ poisson(lambda) {
282
+ const L = Math.exp(-lambda);
283
+ let k = 0, p = 1;
284
+ do { k++; p *= Math.random(); } while (p > L);
285
+ return k - 1;
286
+ },
287
+
288
+ /**
289
+ * Beta distribution via Johnk's method.
290
+ * Useful for modeling probabilities and proportions.
291
+ * @param {number} alpha
292
+ * @param {number} beta
293
+ */
294
+ beta(alpha, beta) {
295
+ const x = this.gamma(alpha, 1);
296
+ const y = this.gamma(beta, 1);
297
+ return x / (x + y);
298
+ },
299
+
300
+ /**
301
+ * Gamma distribution using Marsaglia-Tsang's method.
302
+ * @param {number} shape (k)
303
+ * @param {number} scale (theta) - Default 1.
304
+ */
305
+ gamma(shape, scale = 1) {
306
+ if (shape < 1) return this.gamma(1 + shape, scale) * Math.pow(Math.random(), 1 / shape);
307
+ const d = shape - 1 / 3;
308
+ const c = 1 / Math.sqrt(9 * d);
309
+ while (true) {
310
+ let x, v;
311
+ do { x = this.gaussian(); v = 1 + c * x; } while (v <= 0);
312
+ v = v * v * v;
313
+ const u = Math.random();
314
+ if (u < 1 - 0.0331 * (x * x) * (x * x)) return d * v * scale;
315
+ if (Math.log(u) < 0.5 * x * x + d * (1 - v + Math.log(v))) return d * v * scale;
316
+ }
317
+ },
318
+
319
+ /**
320
+ * Pareto distribution.
321
+ * @param {number} scale - Minimum value (xm).
322
+ * @param {number} shape - Shape parameter (alpha).
323
+ */
324
+ pareto(scale, shape) {
325
+ return scale / Math.pow(Math.random(), 1 / shape);
326
+ },
327
+
328
+ /**
329
+ * Log-normal distribution.
330
+ * @param {number} mean - Mean of the underlying normal.
331
+ * @param {number} stddev - Std dev of the underlying normal.
332
+ */
333
+ logNormal(mean = 0, stddev = 1) {
334
+ return Math.exp(this.gaussian(mean, stddev));
335
+ },
336
+
337
+ /**
338
+ * Cauchy distribution (heavy-tailed).
339
+ * @param {number} location - Default 0.
340
+ * @param {number} scale - Default 1.
341
+ */
342
+ cauchy(location = 0, scale = 1) {
343
+ return location + scale * Math.tan(Math.PI * (Math.random() - 0.5));
344
+ },
345
+
346
+ // ──────────────────────────────────────────────────────────────────────
347
+ // SEEDED RNG (Mulberry32)
348
+ // ──────────────────────────────────────────────────────────────────────
349
+
350
+ /**
351
+ * Create a seeded pseudo-random number generator (Mulberry32).
352
+ * Deterministic: same seed → same sequence every time.
353
+ * @param {number|string} seed
354
+ * @returns {object} A seeded RNG with the same API surface.
355
+ *
356
+ * @example
357
+ * const rng = kitRandom.seeded(42);
358
+ * rng.float(0, 10);
359
+ * rng.pick(["a", "b", "c"]);
360
+ */
361
+ seeded(seed) {
362
+ if (typeof seed === "string") {
363
+ seed = Array.from(seed).reduce((h, c) => Math.imul(31, h) + c.charCodeAt(0) | 0, 0);
364
+ }
365
+ let s = seed >>> 0;
366
+
367
+ const next = () => {
368
+ s += 0x6d2b79f5;
369
+ let t = s;
370
+ t = Math.imul(t ^ (t >>> 15), t | 1);
371
+ t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
372
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
373
+ };
374
+
375
+ return {
376
+ _seed: seed,
377
+ _next: next,
378
+ float01: () => next(),
379
+ float: (min, max) => { if (max===undefined){max=min;min=0;} return min + next()*(max-min); },
380
+ int: (min, max) => { if (max===undefined){max=min;min=0;} return Math.floor(next()*(Math.floor(max)-Math.ceil(min)+1))+Math.ceil(min); },
381
+ bool: () => next() < 0.5,
382
+ chance: (p = 0.5) => next() < p,
383
+ sign: () => next() < 0.5 ? 1 : -1,
384
+ pick: (arr) => arr[Math.floor(next() * arr.length)],
385
+ shuffle(arr) {
386
+ for (let i = arr.length - 1; i > 0; i--) {
387
+ const j = Math.floor(next() * (i + 1));
388
+ [arr[i], arr[j]] = [arr[j], arr[i]];
389
+ }
390
+ return arr;
391
+ },
392
+ shuffled(arr) { return this.shuffle(arr.slice()); },
393
+ gaussian(mean = 0, stddev = 1) {
394
+ let u, v;
395
+ do { u = next(); } while (u === 0);
396
+ do { v = next(); } while (v === 0);
397
+ return mean + Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v) * stddev;
398
+ },
399
+ weighted(items, weights) {
400
+ const total = weights.reduce((s, w) => s + w, 0);
401
+ let r = next() * total;
402
+ for (let i = 0; i < items.length; i++) { r -= weights[i]; if (r <= 0) return items[i]; }
403
+ return items[items.length - 1];
404
+ },
405
+ uuid() {
406
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => {
407
+ const r = Math.floor(next() * 16);
408
+ return (c === "x" ? r : (r & 0x3 | 0x8)).toString(16);
409
+ });
410
+ },
411
+ };
412
+ },
413
+
414
+ // ──────────────────────────────────────────────────────────────────────
415
+ // ID & TOKEN GENERATION
416
+ // ──────────────────────────────────────────────────────────────────────
417
+
418
+ /**
419
+ * Generate a UUID v4 string.
420
+ * Uses crypto.randomUUID() if available, falls back to Math.random().
421
+ */
422
+ uuid() {
423
+ if (typeof crypto !== "undefined" && crypto.randomUUID) return crypto.randomUUID();
424
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => {
425
+ const r = Math.random() * 16 | 0;
426
+ return (c === "x" ? r : (r & 0x3 | 0x8)).toString(16);
427
+ });
428
+ },
429
+
430
+ /**
431
+ * Generate a short random ID (base62, URL-safe).
432
+ * @param {number} length - Default 8.
433
+ * @example nanoid(12) => "aB3kZ9xQ2mLp"
434
+ */
435
+ nanoid(length = 8) {
436
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
437
+ let id = "";
438
+ for (let i = 0; i < length; i++) id += chars[Math.floor(Math.random() * chars.length)];
439
+ return id;
440
+ },
441
+
442
+ /**
443
+ * Generate a random hex string of a given byte length.
444
+ * @param {number} bytes - Default 16 (128-bit).
445
+ * @example hex(4) => "a3f2c1b0"
446
+ */
447
+ hex(bytes = 16) {
448
+ let h = "";
449
+ for (let i = 0; i < bytes; i++) h += Math.floor(Math.random() * 256).toString(16).padStart(2, "0");
450
+ return h;
451
+ },
452
+
453
+ /**
454
+ * Generate a random string from a custom alphabet.
455
+ * @param {number} length
456
+ * @param {string} [alphabet]
457
+ */
458
+ string(length, alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") {
459
+ let s = "";
460
+ for (let i = 0; i < length; i++) s += alphabet[Math.floor(Math.random() * alphabet.length)];
461
+ return s;
462
+ },
463
+
464
+ /**
465
+ * Generate a random numeric PIN of a given length.
466
+ * @param {number} length - Default 4.
467
+ */
468
+ pin(length = 4) {
469
+ return this.string(length, "0123456789");
470
+ },
471
+
472
+ /**
473
+ * Generate a random color in hex format.
474
+ * @example color() => "#a3f2c1"
475
+ */
476
+ color() {
477
+ return `#${this.hex(3)}`;
478
+ },
479
+
480
+ /**
481
+ * Generate a random RGB color object.
482
+ * @returns {{ r, g, b }}
483
+ */
484
+ rgb() {
485
+ return { r: this.int(0, 255), g: this.int(0, 255), b: this.int(0, 255) };
486
+ },
487
+
488
+ // ──────────────────────────────────────────────────────────────────────
489
+ // GEOMETRY & SPATIAL
490
+ // ──────────────────────────────────────────────────────────────────────
491
+
492
+ /**
493
+ * Random point on the surface of a unit circle.
494
+ * Returns { x, y } with x²+y²=1.
495
+ */
496
+ onUnitCircle() {
497
+ const a = Math.random() * 2 * Math.PI;
498
+ return { x: Math.cos(a), y: Math.sin(a) };
499
+ },
500
+
501
+ /**
502
+ * Random point inside a unit disk (uniform, not center-biased).
503
+ * Returns { x, y }.
504
+ */
505
+ inUnitDisk() {
506
+ let x, y;
507
+ do { x = Math.random() * 2 - 1; y = Math.random() * 2 - 1; } while (x * x + y * y >= 1);
508
+ return { x, y };
509
+ },
510
+
511
+ /**
512
+ * Random point on the surface of a unit sphere.
513
+ * Returns { x, y, z } with x²+y²+z²=1.
514
+ */
515
+ onUnitSphere() {
516
+ const u = Math.random() * 2 - 1;
517
+ const t = Math.random() * 2 * Math.PI;
518
+ const r = Math.sqrt(1 - u * u);
519
+ return { x: r * Math.cos(t), y: r * Math.sin(t), z: u };
520
+ },
521
+
522
+ /**
523
+ * Random point uniformly inside an axis-aligned bounding box.
524
+ * @param {{ x?: number, y?: number, w: number, h: number }} rect
525
+ */
526
+ inRect({ x = 0, y = 0, w, h }) {
527
+ return { x: x + Math.random() * w, y: y + Math.random() * h };
528
+ },
529
+
530
+ /**
531
+ * Random point inside an axis-aligned bounding box in 3D.
532
+ * @param {{ x?: number, y?: number, z?: number, w: number, h: number, d: number }} box
533
+ */
534
+ inBox({ x = 0, y = 0, z = 0, w, h, d }) {
535
+ return { x: x + Math.random() * w, y: y + Math.random() * h, z: z + Math.random() * d };
536
+ },
537
+
538
+ /**
539
+ * Random angle in radians in [0, 2π).
540
+ */
541
+ angle() {
542
+ return Math.random() * 2 * Math.PI;
543
+ },
544
+
545
+ /**
546
+ * Random direction vector in 2D (unit length).
547
+ * @returns {{ x, y }}
548
+ */
549
+ direction2D() {
550
+ return this.onUnitCircle();
551
+ },
552
+
553
+ /**
554
+ * Random direction vector in 3D (unit length).
555
+ * @returns {{ x, y, z }}
556
+ */
557
+ direction3D() {
558
+ return this.onUnitSphere();
559
+ },
560
+
561
+ // ──────────────────────────────────────────────────────────────────────
562
+ // DICE & GAMES
563
+ // ──────────────────────────────────────────────────────────────────────
564
+
565
+ /**
566
+ * Roll dice.
567
+ * @param {number} count - Number of dice.
568
+ * @param {number} sides - Sides per die.
569
+ * @returns {{ rolls: number[], total: number }}
570
+ * @example dice(2, 6) => { rolls: [3, 5], total: 8 }
571
+ */
572
+ dice(count, sides) {
573
+ const rolls = Array.from({ length: count }, () => this.int(1, sides));
574
+ return { rolls, total: rolls.reduce((s, v) => s + v, 0) };
575
+ },
576
+
577
+ /**
578
+ * Parse and roll standard dice notation strings.
579
+ * Supports: "2d6", "1d20+5", "4d6k3" (keep highest 3), "2d8-1".
580
+ * @returns {{ rolls, kept, modifier, total }}
581
+ *
582
+ * @example
583
+ * rollNotation("4d6k3") // roll 4d6, keep highest 3
584
+ * rollNotation("1d20+5") // roll 1d20 and add 5
585
+ */
586
+ rollNotation(notation) {
587
+ const m = notation.toLowerCase().match(/^(\d+)d(\d+)(?:k(\d+))?([+-]\d+)?$/);
588
+ if (!m) throw new Error(`Invalid dice notation: "${notation}"`);
589
+ const [, count, sides, keep, mod] = m;
590
+ const { rolls } = this.dice(Number(count), Number(sides));
591
+ const sorted = rolls.slice().sort((a, b) => b - a);
592
+ const kept = keep ? sorted.slice(0, Number(keep)) : sorted;
593
+ const modifier = mod ? Number(mod) : 0;
594
+ return { rolls, kept, modifier, total: kept.reduce((s, v) => s + v, 0) + modifier };
595
+ },
596
+
597
+ /**
598
+ * Flip a coin. Returns "heads" or "tails".
599
+ */
600
+ coin() {
601
+ return Math.random() < 0.5 ? "heads" : "tails";
602
+ },
603
+
604
+ /**
605
+ * Draw a random card from a standard 52-card deck.
606
+ * @returns {{ suit, rank, value, card }}
607
+ */
608
+ drawCard() {
609
+ const suits = ["♠", "♥", "♦", "♣"];
610
+ const ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"];
611
+ const suit = suits[Math.floor(Math.random() * 4)];
612
+ const rank = ranks[Math.floor(Math.random() * 13)];
613
+ const value = rank === "A" ? 11 : ["J","Q","K"].includes(rank) ? 10 : parseInt(rank);
614
+ return { suit, rank, value, card: `${rank}${suit}` };
615
+ },
616
+
617
+ /**
618
+ * Shuffle and return a full 52-card deck.
619
+ * @returns {Array<{ suit, rank, value, card }>}
620
+ */
621
+ shuffleDeck() {
622
+ const suits = ["♠", "♥", "♦", "♣"];
623
+ const ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"];
624
+ const deck = [];
625
+ for (const suit of suits) {
626
+ for (const rank of ranks) {
627
+ const value = rank === "A" ? 11 : ["J","Q","K"].includes(rank) ? 10 : parseInt(rank);
628
+ deck.push({ suit, rank, value, card: `${rank}${suit}` });
629
+ }
630
+ }
631
+ return this.shuffle(deck);
632
+ },
633
+
634
+ // ──────────────────────────────────────────────────────────────────────
635
+ // UTILITIES
636
+ // ──────────────────────────────────────────────────────────────────────
637
+
638
+ /**
639
+ * Randomly split a value into n parts that sum to total.
640
+ * Returns an array of n non-negative floats.
641
+ * @example split(100, 3) => [42.1, 31.7, 26.2]
642
+ */
643
+ split(total, n) {
644
+ const cuts = Array.from({ length: n - 1 }, () => Math.random() * total).sort((a, b) => a - b);
645
+ const parts = [];
646
+ let prev = 0;
647
+ for (const c of cuts) { parts.push(c - prev); prev = c; }
648
+ parts.push(total - prev);
649
+ return parts;
650
+ },
651
+
652
+ /**
653
+ * Randomly split a value into n integer parts that sum to total.
654
+ */
655
+ splitInt(total, n) {
656
+ const parts = this.split(total, n).map(Math.round);
657
+ const diff = total - parts.reduce((s, v) => s + v, 0);
658
+ parts[0] += diff;
659
+ return parts;
660
+ },
661
+
662
+ /**
663
+ * Jitter a value by up to ±amount.
664
+ * @example jitter(100, 5) => somewhere in [95, 105]
665
+ */
666
+ jitter(value, amount) {
667
+ return value + (Math.random() * 2 - 1) * amount;
668
+ },
669
+
670
+ /**
671
+ * Randomly perturb each element of an array by up to ±amount.
672
+ */
673
+ jitterArray(arr, amount) {
674
+ return arr.map(v => this.jitter(v, amount));
675
+ },
676
+
677
+ /**
678
+ * Choose a random date between two dates.
679
+ * @param {Date|string} start
680
+ * @param {Date|string} end
681
+ * @returns {Date}
682
+ */
683
+ date(start, end) {
684
+ const s = new Date(start).getTime();
685
+ const e = new Date(end).getTime();
686
+ return new Date(s + Math.random() * (e - s));
687
+ },
688
+
689
+ /**
690
+ * Pick a random element from a Set.
691
+ * @param {Set} set
692
+ */
693
+ pickFromSet(set) {
694
+ const arr = Array.from(set);
695
+ return arr[Math.floor(Math.random() * arr.length)];
696
+ },
697
+
698
+ /**
699
+ * Pick a random element from a Map (returns [key, value]).
700
+ * @param {Map} map
701
+ */
702
+ pickFromMap(map) {
703
+ const entries = Array.from(map.entries());
704
+ return entries[Math.floor(Math.random() * entries.length)];
705
+ },
706
+
707
+ /**
708
+ * Generate a random IPv4 address.
709
+ */
710
+ ipv4() {
711
+ return Array.from({ length: 4 }, () => this.int(0, 255)).join(".");
712
+ },
713
+
714
+ /**
715
+ * Generate a random MAC address.
716
+ */
717
+ mac() {
718
+ return Array.from({ length: 6 }, () => this.hex(1).padStart(2, "0")).join(":");
719
+ },
720
+
721
+ /**
722
+ * Randomly rotate an array by a random amount.
723
+ * @param {Array} arr
724
+ * @returns {Array}
725
+ */
726
+ rotate(arr) {
727
+ const n = this.int(0, arr.length - 1);
728
+ return [...arr.slice(n), ...arr.slice(0, n)];
729
+ },
730
+
731
+ /**
732
+ * Return true with probability 1/n, simulating a random event trigger.
733
+ * Alias for oneIn() with more semantic naming.
734
+ */
735
+ trigger(n) {
736
+ return this.oneIn(n);
737
+ },
738
+
739
+ }
740
+ };