board-game-engine 2.1.0 → 2.1.1

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 (256) hide show
  1. package/README.md +2 -2
  2. package/dist/board-game-engine.cjs +5509 -5613
  3. package/dist/board-game-engine.js +5509 -5613
  4. package/dist/board-game-engine.min.js +22 -22
  5. package/dist/board-game-engine.mjs +5508 -5611
  6. package/e2e/fixtures/bge-checkers.html +2 -1
  7. package/e2e/fixtures/bge-minimal.html +2 -1
  8. package/e2e/fixtures/bge-ttt.html +2 -1
  9. package/examples/index.html +1 -1
  10. package/package.json +4 -10
  11. package/playwright-report/index.html +1 -1
  12. package/scripts/build.mjs +2 -2
  13. package/src/client/client.js +224 -0
  14. package/src/game-factory/bank/bank-slot.js +69 -0
  15. package/src/game-factory/bank/bank.js +114 -0
  16. package/src/game-factory/{board.ts → board.js} +1 -1
  17. package/src/game-factory/condition/condition-factory.js +52 -0
  18. package/src/game-factory/condition/condition.js +39 -0
  19. package/src/game-factory/condition/{contains-condition.ts → contains-condition.js} +4 -5
  20. package/src/game-factory/condition/{contains-same-condition.ts → contains-same-condition.js} +5 -8
  21. package/src/game-factory/condition/{evaluate-condition.ts → evaluate-condition.js} +3 -4
  22. package/src/game-factory/condition/every-condition.js +25 -0
  23. package/src/game-factory/condition/has-line-condition.js +14 -0
  24. package/src/game-factory/condition/in-line-condition.js +19 -0
  25. package/src/game-factory/condition/is-condition.js +23 -0
  26. package/src/game-factory/condition/is-full-condition.js +9 -0
  27. package/src/game-factory/condition/{no-possible-moves-condition.ts → no-possible-moves-condition.js} +2 -3
  28. package/src/game-factory/condition/{not-condition.ts → not-condition.js} +2 -3
  29. package/src/game-factory/condition/{or-condition.ts → or-condition.js} +2 -3
  30. package/src/game-factory/condition/position-condition.js +12 -0
  31. package/src/game-factory/condition/{some-condition.ts → some-condition.js} +3 -5
  32. package/src/game-factory/condition/would-condition.js +94 -0
  33. package/src/game-factory/entity.js +29 -0
  34. package/src/game-factory/expand-game-rules.js +271 -0
  35. package/src/game-factory/game-factory.js +240 -0
  36. package/{dist/game-factory/move/end-turn.d.ts → src/game-factory/move/end-turn.js} +4 -2
  37. package/src/game-factory/move/for-each.js +18 -0
  38. package/src/game-factory/move/move-entity.js +16 -0
  39. package/src/game-factory/move/move-factory.js +89 -0
  40. package/src/game-factory/move/move.js +131 -0
  41. package/src/game-factory/move/pass-turn.js +10 -0
  42. package/{dist/game-factory/move/pass.d.ts → src/game-factory/move/pass.js} +4 -2
  43. package/src/game-factory/move/place-new.js +33 -0
  44. package/src/game-factory/move/remove-entity.js +7 -0
  45. package/src/game-factory/move/set-active-players.js +23 -0
  46. package/src/game-factory/move/set-state.js +11 -0
  47. package/src/game-factory/move/shuffle.js +7 -0
  48. package/src/game-factory/move/take-from.js +7 -0
  49. package/src/game-factory/space/space.js +30 -0
  50. package/src/game-factory/space-group/grid.js +43 -0
  51. package/src/game-factory/space-group/space-group.js +29 -0
  52. package/src/index.js +2 -0
  53. package/src/utils/{any-valid-moves.ts → any-valid-moves.js} +49 -54
  54. package/src/utils/check-conditions.js +28 -0
  55. package/src/utils/create-payload.js +16 -0
  56. package/src/utils/deserialize-bgio-arguments.js +8 -0
  57. package/src/utils/do-moves.js +18 -0
  58. package/src/utils/entity-matches.js +20 -0
  59. package/src/utils/find-met-condition.js +22 -0
  60. package/src/utils/get-current-moves.js +12 -0
  61. package/src/utils/get-scenario-results.js +23 -0
  62. package/src/utils/get-steps.js +29 -0
  63. package/src/utils/get.js +25 -0
  64. package/src/utils/{grid-contains-sequence.ts → grid-contains-sequence.js} +33 -71
  65. package/src/utils/json-transformer.js +12 -0
  66. package/src/utils/prepare-payload.js +17 -0
  67. package/src/utils/resolve-entity.js +9 -0
  68. package/src/utils/resolve-expression.js +10 -0
  69. package/src/utils/resolve-properties.js +149 -0
  70. package/src/utils/simulate-move.js +25 -0
  71. package/.github/workflows/ci.yml +0 -33
  72. package/dist/client/client.d.ts +0 -76
  73. package/dist/client/client.d.ts.map +0 -1
  74. package/dist/game-factory/bank/bank-slot.d.ts +0 -30
  75. package/dist/game-factory/bank/bank-slot.d.ts.map +0 -1
  76. package/dist/game-factory/bank/bank.d.ts +0 -34
  77. package/dist/game-factory/bank/bank.d.ts.map +0 -1
  78. package/dist/game-factory/board.d.ts +0 -4
  79. package/dist/game-factory/board.d.ts.map +0 -1
  80. package/dist/game-factory/condition/condition-factory.d.ts +0 -4
  81. package/dist/game-factory/condition/condition-factory.d.ts.map +0 -1
  82. package/dist/game-factory/condition/condition.d.ts +0 -13
  83. package/dist/game-factory/condition/condition.d.ts.map +0 -1
  84. package/dist/game-factory/condition/contains-condition.d.ts +0 -8
  85. package/dist/game-factory/condition/contains-condition.d.ts.map +0 -1
  86. package/dist/game-factory/condition/contains-same-condition.d.ts +0 -7
  87. package/dist/game-factory/condition/contains-same-condition.d.ts.map +0 -1
  88. package/dist/game-factory/condition/evaluate-condition.d.ts +0 -8
  89. package/dist/game-factory/condition/evaluate-condition.d.ts.map +0 -1
  90. package/dist/game-factory/condition/every-condition.d.ts +0 -12
  91. package/dist/game-factory/condition/every-condition.d.ts.map +0 -1
  92. package/dist/game-factory/condition/has-line-condition.d.ts +0 -8
  93. package/dist/game-factory/condition/has-line-condition.d.ts.map +0 -1
  94. package/dist/game-factory/condition/in-line-condition.d.ts +0 -8
  95. package/dist/game-factory/condition/in-line-condition.d.ts.map +0 -1
  96. package/dist/game-factory/condition/is-condition.d.ts +0 -8
  97. package/dist/game-factory/condition/is-condition.d.ts.map +0 -1
  98. package/dist/game-factory/condition/is-full-condition.d.ts +0 -7
  99. package/dist/game-factory/condition/is-full-condition.d.ts.map +0 -1
  100. package/dist/game-factory/condition/no-possible-moves-condition.d.ts +0 -7
  101. package/dist/game-factory/condition/no-possible-moves-condition.d.ts.map +0 -1
  102. package/dist/game-factory/condition/not-condition.d.ts +0 -7
  103. package/dist/game-factory/condition/not-condition.d.ts.map +0 -1
  104. package/dist/game-factory/condition/or-condition.d.ts +0 -7
  105. package/dist/game-factory/condition/or-condition.d.ts.map +0 -1
  106. package/dist/game-factory/condition/position-condition.d.ts +0 -7
  107. package/dist/game-factory/condition/position-condition.d.ts.map +0 -1
  108. package/dist/game-factory/condition/some-condition.d.ts +0 -8
  109. package/dist/game-factory/condition/some-condition.d.ts.map +0 -1
  110. package/dist/game-factory/condition/would-condition.d.ts +0 -8
  111. package/dist/game-factory/condition/would-condition.d.ts.map +0 -1
  112. package/dist/game-factory/entity.d.ts +0 -13
  113. package/dist/game-factory/entity.d.ts.map +0 -1
  114. package/dist/game-factory/expand-game-rules.d.ts +0 -3
  115. package/dist/game-factory/expand-game-rules.d.ts.map +0 -1
  116. package/dist/game-factory/game-factory.d.ts +0 -10
  117. package/dist/game-factory/game-factory.d.ts.map +0 -1
  118. package/dist/game-factory/move/end-turn.d.ts.map +0 -1
  119. package/dist/game-factory/move/for-each.d.ts +0 -5
  120. package/dist/game-factory/move/for-each.d.ts.map +0 -1
  121. package/dist/game-factory/move/index.d.ts +0 -6
  122. package/dist/game-factory/move/index.d.ts.map +0 -1
  123. package/dist/game-factory/move/move-entity.d.ts +0 -7
  124. package/dist/game-factory/move/move-entity.d.ts.map +0 -1
  125. package/dist/game-factory/move/move-factory.d.ts +0 -18
  126. package/dist/game-factory/move/move-factory.d.ts.map +0 -1
  127. package/dist/game-factory/move/move.d.ts +0 -54
  128. package/dist/game-factory/move/move.d.ts.map +0 -1
  129. package/dist/game-factory/move/pass-turn.d.ts +0 -5
  130. package/dist/game-factory/move/pass-turn.d.ts.map +0 -1
  131. package/dist/game-factory/move/pass.d.ts.map +0 -1
  132. package/dist/game-factory/move/place-new.d.ts +0 -5
  133. package/dist/game-factory/move/place-new.d.ts.map +0 -1
  134. package/dist/game-factory/move/remove-entity.d.ts +0 -5
  135. package/dist/game-factory/move/remove-entity.d.ts.map +0 -1
  136. package/dist/game-factory/move/set-active-players.d.ts +0 -5
  137. package/dist/game-factory/move/set-active-players.d.ts.map +0 -1
  138. package/dist/game-factory/move/set-state.d.ts +0 -5
  139. package/dist/game-factory/move/set-state.d.ts.map +0 -1
  140. package/dist/game-factory/move/shuffle.d.ts +0 -5
  141. package/dist/game-factory/move/shuffle.d.ts.map +0 -1
  142. package/dist/game-factory/move/take-from.d.ts +0 -11
  143. package/dist/game-factory/move/take-from.d.ts.map +0 -1
  144. package/dist/game-factory/space/space.d.ts +0 -10
  145. package/dist/game-factory/space/space.d.ts.map +0 -1
  146. package/dist/game-factory/space-group/grid.d.ts +0 -15
  147. package/dist/game-factory/space-group/grid.d.ts.map +0 -1
  148. package/dist/game-factory/space-group/space-group.d.ts +0 -20
  149. package/dist/game-factory/space-group/space-group.d.ts.map +0 -1
  150. package/dist/index.d.ts +0 -6
  151. package/dist/index.d.ts.map +0 -1
  152. package/dist/registry.d.ts +0 -17
  153. package/dist/registry.d.ts.map +0 -1
  154. package/dist/types/bagel-types.d.ts +0 -339
  155. package/dist/types/bagel-types.d.ts.map +0 -1
  156. package/dist/types/index.d.ts +0 -3
  157. package/dist/types/index.d.ts.map +0 -1
  158. package/dist/types/rule-with-conditions.d.ts +0 -9
  159. package/dist/types/rule-with-conditions.d.ts.map +0 -1
  160. package/dist/utils/any-valid-moves.d.ts +0 -2
  161. package/dist/utils/any-valid-moves.d.ts.map +0 -1
  162. package/dist/utils/bgio-resolve-types.d.ts +0 -25
  163. package/dist/utils/bgio-resolve-types.d.ts.map +0 -1
  164. package/dist/utils/check-conditions.d.ts +0 -7
  165. package/dist/utils/check-conditions.d.ts.map +0 -1
  166. package/dist/utils/create-payload.d.ts +0 -5
  167. package/dist/utils/create-payload.d.ts.map +0 -1
  168. package/dist/utils/deserialize-bgio-arguments.d.ts +0 -3
  169. package/dist/utils/deserialize-bgio-arguments.d.ts.map +0 -1
  170. package/dist/utils/do-moves.d.ts +0 -8
  171. package/dist/utils/do-moves.d.ts.map +0 -1
  172. package/dist/utils/entity-matches.d.ts +0 -6
  173. package/dist/utils/entity-matches.d.ts.map +0 -1
  174. package/dist/utils/find-met-condition.d.ts +0 -6
  175. package/dist/utils/find-met-condition.d.ts.map +0 -1
  176. package/dist/utils/get-current-moves.d.ts +0 -24
  177. package/dist/utils/get-current-moves.d.ts.map +0 -1
  178. package/dist/utils/get-scenario-results.d.ts +0 -3
  179. package/dist/utils/get-scenario-results.d.ts.map +0 -1
  180. package/dist/utils/get-steps.d.ts +0 -13
  181. package/dist/utils/get-steps.d.ts.map +0 -1
  182. package/dist/utils/get.d.ts +0 -7
  183. package/dist/utils/get.d.ts.map +0 -1
  184. package/dist/utils/grid-contains-sequence.d.ts +0 -27
  185. package/dist/utils/grid-contains-sequence.d.ts.map +0 -1
  186. package/dist/utils/json-transformer.d.ts +0 -8
  187. package/dist/utils/json-transformer.d.ts.map +0 -1
  188. package/dist/utils/prepare-payload.d.ts +0 -2
  189. package/dist/utils/prepare-payload.d.ts.map +0 -1
  190. package/dist/utils/resolve-entity.d.ts +0 -3
  191. package/dist/utils/resolve-entity.d.ts.map +0 -1
  192. package/dist/utils/resolve-expression.d.ts +0 -6
  193. package/dist/utils/resolve-expression.d.ts.map +0 -1
  194. package/dist/utils/resolve-properties.d.ts +0 -4
  195. package/dist/utils/resolve-properties.d.ts.map +0 -1
  196. package/dist/utils/simulate-move.d.ts +0 -16
  197. package/dist/utils/simulate-move.d.ts.map +0 -1
  198. package/src/client/client.ts +0 -305
  199. package/src/game-factory/bank/bank-slot.ts +0 -81
  200. package/src/game-factory/bank/bank.ts +0 -125
  201. package/src/game-factory/condition/condition-factory.ts +0 -59
  202. package/src/game-factory/condition/condition.ts +0 -50
  203. package/src/game-factory/condition/every-condition.ts +0 -27
  204. package/src/game-factory/condition/has-line-condition.ts +0 -15
  205. package/src/game-factory/condition/in-line-condition.ts +0 -25
  206. package/src/game-factory/condition/is-condition.ts +0 -24
  207. package/src/game-factory/condition/is-full-condition.ts +0 -10
  208. package/src/game-factory/condition/position-condition.ts +0 -13
  209. package/src/game-factory/condition/would-condition.ts +0 -104
  210. package/src/game-factory/entity.ts +0 -37
  211. package/src/game-factory/expand-game-rules.ts +0 -263
  212. package/src/game-factory/game-factory.ts +0 -263
  213. package/src/game-factory/move/end-turn.ts +0 -7
  214. package/src/game-factory/move/for-each.ts +0 -20
  215. package/src/game-factory/move/move-entity.ts +0 -18
  216. package/src/game-factory/move/move-factory.ts +0 -107
  217. package/src/game-factory/move/move.ts +0 -147
  218. package/src/game-factory/move/pass-turn.ts +0 -15
  219. package/src/game-factory/move/pass.ts +0 -7
  220. package/src/game-factory/move/place-new.ts +0 -42
  221. package/src/game-factory/move/remove-entity.ts +0 -11
  222. package/src/game-factory/move/set-active-players.ts +0 -26
  223. package/src/game-factory/move/set-state.ts +0 -14
  224. package/src/game-factory/move/shuffle.ts +0 -9
  225. package/src/game-factory/move/take-from.ts +0 -12
  226. package/src/game-factory/space/space.ts +0 -36
  227. package/src/game-factory/space-group/grid.ts +0 -48
  228. package/src/game-factory/space-group/space-group.ts +0 -44
  229. package/src/index.ts +0 -5
  230. package/src/types/bagel-types.ts +0 -449
  231. package/src/types/boardgame-io-core.d.ts +0 -7
  232. package/src/types/index.ts +0 -70
  233. package/src/types/rule-with-conditions.ts +0 -9
  234. package/src/utils/bgio-resolve-types.ts +0 -27
  235. package/src/utils/check-conditions.ts +0 -28
  236. package/src/utils/create-payload.ts +0 -19
  237. package/src/utils/deserialize-bgio-arguments.ts +0 -10
  238. package/src/utils/do-moves.ts +0 -22
  239. package/src/utils/entity-matches.ts +0 -30
  240. package/src/utils/expr-eval.d.ts +0 -6
  241. package/src/utils/find-met-condition.ts +0 -23
  242. package/src/utils/get-current-moves.ts +0 -39
  243. package/src/utils/get-scenario-results.ts +0 -30
  244. package/src/utils/get-steps.ts +0 -38
  245. package/src/utils/get.ts +0 -28
  246. package/src/utils/json-transformer.ts +0 -17
  247. package/src/utils/prepare-payload.ts +0 -20
  248. package/src/utils/resolve-entity.ts +0 -15
  249. package/src/utils/resolve-expression.ts +0 -16
  250. package/src/utils/resolve-properties.ts +0 -172
  251. package/src/utils/simulate-move.ts +0 -32
  252. package/src/wackson.d.ts +0 -4
  253. package/tsconfig.build.json +0 -14
  254. package/tsconfig.json +0 -21
  255. /package/src/game-factory/move/{index.ts → index.js} +0 -0
  256. /package/src/{registry.ts → registry.js} +0 -0
