@inglorious/utils 3.8.0 → 5.0.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 (73) hide show
  1. package/README.md +83 -3
  2. package/package.json +104 -12
  3. package/src/algorithms/decision-tree.js +3 -3
  4. package/src/algorithms/path-finding.js +6 -6
  5. package/src/data-structures/array.js +12 -0
  6. package/src/data-structures/board.js +97 -15
  7. package/src/data-structures/index.js +1 -2
  8. package/src/data-structures/object.js +164 -2
  9. package/src/data-structures/string.js +77 -0
  10. package/src/data-structures/tree.js +1 -1
  11. package/src/functions/function.js +190 -0
  12. package/src/functions/index.js +1 -4
  13. package/src/math/circle.js +5 -7
  14. package/src/math/hitmask.js +1 -1
  15. package/src/math/index.js +2 -6
  16. package/src/math/line.js +4 -4
  17. package/src/math/point.js +31 -9
  18. package/src/math/quaternion.js +19 -2
  19. package/src/math/rectangle.js +16 -4
  20. package/src/math/rng.js +5 -2
  21. package/src/math/segment.js +11 -5
  22. package/src/math/trigonometry.js +1 -1
  23. package/src/math/vector.js +288 -37
  24. package/src/physics/acceleration.js +2 -3
  25. package/src/physics/friction.js +1 -1
  26. package/src/physics/gravity.js +1 -1
  27. package/src/physics/jump.js +0 -4
  28. package/src/physics/velocity.js +2 -3
  29. package/src/v.js +1 -1
  30. package/types/algorithms/decision-tree.d.ts +27 -0
  31. package/types/algorithms/index.d.ts +2 -0
  32. package/types/algorithms/path-finding.d.ts +69 -0
  33. package/types/data-structures/array.d.ts +61 -0
  34. package/types/data-structures/board.d.ts +121 -0
  35. package/types/data-structures/boolean.d.ts +4 -0
  36. package/types/data-structures/heap.d.ts +69 -0
  37. package/types/data-structures/index.d.ts +8 -0
  38. package/types/data-structures/object.d.ts +237 -0
  39. package/types/data-structures/set.d.ts +4 -0
  40. package/types/data-structures/tree.d.ts +21 -0
  41. package/types/functions/function.d.ts +57 -0
  42. package/types/functions/index.d.ts +1 -0
  43. package/types/index.d.ts +6 -4
  44. package/types/math/circle.d.ts +22 -0
  45. package/types/math/hitmask.d.ts +20 -0
  46. package/types/math/index.d.ts +14 -0
  47. package/types/math/line.d.ts +11 -0
  48. package/types/math/linear-interpolation.d.ts +2 -0
  49. package/types/math/number.d.ts +26 -0
  50. package/types/math/point.d.ts +50 -0
  51. package/types/math/quaternion.d.ts +10 -0
  52. package/types/math/rectangle.d.ts +57 -0
  53. package/types/math/rng.d.ts +14 -0
  54. package/types/math/segment.d.ts +23 -0
  55. package/types/math/statistics.d.ts +11 -0
  56. package/types/math/triangle.d.ts +5 -0
  57. package/types/math/trigonometry.d.ts +26 -0
  58. package/types/math/vector.d.ts +219 -0
  59. package/types/physics/acceleration.d.ts +24 -0
  60. package/types/physics/friction.d.ts +11 -0
  61. package/types/physics/gravity.d.ts +20 -0
  62. package/types/physics/index.d.ts +5 -0
  63. package/types/physics/jump.d.ts +10 -0
  64. package/types/physics/velocity.d.ts +20 -0
  65. package/types/v.d.ts +7 -3
  66. package/src/data-structures/objects.js +0 -113
  67. package/src/functions/functions.js +0 -31
  68. package/src/math/quaternions.js +0 -23
  69. package/src/math/vectors.js +0 -212
  70. package/types/algorithms.d.ts +0 -26
  71. package/types/data-structures.d.ts +0 -53
  72. package/types/math.d.ts +0 -90
  73. /package/src/math/{numbers.js → number.js} +0 -0
