@inglorious/engine 0.1.1 → 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.
Files changed (201) hide show
  1. package/README.md +39 -36
  2. package/package.json +10 -22
  3. package/src/engine/ai/movement/dynamic/align.js +63 -63
  4. package/src/engine/ai/movement/dynamic/arrive.js +42 -43
  5. package/src/engine/ai/movement/dynamic/evade.js +38 -38
  6. package/src/engine/ai/movement/dynamic/face.js +19 -20
  7. package/src/engine/ai/movement/dynamic/flee.js +45 -45
  8. package/src/engine/ai/movement/dynamic/look-where-youre-going.js +16 -17
  9. package/src/engine/ai/movement/dynamic/match-velocity.js +51 -50
  10. package/src/engine/ai/movement/dynamic/pursue.js +38 -38
  11. package/src/engine/ai/movement/dynamic/seek.js +44 -44
  12. package/src/engine/ai/movement/dynamic/wander.js +31 -32
  13. package/src/engine/ai/movement/kinematic/align.js +37 -37
  14. package/src/engine/ai/movement/kinematic/arrive.js +42 -42
  15. package/src/engine/ai/movement/kinematic/face.js +19 -20
  16. package/src/engine/ai/movement/kinematic/flee.js +26 -26
  17. package/src/engine/ai/movement/kinematic/seek.js +26 -26
  18. package/src/engine/ai/movement/kinematic/seek.test.js +42 -42
  19. package/src/engine/ai/movement/kinematic/wander-as-seek.js +31 -31
  20. package/src/engine/ai/movement/kinematic/wander.js +27 -27
  21. package/src/engine/animation/sprite.js +101 -0
  22. package/src/engine/animation/ticker.js +38 -0
  23. package/src/engine/behaviors/camera.js +68 -0
  24. package/src/engine/behaviors/controls/dynamic/modern.js +76 -0
  25. package/src/engine/behaviors/controls/dynamic/shooter.js +84 -0
  26. package/src/engine/behaviors/controls/dynamic/tank.js +69 -0
  27. package/src/engine/behaviors/controls/event-handlers.js +17 -0
  28. package/src/engine/behaviors/controls/kinematic/modern.js +76 -0
  29. package/src/engine/behaviors/controls/kinematic/shooter.js +82 -0
  30. package/src/engine/behaviors/controls/kinematic/tank.js +67 -0
  31. package/src/engine/behaviors/debug/collision.js +35 -0
  32. package/src/engine/behaviors/fps.js +29 -0
  33. package/src/engine/behaviors/fsm.js +33 -0
  34. package/src/{game/decorators → engine/behaviors}/fsm.test.js +49 -56
  35. package/src/engine/behaviors/game.js +15 -0
  36. package/src/engine/behaviors/input/controls.js +37 -0
  37. package/src/engine/behaviors/input/gamepad.js +114 -0
  38. package/src/engine/behaviors/input/input.js +48 -0
  39. package/src/engine/behaviors/input/keyboard.js +64 -0
  40. package/src/engine/behaviors/input/mouse.js +91 -0
  41. package/src/engine/behaviors/physics/bouncy.js +25 -0
  42. package/src/engine/behaviors/physics/clamped.js +36 -0
  43. package/src/{game/decorators/collisions.js → engine/behaviors/physics/collidable.js} +20 -24
  44. package/src/engine/behaviors/physics/jumpable.js +145 -0
  45. package/src/engine/behaviors/ui/button.js +17 -0
  46. package/src/engine/collision/detection.js +110 -115
  47. package/src/engine/core/api.js +34 -0
  48. package/src/engine/core/dev-tools.js +135 -0
  49. package/src/engine/core/engine.js +119 -0
  50. package/src/engine/core/loop.js +15 -0
  51. package/src/engine/{loop → core/loops}/animation-frame.js +25 -26
  52. package/src/engine/{loop → core/loops}/elapsed.js +22 -23
  53. package/src/engine/{loop → core/loops}/fixed.js +27 -28
  54. package/src/engine/{loop → core/loops}/flash.js +13 -14
  55. package/src/engine/{loop → core/loops}/lag.js +26 -27
  56. package/src/engine/core/select.js +26 -0
  57. package/src/engine/core/store.js +178 -0
  58. package/src/engine/core/store.test.js +110 -0
  59. package/src/engine/movement/dynamic/modern.js +21 -24
  60. package/src/engine/movement/dynamic/tank.js +43 -43
  61. package/src/engine/movement/kinematic/modern.js +16 -16
  62. package/src/engine/movement/kinematic/modern.test.js +27 -27
  63. package/src/engine/movement/kinematic/tank.js +27 -27
  64. package/src/engine/physics/bounds.js +138 -0
  65. package/src/engine/physics/position.js +43 -0
  66. package/src/engine/physics/position.test.js +80 -0
  67. package/src/engine/systems/sprite-animation.js +27 -0
  68. package/src/main.js +10 -5
  69. package/src/renderers/canvas/absolute-position.js +18 -0
  70. package/src/renderers/canvas/camera.js +13 -0
  71. package/src/renderers/canvas/canvas-renderer.js +68 -0
  72. package/src/{ui → renderers}/canvas/character.js +38 -35
  73. package/src/{ui → renderers}/canvas/form/button.js +25 -25
  74. package/src/{ui → renderers}/canvas/fps.js +18 -18
  75. package/src/renderers/canvas/image/hitmask.js +51 -0
  76. package/src/{ui → renderers}/canvas/image/image.js +34 -37
  77. package/src/{ui → renderers}/canvas/image/sprite.js +49 -49
  78. package/src/{ui → renderers}/canvas/image/tilemap.js +66 -64
  79. package/src/{ui → renderers}/canvas/mouse.js +37 -37
  80. package/src/renderers/canvas/rendering-system.js +79 -0
  81. package/src/{ui → renderers}/canvas/shapes/circle.js +29 -31
  82. package/src/{ui → renderers}/canvas/shapes/rectangle.js +27 -31
  83. package/src/renderers/react/game/character/index.jsx +20 -0
  84. package/src/{ui → renderers}/react/game/cursor/index.jsx +20 -20
  85. package/src/{ui → renderers}/react/game/form/fields/field/index.jsx +56 -56
  86. package/src/{ui → renderers}/react/game/form/fields/index.jsx +12 -12
  87. package/src/{ui → renderers}/react/game/form/index.jsx +22 -22
  88. package/src/{ui → renderers}/react/game/fps/index.jsx +16 -16
  89. package/src/{ui → renderers}/react/game/game.jsx +72 -71
  90. package/src/{ui → renderers}/react/game/index.jsx +29 -29
  91. package/src/{ui → renderers}/react/game/platform/index.jsx +30 -30
  92. package/src/{ui → renderers}/react/game/scene/index.jsx +27 -25
  93. package/src/{ui → renderers}/react/game/sprite/index.jsx +60 -58
  94. package/src/{ui → renderers}/react/game/stats/index.jsx +22 -22
  95. package/src/{ui → renderers}/react/hocs/with-absolute-position/index.jsx +20 -20
  96. package/src/{ui → renderers}/react/index.jsx +9 -9
  97. package/src/utils/algorithms/decision-tree.js +24 -24
  98. package/src/utils/algorithms/decision-tree.test.js +153 -102
  99. package/src/utils/algorithms/path-finding.js +155 -155
  100. package/src/utils/algorithms/path-finding.test.js +151 -151
  101. package/src/utils/data-structures/array.js +83 -83
  102. package/src/utils/data-structures/array.test.js +173 -173
  103. package/src/utils/data-structures/board.js +159 -159
  104. package/src/utils/data-structures/board.test.js +242 -242
  105. package/src/utils/data-structures/boolean.js +9 -9
  106. package/src/utils/data-structures/heap.js +164 -164
  107. package/src/utils/data-structures/heap.test.js +103 -103
  108. package/src/utils/data-structures/object.js +138 -102
  109. package/src/utils/data-structures/object.test.js +218 -121
  110. package/src/utils/data-structures/objects.js +66 -48
  111. package/src/utils/data-structures/objects.test.js +99 -99
  112. package/src/utils/data-structures/tree.js +36 -36
  113. package/src/utils/data-structures/tree.test.js +33 -33
  114. package/src/utils/functions/functions.js +19 -19
  115. package/src/utils/functions/functions.test.js +23 -23
  116. package/src/utils/math/geometry/circle.js +70 -117
  117. package/src/utils/math/geometry/circle.test.js +97 -97
  118. package/src/utils/math/geometry/hitmask.js +70 -39
  119. package/src/utils/math/geometry/hitmask.test.js +155 -84
  120. package/src/utils/math/geometry/line.js +35 -35
  121. package/src/utils/math/geometry/line.test.js +49 -49
  122. package/src/utils/math/geometry/point.js +78 -71
  123. package/src/utils/math/geometry/point.test.js +81 -81
  124. package/src/utils/math/geometry/rectangle.js +76 -45
  125. package/src/utils/math/geometry/rectangle.test.js +42 -42
  126. package/src/utils/math/geometry/segment.js +80 -80
  127. package/src/utils/math/geometry/segment.test.js +183 -183
  128. package/src/utils/math/geometry/triangle.js +15 -15
  129. package/src/utils/math/geometry/triangle.test.js +11 -11
  130. package/src/utils/math/linear-algebra/2d.js +28 -28
  131. package/src/utils/math/linear-algebra/2d.test.js +17 -17
  132. package/src/utils/math/linear-algebra/quaternion.js +22 -22
  133. package/src/utils/math/linear-algebra/quaternion.test.js +25 -25
  134. package/src/utils/math/linear-algebra/quaternions.js +20 -20
  135. package/src/utils/math/linear-algebra/quaternions.test.js +29 -29
  136. package/src/utils/math/linear-algebra/vector.js +327 -302
  137. package/src/utils/math/linear-algebra/vector.test.js +265 -257
  138. package/src/utils/math/linear-algebra/vectors.js +122 -122
  139. package/src/utils/math/linear-algebra/vectors.test.js +65 -65
  140. package/src/utils/math/linear-interpolation.js +9 -0
  141. package/src/utils/math/numbers.js +90 -90
  142. package/src/utils/math/numbers.test.js +137 -137
  143. package/src/utils/math/rng.js +44 -44
  144. package/src/utils/math/rng.test.js +39 -39
  145. package/src/utils/math/statistics.js +43 -43
  146. package/src/utils/math/statistics.test.js +47 -47
  147. package/src/utils/math/trigonometry.js +89 -89
  148. package/src/utils/math/trigonometry.test.js +52 -52
  149. package/src/utils/physics/acceleration.js +61 -63
  150. package/src/utils/physics/friction.js +28 -30
  151. package/src/utils/physics/friction.test.js +42 -44
  152. package/src/utils/physics/gravity.js +69 -71
  153. package/src/utils/physics/gravity.test.js +77 -80
  154. package/src/utils/physics/jump.js +31 -41
  155. package/src/utils/physics/velocity.js +36 -38
  156. package/src/engine/loop.js +0 -15
  157. package/src/engine/store.js +0 -174
  158. package/src/engine/store.test.js +0 -256
  159. package/src/engine.js +0 -74
  160. package/src/game/animation.js +0 -26
  161. package/src/game/bounds.js +0 -66
  162. package/src/game/decorators/character.js +0 -5
  163. package/src/game/decorators/clamp-to-bounds.js +0 -15
  164. package/src/game/decorators/controls/dynamic/modern.js +0 -48
  165. package/src/game/decorators/controls/dynamic/shooter.js +0 -47
  166. package/src/game/decorators/controls/dynamic/tank.js +0 -55
  167. package/src/game/decorators/controls/kinematic/modern.js +0 -49
  168. package/src/game/decorators/controls/kinematic/shooter.js +0 -45
  169. package/src/game/decorators/controls/kinematic/tank.js +0 -52
  170. package/src/game/decorators/debug/collisions.js +0 -32
  171. package/src/game/decorators/double-jump.js +0 -70
  172. package/src/game/decorators/fps.js +0 -30
  173. package/src/game/decorators/fsm.js +0 -27
  174. package/src/game/decorators/game.js +0 -11
  175. package/src/game/decorators/image/image.js +0 -5
  176. package/src/game/decorators/image/sprite.js +0 -5
  177. package/src/game/decorators/image/tilemap.js +0 -5
  178. package/src/game/decorators/input/controls.js +0 -27
  179. package/src/game/decorators/input/gamepad.js +0 -74
  180. package/src/game/decorators/input/input.js +0 -41
  181. package/src/game/decorators/input/keyboard.js +0 -49
  182. package/src/game/decorators/input/mouse.js +0 -65
  183. package/src/game/decorators/jump.js +0 -72
  184. package/src/game/decorators/platform.js +0 -5
  185. package/src/game/decorators/ui/button.js +0 -21
  186. package/src/game/sprite.js +0 -119
  187. package/src/ui/canvas/absolute-position.js +0 -17
  188. package/src/ui/canvas/image/hitmask.js +0 -37
  189. package/src/ui/canvas.js +0 -81
  190. package/src/ui/react/game/character/index.jsx +0 -30
  191. package/src/utils/math/geometry/platform.js +0 -42
  192. package/src/utils/math/geometry/platform.test.js +0 -133
  193. /package/src/{ui → renderers}/react/game/character/character.module.scss +0 -0
  194. /package/src/{ui → renderers}/react/game/cursor/cursor.module.scss +0 -0
  195. /package/src/{ui → renderers}/react/game/form/fields/field/field.module.scss +0 -0
  196. /package/src/{ui → renderers}/react/game/form/fields/fields.module.scss +0 -0
  197. /package/src/{ui → renderers}/react/game/form/form.module.scss +0 -0
  198. /package/src/{ui → renderers}/react/game/platform/platform.module.scss +0 -0
  199. /package/src/{ui → renderers}/react/game/scene/scene.module.scss +0 -0
  200. /package/src/{ui → renderers}/react/game/sprite/sprite.module.css +0 -0
  201. /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
+ })
@@ -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
+ })