@@ -0,0 +1,43 @@
1
+ import chunk from "lodash/chunk.js";
2
+ import SpaceGroup from "../space-group/space-group.js";
3
+
4
+ export default class Grid extends SpaceGroup {
5
+ getSpacesCount () {
6
+ return this.rule.width * this.rule.height
7
+ }
8
+
9
+ getRows () {
10
+ return chunk(this.spaces, this.rule.width)
11
+ }
12
+
13
+ getCoordinates (index) {
14
+ const { width } = this.rule
15
+ return [
16
+ index % width,
17
+ Math.floor(index/width)
18
+ ]
19
+ }
20
+
21
+ getIndex ([ x, y ]) {
22
+ const { width } = this.rule
23
+ return y * width + x
24
+ }
25
+
26
+ getSpace (coordinates) {
27
+ return this.spaces[this.getIndex(coordinates)]
28
+ }
29
+
30
+ getRelativeCoordinates ([oldX, oldY], [relativeX, relativeY]) {
31
+ const newCoordinates = [oldX + relativeX, oldY + relativeY]
32
+ return this.areCoordinatesValid(newCoordinates)
33
+ ? newCoordinates
34
+ : null
35
+ }
36
+
37
+ areCoordinatesValid([x, y]) {
38
+ return x >= 0
39
+ && y >= 0
40
+ && x < this.rule.width
41
+ && y < this.rule.height
42
+ }
43
+ }
@@ -0,0 +1,29 @@
1
+ import Entity from "../entity.js";
2
+
3
+ export default class SpaceGroup extends Entity {
4
+ constructor (options, ...rest) {
5
+ super(options, ...rest)
6
+ this.spaces = this.makeSpaces(options.bank);
7
+ }
8
+
9
+ makeSpaces (bank) {
10
+ return Array(this.getSpacesCount()).fill()
11
+ .map((_, i) => bank.createEntity({ entityType: 'Space', index: i }))
12
+ }
13
+
14
+ getEmptySpaces() {
15
+ return this.spaces.filter(space => space.isEmpty())
16
+ }
17
+
18
+ getSpace(index) {
19
+ return this.spaces[index]
20
+ }
21
+
22
+ getEntities(index) {
23
+ return this.getSpace(index).entities;
24
+ }
25
+
26
+ placeEntity(index, entity) {
27
+ this.getSpace(index).placeEntity(entity);
28
+ }
29
+ }
package/src/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { default as gameFactory } from './game-factory/game-factory'
2
+ export { Client } from './client/client'
@@ -1,83 +1,83 @@
1
1
  import isPlainObject from "lodash/isPlainObject.js";