@@ -1,16 +1,33 @@
1
1
  /**
2
- * @typedef {import("../../types/math").Vector3} Vector3
3
- * @typedef {import("../../types/math").Quaternion} Quaternion
2
+ * @typedef {import("../../types/math/vector").Vector3} Vector3
3
+ * @typedef {import("../../types/math/quaternion").Quaternion} Quaternion
4
4
  */
5
5
 
6
6
  import { v } from "../v.js"
7
7
  import { cos, sin } from "./trigonometry.js"
8
+ import { cross, dot, multiply, sum } from "./vector.js"
8
9
 
9
10
  const DEFAULT_ANGLE = 0
10
11
  const HALF = 2 // Constant representing the divisor for halving an angle.
11
12
  // eslint-disable-next-line no-magic-numbers
12
13
  const Y_AXIS = v(0, 1, 0) // Default axis of rotation (Y-axis).
13
14
 
15
+ /**
16
+ * Combines two quaternions using the Hamilton product.
17
+ * @param {Quaternion} q1 - The first quaternion.
18
+ * @param {Quaternion} q2 - The second quaternion.
19
+ * @returns {Quaternion} - The resulting quaternion after combining q1 and q2.
20
+ */
21
+ export function combine(q1, q2) {
22
+ const [s1, ...v1] = q1
23
+ const [s2, ...v2] = q2
24
+
25
+ return v(
26
+ s1 * s2 - dot(v1, v2),
27
+ ...sum(multiply(v2, s1), multiply(v1, s2), cross(v1, v2)),
28
+ )
29
+ }
30
+
14
31
  /**
15
32
  * Computes a quaternion representing a rotation around a given axis.
16
33
  * @param {number} [angle=0] - The angle of rotation in radians. Defaults to 0.
@@ -1,7 +1,14 @@
1
1
  /**
2
- * @typedef {import("../../types/math").Circle} Circle
3
- * @typedef {import("../../types/math").Rectangle} Rectangle
4
- * @typedef {import("../../types/math").Platform} Platform
2
+ * `height` and `depth` are independent axes, not halves of one screen
3
+ * dimension, so a body on the `xy` plane is sized `v(w, h, 0)` and one on the
4
+ * `xz` plane `v(w, 0, h)`. `@inglorious/renderer-2d` flattens both onto the
5
+ * screen and draws a rectangle `height + depth` tall, while
6
+ * {@link intersectsRectangle} tests the two axes separately.
7
+ *
8
+ * @typedef {import("../../types/math/rectangle").Size} Size
9
+ * @typedef {import("../../types/math/circle").Circle} Circle
10
+ * @typedef {import("../../types/math/point").PointInput} PointInput
11
+ * @typedef {import("../../types/math/rectangle").Rectangle} Rectangle
5
12
  */
6
13
 
7
14
  import { intersectsRectangle as circleIntersectsRectangle } from "./circle.js"
@@ -11,8 +18,13 @@ const HALF = 2
11
18
 
12
19
  /**
13
20
  * Checks if a rectangle intersects with a point.
21
+ *
22
+ * The rectangle's `position` is its center, and `size` extends around it. An
23
+ * anchored shape is the exception: its `anchor` picks which point sits on the
24
+ * position, so the two only line up when the anchor matches, such as
25
+ * `[0.5, 0.5]` for a centred one.
14
26
  * @param {Rectangle} rectangle - The rectangle to check.
15
- * @param {Point} point - The point to check.
27
+ * @param {PointInput} point - The point to check.
16
28
  * @returns {boolean} True if the point intersects the circle, false otherwise.
17
29
  */
