@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.
Files changed (292) hide show
  1. package/README.md +39 -36
  2. package/package.json +20 -33
  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/docs/ai/movement/dynamic/align.js +0 -131
  157. package/src/docs/ai/movement/dynamic/arrive.js +0 -88
  158. package/src/docs/ai/movement/dynamic/dynamic.mdx +0 -99
  159. package/src/docs/ai/movement/dynamic/dynamic.stories.js +0 -58
  160. package/src/docs/ai/movement/dynamic/evade.js +0 -72
  161. package/src/docs/ai/movement/dynamic/face.js +0 -90
  162. package/src/docs/ai/movement/dynamic/flee.js +0 -38
  163. package/src/docs/ai/movement/dynamic/look-where-youre-going.js +0 -114
  164. package/src/docs/ai/movement/dynamic/match-velocity.js +0 -92
  165. package/src/docs/ai/movement/dynamic/pursue.js +0 -72
  166. package/src/docs/ai/movement/dynamic/seek.js +0 -37
  167. package/src/docs/ai/movement/dynamic/wander.js +0 -71
  168. package/src/docs/ai/movement/kinematic/align.js +0 -122
  169. package/src/docs/ai/movement/kinematic/arrive.js +0 -78
  170. package/src/docs/ai/movement/kinematic/face.js +0 -82
  171. package/src/docs/ai/movement/kinematic/flee.js +0 -36
  172. package/src/docs/ai/movement/kinematic/kinematic.mdx +0 -67
  173. package/src/docs/ai/movement/kinematic/kinematic.stories.js +0 -42
  174. package/src/docs/ai/movement/kinematic/seek.js +0 -34
  175. package/src/docs/ai/movement/kinematic/wander-as-seek.js +0 -62
  176. package/src/docs/ai/movement/kinematic/wander.js +0 -28
  177. package/src/docs/bounds.js +0 -7
  178. package/src/docs/code-reuse.js +0 -35
  179. package/src/docs/collision/circles.js +0 -58
  180. package/src/docs/collision/collision.mdx +0 -27
  181. package/src/docs/collision/collision.stories.js +0 -22
  182. package/src/docs/collision/platform.js +0 -76
  183. package/src/docs/collision/tilemap.js +0 -181
  184. package/src/docs/empty.js +0 -1
  185. package/src/docs/engine.mdx +0 -81
  186. package/src/docs/engine.stories.js +0 -37
  187. package/src/docs/event-handlers.js +0 -68
  188. package/src/docs/framerate.js +0 -37
  189. package/src/docs/game.jsx +0 -15
  190. package/src/docs/image/image.js +0 -19
  191. package/src/docs/image/image.stories.js +0 -22
  192. package/src/docs/image/sprite.js +0 -39
  193. package/src/docs/image/tilemap.js +0 -84
  194. package/src/docs/input/controls.js +0 -67
  195. package/src/docs/input/gamepad.js +0 -67
  196. package/src/docs/input/input.mdx +0 -55
  197. package/src/docs/input/input.stories.js +0 -27
  198. package/src/docs/input/keyboard.js +0 -58
  199. package/src/docs/input/mouse.js +0 -32
  200. package/src/docs/instances.js +0 -49
  201. package/src/docs/player/dynamic/double-jump.js +0 -90
  202. package/src/docs/player/dynamic/dynamic.stories.js +0 -32
  203. package/src/docs/player/dynamic/jump.js +0 -83
  204. package/src/docs/player/dynamic/modern-controls.js +0 -57
  205. package/src/docs/player/dynamic/shooter-controls.js +0 -51
  206. package/src/docs/player/dynamic/tank-controls.js +0 -44
  207. package/src/docs/player/kinematic/double-jump.js +0 -90
  208. package/src/docs/player/kinematic/jump.js +0 -82
  209. package/src/docs/player/kinematic/kinematic.stories.js +0 -32
  210. package/src/docs/player/kinematic/modern-controls.js +0 -56
  211. package/src/docs/player/kinematic/shooter-controls.js +0 -48
  212. package/src/docs/player/kinematic/tank-controls.js +0 -42
  213. package/src/docs/quick-start/first-game.js +0 -49
  214. package/src/docs/quick-start/hello-world.js +0 -1
  215. package/src/docs/quick-start.mdx +0 -127
  216. package/src/docs/quick-start.stories.js +0 -17
  217. package/src/docs/recipes/add-and-remove.js +0 -71
  218. package/src/docs/recipes/add-instance.js +0 -42
  219. package/src/docs/recipes/decision-tree.js +0 -169
  220. package/src/docs/recipes/random-instances.js +0 -25
  221. package/src/docs/recipes/recipes.mdx +0 -81
  222. package/src/docs/recipes/recipes.stories.js +0 -37
  223. package/src/docs/recipes/remove-instance.js +0 -52
  224. package/src/docs/recipes/states.js +0 -64
  225. package/src/docs/ui/button.js +0 -28
  226. package/src/docs/ui/form.stories.js +0 -55
  227. package/src/docs/ui-chooser.jsx +0 -6
  228. package/src/docs/utils/data-structures/object.mdx +0 -47
  229. package/src/docs/utils/data-structures/objects.mdx +0 -30
  230. package/src/docs/utils/functions/functions.mdx +0 -34
  231. package/src/docs/utils/math/geometry/circle.mdx +0 -55
  232. package/src/docs/utils/math/geometry/point.mdx +0 -38
  233. package/src/docs/utils/math/geometry/rectangle.mdx +0 -24
  234. package/src/docs/utils/math/geometry/segment.mdx +0 -55
  235. package/src/docs/utils/math/geometry/triangle.mdx +0 -22
  236. package/src/docs/utils/math/linear-algebra/2d.mdx +0 -22
  237. package/src/docs/utils/math/linear-algebra/quaternion.mdx +0 -21
  238. package/src/docs/utils/math/linear-algebra/quaternions.mdx +0 -22
  239. package/src/docs/utils/math/linear-algebra/vector.mdx +0 -177
  240. package/src/docs/utils/math/linear-algebra/vectors.mdx +0 -58
  241. package/src/docs/utils/math/numbers.mdx +0 -76
  242. package/src/docs/utils/math/random.mdx +0 -35
  243. package/src/docs/utils/math/statistics.mdx +0 -38
  244. package/src/docs/utils/math/trigonometry.mdx +0 -85
  245. package/src/docs/utils/physics/friction.mdx +0 -20
  246. package/src/docs/utils/physics/gravity.mdx +0 -28
  247. package/src/engine/loop.js +0 -15
  248. package/src/engine/store.js +0 -174
  249. package/src/engine/store.test.js +0 -256
  250. package/src/engine.js +0 -74
  251. package/src/game/animation.js +0 -26
  252. package/src/game/bounds.js +0 -66
  253. package/src/game/decorators/character.js +0 -5
  254. package/src/game/decorators/clamp-to-bounds.js +0 -15
  255. package/src/game/decorators/controls/dynamic/modern.js +0 -48
  256. package/src/game/decorators/controls/dynamic/shooter.js +0 -47
  257. package/src/game/decorators/controls/dynamic/tank.js +0 -55
  258. package/src/game/decorators/controls/kinematic/modern.js +0 -49
  259. package/src/game/decorators/controls/kinematic/shooter.js +0 -45
  260. package/src/game/decorators/controls/kinematic/tank.js +0 -52
  261. package/src/game/decorators/debug/collisions.js +0 -32
  262. package/src/game/decorators/double-jump.js +0 -70
  263. package/src/game/decorators/fps.js +0 -30
  264. package/src/game/decorators/fsm.js +0 -27
  265. package/src/game/decorators/game.js +0 -11
  266. package/src/game/decorators/image/image.js +0 -5
  267. package/src/game/decorators/image/sprite.js +0 -5
  268. package/src/game/decorators/image/tilemap.js +0 -5
  269. package/src/game/decorators/input/controls.js +0 -27
  270. package/src/game/decorators/input/gamepad.js +0 -74
  271. package/src/game/decorators/input/input.js +0 -41
  272. package/src/game/decorators/input/keyboard.js +0 -49
  273. package/src/game/decorators/input/mouse.js +0 -65
  274. package/src/game/decorators/jump.js +0 -72
  275. package/src/game/decorators/platform.js +0 -5
  276. package/src/game/decorators/ui/button.js +0 -21
  277. package/src/game/sprite.js +0 -119
  278. package/src/ui/canvas/absolute-position.js +0 -17
  279. package/src/ui/canvas/image/hitmask.js +0 -37
  280. package/src/ui/canvas.js +0 -81
  281. package/src/ui/react/game/character/index.jsx +0 -30
  282. package/src/utils/math/geometry/platform.js +0 -42
  283. package/src/utils/math/geometry/platform.test.js +0 -133
  284. /package/src/{ui → renderers}/react/game/character/character.module.scss +0 -0
  285. /package/src/{ui → renderers}/react/game/cursor/cursor.module.scss +0 -0
  286. /package/src/{ui → renderers}/react/game/form/fields/field/field.module.scss +0 -0
  287. /package/src/{ui → renderers}/react/game/form/fields/fields.module.scss +0 -0
  288. /package/src/{ui → renderers}/react/game/form/form.module.scss +0 -0
  289. /package/src/{ui → renderers}/react/game/platform/platform.module.scss +0 -0
  290. /package/src/{ui → renderers}/react/game/scene/scene.module.scss +0 -0
  291. /package/src/{ui → renderers}/react/game/sprite/sprite.module.css +0 -0
  292. /package/src/{ui → renderers}/react/hocs/with-absolute-position/with-absolute-position.module.scss +0 -0