2
- import type { BgioResolveState } from "./bgio-resolve-types.js";
3
2
  import resolveProperties from "./resolve-properties.js";
4
3
  import resolveEntity from "./resolve-entity.js";
5
4
 
6
5
  // Recursively find all contextPath references to moveArguments
7
- function findMoveArgumentReferences (obj: unknown, refs = new Set<string>()): Set<string> {
8
- if (!obj || typeof obj !== "object") {
6
+ function findMoveArgumentReferences(obj, refs = new Set()) {
7
+ if (!obj || typeof obj !== 'object') {
9
8
  return refs;
10
9
  }
11
-
12
- const o = obj as { type?: string; path?: unknown[] };
13
- if (o.type === "contextPath" && Array.isArray(o.path)) {
14
- if (o.path[0] === "moveArguments" && o.path[1]) {
15
- refs.add(String(o.path[1]));
10
+
11
+ // Check if this is a contextPath reference to moveArguments
12
+ if (obj.type === 'contextPath' && Array.isArray(obj.path)) {
13
+ if (obj.path[0] === 'moveArguments' && obj.path[1]) {
14
+ refs.add(obj.path[1]);
16
15
  }
17
16
  }
18
-
19
- for (const value of Object.values(obj as object)) {
17
+
18
+ // Recurse into object properties and array elements
19
+ for (const value of Object.values(obj)) {
20
20
  findMoveArgumentReferences(value, refs);
21
21
  }
22
-
22
+
23
23
  return refs;
24
24
  }
25
25
 
26
26
  // Build a dependency graph and return topologically sorted argument names
27
- function getArgumentOrder (ruleArguments: Record<string, unknown>) {
27
+ function getArgumentOrder(ruleArguments) {
28
28
  const argNames = Object.keys(ruleArguments);
29
- const graph: Record<string, string[]> = {};
30
- const inDegree: Record<string, number> = {};
31
-
32
- argNames.forEach((name) => {
29
+ const graph = {};
30
+ const inDegree = {};
31
+
32
+ // Initialize
33
+ argNames.forEach(name => {
33
34
  graph[name] = [];
34
35
  inDegree[name] = 0;
35
36
  });
36
-
37
- argNames.forEach((argName) => {
37
+
38
+ // Build dependency edges (if arg B references arg A, A -> B)
39
+ argNames.forEach(argName => {
38
40
  const arg = ruleArguments[argName];
39
41
  const referencedArgs = findMoveArgumentReferences(arg);
40
-
41
- referencedArgs.forEach((refArg) => {
42
+
43
+ referencedArgs.forEach(refArg => {
42
44
  if (argNames.includes(refArg) && refArg !== argName) {
43
45
  graph[refArg].push(argName);
44
46
  inDegree[argName]++;
45
47
  }
46
48
  });
47
49
  });
48
-
49
- const queue = argNames.filter((name) => inDegree[name] === 0);
50
- const sorted: string[] = [];
51
-
50
+
51
+ // Topological sort (Kahn's algorithm)
52
+ const queue = argNames.filter(name => inDegree[name] === 0);
53
+ const sorted = [];
54
+
52
55
  while (queue.length > 0) {
53
- const current = queue.shift()!;
56
+ const current = queue.shift();
54
57
  sorted.push(current);
55
-
56
- graph[current].forEach((neighbor) => {
58
+
59
+ graph[current].forEach(neighbor => {
57
60
  inDegree[neighbor]--;
58
61
  if (inDegree[neighbor] === 0) {
59
62
  queue.push(neighbor);
60
63
  }
61
64
  });
62
65
  }
63
-
66
+
67
+ // If not all nodes processed, there's a cycle - fall back to original order
64
68
  return sorted.length === argNames.length ? sorted : argNames;
65
69
  }
66
70
 
67
- type MoveEntry = {
68
- moveInstance: { isValid: (a: unknown, p: unknown, c: unknown) => boolean; rule: unknown };
69
- };
70
-
71
71
  // Recursively try to build a valid argument combination
72
- function findValidCombination (
73
- bgioArguments: BgioResolveState,
74
- moveInstance: MoveEntry["moveInstance"],
75
- ruleArguments: Record<string, unknown>,
76
- orderedArgNames: string[],
77
- context: Record<string, unknown>,
72
+ function findValidCombination(
73
+ bgioArguments,
74
+ moveInstance,
75
+ ruleArguments,
76
+ orderedArgNames,
77
+ context,
78
78
  index = 0,
79
- currentArgs: Record<string, unknown> = {}
80
- ): boolean {
79
+ currentArgs = {}
80
+ ) {
81
81
  // Base case: all arguments resolved
82
82
  if (index === orderedArgNames.length) {
83
83
  const resolvedPayload = { arguments: currentArgs };
@@ -98,7 +98,7 @@ function findValidCombination (
98
98
  const matches = isPlainObject(arg)
99
99
  ? resolveEntity(
100
100
  bgioArguments,
101
- { ...(arg as Record<string, unknown>), matchMultiple: true },
101
+ { ...arg, matchMultiple: true },
102
102
  updatedContext,
103
103
  argName
104
104
  )
@@ -112,7 +112,7 @@ function findValidCombination (
112
112
  }
113
113
 
114
114
  // Try each possible value (short-circuits on first success)
115
- return matchArray.some((value: unknown) => {
115
+ return matchArray.some(value => {
116
116
  return findValidCombination(
117
117
  bgioArguments,
118
118
  moveInstance,
@@ -125,26 +125,21 @@ function findValidCombination (
125
125
  });
126
126
  }
127
127
 
128
- export default function areThereValidMoves (
129
- bgioArguments: unknown,
130
- moves: Record<string, unknown>
131
- ) {
132
- const bgio = bgioArguments as BgioResolveState;
133
- return Object.values(moves).some((move) => {
134
- const moveInstance = (move as MoveEntry | undefined)?.moveInstance;
135
- if (!moveInstance) return false;
128
+ export default function areThereValidMoves(bgioArguments, moves) {
129
+ return Object.values(moves).some(move => {
130
+ const { moveInstance } = move;
136
131
  const context = { moveInstance };
137
132
  const rule = resolveProperties(
138
- bgio,
133
+ bgioArguments,
139
134
  moveInstance.rule,
140
135
  context
141
- ) as { arguments?: Record<string, unknown> };
136
+ );
142
137
 
143
138
  const ruleArguments = rule.arguments ?? {};
144
139
 
145
140
  // If no arguments required, just check if move is valid
146
141
  if (Object.keys(ruleArguments).length === 0) {
147
- return moveInstance.isValid(bgio, { arguments: {} }, context);
142
+ return moveInstance.isValid(bgioArguments, { arguments: {} }, context);
148
143
  }
149
144
 
150
145
  // Get dependency-ordered argument names
@@ -152,7 +147,7 @@ export default function areThereValidMoves (
152
147
 
153
148
  // Recursively search for any valid combination (short-circuits on first valid)
154
149
  return findValidCombination(
155
- bgio,
150
+ bgioArguments,
156
151
  moveInstance,
157
152
  ruleArguments,
158
153
  orderedArgNames,
@@ -0,0 +1,28 @@
1
+ import conditionFactory from '../game-factory/condition/condition-factory.js';
2
+
3
+ export default function checkConditions (
4
+ bgioArguments,
5
+ rule,
6
+ payload,
7
+ context
8
+ ) {
9
+ const { conditions = [] } = rule
10
+ const results = [];
11
+ let failedAt
12
+ for (const conditionRule of conditions) {
13
+ const result = conditionFactory(conditionRule)
14
+ .check(bgioArguments, payload, context);
15
+ if (!result.conditionIsMet) {
16
+ failedAt = conditionRule
17
+ break
18
+ } else {
19
+ results.push(result);
20
+ }
21
+ }
22
+
23
+ return {
24
+ results,
25
+ failedAt,
26
+ conditionsAreMet: results.length === conditions.length
27
+ };
28
+ }
@@ -0,0 +1,16 @@
1
+ import getSteps from './get-steps.js';
2
+
3
+ export default function createPayload (bgioState, moveRule, targets, context) {
4
+ const argNames = getSteps(
5
+ bgioState,
6
+ moveRule,
7
+ context
8
+ ).map(s => s.argName)
9
+ return {
10
+ arguments: targets.reduce((acc, target, i) => ({
11
+ ...acc,
12
+ [argNames[i]]: target
13
+ }), {})
14
+ }
15
+ }
16
+
@@ -0,0 +1,8 @@
1
+ import { deserialize } from "wackson";
2
+ import { registry } from "../registry.js";
3
+ export default function deserializeBgioArguments (bgioArguments) {
4
+ return {
5
+ ...bgioArguments,
6
+ G: deserialize(JSON.stringify(bgioArguments.G), registry)
7
+ }
8
+ }
@@ -0,0 +1,18 @@
1
+ import moveFactory from "../game-factory/move/move-factory.js";
2
+
3
+ export default function doMoves (bgioArguments, moves = [], context) {
4
+ if (!moves?.length) {
5
+ return bgioArguments.G
6
+ }
7
+
8
+ moves.forEach((moveRule) => {
9
+ moveFactory(moveRule, context.game).moveInstance.doMove(
10
+ bgioArguments,
11
+ undefined,
12
+ context
13
+ );
14
+ })
15
+
16
+ return bgioArguments.G
17
+ }
18
+
@@ -0,0 +1,20 @@
1
+ import matches from 'lodash/matches.js'
2
+ import resolveProperties from '../utils/resolve-properties.js'
3
+
4
+ function resolveMatcher (bgioArguments, matcher, context) {
5
+ const resolvedMatcher = { ...matcher }
6
+ delete resolvedMatcher.state
7
+ delete resolvedMatcher.stateGroups
8
+ return resolveProperties(bgioArguments, resolvedMatcher, context)
9
+ }
10
+
11
+ function getEntityMatcher (entity) {
12
+ return {
13
+ ...entity.rule,
14
+ ...entity.state
15
+ }
16
+ }
17
+
18
+ export default function entityMatches (bgioArguments, matcher, entity, context) {
19
+ return matches(resolveMatcher(bgioArguments, matcher, context))(getEntityMatcher(entity))
20
+ }
@@ -0,0 +1,22 @@
1
+ import conditionFactory from '../game-factory/condition/condition-factory.js';
2
+
3
+ export default function findMetCondition (
4
+ bgioArguments,
5
+ { conditions = [] },
6
+ payload,
7
+ context,
8
+ ) {
9
+ let success
10
+ for (const conditionRule of conditions) {
11
+ const result = conditionFactory(conditionRule)
12
+ .check(bgioArguments, payload, context);
13
+ if (result.conditionIsMet) {
14
+ success = {
15
+ ...result,
16
+ conditionRule
17
+ }
18
+ break
19
+ }
20
+ }
21
+ return success
22
+ }
@@ -0,0 +1,12 @@
1
+ // get the most specific set of moves for current stage/phase
2
+ // this will probably all break for complex stages with multiple active players
3
+ export default function getCurrentMoves (state, { game, playerID, stageName }) {
4
+ const phaseName = state.ctx.phase
5
+
6
+ // currentPlayer used for single player editor mode
7
+ const stageNameToUse = stageName ?? state.ctx.activePlayers?.[playerID ?? state.ctx.currentPlayer]
8
+ const phaseOrRoot = game.phases?.[phaseName] ?? game
9
+ const stageOrPhaseOrRoot = phaseOrRoot.turn?.stages?.[stageNameToUse] ?? phaseOrRoot
10
+
11
+ return stageOrPhaseOrRoot.moves ?? {}
12
+ }
@@ -0,0 +1,23 @@
1
+ import checkConditions from "./check-conditions.js";
2
+ import resolveProperties from './resolve-properties.js'
3
+
4
+ export default function getScenarioResults(bgioArguments, scenarios, context) {
5
+ let match
6
+ for (const scenario of scenarios) {
7
+ const conditionResults = checkConditions(bgioArguments, scenario)
8
+ if (conditionResults.conditionsAreMet) {
9
+ match = { scenario, conditionResults }
10
+ break
11
+ }
12
+ }
13
+
14
+ if (match?.scenario?.result) {
15
+ return resolveProperties(
16
+ bgioArguments,
17
+ match.scenario.result,
18
+ { results: match.conditionResults.results }
19
+ )
20
+ } else {
21
+ return match
22
+ }
23
+ }
@@ -0,0 +1,29 @@
1
+ // controls order of what players need to click first
2
+ const argNamesMap = {
3
+ PlaceNew: ['destination'],
4
+ RemoveEntity: ['entity'],
5
+ MoveEntity: ['entity', 'destination'],
6
+ TakeFrom: ['source', 'destination'],
7
+ SetState: ['entity', 'state'],
8
+ }
9
+
10
+ // this might not be where special handling for setstate wants to live
11
+ export default function getSteps (bgioState, moveRule) {
12
+ return argNamesMap[moveRule.moveType]
13
+ .filter(argName => moveRule.arguments[argName].playerChoice)
14
+ .map(argName => ({
15
+ argName,
16
+ getClickable: argName === 'state'
17
+ ? () => moveRule.arguments[argName].possibleValues.map((value) => ({
18
+ abstract: true,
19
+ ...moveRule.arguments[argName],
20
+ value
21
+ }))
22
+ : (context) => bgioState.G.bank.findAll(
23
+ bgioState,
24
+ moveRule.arguments[argName],
25
+ context
26
+ )
27
+
28
+ }))
29
+ }
@@ -0,0 +1,25 @@
1
+ export default function get (obj, pathArray) {
2
+ let current = obj;
3
+
4
+ for (const step of pathArray) {
5
+ if (current === undefined) {
6
+ return current
7
+ }
8
+
9
+ if (step?.flatten) {
10
+ if (!Array.isArray(current)) {
11
+ return undefined;
12
+ }
13
+
14
+ current = current.flat();
15
+
16
+ if (step.map) {
17
+ current = current.map(item => get(item, step.map));
18
+ }
19
+ } else {
20
+ current = current[step];
21
+ }
22
+ }
23
+
24
+ return current;
25
+ }
@@ -1,37 +1,20 @@
1
1
  // claude ai did most of this
2
2
  import _matches from "lodash/matches.js";
3
- import type { Condition } from "../types/bagel-types.js";
4
3
  import checkConditions from "./check-conditions.js";
5
4
 
6
- export type SequenceChunk = {
7
- count?: number;
8
- minCount?: number;
9
- maxCount?: number;
10
- conditions?: Condition[];
11
- };
12
-
13
- type GridEntity = { entities?: unknown[]; [k: string]: unknown };
14
- type GridSpace = { entities?: GridEntity[]; [k: string]: unknown };
15
- export type GridLike = {
16
- attributes: { width: number; height: number };
17
- entities?: GridSpace[];
18
- areCoordinatesValid: (c: number[]) => boolean;
19
- getSpace: (c: number[]) => unknown;
20
- };
21
-
22
5
  // We'll check reverse directions along each line
23
- const directions: [number, number][] = [
6
+ const directions = [
24
7
  [1, 0], // horizontal
25
8
  [0, 1], // vertical
26
9
  [1, 1], // diagonal down-right
27
10
  [-1, 1], // diagonal down-left
28
11
  ];
29
12
 
30
- const sequenceCache = new WeakMap<object, Map<string, { stateKey: string; result: unknown }>>();
13
+ const sequenceCache = new WeakMap();
31
14
 
32
- function getSequenceKey (sequencePattern: unknown, context: Record<string, unknown>) {
15
+ function getSequenceKey(sequencePattern, context) {
33
16
  const contextKey = {
34
- moveInstance: (context.moveInstance as { id?: unknown } | undefined)?.id,
17
+ moveInstance: context.moveInstance?.id,
35
18
  moveArguments: context.moveArguments,
36
19
  // Add other context properties that conditions might use
37
20
  };
@@ -39,17 +22,17 @@ function getSequenceKey (sequencePattern: unknown, context: Record<string, unkno
39
22
  }
40
23
 
41
24
  // todo: use stable hash library that we're using for game rules hash
42
- function getGridStateKey (grid: GridLike) {
25
+ function getGridStateKey(grid) {
43
26
  const spaces = grid.entities || [];
44
-
45
- return spaces.map((space) => {
27
+
28
+ return spaces.map(space => {
46
29
  const entities = space.entities || [];
47
- if (entities.length === 0) return "empty";
48
-
49
- return entities.map((entity) => {
30
+ if (entities.length === 0) return 'empty';
31
+
32
+ return entities.map(entity => {
50
33
  const sortedKeys = Object.keys(entity).sort();
51
- const stateObj: Record<string, unknown> = {};
52
- sortedKeys.forEach((key) => {
34
+ const stateObj = {};
35
+ sortedKeys.forEach(key => {
53
36
  stateObj[key] = entity[key];
54
37
  });
55
38
  return JSON.stringify(stateObj);
@@ -57,15 +40,8 @@ function getGridStateKey (grid: GridLike) {
57
40
  }).join(',');
58
41
  }
59
42
 
60
- function findSequencesInLine (
61
- bgioArguments: unknown,
62
- lineSpaces: unknown[],
63
- sequencePattern: SequenceChunk[],
64
- minSequenceLength: number,
65
- context: Record<string, unknown>,
66
- reverse = false
67
- ) {
68
- const matches: unknown[][] = [];
43
+ function findSequencesInLine(bgioArguments, lineSpaces, sequencePattern, minSequenceLength, context, reverse = false) {
44
+ const matches = [];
69
45
 
70
46
  // Use original array or iterate in reverse without creating new array
71
47
  const length = lineSpaces.length;
@@ -92,9 +68,9 @@ function findSequencesInLine (
92
68
  return matches;
93
69
  }
94
70
 
95
- function getLineStartingPoints (grid: GridLike, dx: number, dy: number) {
71
+ function getLineStartingPoints(grid, dx, dy) {
96
72
  const { width, height } = grid.attributes;
97
- const starts: [number, number][] = [];
73
+ const starts = [];
98
74
 
99
75
  if (dx === 1 && dy === 0) {
100
76
  // Horizontal: start at leftmost column
@@ -115,8 +91,8 @@ function getLineStartingPoints (grid: GridLike, dx: number, dy: number) {
115
91
  return starts;
116
92
  }
117
93
 
118
- function getLineSpaces (grid: GridLike, startX: number, startY: number, dx: number, dy: number) {
119
- const spaces: unknown[] = [];
94
+ function getLineSpaces(grid, startX, startY, dx, dy) {
95
+ const spaces = [];
120
96
  let [x, y] = [startX, startY];
121
97
 
122
98
  while (grid.areCoordinatesValid([x, y])) {
@@ -127,16 +103,9 @@ function getLineSpaces (grid: GridLike, startX: number, startY: number, dx: numb
127
103
  return spaces;
128
104
  }
129
105
 
130
- function tryMatchSequence (
131
- bgioArguments: unknown,
132
- lineSpaces: unknown[],
133
- startIndex: number,
134
- sequencePattern: SequenceChunk[],
135
- context: Record<string, unknown>,
136
- reverse = false
137
- ) {
106
+ function tryMatchSequence(bgioArguments, lineSpaces, startIndex, sequencePattern, context, reverse = false) {
138
107
  let spaceIndex = startIndex;
139
- const matchedSpaces: unknown[] = [];
108
+ const matchedSpaces = [];
140
109
  const length = lineSpaces.length;
141
110
 
142
111
  for (const chunk of sequencePattern) {
@@ -153,7 +122,7 @@ function tryMatchSequence (
153
122
  }
154
123
 
155
124
  let matchedCount = 0;
156
- const chunkMatches: unknown[] = [];
125
+ const chunkMatches = [];
157
126
 
158
127
  // Greedy: try to match as many as possible up to max
159
128
  while (matchedCount < max && spaceIndex < length) {
@@ -183,16 +152,15 @@ function tryMatchSequence (
183
152
  return matchedSpaces.length > 0 ? matchedSpaces : null;
184
153
  }
185
154
 
186
- function checkSpaceConditions (
187
- bgioArguments: unknown,
188
- space: unknown,
189
- conditions: Condition[] | undefined,
190
- chunkMatches: unknown[] = [],
191
- context?: Record<string, unknown>
192
- ) {
155
+ function checkSpaceConditions(bgioArguments, space, conditions, chunkMatches = [], context) {
156
+ // Early exit if no conditions
157
+ if (!conditions || conditions.length === 0) {
158
+ return true;
159
+ }
160
+
193
161
  return checkConditions(
194
162
  bgioArguments,
195
- conditions,
163
+ { conditions },
196
164
  {
197
165
  target: space,
198
166
  targets: [space, ...chunkMatches] // for ContainsSame, other group conditions
@@ -201,12 +169,7 @@ function checkSpaceConditions (
201
169
  ).conditionsAreMet
202
170
  }
203
171
 
204
- export default function gridContainsSequence (
205
- bgioArguments: unknown,
206
- grid: GridLike,
207
- sequencePattern: SequenceChunk[],
208
- context: Record<string, unknown>
209
- ) {
172
+ export default function gridContainsSequence(bgioArguments, grid, sequencePattern, context) {
210
173
  const cacheKey = getSequenceKey(sequencePattern, context);
211
174
  let gridCache = sequenceCache.get(grid);
212
175
 
@@ -222,11 +185,10 @@ export default function gridContainsSequence (
222
185
  return cacheEntry.result;
223
186
  }
224
187
 
225
- const matches: unknown[][] = [];
226
-
227
- const minSequenceLength = sequencePattern.reduce(
228
- (sum: number, chunk: SequenceChunk) => sum + (chunk.minCount || chunk.count || 1),
229
- 0
188
+ const matches = [];
189
+
190
+ const minSequenceLength = sequencePattern.reduce((sum, chunk) =>
191
+ sum + (chunk.minCount || chunk.count || 1), 0
230
192
  );
231
193
 
232
194
  // For each direction, scan each row/column/diagonal once
@@ -0,0 +1,12 @@
1
+ // recurse and replace. circular references not allowed
2
+ export default function transformJSON(data, rules) {
3
+ return JSON.parse(JSON.stringify(data), (key, value) => {
4
+ let result = value;
5
+ for (const rule of rules) {
6
+ if (rule.test(result)) {
7
+ result = rule.replace(result);
8
+ }
9
+ }
10
+ return result;
11
+ });
12
+ }