@inglorious/engine 0.1.0 → 0.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.
- package/README.md +39 -36
- package/package.json +20 -33
- package/src/engine/ai/movement/dynamic/align.js +63 -63
- package/src/engine/ai/movement/dynamic/arrive.js +42 -43
- package/src/engine/ai/movement/dynamic/evade.js +38 -38
- package/src/engine/ai/movement/dynamic/face.js +19 -20
- package/src/engine/ai/movement/dynamic/flee.js +45 -45
- package/src/engine/ai/movement/dynamic/look-where-youre-going.js +16 -17
- package/src/engine/ai/movement/dynamic/match-velocity.js +51 -50
- package/src/engine/ai/movement/dynamic/pursue.js +38 -38
- package/src/engine/ai/movement/dynamic/seek.js +44 -44
- package/src/engine/ai/movement/dynamic/wander.js +31 -32
- package/src/engine/ai/movement/kinematic/align.js +37 -37
- package/src/engine/ai/movement/kinematic/arrive.js +42 -42
- package/src/engine/ai/movement/kinematic/face.js +19 -20
- package/src/engine/ai/movement/kinematic/flee.js +26 -26
- package/src/engine/ai/movement/kinematic/seek.js +26 -26
- package/src/engine/ai/movement/kinematic/seek.test.js +42 -42
- package/src/engine/ai/movement/kinematic/wander-as-seek.js +31 -31
- package/src/engine/ai/movement/kinematic/wander.js +27 -27
- package/src/engine/animation/sprite.js +101 -0
- package/src/engine/animation/ticker.js +38 -0
- package/src/engine/behaviors/camera.js +68 -0
- package/src/engine/behaviors/controls/dynamic/modern.js +76 -0
- package/src/engine/behaviors/controls/dynamic/shooter.js +84 -0
- package/src/engine/behaviors/controls/dynamic/tank.js +69 -0
- package/src/engine/behaviors/controls/event-handlers.js +17 -0
- package/src/engine/behaviors/controls/kinematic/modern.js +76 -0
- package/src/engine/behaviors/controls/kinematic/shooter.js +82 -0
- package/src/engine/behaviors/controls/kinematic/tank.js +67 -0
- package/src/engine/behaviors/debug/collision.js +35 -0
- package/src/engine/behaviors/fps.js +29 -0
- package/src/engine/behaviors/fsm.js +33 -0
- package/src/{game/decorators → engine/behaviors}/fsm.test.js +49 -56
- package/src/engine/behaviors/game.js +15 -0
- package/src/engine/behaviors/input/controls.js +37 -0
- package/src/engine/behaviors/input/gamepad.js +114 -0
- package/src/engine/behaviors/input/input.js +48 -0
- package/src/engine/behaviors/input/keyboard.js +64 -0
- package/src/engine/behaviors/input/mouse.js +91 -0
- package/src/engine/behaviors/physics/bouncy.js +25 -0
- package/src/engine/behaviors/physics/clamped.js +36 -0
- package/src/{game/decorators/collisions.js → engine/behaviors/physics/collidable.js} +20 -24
- package/src/engine/behaviors/physics/jumpable.js +145 -0
- package/src/engine/behaviors/ui/button.js +17 -0
- package/src/engine/collision/detection.js +110 -115
- package/src/engine/core/api.js +34 -0
- package/src/engine/core/dev-tools.js +135 -0
- package/src/engine/core/engine.js +119 -0
- package/src/engine/core/loop.js +15 -0
- package/src/engine/{loop → core/loops}/animation-frame.js +25 -26
- package/src/engine/{loop → core/loops}/elapsed.js +22 -23
- package/src/engine/{loop → core/loops}/fixed.js +27 -28
- package/src/engine/{loop → core/loops}/flash.js +13 -14
- package/src/engine/{loop → core/loops}/lag.js +26 -27
- package/src/engine/core/select.js +26 -0
- package/src/engine/core/store.js +178 -0
- package/src/engine/core/store.test.js +110 -0
- package/src/engine/movement/dynamic/modern.js +21 -24
- package/src/engine/movement/dynamic/tank.js +43 -43
- package/src/engine/movement/kinematic/modern.js +16 -16
- package/src/engine/movement/kinematic/modern.test.js +27 -27
- package/src/engine/movement/kinematic/tank.js +27 -27
- package/src/engine/physics/bounds.js +138 -0
- package/src/engine/physics/position.js +43 -0
- package/src/engine/physics/position.test.js +80 -0
- package/src/engine/systems/sprite-animation.js +27 -0
- package/src/main.js +10 -5
- package/src/renderers/canvas/absolute-position.js +18 -0
- package/src/renderers/canvas/camera.js +13 -0
- package/src/renderers/canvas/canvas-renderer.js +68 -0
- package/src/{ui → renderers}/canvas/character.js +38 -35
- package/src/{ui → renderers}/canvas/form/button.js +25 -25
- package/src/{ui → renderers}/canvas/fps.js +18 -18
- package/src/renderers/canvas/image/hitmask.js +51 -0
- package/src/{ui → renderers}/canvas/image/image.js +34 -37
- package/src/{ui → renderers}/canvas/image/sprite.js +49 -49
- package/src/{ui → renderers}/canvas/image/tilemap.js +66 -64
- package/src/{ui → renderers}/canvas/mouse.js +37 -37
- package/src/renderers/canvas/rendering-system.js +79 -0
- package/src/{ui → renderers}/canvas/shapes/circle.js +29 -31
- package/src/{ui → renderers}/canvas/shapes/rectangle.js +27 -31
- package/src/renderers/react/game/character/index.jsx +20 -0
- package/src/{ui → renderers}/react/game/cursor/index.jsx +20 -20
- package/src/{ui → renderers}/react/game/form/fields/field/index.jsx +56 -56
- package/src/{ui → renderers}/react/game/form/fields/index.jsx +12 -12
- package/src/{ui → renderers}/react/game/form/index.jsx +22 -22
- package/src/{ui → renderers}/react/game/fps/index.jsx +16 -16
- package/src/{ui → renderers}/react/game/game.jsx +72 -71
- package/src/{ui → renderers}/react/game/index.jsx +29 -29
- package/src/{ui → renderers}/react/game/platform/index.jsx +30 -30
- package/src/{ui → renderers}/react/game/scene/index.jsx +27 -25
- package/src/{ui → renderers}/react/game/sprite/index.jsx +60 -58
- package/src/{ui → renderers}/react/game/stats/index.jsx +22 -22
- package/src/{ui → renderers}/react/hocs/with-absolute-position/index.jsx +20 -20
- package/src/{ui → renderers}/react/index.jsx +9 -9
- package/src/utils/algorithms/decision-tree.js +24 -24
- package/src/utils/algorithms/decision-tree.test.js +153 -102
- package/src/utils/algorithms/path-finding.js +155 -155
- package/src/utils/algorithms/path-finding.test.js +151 -151
- package/src/utils/data-structures/array.js +83 -83
- package/src/utils/data-structures/array.test.js +173 -173
- package/src/utils/data-structures/board.js +159 -159
- package/src/utils/data-structures/board.test.js +242 -242
- package/src/utils/data-structures/boolean.js +9 -9
- package/src/utils/data-structures/heap.js +164 -164
- package/src/utils/data-structures/heap.test.js +103 -103
- package/src/utils/data-structures/object.js +138 -102
- package/src/utils/data-structures/object.test.js +218 -121
- package/src/utils/data-structures/objects.js +66 -48
- package/src/utils/data-structures/objects.test.js +99 -99
- package/src/utils/data-structures/tree.js +36 -36
- package/src/utils/data-structures/tree.test.js +33 -33
- package/src/utils/functions/functions.js +19 -19
- package/src/utils/functions/functions.test.js +23 -23
- package/src/utils/math/geometry/circle.js +70 -117
- package/src/utils/math/geometry/circle.test.js +97 -97
- package/src/utils/math/geometry/hitmask.js +70 -39
- package/src/utils/math/geometry/hitmask.test.js +155 -84
- package/src/utils/math/geometry/line.js +35 -35
- package/src/utils/math/geometry/line.test.js +49 -49
- package/src/utils/math/geometry/point.js +78 -71
- package/src/utils/math/geometry/point.test.js +81 -81
- package/src/utils/math/geometry/rectangle.js +76 -45
- package/src/utils/math/geometry/rectangle.test.js +42 -42
- package/src/utils/math/geometry/segment.js +80 -80
- package/src/utils/math/geometry/segment.test.js +183 -183
- package/src/utils/math/geometry/triangle.js +15 -15
- package/src/utils/math/geometry/triangle.test.js +11 -11
- package/src/utils/math/linear-algebra/2d.js +28 -28
- package/src/utils/math/linear-algebra/2d.test.js +17 -17
- package/src/utils/math/linear-algebra/quaternion.js +22 -22
- package/src/utils/math/linear-algebra/quaternion.test.js +25 -25
- package/src/utils/math/linear-algebra/quaternions.js +20 -20
- package/src/utils/math/linear-algebra/quaternions.test.js +29 -29
- package/src/utils/math/linear-algebra/vector.js +327 -302
- package/src/utils/math/linear-algebra/vector.test.js +265 -257
- package/src/utils/math/linear-algebra/vectors.js +122 -122
- package/src/utils/math/linear-algebra/vectors.test.js +65 -65
- package/src/utils/math/linear-interpolation.js +9 -0
- package/src/utils/math/numbers.js +90 -90
- package/src/utils/math/numbers.test.js +137 -137
- package/src/utils/math/rng.js +44 -44
- package/src/utils/math/rng.test.js +39 -39
- package/src/utils/math/statistics.js +43 -43
- package/src/utils/math/statistics.test.js +47 -47
- package/src/utils/math/trigonometry.js +89 -89
- package/src/utils/math/trigonometry.test.js +52 -52
- package/src/utils/physics/acceleration.js +61 -63
- package/src/utils/physics/friction.js +28 -30
- package/src/utils/physics/friction.test.js +42 -44
- package/src/utils/physics/gravity.js +69 -71
- package/src/utils/physics/gravity.test.js +77 -80
- package/src/utils/physics/jump.js +31 -41
- package/src/utils/physics/velocity.js +36 -38
- package/src/docs/ai/movement/dynamic/align.js +0 -131
- package/src/docs/ai/movement/dynamic/arrive.js +0 -88
- package/src/docs/ai/movement/dynamic/dynamic.mdx +0 -99
- package/src/docs/ai/movement/dynamic/dynamic.stories.js +0 -58
- package/src/docs/ai/movement/dynamic/evade.js +0 -72
- package/src/docs/ai/movement/dynamic/face.js +0 -90
- package/src/docs/ai/movement/dynamic/flee.js +0 -38
- package/src/docs/ai/movement/dynamic/look-where-youre-going.js +0 -114
- package/src/docs/ai/movement/dynamic/match-velocity.js +0 -92
- package/src/docs/ai/movement/dynamic/pursue.js +0 -72
- package/src/docs/ai/movement/dynamic/seek.js +0 -37
- package/src/docs/ai/movement/dynamic/wander.js +0 -71
- package/src/docs/ai/movement/kinematic/align.js +0 -122
- package/src/docs/ai/movement/kinematic/arrive.js +0 -78
- package/src/docs/ai/movement/kinematic/face.js +0 -82
- package/src/docs/ai/movement/kinematic/flee.js +0 -36
- package/src/docs/ai/movement/kinematic/kinematic.mdx +0 -67
- package/src/docs/ai/movement/kinematic/kinematic.stories.js +0 -42
- package/src/docs/ai/movement/kinematic/seek.js +0 -34
- package/src/docs/ai/movement/kinematic/wander-as-seek.js +0 -62
- package/src/docs/ai/movement/kinematic/wander.js +0 -28
- package/src/docs/bounds.js +0 -7
- package/src/docs/code-reuse.js +0 -35
- package/src/docs/collision/circles.js +0 -58
- package/src/docs/collision/collision.mdx +0 -27
- package/src/docs/collision/collision.stories.js +0 -22
- package/src/docs/collision/platform.js +0 -76
- package/src/docs/collision/tilemap.js +0 -181
- package/src/docs/empty.js +0 -1
- package/src/docs/engine.mdx +0 -81
- package/src/docs/engine.stories.js +0 -37
- package/src/docs/event-handlers.js +0 -68
- package/src/docs/framerate.js +0 -37
- package/src/docs/game.jsx +0 -15
- package/src/docs/image/image.js +0 -19
- package/src/docs/image/image.stories.js +0 -22
- package/src/docs/image/sprite.js +0 -39
- package/src/docs/image/tilemap.js +0 -84
- package/src/docs/input/controls.js +0 -67
- package/src/docs/input/gamepad.js +0 -67
- package/src/docs/input/input.mdx +0 -55
- package/src/docs/input/input.stories.js +0 -27
- package/src/docs/input/keyboard.js +0 -58
- package/src/docs/input/mouse.js +0 -32
- package/src/docs/instances.js +0 -49
- package/src/docs/player/dynamic/double-jump.js +0 -90
- package/src/docs/player/dynamic/dynamic.stories.js +0 -32
- package/src/docs/player/dynamic/jump.js +0 -83
- package/src/docs/player/dynamic/modern-controls.js +0 -57
- package/src/docs/player/dynamic/shooter-controls.js +0 -51
- package/src/docs/player/dynamic/tank-controls.js +0 -44
- package/src/docs/player/kinematic/double-jump.js +0 -90
- package/src/docs/player/kinematic/jump.js +0 -82
- package/src/docs/player/kinematic/kinematic.stories.js +0 -32
- package/src/docs/player/kinematic/modern-controls.js +0 -56
- package/src/docs/player/kinematic/shooter-controls.js +0 -48
- package/src/docs/player/kinematic/tank-controls.js +0 -42
- package/src/docs/quick-start/first-game.js +0 -49
- package/src/docs/quick-start/hello-world.js +0 -1
- package/src/docs/quick-start.mdx +0 -127
- package/src/docs/quick-start.stories.js +0 -17
- package/src/docs/recipes/add-and-remove.js +0 -71
- package/src/docs/recipes/add-instance.js +0 -42
- package/src/docs/recipes/decision-tree.js +0 -169
- package/src/docs/recipes/random-instances.js +0 -25
- package/src/docs/recipes/recipes.mdx +0 -81
- package/src/docs/recipes/recipes.stories.js +0 -37
- package/src/docs/recipes/remove-instance.js +0 -52
- package/src/docs/recipes/states.js +0 -64
- package/src/docs/ui/button.js +0 -28
- package/src/docs/ui/form.stories.js +0 -55
- package/src/docs/ui-chooser.jsx +0 -6
- package/src/docs/utils/data-structures/object.mdx +0 -47
- package/src/docs/utils/data-structures/objects.mdx +0 -30
- package/src/docs/utils/functions/functions.mdx +0 -34
- package/src/docs/utils/math/geometry/circle.mdx +0 -55
- package/src/docs/utils/math/geometry/point.mdx +0 -38
- package/src/docs/utils/math/geometry/rectangle.mdx +0 -24
- package/src/docs/utils/math/geometry/segment.mdx +0 -55
- package/src/docs/utils/math/geometry/triangle.mdx +0 -22
- package/src/docs/utils/math/linear-algebra/2d.mdx +0 -22
- package/src/docs/utils/math/linear-algebra/quaternion.mdx +0 -21
- package/src/docs/utils/math/linear-algebra/quaternions.mdx +0 -22
- package/src/docs/utils/math/linear-algebra/vector.mdx +0 -177
- package/src/docs/utils/math/linear-algebra/vectors.mdx +0 -58
- package/src/docs/utils/math/numbers.mdx +0 -76
- package/src/docs/utils/math/random.mdx +0 -35
- package/src/docs/utils/math/statistics.mdx +0 -38
- package/src/docs/utils/math/trigonometry.mdx +0 -85
- package/src/docs/utils/physics/friction.mdx +0 -20
- package/src/docs/utils/physics/gravity.mdx +0 -28
- package/src/engine/loop.js +0 -15
- package/src/engine/store.js +0 -174
- package/src/engine/store.test.js +0 -256
- package/src/engine.js +0 -74
- package/src/game/animation.js +0 -26
- package/src/game/bounds.js +0 -66
- package/src/game/decorators/character.js +0 -5
- package/src/game/decorators/clamp-to-bounds.js +0 -15
- package/src/game/decorators/controls/dynamic/modern.js +0 -48
- package/src/game/decorators/controls/dynamic/shooter.js +0 -47
- package/src/game/decorators/controls/dynamic/tank.js +0 -55
- package/src/game/decorators/controls/kinematic/modern.js +0 -49
- package/src/game/decorators/controls/kinematic/shooter.js +0 -45
- package/src/game/decorators/controls/kinematic/tank.js +0 -52
- package/src/game/decorators/debug/collisions.js +0 -32
- package/src/game/decorators/double-jump.js +0 -70
- package/src/game/decorators/fps.js +0 -30
- package/src/game/decorators/fsm.js +0 -27
- package/src/game/decorators/game.js +0 -11
- package/src/game/decorators/image/image.js +0 -5
- package/src/game/decorators/image/sprite.js +0 -5
- package/src/game/decorators/image/tilemap.js +0 -5
- package/src/game/decorators/input/controls.js +0 -27
- package/src/game/decorators/input/gamepad.js +0 -74
- package/src/game/decorators/input/input.js +0 -41
- package/src/game/decorators/input/keyboard.js +0 -49
- package/src/game/decorators/input/mouse.js +0 -65
- package/src/game/decorators/jump.js +0 -72
- package/src/game/decorators/platform.js +0 -5
- package/src/game/decorators/ui/button.js +0 -21
- package/src/game/sprite.js +0 -119
- package/src/ui/canvas/absolute-position.js +0 -17
- package/src/ui/canvas/image/hitmask.js +0 -37
- package/src/ui/canvas.js +0 -81
- package/src/ui/react/game/character/index.jsx +0 -30
- package/src/utils/math/geometry/platform.js +0 -42
- package/src/utils/math/geometry/platform.test.js +0 -133
- /package/src/{ui → renderers}/react/game/character/character.module.scss +0 -0
- /package/src/{ui → renderers}/react/game/cursor/cursor.module.scss +0 -0
- /package/src/{ui → renderers}/react/game/form/fields/field/field.module.scss +0 -0
- /package/src/{ui → renderers}/react/game/form/fields/fields.module.scss +0 -0
- /package/src/{ui → renderers}/react/game/form/form.module.scss +0 -0
- /package/src/{ui → renderers}/react/game/platform/platform.module.scss +0 -0
- /package/src/{ui → renderers}/react/game/scene/scene.module.scss +0 -0
- /package/src/{ui → renderers}/react/game/sprite/sprite.module.css +0 -0
- /package/src/{ui → renderers}/react/hocs/with-absolute-position/with-absolute-position.module.scss +0 -0
|
@@ -1,137 +1,137 @@
|
|
|
1
|
-
import { expect, test } from "vitest"
|
|
2
|
-
|
|
3
|
-
import { abs, clamp, isClose, mod, sign, snap, sqrt } from "./numbers.js"
|
|
4
|
-
|
|
5
|
-
test("it should return the same number if already positive", () => {
|
|
6
|
-
const num = 42
|
|
7
|
-
const expectedResult = 42
|
|
8
|
-
|
|
9
|
-
expect(abs(num)).toBe(expectedResult)
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
test("it should return the absolute value of a number", () => {
|
|
13
|
-
const num = -42
|
|
14
|
-
const expectedResult = 42
|
|
15
|
-
|
|
16
|
-
expect(abs(num)).toBe(expectedResult)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test("it should not clamp a number in the range", () => {
|
|
20
|
-
const num = 42
|
|
21
|
-
const min = 0
|
|
22
|
-
const max = 100
|
|
23
|
-
const expectedResult = 42
|
|
24
|
-
|
|
25
|
-
expect(clamp(num, min, max)).toBe(expectedResult)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
test("it should clamp a number too small", () => {
|
|
29
|
-
const num = -42
|
|
30
|
-
const min = 0
|
|
31
|
-
const max = 100
|
|
32
|
-
const expectedResult = 0
|
|
33
|
-
|
|
34
|
-
expect(clamp(num, min, max)).toBe(expectedResult)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
test("it should clamp a number too big", () => {
|
|
38
|
-
const num = 142
|
|
39
|
-
const min = 0
|
|
40
|
-
const max = 100
|
|
41
|
-
const expectedResult = 100
|
|
42
|
-
|
|
43
|
-
expect(clamp(num, min, max)).toBe(expectedResult)
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
test("it should check if two numbers are close given some tolerance", () => {
|
|
47
|
-
const num1 = 42
|
|
48
|
-
const num2 = 42.1
|
|
49
|
-
const tolerance = 0.2
|
|
50
|
-
const expectedResult = true
|
|
51
|
-
|
|
52
|
-
expect(isClose(num1, num2, tolerance)).toBe(expectedResult)
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
test("it should return zero if dividend equals divisor", () => {
|
|
56
|
-
const num = 2
|
|
57
|
-
const divisor = 2
|
|
58
|
-
const expectedResult = 0
|
|
59
|
-
|
|
60
|
-
expect(mod(num, divisor)).toBe(expectedResult)
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
test("it should return one if number is odd", () => {
|
|
64
|
-
const num = 3
|
|
65
|
-
const divisor = 2
|
|
66
|
-
const expectedResult = 1
|
|
67
|
-
|
|
68
|
-
expect(mod(num, divisor)).toBe(expectedResult)
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
test("it should return one if negative number turns to positive one", () => {
|
|
72
|
-
const num = -3
|
|
73
|
-
const divisor = 2
|
|
74
|
-
const expectedResult = 1
|
|
75
|
-
|
|
76
|
-
expect(mod(num, divisor)).toBe(expectedResult)
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
test("it should convert a float number greater than 1 to a range between -1 and 1", () => {
|
|
80
|
-
const num = 5 / 4
|
|
81
|
-
const divisor = 1
|
|
82
|
-
const expectedResult = 1 / 4
|
|
83
|
-
|
|
84
|
-
expect(mod(num, divisor)).toBe(expectedResult)
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
test("it should convert a float number greater than 2 to a range between -1 and 1", () => {
|
|
88
|
-
const num = 13 / 4
|
|
89
|
-
const divisor = 1
|
|
90
|
-
const expectedResult = 1 / 4
|
|
91
|
-
|
|
92
|
-
expect(mod(num, divisor)).toBe(expectedResult)
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
test("it should convert a negative float number to a range between -1 and 1", () => {
|
|
96
|
-
const num = -5 / 4
|
|
97
|
-
const divisor = 1
|
|
98
|
-
const expectedResult = 3 / 4
|
|
99
|
-
|
|
100
|
-
expect(mod(num, divisor)).toBe(expectedResult)
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
test("it should return one if number is positive", () => {
|
|
104
|
-
const num = 42
|
|
105
|
-
const expectedResult = 1
|
|
106
|
-
|
|
107
|
-
expect(sign(num)).toBe(expectedResult)
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
test("it should return minus one if number is negative", () => {
|
|
111
|
-
const num = -42
|
|
112
|
-
const expectedResult = -1
|
|
113
|
-
|
|
114
|
-
expect(sign(num)).toBe(expectedResult)
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
test("it should return the number itself if the sign is zero", () => {
|
|
118
|
-
const num = 0
|
|
119
|
-
const expectedResult = 0
|
|
120
|
-
|
|
121
|
-
expect(sign(num)).toBe(expectedResult)
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
test("it should snap the number to the given precision", () => {
|
|
125
|
-
const num = 42
|
|
126
|
-
const precision = 10
|
|
127
|
-
const expectedResult = 40
|
|
128
|
-
|
|
129
|
-
expect(snap(num, precision)).toBe(expectedResult)
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
test("it should compute the square root of the number", () => {
|
|
133
|
-
const num = 9
|
|
134
|
-
const expectedResult = 3
|
|
135
|
-
|
|
136
|
-
expect(sqrt(num)).toBe(expectedResult)
|
|
137
|
-
})
|
|
1
|
+
import { expect, test } from "vitest"
|
|
2
|
+
|
|
3
|
+
import { abs, clamp, isClose, mod, sign, snap, sqrt } from "./numbers.js"
|
|
4
|
+
|
|
5
|
+
test("it should return the same number if already positive", () => {
|
|
6
|
+
const num = 42
|
|
7
|
+
const expectedResult = 42
|
|
8
|
+
|
|
9
|
+
expect(abs(num)).toBe(expectedResult)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test("it should return the absolute value of a number", () => {
|
|
13
|
+
const num = -42
|
|
14
|
+
const expectedResult = 42
|
|
15
|
+
|
|
16
|
+
expect(abs(num)).toBe(expectedResult)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test("it should not clamp a number in the range", () => {
|
|
20
|
+
const num = 42
|
|
21
|
+
const min = 0
|
|
22
|
+
const max = 100
|
|
23
|
+
const expectedResult = 42
|
|
24
|
+
|
|
25
|
+
expect(clamp(num, min, max)).toBe(expectedResult)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test("it should clamp a number too small", () => {
|
|
29
|
+
const num = -42
|
|
30
|
+
const min = 0
|
|
31
|
+
const max = 100
|
|
32
|
+
const expectedResult = 0
|
|
33
|
+
|
|
34
|
+
expect(clamp(num, min, max)).toBe(expectedResult)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test("it should clamp a number too big", () => {
|
|
38
|
+
const num = 142
|
|
39
|
+
const min = 0
|
|
40
|
+
const max = 100
|
|
41
|
+
const expectedResult = 100
|
|
42
|
+
|
|
43
|
+
expect(clamp(num, min, max)).toBe(expectedResult)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test("it should check if two numbers are close given some tolerance", () => {
|
|
47
|
+
const num1 = 42
|
|
48
|
+
const num2 = 42.1
|
|
49
|
+
const tolerance = 0.2
|
|
50
|
+
const expectedResult = true
|
|
51
|
+
|
|
52
|
+
expect(isClose(num1, num2, tolerance)).toBe(expectedResult)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test("it should return zero if dividend equals divisor", () => {
|
|
56
|
+
const num = 2
|
|
57
|
+
const divisor = 2
|
|
58
|
+
const expectedResult = 0
|
|
59
|
+
|
|
60
|
+
expect(mod(num, divisor)).toBe(expectedResult)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test("it should return one if number is odd", () => {
|
|
64
|
+
const num = 3
|
|
65
|
+
const divisor = 2
|
|
66
|
+
const expectedResult = 1
|
|
67
|
+
|
|
68
|
+
expect(mod(num, divisor)).toBe(expectedResult)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test("it should return one if negative number turns to positive one", () => {
|
|
72
|
+
const num = -3
|
|
73
|
+
const divisor = 2
|
|
74
|
+
const expectedResult = 1
|
|
75
|
+
|
|
76
|
+
expect(mod(num, divisor)).toBe(expectedResult)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
test("it should convert a float number greater than 1 to a range between -1 and 1", () => {
|
|
80
|
+
const num = 5 / 4
|
|
81
|
+
const divisor = 1
|
|
82
|
+
const expectedResult = 1 / 4
|
|
83
|
+
|
|
84
|
+
expect(mod(num, divisor)).toBe(expectedResult)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
test("it should convert a float number greater than 2 to a range between -1 and 1", () => {
|
|
88
|
+
const num = 13 / 4
|
|
89
|
+
const divisor = 1
|
|
90
|
+
const expectedResult = 1 / 4
|
|
91
|
+
|
|
92
|
+
expect(mod(num, divisor)).toBe(expectedResult)
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
test("it should convert a negative float number to a range between -1 and 1", () => {
|
|
96
|
+
const num = -5 / 4
|
|
97
|
+
const divisor = 1
|
|
98
|
+
const expectedResult = 3 / 4
|
|
99
|
+
|
|
100
|
+
expect(mod(num, divisor)).toBe(expectedResult)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
test("it should return one if number is positive", () => {
|
|
104
|
+
const num = 42
|
|
105
|
+
const expectedResult = 1
|
|
106
|
+
|
|
107
|
+
expect(sign(num)).toBe(expectedResult)
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
test("it should return minus one if number is negative", () => {
|
|
111
|
+
const num = -42
|
|
112
|
+
const expectedResult = -1
|
|
113
|
+
|
|
114
|
+
expect(sign(num)).toBe(expectedResult)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
test("it should return the number itself if the sign is zero", () => {
|
|
118
|
+
const num = 0
|
|
119
|
+
const expectedResult = 0
|
|
120
|
+
|
|
121
|
+
expect(sign(num)).toBe(expectedResult)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
test("it should snap the number to the given precision", () => {
|
|
125
|
+
const num = 42
|
|
126
|
+
const precision = 10
|
|
127
|
+
const expectedResult = 40
|
|
128
|
+
|
|
129
|
+
expect(snap(num, precision)).toBe(expectedResult)
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
test("it should compute the square root of the number", () => {
|
|
133
|
+
const num = 9
|
|
134
|
+
const expectedResult = 3
|
|
135
|
+
|
|
136
|
+
expect(sqrt(num)).toBe(expectedResult)
|
|
137
|
+
})
|
package/src/utils/math/rng.js
CHANGED
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
/* eslint-disable no-magic-numbers */
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Generates a random number.
|
|
5
|
-
* - If no arguments are provided, returns a random float between 0 (inclusive) and 1 (exclusive).
|
|
6
|
-
* - If one argument is provided, returns a random integer between 0 and the given number (inclusive).
|
|
7
|
-
* - If two or more arguments are provided, returns a random integer within the specified range and step.
|
|
8
|
-
*
|
|
9
|
-
* @param {number} [to] - The upper bound (inclusive) if one argument is provided.
|
|
10
|
-
* @param {number} [from] - The lower bound (inclusive) if two arguments are provided.
|
|
11
|
-
* @param {number} [step=1] - The step size if two or more arguments are provided.
|
|
12
|
-
* @returns {number} A random number based on the provided arguments.
|
|
13
|
-
*/
|
|
14
|
-
export function random(...args) {
|
|
15
|
-
let step, from, to
|
|
16
|
-
|
|
17
|
-
if (!args.length) {
|
|
18
|
-
return Math.random()
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (args.length === 1) {
|
|
22
|
-
step = 1
|
|
23
|
-
from = 0
|
|
24
|
-
to = args[0] + 1
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (args.length > 1) {
|
|
28
|
-
step = args[2] ?? 1
|
|
29
|
-
from = args[0] / step
|
|
30
|
-
to = (args[1] + 1) / step
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return Math.floor(Math.random() * (to - from) + from) * step
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Generates a random binomial value.
|
|
38
|
-
* The result is the difference between two random numbers.
|
|
39
|
-
*
|
|
40
|
-
* @returns {number} A random binomial value.
|
|
41
|
-
*/
|
|
42
|
-
export function randomBinomial() {
|
|
43
|
-
return random() - random()
|
|
44
|
-
}
|
|
1
|
+
/* eslint-disable no-magic-numbers */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generates a random number.
|
|
5
|
+
* - If no arguments are provided, returns a random float between 0 (inclusive) and 1 (exclusive).
|
|
6
|
+
* - If one argument is provided, returns a random integer between 0 and the given number (inclusive).
|
|
7
|
+
* - If two or more arguments are provided, returns a random integer within the specified range and step.
|
|
8
|
+
*
|
|
9
|
+
* @param {number} [to] - The upper bound (inclusive) if one argument is provided.
|
|
10
|
+
* @param {number} [from] - The lower bound (inclusive) if two arguments are provided.
|
|
11
|
+
* @param {number} [step=1] - The step size if two or more arguments are provided.
|
|
12
|
+
* @returns {number} A random number based on the provided arguments.
|
|
13
|
+
*/
|
|
14
|
+
export function random(...args) {
|
|
15
|
+
let step, from, to
|
|
16
|
+
|
|
17
|
+
if (!args.length) {
|
|
18
|
+
return Math.random()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (args.length === 1) {
|
|
22
|
+
step = 1
|
|
23
|
+
from = 0
|
|
24
|
+
to = args[0] + 1
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (args.length > 1) {
|
|
28
|
+
step = args[2] ?? 1
|
|
29
|
+
from = args[0] / step
|
|
30
|
+
to = (args[1] + 1) / step
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return Math.floor(Math.random() * (to - from) + from) * step
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Generates a random binomial value.
|
|
38
|
+
* The result is the difference between two random numbers.
|
|
39
|
+
*
|
|
40
|
+
* @returns {number} A random binomial value.
|
|
41
|
+
*/
|
|
42
|
+
export function randomBinomial() {
|
|
43
|
+
return random() - random()
|
|
44
|
+
}
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import { expect, test } from "vitest"
|
|
2
|
-
|
|
3
|
-
import { random, randomBinomial } from "./rng.js"
|
|
4
|
-
|
|
5
|
-
test("it should create a random number in the range [0, 1)", () => {
|
|
6
|
-
const randomNumber = random()
|
|
7
|
-
|
|
8
|
-
expect(randomNumber).toBeGreaterThanOrEqual(0)
|
|
9
|
-
expect(randomNumber).toBeLessThan(1)
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
test("it should create a random integer in the range [0, 6]", () => {
|
|
13
|
-
const randomNumber = random(6)
|
|
14
|
-
|
|
15
|
-
expect(randomNumber).toBeGreaterThanOrEqual(0)
|
|
16
|
-
expect(randomNumber).toBeLessThanOrEqual(6)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test("it should create a random integer in the range [1, 6]", () => {
|
|
20
|
-
const randomNumber = random(1, 6)
|
|
21
|
-
|
|
22
|
-
expect(randomNumber).toBeGreaterThanOrEqual(1)
|
|
23
|
-
expect(randomNumber).toBeLessThanOrEqual(6)
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
test("it should create a random even number in the range [2, 6]", () => {
|
|
27
|
-
const randomNumber = random(2, 6, 2)
|
|
28
|
-
|
|
29
|
-
expect(randomNumber).toBeGreaterThanOrEqual(1)
|
|
30
|
-
expect(randomNumber).toBeLessThanOrEqual(6)
|
|
31
|
-
expect(randomNumber % 2).toBe(0)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
test("it should create a random number in the range (-1, 1)", () => {
|
|
35
|
-
const randomNumber = randomBinomial()
|
|
36
|
-
|
|
37
|
-
expect(randomNumber).toBeGreaterThan(-1)
|
|
38
|
-
expect(randomNumber).toBeLessThan(1)
|
|
39
|
-
})
|
|
1
|
+
import { expect, test } from "vitest"
|
|
2
|
+
|
|
3
|
+
import { random, randomBinomial } from "./rng.js"
|
|
4
|
+
|
|
5
|
+
test("it should create a random number in the range [0, 1)", () => {
|
|
6
|
+
const randomNumber = random()
|
|
7
|
+
|
|
8
|
+
expect(randomNumber).toBeGreaterThanOrEqual(0)
|
|
9
|
+
expect(randomNumber).toBeLessThan(1)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test("it should create a random integer in the range [0, 6]", () => {
|
|
13
|
+
const randomNumber = random(6)
|
|
14
|
+
|
|
15
|
+
expect(randomNumber).toBeGreaterThanOrEqual(0)
|
|
16
|
+
expect(randomNumber).toBeLessThanOrEqual(6)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test("it should create a random integer in the range [1, 6]", () => {
|
|
20
|
+
const randomNumber = random(1, 6)
|
|
21
|
+
|
|
22
|
+
expect(randomNumber).toBeGreaterThanOrEqual(1)
|
|
23
|
+
expect(randomNumber).toBeLessThanOrEqual(6)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test("it should create a random even number in the range [2, 6]", () => {
|
|
27
|
+
const randomNumber = random(2, 6, 2)
|
|
28
|
+
|
|
29
|
+
expect(randomNumber).toBeGreaterThanOrEqual(1)
|
|
30
|
+
expect(randomNumber).toBeLessThanOrEqual(6)
|
|
31
|
+
expect(randomNumber % 2).toBe(0)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test("it should create a random number in the range (-1, 1)", () => {
|
|
35
|
+
const randomNumber = randomBinomial()
|
|
36
|
+
|
|
37
|
+
expect(randomNumber).toBeGreaterThan(-1)
|
|
38
|
+
expect(randomNumber).toBeLessThan(1)
|
|
39
|
+
})
|
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
const HALF = 2
|
|
2
|
-
const AROUND_INDEX = 1
|
|
3
|
-
const NO_OCCURRENCES = 0
|
|
4
|
-
|
|
5
|
-
export const average = mean
|
|
6
|
-
|
|
7
|
-
export function mean(...numbers) {
|
|
8
|
-
return numbers.reduce((acc, num) => acc + num) / numbers.length
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function median(...numbers) {
|
|
12
|
-
const sortedNumbers = numbers.toSorted()
|
|
13
|
-
const middleIndex = numbers.length / HALF
|
|
14
|
-
|
|
15
|
-
if (Number.isInteger(middleIndex)) {
|
|
16
|
-
return mean(
|
|
17
|
-
...sortedNumbers.slice(
|
|
18
|
-
middleIndex - AROUND_INDEX,
|
|
19
|
-
middleIndex + AROUND_INDEX,
|
|
20
|
-
),
|
|
21
|
-
)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return sortedNumbers[Math.floor(middleIndex)]
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function mode(...values) {
|
|
28
|
-
const occurrences = values.reduce((acc, value) => {
|
|
29
|
-
acc[value] = acc[value] ?? NO_OCCURRENCES
|
|
30
|
-
acc[value]++
|
|
31
|
-
return acc
|
|
32
|
-
}, {})
|
|
33
|
-
|
|
34
|
-
return Object.entries(occurrences).reduce(
|
|
35
|
-
(acc, [value, occurrences]) => {
|
|
36
|
-
if (occurrences > acc.occurrences) {
|
|
37
|
-
acc = { value, occurrences }
|
|
38
|
-
}
|
|
39
|
-
return acc
|
|
40
|
-
},
|
|
41
|
-
{ occurrences: 0 },
|
|
42
|
-
).value
|
|
43
|
-
}
|
|
1
|
+
const HALF = 2
|
|
2
|
+
const AROUND_INDEX = 1
|
|
3
|
+
const NO_OCCURRENCES = 0
|
|
4
|
+
|
|
5
|
+
export const average = mean
|
|
6
|
+
|
|
7
|
+
export function mean(...numbers) {
|
|
8
|
+
return numbers.reduce((acc, num) => acc + num) / numbers.length
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function median(...numbers) {
|
|
12
|
+
const sortedNumbers = numbers.toSorted()
|
|
13
|
+
const middleIndex = numbers.length / HALF
|
|
14
|
+
|
|
15
|
+
if (Number.isInteger(middleIndex)) {
|
|
16
|
+
return mean(
|
|
17
|
+
...sortedNumbers.slice(
|
|
18
|
+
middleIndex - AROUND_INDEX,
|
|
19
|
+
middleIndex + AROUND_INDEX,
|
|
20
|
+
),
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return sortedNumbers[Math.floor(middleIndex)]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function mode(...values) {
|
|
28
|
+
const occurrences = values.reduce((acc, value) => {
|
|
29
|
+
acc[value] = acc[value] ?? NO_OCCURRENCES
|
|
30
|
+
acc[value]++
|
|
31
|
+
return acc
|
|
32
|
+
}, {})
|
|
33
|
+
|
|
34
|
+
return Object.entries(occurrences).reduce(
|
|
35
|
+
(acc, [value, occurrences]) => {
|
|
36
|
+
if (occurrences > acc.occurrences) {
|
|
37
|
+
acc = { value, occurrences }
|
|
38
|
+
}
|
|
39
|
+
return acc
|
|
40
|
+
},
|
|
41
|
+
{ occurrences: 0 },
|
|
42
|
+
).value
|
|
43
|
+
}
|
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
import { expect, test } from "vitest"
|
|
2
|
-
|
|
3
|
-
import { mean, median, mode } from "./statistics.js"
|
|
4
|
-
|
|
5
|
-
test("it should return the average of the given numbers", () => {
|
|
6
|
-
const numbers = [1, 3, 2]
|
|
7
|
-
const expectedResult = 2
|
|
8
|
-
|
|
9
|
-
expect(mean(...numbers)).toBeCloseTo(expectedResult)
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
test("it should return the median value from an odd list of numbers", () => {
|
|
13
|
-
const numbers = [1, 3, 2]
|
|
14
|
-
const expectedResult = 2
|
|
15
|
-
|
|
16
|
-
expect(median(...numbers)).toBe(expectedResult)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test("it should return the median value from an even list of numbers", () => {
|
|
20
|
-
const numbers = [1, 3, 2, 4]
|
|
21
|
-
const expectedResult = 2.5
|
|
22
|
-
|
|
23
|
-
expect(median(...numbers)).toBe(expectedResult)
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
test("it should find the mode of a list of values", () => {
|
|
27
|
-
const values = [
|
|
28
|
-
"rarely",
|
|
29
|
-
"seldom",
|
|
30
|
-
"seldom",
|
|
31
|
-
"sometimes",
|
|
32
|
-
"sometimes",
|
|
33
|
-
"sometimes",
|
|
34
|
-
"often",
|
|
35
|
-
"often",
|
|
36
|
-
"often",
|
|
37
|
-
"often",
|
|
38
|
-
"always",
|
|
39
|
-
"always",
|
|
40
|
-
"always",
|
|
41
|
-
"always",
|
|
42
|
-
"always",
|
|
43
|
-
]
|
|
44
|
-
const expectedResult = "always"
|
|
45
|
-
|
|
46
|
-
expect(mode(...values)).toBe(expectedResult)
|
|
47
|
-
})
|
|
1
|
+
import { expect, test } from "vitest"
|
|
2
|
+
|
|
3
|
+
import { mean, median, mode } from "./statistics.js"
|
|
4
|
+
|
|
5
|
+
test("it should return the average of the given numbers", () => {
|
|
6
|
+
const numbers = [1, 3, 2]
|
|
7
|
+
const expectedResult = 2
|
|
8
|
+
|
|
9
|
+
expect(mean(...numbers)).toBeCloseTo(expectedResult)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test("it should return the median value from an odd list of numbers", () => {
|
|
13
|
+
const numbers = [1, 3, 2]
|
|
14
|
+
const expectedResult = 2
|
|
15
|
+
|
|
16
|
+
expect(median(...numbers)).toBe(expectedResult)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test("it should return the median value from an even list of numbers", () => {
|
|
20
|
+
const numbers = [1, 3, 2, 4]
|
|
21
|
+
const expectedResult = 2.5
|
|
22
|
+
|
|
23
|
+
expect(median(...numbers)).toBe(expectedResult)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test("it should find the mode of a list of values", () => {
|
|
27
|
+
const values = [
|
|
28
|
+
"rarely",
|
|
29
|
+
"seldom",
|
|
30
|
+
"seldom",
|
|
31
|
+
"sometimes",
|
|
32
|
+
"sometimes",
|
|
33
|
+
"sometimes",
|
|
34
|
+
"often",
|
|
35
|
+
"often",
|
|
36
|
+
"often",
|
|
37
|
+
"often",
|
|
38
|
+
"always",
|
|
39
|
+
"always",
|
|
40
|
+
"always",
|
|
41
|
+
"always",
|
|
42
|
+
"always",
|
|
43
|
+
]
|
|
44
|
+
const expectedResult = "always"
|
|
45
|
+
|
|
46
|
+
expect(mode(...values)).toBe(expectedResult)
|
|
47
|
+
})
|