18
30
  export function intersectsPoint(rectangle, point) {
package/src/math/rng.js CHANGED
@@ -31,10 +31,13 @@ export function random(...args) {
31
31
  return Math.random()
32
32
  }
33
33
 
34
+ // A range with a fractional bound cannot be stepped through as integers, so it
35
+ // is read as a continuous range. Requiring both bounds to be floats used to
36
+ // send `random(0.5, 1)` down the integer path, where it could only ever answer
37
+ // 0 or 1.
34
38
  if (
35
39
  args.length > 1 &&
36
- !Number.isInteger(args[0]) &&
37
- !Number.isInteger(args[1])
40
+ (!Number.isInteger(args[0]) || !Number.isInteger(args[1]))
38
41
  ) {
39
42
  const [from, to] = args
40
43
  return Math.random() * (to - from) + from
@@ -1,11 +1,17 @@
1
1
  /**
2
- * @typedef {import("../../types/math").Segment} Segment
3
- * @typedef {import("../../types/math").Point} Point
4
- * @typedef {import("../../types/math").Circle} Circle
2
+ * @typedef {import("../../types/math/segment").Segment} Segment
3
+ * @typedef {import("../../types/math/point").Point} Point
4
+ * @typedef {import("../../types/math/circle").Circle} Circle
5
5
  */
6
6
 
7
- import { magnitude, setMagnitude } from "./vector.js"
8
- import { distance, dot, subtract, sum } from "./vectors.js"
7
+ import {
8
+ distance,
9
+ dot,
10
+ magnitude,
11
+ setMagnitude,
12
+ subtract,
13
+ sum,
14
+ } from "./vector.js"
9
15
 
10
16
  const BEFORE_SEGMENT = 0
11
17
 
@@ -1,4 +1,4 @@
1
- import { mod } from "./numbers.js"
1
+ import { mod } from "./number.js"
2
2
 
3
3
  const HALF_CIRCLE_IN_DEGRESS = 180 // Half-circle in degrees (180°)
4
4
  const FULL_CIRCLE = 2 // Full circle multiplier for radians (2π)
@@ -1,7 +1,8 @@
1
1
  /**
2
- * @typedef {import("../../types/math").Vector} Vector
3
- * @typedef {import("../../types/math").Vector2} Vector2
4
- * @typedef {import("../../types/math").Vector3} Vector3
2
+ * @typedef {import("../../types/math/vector").Vector} Vector
3
+ * @typedef {import("../../types/math/vector").Vector2} Vector2
4
+ * @typedef {import("../../types/math/vector").Vector3} Vector3
5
+ * @typedef {import("../../types/math/vector").Vector7} Vector7
5
6
  */
6
7
 
7
8
  import { v } from "../v.js"
@@ -10,14 +11,32 @@ import {
10
11
  clamp as nClamp,
11
12
  mod as nMod,
12
13
  snap as nSnap,
13
- } from "./numbers.js"
14
+ } from "./number.js"
14
15
  import { quaternion } from "./quaternion.js"
16
+ import { random } from "./rng.js"
15
17
  import { hypothenuse } from "./triangle.js"
16
18
  import { atan2, cos, sin } from "./trigonometry.js"
17
- import { cross, sum } from "./vectors.js"
18
19
 
19
- const ZERO_VECTOR = v(0, 0, 0) // eslint-disable-line no-magic-numbers
20
- const UNIT_VECTOR = v(1, 0, 0) // eslint-disable-line no-magic-numbers
20
+ /**
21
+ * The vector with every component at zero. Useful for naming the components you
22
+ * care about, and for building a vector up from scratch:
23
+ *
24
+ * const [, NO_RISE, NO_DEPTH] = ZERO_VECTOR
25
+ * const position = v(10, 20, NO_DEPTH)
26
+ *
27
+ * Vectors are mutable arrays, so copy it rather than storing it where something
28
+ * writes to one, such as an entity position. Copy it with `v(...ZERO_VECTOR)`,
29
+ * since a plain spread drops the tag `isVector` looks for.
30
+ */
31
+ export const ZERO_VECTOR = v(0, 0, 0) // eslint-disable-line no-magic-numbers
32
+
33
+ /**
34
+ * The vector one unit long along the x axis. Useful for facing a direction, as
35
+ * in `rotate(UNIT_VECTOR, angle)`.
36
+ *
37
+ * As with `ZERO_VECTOR`, copy it with `v(...UNIT_VECTOR)` before storing it.
38
+ */
39
+ export const UNIT_VECTOR = v(1, 0, 0) // eslint-disable-line no-magic-numbers
21
40
 
22
41
  const X = 0
23
42
  const Y = 1
@@ -25,6 +44,7 @@ const Z = 2
25
44
  const LAST_COORDINATE = 1
26
45
  const TWO_COORDINATES = 2
27
46
  const NO_Y = 0
47
+ const NO_COMPONENT = 0
28
48
  const DEFAULT_PRECISION = 1
29
49
  const DEFAULT_DECIMALS = 0
30
50
 
@@ -37,6 +57,12 @@ export function abs(vector) {
37
57
  return v(...vector.map(nAbs))
38
58
  }
39
59
 
60
+ /**
61
+ * Alias for the sum function.
62
+ * @type {typeof sum}
63
+ */
64
+ export const add = sum
65
+
40
66
  /**
41
67
  * Calculates the angle of the vector in radians.
42
68
  * @param {Vector} vector - The input vector.
@@ -96,6 +122,34 @@ export function createVector(magnitude, angle) {
96
122
  return scale(fromAngle(angle), magnitude)
97
123
  }
98
124
 
125
+ /**
126
+ * Computes the cross product of multiple vectors.
127
+ * @param {...Vector3 | Vector7} vectors - The vectors to compute the cross product for.
128
+ * @returns {Vector3 | Vector7} The resulting vector after the cross product.
129
+ */
130
+ export function cross(...vectors) {
131
+ return v(...vectors.reduce(crossMultiplyCoordinates))
132
+ }
133
+
134
+ /**
135
+ * Computes the distance between multiple vectors.
136
+ * @param {...Vector2 | Vector3} vectors - The vectors to compute the distance between.
137
+ * @returns {number} The distance between the vectors.
138
+ */
139
+ export function distance(...vectors) {
140
+ return magnitude(subtract(...vectors))
141
+ }
142
+
143
+ /**
144
+ * Computes the component-wise division of vectors. A scalar operand is applied
145
+ * to every component.
146
+ * @param {...(Vector2 | Vector3 | number)} operands - The vectors to divide, or a scalar to divide each component by.
147
+ * @returns {Vector2 | Vector3} The resulting vector.
148
+ */
149
+ export function divide(...operands) {
150
+ return v(...operands.reduce(divideCoordinates))
151
+ }
152
+
99
153
  /**
100
154
  * Divides a scalar by each component of the vector.
101
155
  * @param {number} scalar - The dividend.
@@ -107,13 +161,14 @@ export function divideBy(scalar, vector) {
107
161
  }
108
162
 
109
163
  /**
110
- * Divides each component of the vector by the given scalar.
111
- * @param {Vector} vector - The input vector.
112
- * @param {number} scalar - The scalar value.
113
- * @returns {Vector} The resulting vector.
164
+ * Computes the dot product of multiple vectors.
165
+ * @param {...Vector2 | Vector3} vectors - The vectors to compute the dot product for.
166
+ * @returns {number} The resulting scalar value of the dot product.
114
167
  */
115
- export function divide(vector, scalar) {
116
- return v(...vector.map((coordinate) => coordinate / scalar))
168
+ export function dot(...vectors) {
169
+ return vectors
170
+ .reduce(dotMultiplyCoordinates)
171
+ .reduce((coord1, coord2) => coord1 + coord2)
117
172
  }
118
173
 
119
174
  /**
@@ -135,6 +190,12 @@ export function fromAngle(angle) {
135
190
  return rotate(UNIT_VECTOR, angle)
136
191
  }
137
192
 
193
+ /**
194
+ * Alias for the multiply function.
195
+ * @type {typeof multiply}
196
+ */
197
+ export const hadamard = multiply
198
+
138
199
  /**
139
200
  * Checks if a value is a vector.
140
201
  * This is determined by checking for the `__isVector__` property, which is
@@ -158,13 +219,13 @@ export function magnitude(vector) {
158
219
  export const length = magnitude
159
220
 
160
221
  /**
161
- * Calculates the modulus of each component in the vector with the given divisor.
162
- * @param {Vector} vector - The input vector.
163
- * @param {number} divisor - The divisor value.
164
- * @returns {Vector} The resulting vector.
222
+ * Computes the component-wise modulus of vectors. A scalar operand is applied
223
+ * to every component.
224
+ * @param {...(Vector2 | Vector3 | number)} operands - The vectors to compute the modulus for, or a scalar divisor for each component.
225
+ * @returns {Vector2 | Vector3} The resulting vector after the modulus.
165
226
  */
166
- export function mod(vector, divisor) {
167
- return v(...vector.map((coordinate) => nMod(coordinate, divisor)))
227
+ export function mod(...operands) {
228
+ return v(...operands.reduce(modCoordinates))
168
229
  }
169
230
 
170
231
  /**
@@ -178,13 +239,33 @@ export function modOf(scalar, vector) {
178
239
  }
179
240
 
180
241
  /**
181
- * Multiplies each component of the vector by the given scalar.
242
+ * Computes the component-wise multiplication of vectors. A scalar operand is
243
+ * applied to every component.
244
+ * @param {...(Vector2 | Vector3 | number)} operands - The vectors to multiply, or a scalar to multiply each component by.
245
+ * @returns {Vector2 | Vector3} The resulting vector.
246
+ */
247
+ export function multiply(...operands) {
248
+ return v(...operands.reduce(multiplyCoordinates))
249
+ }
250
+
251
+ /**
252
+ * Flips the direction of every component, so that adding the result to a vector
253
+ * gives back the point mirrored through it.
182
254
  * @param {Vector} vector - The input vector.
183
- * @param {number} scalar - The scalar value.
184
- * @returns {Vector} The resulting vector.
255
+ * @returns {Vector} The negated vector.
185
256
  */
186
- export function multiply(vector, scalar) {
187
- return v(...vector.map((coordinate) => coordinate * scalar))
257
+ export function negate(vector) {
258
+ return v(...vector.map((coordinate) => -coordinate))
259
+ }
260
+
261
+ /**
262
+ * Normalizes the vector to have a magnitude of 1.
263
+ * @param {Vector} vector - The input vector.
264
+ * @returns {Vector} The normalized vector.
265
+ */
266
+ export function normalize(vector) {
267
+ const length = magnitude(vector)
268
+ return v(...vector.map((coordinate) => coordinate / length))
188
269
  }
189
270
 
190
271
  /**
@@ -194,13 +275,13 @@ export function multiply(vector, scalar) {
194
275
  export const pow = power
195
276
 
196
277
  /**
197
- * Raises each component of the vector to the given exponent.
198
- * @param {Vector} vector - The input vector.
199
- * @param {number} exponent - The exponent value.
200
- * @returns {Vector} The resulting vector.
278
+ * Computes the component-wise power of vectors. A scalar operand is applied
279
+ * to every component.
280
+ * @param {...(Vector2 | Vector3 | number)} operands - The vectors to compute the power for, or a scalar exponent for each component.
281
+ * @returns {Vector2 | Vector3} The resulting vector after the power.
201
282
  */
202
- export function power(vector, exponent) {
203
- return v(...vector.map((coordinate) => coordinate ** exponent))
283
+ export function power(...operands) {
284
+ return v(...operands.reduce(powerCoordinates))
204
285
  }
205
286
 
206
287
  /**
@@ -214,13 +295,32 @@ export function powerOf(scalar, vector) {
214
295
  }
215
296
 
216
297
  /**
217
- * Normalizes the vector to have a magnitude of 1.
218
- * @param {Vector} vector - The input vector.
219
- * @returns {Vector} The normalized vector.
220
- */
221
- export function normalize(vector) {
222
- const length = magnitude(vector)
223
- return v(...vector.map((coordinate) => coordinate / length))
298
+ * Draws a random vector, taking each component from its own range: the low end is
299
+ * where that axis starts, the high end where it can reach. This is `random`
300
+ * applied per axis, so it suits ranges that differ by axis, where a single pair of
301
+ * bounds would have to be square.
302
+ *
303
+ * A component whose bounds are the same always comes out equal to them, and either
304
+ * bound may be left out to fall back to zero on that axis.
305
+ *
306
+ * @param {Vector} [low] - Where each axis starts.
307
+ * @param {Vector} [high] - Where each axis can reach.
308
+ * @returns {Vector} The random vector.
309
+ * @example
310
+ * ```js
311
+ * // Debris thrown to the left or right, never up or down.
312
+ * randomVector(v(-15, 0, 0), v(15, 0, 0))
313
+ * ```
314
+ */
315
+ export function randomVector(low, high) {
316
+ const [lowX, lowY, lowZ] = low ?? []
317
+ const [highX, highY, highZ] = high ?? []
318
+
319
+ return v(
320
+ random(lowX ?? NO_COMPONENT, highX ?? NO_COMPONENT),
321
+ random(lowY ?? NO_COMPONENT, highY ?? NO_COMPONENT),
322
+ random(lowZ ?? NO_COMPONENT, highZ ?? NO_COMPONENT),
323
+ )
224
324
  }
225
325
 
226
326
  /**
@@ -246,6 +346,12 @@ export function rotate(vector, angle) {
246
346
  return is2D ? to2D(result) : result
247
347
  }
248
348
 
349
+ /**
350
+ * Alias for the dot product function.
351
+ * @type {typeof dot}
352
+ */
353
+ export const scalarProduct = dot
354
+
249
355
  /**
250
356
  * Alias for the multiply function.
251
357
  * @type {typeof multiply}
@@ -303,6 +409,24 @@ export function snap(vector, precision = DEFAULT_PRECISION) {
303
409
  )
304
410
  }
305
411
 
412
+ /**
413
+ * Subtracts multiple vectors.
414
+ * @param {...Vector2 | Vector3} vectors - The vectors to subtract.
415
+ * @returns {Vector2 | Vector3} The resulting vector after subtraction.
416
+ */
417
+ export function subtract(...vectors) {
418
+ return v(...vectors.reduce(subtractCoordinates))
419
+ }
420
+
421
+ /**
422
+ * Sums multiple vectors.
423
+ * @param {...Vector2 | Vector3} vectors - The vectors to sum.
424
+ * @returns {Vector2 | Vector3} The resulting vector after summation.
425
+ */
426
+ export function sum(...vectors) {
427
+ return v(...vectors.reduce(sumCoordinates))
428
+ }
429
+
306
430
  /**
307
431
  * Alias for the multiply function.
308
432
  * @type {typeof multiply}
@@ -396,6 +520,12 @@ export function unit(angle) {
396
520
  return setAngle(UNIT_VECTOR, angle)
397
521
  }
398
522
 
523
+ /**
524
+ * Alias for the cross product function.
525
+ * @type {typeof cross}
526
+ */
527
+ export const vectorProduct = cross
528
+
399
529
  /**
400
530
  * Creates a zero vector of 3 dimensions.
401
531
  * @returns {Vector3} The zero vector.
@@ -404,6 +534,127 @@ export function zero() {
404
534
  return v(...ZERO_VECTOR)
405
535
  }
406
536
 
537
+ /**
538
+ * Reads the value at the given index of a vector operand, broadcasting a
539
+ * scalar operand to every index.
540
+ * @param {number | Vector2 | Vector3 | Vector7} operand - A vector or a scalar.
541
+ * @param {number} index - The index of the coordinate to read.
542
+ * @returns {number} The coordinate value.
543
+ */
544
+ function broadcast(operand, index) {
545
+ return typeof operand === "number" ? operand : operand[index]
546
+ }
547
+
548
+ /**
549
+ * Computes the cross product of two vectors' coordinates.
550
+ * @param {Vector3} vector1 - The first vector.
551
+ * @param {Vector3} vector2 - The second vector.
552
+ * @returns {Vector3} The resulting vector after the cross product.
553
+ */
554
+ function crossMultiplyCoordinates(vector1, vector2) {
555
+ const indexes = Array(vector1.length)
556
+ .fill(null)
557
+ .map((_, index) => index)
558
+
559
+ return v(
560
+ ...indexes.map((_, index) => {
561
+ const [index1, index2] = shift(
562
+ indexes.filter((_, i) => i !== index),
563
+ index,
564
+ )
565
+ return (
566
+ vector1[index1] * vector2[index2] - vector1[index2] * vector2[index1]
567
+ )
568
+ }),
569
+ )
570
+ }
571
+
572
+ /**
573
+ * Divides the coordinates of two vectors component-wise. Scalars are broadcast.
574
+ * @param {Vector2 | Vector3} vector1 - The dividend vector.
575
+ * @param {number | Vector2 | Vector3} vector2 - The divisor vector or scalar.
576
+ * @returns {Vector2 | Vector3} The resulting vector.
577
+ */
578
+ function divideCoordinates(vector1, vector2) {
579
+ return v(
580
+ ...vector1.map(
581
+ (coordinate, index) => coordinate / broadcast(vector2, index),
582
+ ),
583
+ )
584
+ }
585
+
586
+ /**
587
+ * Multiplies the coordinates of two vectors component-wise. Scalars are broadcast.
588
+ * @param {Vector2 | Vector3} vector1 - The first vector.
589
+ * @param {number | Vector2 | Vector3} vector2 - The second vector or scalar.
590
+ * @returns {Vector2 | Vector3} The resulting vector.
591
+ */
592
+ function dotMultiplyCoordinates(vector1, vector2) {
593
+ return v(...vector1.map((coordinate, index) => coordinate * vector2[index]))
594
+ }
595
+
596
+ /**
597
+ * Computes the component-wise modulus of two vectors. Scalars are broadcast.
598
+ * @param {Vector2 | Vector3} vector1 - The first vector.
599
+ * @param {number | Vector2 | Vector3} vector2 - The second vector or scalar.
600
+ * @returns {Vector2 | Vector3} The resulting vector.
601
+ */
602
+ function modCoordinates(vector1, vector2) {
603
+ return v(
604
+ ...vector1.map((coordinate, index) =>
605
+ nMod(coordinate, broadcast(vector2, index)),
606
+ ),
607
+ )
608
+ }
609
+
610
+ /**
611
+ * Multiplies the coordinates of two vectors component-wise. Scalars are broadcast.
612
+ * @param {Vector2 | Vector3} vector1 - The first vector.
613
+ * @param {number | Vector2 | Vector3} vector2 - The second vector or scalar.
614
+ * @returns {Vector2 | Vector3} The resulting vector.
615
+ */
616
+ function multiplyCoordinates(vector1, vector2) {
617
+ return v(
618
+ ...vector1.map(
619
+ (coordinate, index) => coordinate * broadcast(vector2, index),
620
+ ),
621
+ )
622
+ }
623
+
624
+ /**
625
+ * Raises the coordinates of the first vector to the power of the second vector's coordinates. Scalars are broadcast.
626
+ * @param {Vector2 | Vector3} vector1 - The base vector.
627
+ * @param {number | Vector2 | Vector3} vector2 - The exponent vector or scalar.
628
+ * @returns {Vector2 | Vector3} The resulting vector.
629
+ */
630
+ function powerCoordinates(vector1, vector2) {
631
+ return v(
632
+ ...vector1.map(
633
+ (coordinate, index) => coordinate ** broadcast(vector2, index),
634
+ ),
635
+ )
636
+ }
637
+
638
+ /**
639
+ * Subtracts the coordinates of two vectors.
640
+ * @param {Vector2 | Vector3} vector1 - The first vector.
641
+ * @param {Vector2 | Vector3} vector2 - The second vector.
642
+ * @returns {Vector2 | Vector3} The resulting vector after subtraction.
643
+ */
644
+ function subtractCoordinates(vector1, vector2) {
645
+ return v(...vector1.map((coordinate, index) => coordinate - vector2[index]))
646
+ }
647
+
648
+ /**
649
+ * Adds the coordinates of two vectors.
650
+ * @param {Vector2 | Vector3} vector1 - The first vector.
651
+ * @param {Vector2 | Vector3} vector2 - The second vector.
652
+ * @returns {Vector2 | Vector3} The resulting vector after addition.
653
+ */
654
+ function sumCoordinates(vector1, vector2) {
655
+ return v(...vector1.map((coordinate, index) => coordinate + vector2[index]))
656
+ }
657
+
407
658
  /**
408
659
  * Rotates a 3D vector around the Y-axis using a quaternion.
409
660
  * @param {Vector3} vector - The input vector.
@@ -1,9 +1,8 @@
1
1
  /**
2
- * @typedef {import("../../types/math").Vector3} Vector3
2
+ * @typedef {import("../../types/math/vector").Vector3} Vector3
3
3
  */
4
4
 
5
- import { clamp, multiply, zero } from "../math/vector.js"
6
- import { sum } from "../math/vectors.js"
5
+ import { clamp, multiply, sum, zero } from "../math/vector.js"
7
6
  import { applyFriction } from "./friction.js"
8
7
 
9
8
  const DEFAULT_DT = 1 // Default time delta for the applyAcceleration function.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @typedef {import("../../types/math").Vector3} Vector3
2
+ * @typedef {import("../../types/math/vector").Vector3} Vector3
3
3
  */
4
4
 
5
5
  import { magnitude, setMagnitude, zero } from "../math/vector.js"
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @typedef {import("../../types/math").Vector3} Vector3
2
+ * @typedef {import("../../types/math/vector").Vector3} Vector3
3
3
  */
4
4
 
5
5
  /* eslint-disable no-magic-numbers */
@@ -1,7 +1,3 @@
1
- /**
2
- * @typedef {import("../../types/math").Vector3} Vector3
3
- */
4
-
5
1
  /* eslint-disable no-magic-numbers */
6
2
 
7
3
  const DEFAULT_MAX_JUMP = 0 // Default maximum jump height.
@@ -1,9 +1,8 @@
1
1
  /**
2
- * @typedef {import("../../types/math").Vector3} Vector3
2
+ * @typedef {import("../../types/math/vector").Vector3} Vector3
3
3
  */
4
4
 
5
- import { clamp, multiply, zero } from "../math/vector.js"
6
- import { sum } from "../math/vectors.js"
5
+ import { clamp, multiply, sum, zero } from "../math/vector.js"
7
6
 
8
7
  const DEFAULT_DT = 1 // Default time delta for the applyVelocity function.
9
8
  const DEFAULT_MAX_SPEED = 0 // Default maximum speed for velocity clamping.
package/src/v.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @typedef {import("../types/math").Vector} Vector
2
+ * @typedef {import("../types/math/vector").Vector} Vector
3
3
  */
4
4
 
5
5
  import { isArray } from "./data-structures/array.js"
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Represents the input conditions evaluated by a decision tree.
3
+ */
4
+ export type Conditions = unknown
5
+
6
+ /**
7
+ * Represents the value returned by a decision tree node's test function.
8
+ */
9
+ export type Outcome = string | boolean
10
+
11
+ /**
12
+ * Represents a node in a decision tree.
13
+ */
14
+ export interface DecisionTree<C = Conditions> {
15
+ /** Evaluates conditions and returns the key of the branch to follow. */
16
+ test?: (conditions: C) => Outcome
17
+ /** Resolves the branch associated with a test outcome. */
18
+ [outcome: string]: ((conditions: C) => Outcome | DecisionTree<C>) | undefined
19
+ }
20
+
21
+ /**
22
+ * Traverses a decision tree based on the provided conditions.
23
+ */
24
+ export function decide<C>(
25
+ tree: DecisionTree<C>,
26
+ conditions: NoInfer<C>,
27
+ ): Outcome | DecisionTree<C> | undefined
@@ -0,0 +1,2 @@
1
+ export * as decisionTree from "./decision-tree"
2
+ export * as pathfinding from "./path-finding"