@@ -1,22 +1,22 @@
1
- import { toString } from "@inglorious/utils/math/linear-algebra/vector.js"
2
-
3
- const DECIMALS = 1
4
-
5
- export default function Stats({ instance, instances, className, style }) {
6
- const { acceleration, velocity, position, orientation, ay, vy } =
7
- instances[instance.target]
8
-
9
- return (
10
- <div className={className} style={style}>
11
- {acceleration && <div>Acceleration: {toString(acceleration)}</div>}
12
- {velocity && <div>Velocity: {toString(velocity)}</div>}
13
- {position && <div>Position: {toString(position)}</div>}
14
- {orientation != null && (
15
- <div>Orientation: {orientation.toFixed(DECIMALS)}</div>
16
- )}
17
-
18
- {ay != null && <div>ay: {ay.toFixed(DECIMALS)}</div>}
19
- {vy != null && <div>vy: {vy.toFixed(DECIMALS)}</div>}
20
- </div>
21
- )
22
- }
1
+ import { toString } from "@inglorious/utils/math/linear-algebra/vector.js"
2
+
3
+ const DECIMALS = 1
4
+
5
+ export default function Stats({ entity, entities, className, style }) {
6
+ const { acceleration, velocity, position, orientation, ay, vy } =
7
+ entities[entity.target]
8
+
9
+ return (
10
+ <div className={className} style={style}>
11
+ {acceleration && <div>Acceleration: {toString(acceleration)}</div>}
12
+ {velocity && <div>Velocity: {toString(velocity)}</div>}
13
+ {position && <div>Position: {toString(position)}</div>}
14
+ {orientation != null && (
15
+ <div>Orientation: {orientation.toFixed(DECIMALS)}</div>
16
+ )}
17
+
18
+ {ay != null && <div>ay: {ay.toFixed(DECIMALS)}</div>}
19
+ {vy != null && <div>vy: {vy.toFixed(DECIMALS)}</div>}
20
+ </div>
21
+ )
22
+ }
@@ -1,20 +1,20 @@
1
- import { zero } from "@inglorious/utils/math/linear-algebra/vector.js"
2
-
3
- import classes from "./with-absolute-position.module.scss"
4
-
5
- export function withAbsolutePosition(Component) {
6
- return function AbsolutePosition(props) {
7
- const [, , , screenHeight] = props.instances.game.bounds
8
- const { position = zero() } = props.instance
9
-
10
- const [x, y, z] = position
11
-
12
- return (
13
- <Component
14
- {...props}
15
- className={classes.withAbsolutePosition}
16
- style={{ "--x": `${x}px`, "--y": `${screenHeight - y - z}px` }}
17
- />
18
- )
19
- }
20
- }
1
+ import { zero } from "@inglorious/utils/math/linear-algebra/vector.js"
2
+
3
+ import classes from "./with-absolute-position.module.scss"
4
+
5
+ export function withAbsolutePosition(Component) {
6
+ return function AbsolutePosition(props) {
7
+ const [, , , screenHeight] = props.entities.game.bounds
8
+ const { position = zero() } = props.entity
9
+
10
+ const [x, y, z] = position
11
+
12
+ return (
13
+ <Component
14
+ {...props}
15
+ className={classes.withAbsolutePosition}
16
+ style={{ "--x": `${x}px`, "--y": `${screenHeight - y - z}px` }}
17
+ />
18
+ )
19
+ }
20
+ }
@@ -1,9 +1,9 @@
1
- import ReactDOM from "react-dom/client"
2
-
3
- import Game from "./game/index.jsx"
4
-
5
- export function start(game) {
6
- ReactDOM.createRoot(document.getElementById("root")).render(
7
- <Game config={game} />,
8
- )
9
- }
1
+ import ReactDOM from "react-dom/client"
2
+
3
+ import Game from "./game/index.jsx"
4
+
5
+ export function start(game) {
6
+ ReactDOM.createRoot(document.getElementById("root")).render(
7
+ <Game config={game} />,
8
+ )
9
+ }
@@ -1,24 +1,24 @@
1
- /**
2
- * @typedef {import("./types").Conditions} Conditions
3
- * @typedef {import("./types").Outcome} Outcome
4
- * @typedef {import("./types").DecisionTree} DecisionTree
5
- */
6
-
7
- /**
8
- * Traverses a decision tree recursively based on the provided conditions and returns the resulting node.
9
- *
10
- * @param {DecisionTree} tree - The decision tree to traverse. Each node contains:
11
- * - `test` {Function}: A function that evaluates the conditions and determines the next branch.
12
- * - Branches keyed by the possible outcomes of the `test` function.
13
- * @param {Conditions} conditions - The conditions object passed to the `test` function at each node.
14
- * @returns {Outcome | DecisionTree} - The resulting outcome or decision tree itself after traversing the decision tree.
15
- */
16
- export function decide(tree, conditions) {
17
- if (!tree.test) {
18
- return tree
19
- }
20
-
21
- const value = tree.test(conditions)
22
-
23
- return tree[value] && decide(tree[value](conditions), conditions)
24
- }
1
+ /**
2
+ * @typedef {import("./types").Conditions} Conditions
3
+ * @typedef {import("./types").Outcome} Outcome
4
+ * @typedef {import("./types").DecisionTree} DecisionTree
5
+ */
6
+
7
+ /**
8
+ * Traverses a decision tree recursively based on the provided conditions and returns the resulting node.
9
+ *
10
+ * @param {DecisionTree} tree - The decision tree to traverse. Each node contains:
11
+ * - `test` {Function}: A function that evaluates the conditions and determines the next branch.
12
+ * - Branches keyed by the possible outcomes of the `test` function.
13
+ * @param {Conditions} conditions - The conditions object passed to the `test` function at each node.
14
+ * @returns {Outcome | DecisionTree} - The resulting outcome or decision tree itself after traversing the decision tree.
15
+ */
16
+ export function decide(tree, conditions) {
17
+ if (!tree.test) {
18
+ return tree
19
+ }
20
+
21
+ const value = tree.test(conditions)
22
+
23
+ return tree[value] && decide(tree[value](conditions), conditions)
24
+ }
@@ -1,102 +1,153 @@
1
- import { length } from "@inglorious/utils/math/linear-algebra/vector.js"
2
- import { subtract } from "@inglorious/utils/math/linear-algebra/vectors.js"
3
- import { expect, test } from "vitest"
4
-
5
- import { decide } from "./decision-tree.js"
6
-
7
- test("it should make a decision based on a binary decision tree", () => {
8
- const instance = { state: "sleeping", position: [0, 0, 0] }
9
- const target = { position: [10, 0, 0] }
10
- const tree = {
11
- test: ({ instance }) => instance.state === "idle",
12
- true: () => ({
13
- test: ({ instance, mouse }) => {
14
- const distance = length(subtract(mouse.position, instance.position))
15
- return distance < 250
16
- },
17
- true: () => "aware",
18
- }),
19
- false: () => ({
20
- test: ({ instance }) => instance.state === "chasing",
21
- true: () => ({
22
- test: ({ instance, mouse }) => {
23
- const distance = length(subtract(mouse.position, instance.position))
24
- return distance >= 250
25
- },
26
- true: () => "idle",
27
- false: () => ({
28
- test: ({ instance, mouse }) => {
29
- const distance = length(subtract(mouse.position, instance.position))
30
- return distance < 10
31
- },
32
- true: () => "sleepy",
33
- }),
34
- }),
35
- false: () => ({
36
- test: ({ instance }) => ["sleepy", "sleeping"].includes(instance.state),
37
- true: () => ({
38
- test: ({ instance, mouse }) => {
39
- const distance = length(subtract(mouse.position, instance.position))
40
- return distance >= 10
41
- },
42
- true: () => "aware",
43
- }),
44
- }),
45
- }),
46
- }
47
-
48
- const state = decide(tree, { instance, mouse: target })
49
-
50
- expect(state).toBe("aware")
51
- })
52
-
53
- test("it should make a decision on a multi-child tree", () => {
54
- const instance = { state: "sleeping", position: [0, 0, 0] }
55
- const target = { position: [10, 0, 0] }
56
- const tree = {
57
- test: ({ instance }) => instance.state,
58
- idle: () => ({
59
- test: ({ instance, target }) => {
60
- const distance = length(subtract(target.position, instance.position))
61
- return distance < 250
62
- },
63
- true: () => "aware",
64
- false: ({ instance }) => instance.state,
65
- }),
66
- chasing: () => ({
67
- test: ({ instance, target }) => {
68
- const distance = length(subtract(target.position, instance.position))
69
- return distance >= 250
70
- },
71
- true: () => "idle",
72
- false: () => ({
73
- test: ({ instance, target }) => {
74
- const distance = length(subtract(target.position, instance.position))
75
- return distance < 10
76
- },
77
- true: () => "sleepy",
78
- false: ({ instance }) => instance.state,
79
- }),
80
- }),
81
- sleepy: () => ({
82
- test: ({ instance, target }) => {
83
- const distance = length(subtract(target.position, instance.position))
84
- return distance >= 10
85
- },
86
- true: () => "aware",
87
- false: ({ instance }) => instance.state,
88
- }),
89
- sleeping: () => ({
90
- test: ({ instance, target }) => {
91
- const distance = length(subtract(target.position, instance.position))
92
- return distance >= 10
93
- },
94
- true: () => "aware",
95
- false: ({ instance }) => instance.state,
96
- }),
97
- }
98
-
99
- const state = decide(tree, { instance, target })
100
-
101
- expect(state).toBe("aware")
102
- })
1
+ import { length } from "@inglorious/utils/math/linear-algebra/vector.js"
2
+ import { subtract } from "@inglorious/utils/math/linear-algebra/vectors.js"
3
+ import { expect, test } from "vitest"
4
+
5
+ import { decide } from "./decision-tree.js"
6
+
7
+ test("it should make a decision based on a binary decision tree", () => {
8
+ const entity = { state: "sleeping", position: [0, 0, 0] }
9
+ const target = { position: [10, 0, 0] }
10
+ const tree = {
11
+ test({ entity }) {
12
+ return entity.state === "idle"
13
+ },
14
+ true() {
15
+ return {
16
+ test({ entity, target }) {
17
+ const distance = length(subtract(target.position, entity.position))
18
+ return distance < 250
19
+ },
20
+ true() {
21
+ return "aware"
22
+ },
23
+ }
24
+ },
25
+ false() {
26
+ return {
27
+ test({ entity }) {
28
+ return entity.state === "chasing"
29
+ },
30
+ true() {
31
+ return {
32
+ test({ entity, target }) {
33
+ const distance = length(
34
+ subtract(target.position, entity.position),
35
+ )
36
+ return distance >= 250
37
+ },
38
+ true() {
39
+ return "idle"
40
+ },
41
+ false() {
42
+ return {
43
+ test({ entity, target }) {
44
+ const distance = length(
45
+ subtract(target.position, entity.position),
46
+ )
47
+ return distance < 10
48
+ },
49
+ true() {
50
+ return "sleepy"
51
+ },
52
+ }
53
+ },
54
+ }
55
+ },
56
+ false() {
57
+ return {
58
+ test({ entity }) {
59
+ return ["sleepy", "sleeping"].includes(entity.state)
60
+ },
61
+ true() {
62
+ return {
63
+ test({ entity, target }) {
64
+ const distance = length(
65
+ subtract(target.position, entity.position),
66
+ )
67
+ return distance >= 10
68
+ },
69
+ true() {
70
+ return "aware"
71
+ },
72
+ }
73
+ },
74
+ }
75
+ },
76
+ }
77
+ },
78
+ }
79
+
80
+ const state = decide(tree, { entity, target })
81
+
82
+ expect(state).toBe("aware")
83
+ })
84
+
85
+ test("it should make a decision on a multi-child tree", () => {
86
+ const entity = { state: "sleeping", position: [0, 0, 0] }
87
+ const target = { position: [10, 0, 0] }
88
+ const wakeUp = () => ({
89
+ test({ entity, target }) {
90
+ const distance = length(subtract(target.position, entity.position))
91
+ return distance >= 10
92
+ },
93
+ true() {
94
+ return "aware"
95
+ },
96
+ false({ entity }) {
97
+ return entity.state
98
+ },
99
+ })
100
+
101
+ const tree = {
102
+ test({ entity }) {
103
+ return entity.state
104
+ },
105
+ idle() {
106
+ return {
107
+ test({ entity, target }) {
108
+ const distance = length(subtract(target.position, entity.position))
109
+ return distance < 250
110
+ },
111
+ true() {
112
+ return "aware"
113
+ },
114
+ false({ entity }) {
115
+ return entity.state
116
+ },
117
+ }
118
+ },
119
+ chasing() {
120
+ return {
121
+ test({ entity, target }) {
122
+ const distance = length(subtract(target.position, entity.position))
123
+ return distance >= 250
124
+ },
125
+ true() {
126
+ return "idle"
127
+ },
128
+ false() {
129
+ return {
130
+ test({ entity, target }) {
131
+ const distance = length(
132
+ subtract(target.position, entity.position),
133
+ )
134
+ return distance < 10
135
+ },
136
+ true() {
137
+ return "sleepy"
138
+ },
139
+ false({ entity }) {
140
+ return entity.state
141
+ },
142
+ }
143
+ },
144
+ }
145
+ },
146
+ sleepy: wakeUp,
147
+ sleeping: wakeUp,
148
+ }
149
+
150
+ const state = decide(tree, { entity, target })
151
+
152
+ expect(state).toBe("aware")
153
+ })