board-game-engine 1.0.5 → 2.0.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 (254) hide show
  1. package/.github/workflows/ci.yml +33 -0
  2. package/dist/board-game-engine.cjs +463 -349
  3. package/dist/board-game-engine.js +463 -349
  4. package/dist/board-game-engine.min.js +22 -22
  5. package/dist/board-game-engine.mjs +461 -348
  6. package/dist/client/client.d.ts +76 -0
  7. package/dist/client/client.d.ts.map +1 -0
  8. package/dist/game-factory/bank/bank-slot.d.ts +30 -0
  9. package/dist/game-factory/bank/bank-slot.d.ts.map +1 -0
  10. package/dist/game-factory/bank/bank.d.ts +34 -0
  11. package/dist/game-factory/bank/bank.d.ts.map +1 -0
  12. package/dist/game-factory/board.d.ts +4 -0
  13. package/dist/game-factory/board.d.ts.map +1 -0
  14. package/dist/game-factory/condition/condition-factory.d.ts +4 -0
  15. package/dist/game-factory/condition/condition-factory.d.ts.map +1 -0
  16. package/dist/game-factory/condition/condition.d.ts +13 -0
  17. package/dist/game-factory/condition/condition.d.ts.map +1 -0
  18. package/dist/game-factory/condition/contains-condition.d.ts +8 -0
  19. package/dist/game-factory/condition/contains-condition.d.ts.map +1 -0
  20. package/dist/game-factory/condition/contains-same-condition.d.ts +7 -0
  21. package/dist/game-factory/condition/contains-same-condition.d.ts.map +1 -0
  22. package/dist/game-factory/condition/evaluate-condition.d.ts +8 -0
  23. package/dist/game-factory/condition/evaluate-condition.d.ts.map +1 -0
  24. package/dist/game-factory/condition/every-condition.d.ts +12 -0
  25. package/dist/game-factory/condition/every-condition.d.ts.map +1 -0
  26. package/dist/game-factory/condition/has-line-condition.d.ts +8 -0
  27. package/dist/game-factory/condition/has-line-condition.d.ts.map +1 -0
  28. package/dist/game-factory/condition/in-line-condition.d.ts +8 -0
  29. package/dist/game-factory/condition/in-line-condition.d.ts.map +1 -0
  30. package/dist/game-factory/condition/is-condition.d.ts +8 -0
  31. package/dist/game-factory/condition/is-condition.d.ts.map +1 -0
  32. package/dist/game-factory/condition/is-full-condition.d.ts +7 -0
  33. package/dist/game-factory/condition/is-full-condition.d.ts.map +1 -0
  34. package/dist/game-factory/condition/no-possible-moves-condition.d.ts +7 -0
  35. package/dist/game-factory/condition/no-possible-moves-condition.d.ts.map +1 -0
  36. package/dist/game-factory/condition/not-condition.d.ts +7 -0
  37. package/dist/game-factory/condition/not-condition.d.ts.map +1 -0
  38. package/dist/game-factory/condition/or-condition.d.ts +7 -0
  39. package/dist/game-factory/condition/or-condition.d.ts.map +1 -0
  40. package/dist/game-factory/condition/position-condition.d.ts +7 -0
  41. package/dist/game-factory/condition/position-condition.d.ts.map +1 -0
  42. package/dist/game-factory/condition/some-condition.d.ts +8 -0
  43. package/dist/game-factory/condition/some-condition.d.ts.map +1 -0
  44. package/dist/game-factory/condition/would-condition.d.ts +8 -0
  45. package/dist/game-factory/condition/would-condition.d.ts.map +1 -0
  46. package/dist/game-factory/entity.d.ts +13 -0
  47. package/dist/game-factory/entity.d.ts.map +1 -0
  48. package/dist/game-factory/expand-game-rules.d.ts +3 -0
  49. package/dist/game-factory/expand-game-rules.d.ts.map +1 -0
  50. package/dist/game-factory/game-factory.d.ts +10 -0
  51. package/dist/game-factory/game-factory.d.ts.map +1 -0
  52. package/{src/game-factory/move/end-turn.js → dist/game-factory/move/end-turn.d.ts} +2 -4
  53. package/dist/game-factory/move/end-turn.d.ts.map +1 -0
  54. package/dist/game-factory/move/for-each.d.ts +5 -0
  55. package/dist/game-factory/move/for-each.d.ts.map +1 -0
  56. package/dist/game-factory/move/index.d.ts +6 -0
  57. package/dist/game-factory/move/index.d.ts.map +1 -0
  58. package/dist/game-factory/move/move-entity.d.ts +7 -0
  59. package/dist/game-factory/move/move-entity.d.ts.map +1 -0
  60. package/dist/game-factory/move/move-factory.d.ts +18 -0
  61. package/dist/game-factory/move/move-factory.d.ts.map +1 -0
  62. package/dist/game-factory/move/move.d.ts +54 -0
  63. package/dist/game-factory/move/move.d.ts.map +1 -0
  64. package/dist/game-factory/move/pass-turn.d.ts +5 -0
  65. package/dist/game-factory/move/pass-turn.d.ts.map +1 -0
  66. package/{src/game-factory/move/pass.js → dist/game-factory/move/pass.d.ts} +2 -4
  67. package/dist/game-factory/move/pass.d.ts.map +1 -0
  68. package/dist/game-factory/move/place-new.d.ts +5 -0
  69. package/dist/game-factory/move/place-new.d.ts.map +1 -0
  70. package/dist/game-factory/move/remove-entity.d.ts +5 -0
  71. package/dist/game-factory/move/remove-entity.d.ts.map +1 -0
  72. package/dist/game-factory/move/set-active-players.d.ts +5 -0
  73. package/dist/game-factory/move/set-active-players.d.ts.map +1 -0
  74. package/dist/game-factory/move/set-state.d.ts +5 -0
  75. package/dist/game-factory/move/set-state.d.ts.map +1 -0
  76. package/dist/game-factory/move/shuffle.d.ts +5 -0
  77. package/dist/game-factory/move/shuffle.d.ts.map +1 -0
  78. package/dist/game-factory/move/take-from.d.ts +11 -0
  79. package/dist/game-factory/move/take-from.d.ts.map +1 -0
  80. package/dist/game-factory/space/space.d.ts +10 -0
  81. package/dist/game-factory/space/space.d.ts.map +1 -0
  82. package/dist/game-factory/space-group/grid.d.ts +15 -0
  83. package/dist/game-factory/space-group/grid.d.ts.map +1 -0
  84. package/dist/game-factory/space-group/space-group.d.ts +20 -0
  85. package/dist/game-factory/space-group/space-group.d.ts.map +1 -0
  86. package/dist/index.d.ts +6 -0
  87. package/dist/index.d.ts.map +1 -0
  88. package/dist/registry.d.ts +17 -0
  89. package/dist/registry.d.ts.map +1 -0
  90. package/dist/types/bagel-types.d.ts +339 -0
  91. package/dist/types/bagel-types.d.ts.map +1 -0
  92. package/dist/types/index.d.ts +3 -0
  93. package/dist/types/index.d.ts.map +1 -0
  94. package/dist/types/rule-with-conditions.d.ts +9 -0
  95. package/dist/types/rule-with-conditions.d.ts.map +1 -0
  96. package/dist/utils/any-valid-moves.d.ts +2 -0
  97. package/dist/utils/any-valid-moves.d.ts.map +1 -0
  98. package/dist/utils/bgio-resolve-types.d.ts +25 -0
  99. package/dist/utils/bgio-resolve-types.d.ts.map +1 -0
  100. package/dist/utils/check-conditions.d.ts +7 -0
  101. package/dist/utils/check-conditions.d.ts.map +1 -0
  102. package/dist/utils/create-payload.d.ts +5 -0
  103. package/dist/utils/create-payload.d.ts.map +1 -0
  104. package/dist/utils/deserialize-bgio-arguments.d.ts +3 -0
  105. package/dist/utils/deserialize-bgio-arguments.d.ts.map +1 -0
  106. package/dist/utils/do-moves.d.ts +8 -0
  107. package/dist/utils/do-moves.d.ts.map +1 -0
  108. package/dist/utils/entity-matches.d.ts +6 -0
  109. package/dist/utils/entity-matches.d.ts.map +1 -0
  110. package/dist/utils/find-met-condition.d.ts +6 -0
  111. package/dist/utils/find-met-condition.d.ts.map +1 -0
  112. package/dist/utils/get-current-moves.d.ts +24 -0
  113. package/dist/utils/get-current-moves.d.ts.map +1 -0
  114. package/dist/utils/get-scenario-results.d.ts +3 -0
  115. package/dist/utils/get-scenario-results.d.ts.map +1 -0
  116. package/dist/utils/get-steps.d.ts +13 -0
  117. package/dist/utils/get-steps.d.ts.map +1 -0
  118. package/dist/utils/get.d.ts +7 -0
  119. package/dist/utils/get.d.ts.map +1 -0
  120. package/dist/utils/grid-contains-sequence.d.ts +27 -0
  121. package/dist/utils/grid-contains-sequence.d.ts.map +1 -0
  122. package/dist/utils/json-transformer.d.ts +8 -0
  123. package/dist/utils/json-transformer.d.ts.map +1 -0
  124. package/dist/utils/prepare-payload.d.ts +2 -0
  125. package/dist/utils/prepare-payload.d.ts.map +1 -0
  126. package/dist/utils/resolve-entity.d.ts +3 -0
  127. package/dist/utils/resolve-entity.d.ts.map +1 -0
  128. package/dist/utils/resolve-expression.d.ts +6 -0
  129. package/dist/utils/resolve-expression.d.ts.map +1 -0
  130. package/dist/utils/resolve-properties.d.ts +4 -0
  131. package/dist/utils/resolve-properties.d.ts.map +1 -0
  132. package/dist/utils/simulate-move.d.ts +16 -0
  133. package/dist/utils/simulate-move.d.ts.map +1 -0
  134. package/examples/checkers.json +2 -2
  135. package/examples/connect-four.json +1 -1
  136. package/examples/eights.json +15 -15
  137. package/package.json +9 -3
  138. package/playwright-report/index.html +1 -1
  139. package/scripts/build.mjs +2 -2
  140. package/src/client/client.ts +306 -0
  141. package/src/game-factory/bank/bank-slot.ts +81 -0
  142. package/src/game-factory/bank/bank.ts +125 -0
  143. package/src/game-factory/{board.js → board.ts} +1 -1
  144. package/src/game-factory/condition/condition-factory.ts +59 -0
  145. package/src/game-factory/condition/condition.ts +50 -0
  146. package/src/game-factory/condition/{contains-condition.js → contains-condition.ts} +5 -4
  147. package/src/game-factory/condition/{contains-same-condition.js → contains-same-condition.ts} +8 -5
  148. package/src/game-factory/condition/{evaluate-condition.js → evaluate-condition.ts} +4 -3
  149. package/src/game-factory/condition/every-condition.ts +27 -0
  150. package/src/game-factory/condition/has-line-condition.ts +15 -0
  151. package/src/game-factory/condition/in-line-condition.ts +25 -0
  152. package/src/game-factory/condition/is-condition.ts +24 -0
  153. package/src/game-factory/condition/is-full-condition.ts +10 -0
  154. package/src/game-factory/condition/{no-possible-moves-condition.js → no-possible-moves-condition.ts} +3 -2
  155. package/src/game-factory/condition/{not-condition.js → not-condition.ts} +3 -2
  156. package/src/game-factory/condition/{or-condition.js → or-condition.ts} +3 -2
  157. package/src/game-factory/condition/position-condition.ts +13 -0
  158. package/src/game-factory/condition/{some-condition.js → some-condition.ts} +5 -3
  159. package/src/game-factory/condition/would-condition.ts +104 -0
  160. package/src/game-factory/entity.ts +37 -0
  161. package/src/game-factory/expand-game-rules.ts +263 -0
  162. package/src/game-factory/game-factory.ts +263 -0
  163. package/src/game-factory/move/end-turn.ts +7 -0
  164. package/src/game-factory/move/for-each.ts +20 -0
  165. package/src/game-factory/move/move-entity.ts +18 -0
  166. package/src/game-factory/move/move-factory.ts +107 -0
  167. package/src/game-factory/move/move.ts +147 -0
  168. package/src/game-factory/move/pass-turn.ts +15 -0
  169. package/src/game-factory/move/pass.ts +7 -0
  170. package/src/game-factory/move/place-new.ts +42 -0
  171. package/src/game-factory/move/remove-entity.ts +11 -0
  172. package/src/game-factory/move/set-active-players.ts +26 -0
  173. package/src/game-factory/move/set-state.ts +14 -0
  174. package/src/game-factory/move/shuffle.ts +9 -0
  175. package/src/game-factory/move/take-from.ts +12 -0
  176. package/src/game-factory/space/space.ts +36 -0
  177. package/src/game-factory/space-group/grid.ts +48 -0
  178. package/src/game-factory/space-group/space-group.ts +44 -0
  179. package/src/index.ts +5 -0
  180. package/src/types/bagel-types.ts +449 -0
  181. package/src/types/boardgame-io-core.d.ts +7 -0
  182. package/src/types/index.ts +70 -0
  183. package/src/types/rule-with-conditions.ts +9 -0
  184. package/src/utils/{any-valid-moves.js → any-valid-moves.ts} +54 -49
  185. package/src/utils/bgio-resolve-types.ts +27 -0
  186. package/src/utils/check-conditions.ts +28 -0
  187. package/src/utils/create-payload.ts +19 -0
  188. package/src/utils/deserialize-bgio-arguments.ts +10 -0
  189. package/src/utils/do-moves.ts +22 -0
  190. package/src/utils/entity-matches.ts +30 -0
  191. package/src/utils/expr-eval.d.ts +6 -0
  192. package/src/utils/find-met-condition.ts +23 -0
  193. package/src/utils/get-current-moves.ts +39 -0
  194. package/src/utils/get-scenario-results.ts +30 -0
  195. package/src/utils/get-steps.ts +38 -0
  196. package/src/utils/get.ts +28 -0
  197. package/src/utils/{grid-contains-sequence.js → grid-contains-sequence.ts} +71 -33
  198. package/src/utils/json-transformer.ts +17 -0
  199. package/src/utils/prepare-payload.ts +20 -0
  200. package/src/utils/resolve-entity.ts +15 -0
  201. package/src/utils/resolve-expression.ts +16 -0
  202. package/src/utils/resolve-properties.ts +172 -0
  203. package/src/utils/simulate-move.ts +32 -0
  204. package/src/wackson.d.ts +4 -0
  205. package/tsconfig.build.json +14 -0
  206. package/tsconfig.json +21 -0
  207. package/src/client/client.js +0 -224
  208. package/src/game-factory/bank/bank-slot.js +0 -69
  209. package/src/game-factory/bank/bank.js +0 -114
  210. package/src/game-factory/condition/condition-factory.js +0 -52
  211. package/src/game-factory/condition/condition.js +0 -39
  212. package/src/game-factory/condition/every-condition.js +0 -25
  213. package/src/game-factory/condition/has-line-condition.js +0 -14
  214. package/src/game-factory/condition/in-line-condition.js +0 -19
  215. package/src/game-factory/condition/is-condition.js +0 -23
  216. package/src/game-factory/condition/is-full-condition.js +0 -9
  217. package/src/game-factory/condition/position-condition.js +0 -12
  218. package/src/game-factory/condition/would-condition.js +0 -94
  219. package/src/game-factory/entity.js +0 -29
  220. package/src/game-factory/expand-game-rules.js +0 -271
  221. package/src/game-factory/game-factory.js +0 -239
  222. package/src/game-factory/move/for-each.js +0 -18
  223. package/src/game-factory/move/move-entity.js +0 -16
  224. package/src/game-factory/move/move-factory.js +0 -89
  225. package/src/game-factory/move/move.js +0 -131
  226. package/src/game-factory/move/pass-turn.js +0 -10
  227. package/src/game-factory/move/place-new.js +0 -33
  228. package/src/game-factory/move/remove-entity.js +0 -7
  229. package/src/game-factory/move/set-active-players.js +0 -23
  230. package/src/game-factory/move/set-state.js +0 -11
  231. package/src/game-factory/move/shuffle.js +0 -7
  232. package/src/game-factory/move/take-from.js +0 -7
  233. package/src/game-factory/space/space.js +0 -30
  234. package/src/game-factory/space-group/grid.js +0 -43
  235. package/src/game-factory/space-group/space-group.js +0 -29
  236. package/src/index.js +0 -2
  237. package/src/utils/check-conditions.js +0 -28
  238. package/src/utils/create-payload.js +0 -16
  239. package/src/utils/deserialize-bgio-arguments.js +0 -8
  240. package/src/utils/do-moves.js +0 -18
  241. package/src/utils/entity-matches.js +0 -20
  242. package/src/utils/find-met-condition.js +0 -22
  243. package/src/utils/get-current-moves.js +0 -12
  244. package/src/utils/get-scenario-results.js +0 -23
  245. package/src/utils/get-steps.js +0 -29
  246. package/src/utils/get.js +0 -25
  247. package/src/utils/json-transformer.js +0 -12
  248. package/src/utils/prepare-payload.js +0 -16
  249. package/src/utils/resolve-entity.js +0 -9
  250. package/src/utils/resolve-expression.js +0 -10
  251. package/src/utils/resolve-properties.js +0 -149
  252. package/src/utils/simulate-move.js +0 -25
  253. /package/src/game-factory/move/{index.js → index.ts} +0 -0
  254. /package/src/{registry.js → registry.ts} +0 -0
@@ -1,83 +1,83 @@
1
1
  import isPlainObject from "lodash/isPlainObject.js";
2
+ import type { BgioResolveState } from "./bgio-resolve-types.js";
2
3
  import resolveProperties from "./resolve-properties.js";
3
4
  import resolveEntity from "./resolve-entity.js";
4
5
 
5
6
  // Recursively find all contextPath references to moveArguments
6
- function findMoveArgumentReferences(obj, refs = new Set()) {
7
- if (!obj || typeof obj !== 'object') {
7
+ function findMoveArgumentReferences (obj: unknown, refs = new Set<string>()): Set<string> {
8
+ if (!obj || typeof obj !== "object") {
8
9
  return refs;
9
10
  }
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]);
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]));
15
16
  }
16
17
  }
17
-
18
- // Recurse into object properties and array elements
19
- for (const value of Object.values(obj)) {
18
+
19
+ for (const value of Object.values(obj as object)) {
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) {
27
+ function getArgumentOrder (ruleArguments: Record<string, unknown>) {
28
28
  const argNames = Object.keys(ruleArguments);
29
- const graph = {};
30
- const inDegree = {};
31
-
32
- // Initialize
33
- argNames.forEach(name => {
29
+ const graph: Record<string, string[]> = {};
30
+ const inDegree: Record<string, number> = {};
31
+
32
+ argNames.forEach((name) => {
34
33
  graph[name] = [];
35
34
  inDegree[name] = 0;
36
35
  });
37
-
38
- // Build dependency edges (if arg B references arg A, A -> B)
39
- argNames.forEach(argName => {
36
+
37
+ argNames.forEach((argName) => {
40
38
  const arg = ruleArguments[argName];
41
39
  const referencedArgs = findMoveArgumentReferences(arg);
42
-
43
- referencedArgs.forEach(refArg => {
40
+
41
+ referencedArgs.forEach((refArg) => {
44
42
  if (argNames.includes(refArg) && refArg !== argName) {
45
43
  graph[refArg].push(argName);
46
44
  inDegree[argName]++;
47
45
  }
48
46
  });
49
47
  });
50
-
51
- // Topological sort (Kahn's algorithm)
52
- const queue = argNames.filter(name => inDegree[name] === 0);
53
- const sorted = [];
54
-
48
+
49
+ const queue = argNames.filter((name) => inDegree[name] === 0);
50
+ const sorted: string[] = [];
51
+
55
52
  while (queue.length > 0) {
56
- const current = queue.shift();
53
+ const current = queue.shift()!;
57
54
  sorted.push(current);
58
-
59
- graph[current].forEach(neighbor => {
55
+
56
+ graph[current].forEach((neighbor) => {
60
57
  inDegree[neighbor]--;
61
58
  if (inDegree[neighbor] === 0) {
62
59
  queue.push(neighbor);
63
60
  }
64
61
  });
65
62
  }
66
-
67
- // If not all nodes processed, there's a cycle - fall back to original order
63
+
68
64
  return sorted.length === argNames.length ? sorted : argNames;
69
65
  }
70
66
 
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,
74
- moveInstance,
75
- ruleArguments,
76
- orderedArgNames,
77
- context,
72
+ function findValidCombination (
73
+ bgioArguments: BgioResolveState,
74
+ moveInstance: MoveEntry["moveInstance"],
75
+ ruleArguments: Record<string, unknown>,
76
+ orderedArgNames: string[],
77
+ context: Record<string, unknown>,
78
78
  index = 0,
79
- currentArgs = {}
80
- ) {
79
+ currentArgs: Record<string, unknown> = {}
80
+ ): boolean {
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, matchMultiple: true },
101
+ { ...(arg as Record<string, unknown>), 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 => {
115
+ return matchArray.some((value: unknown) => {
116
116
  return findValidCombination(
117
117
  bgioArguments,
118
118
  moveInstance,
@@ -125,21 +125,26 @@ function findValidCombination(
125
125
  });
126
126
  }
127
127
 
128
- export default function areThereValidMoves(bgioArguments, moves) {
129
- return Object.values(moves).some(move => {
130
- const { moveInstance } = move;
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;
131
136
  const context = { moveInstance };
132
137
  const rule = resolveProperties(
133
- bgioArguments,
138
+ bgio,
134
139
  moveInstance.rule,
135
140
  context
136
- );
141
+ ) as { arguments?: Record<string, unknown> };
137
142
 
138
143
  const ruleArguments = rule.arguments ?? {};
139
144
 
140
145
  // If no arguments required, just check if move is valid
141
146
  if (Object.keys(ruleArguments).length === 0) {
142
- return moveInstance.isValid(bgioArguments, { arguments: {} }, context);
147
+ return moveInstance.isValid(bgio, { arguments: {} }, context);
143
148
  }
144
149
 
145
150
  // Get dependency-ordered argument names
@@ -147,7 +152,7 @@ export default function areThereValidMoves(bgioArguments, moves) {
147
152
 
148
153
  // Recursively search for any valid combination (short-circuits on first valid)
149
154
  return findValidCombination(
150
- bgioArguments,
155
+ bgio,
151
156
  moveInstance,
152
157
  ruleArguments,
153
158
  orderedArgNames,
@@ -0,0 +1,27 @@
1
+ import type { RuleWithConditions } from "../types/rule-with-conditions.js";
2
+
3
+ /** boardgame.io match args + engine `G` after setup (deserialized, many fields). */
4
+ export type BgioResolveState = {
5
+ ctx: Record<string, unknown>;
6
+ G: Record<string, unknown>;
7
+ playerID?: string;
8
+ } & Record<string, unknown>;
9
+
10
+ /** Bank API on `G` used by resolution and moves (subset of {@link Bank} methods). */
11
+ export type BankApi = {
12
+ find: (a: unknown, t: unknown, c: unknown) => unknown;
13
+ findAll: (a: unknown, t: unknown, c: unknown) => unknown[];
14
+ findParent: (t: unknown) => unknown;
15
+ getOne: (a: BgioResolveState, rule: RuleWithConditions & { state?: unknown }, c: Record<string, unknown>) => unknown;
16
+ getMultiple: (
17
+ a: BgioResolveState,
18
+ rule: RuleWithConditions & { state?: unknown },
19
+ count: number,
20
+ c: Record<string, unknown>
21
+ ) => unknown[];
22
+ returnToBank: (a: BgioResolveState, entity: { entityId: number; rule: Record<string, unknown> }) => void;
23
+ };
24
+
25
+ export function bankOf (bg: BgioResolveState): BankApi {
26
+ return (bg.G as { bank: BankApi }).bank;
27
+ }
@@ -0,0 +1,28 @@
1
+ import conditionFactory from "../game-factory/condition/condition-factory.js";
2
+ import type { Condition as ConditionRule } from "../types/bagel-types.js";
3
+
4
+ export default function checkConditions (
5
+ bgioArguments: unknown,
6
+ conditions: ConditionRule[] = [],
7
+ payload: Record<string, unknown> = {},
8
+ context: Record<string, unknown> = {}
9
+ ) {
10
+ const results: unknown[] = [];
11
+ let failedAt: unknown;
12
+ for (const conditionRule of conditions) {
13
+ const result = conditionFactory(conditionRule as ConditionRule)!
14
+ .check(bgioArguments, payload, context);
15
+ if (!(result as { conditionIsMet: boolean }).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,19 @@
1
+ import getSteps from "./get-steps.js";
2
+
3
+ export default function createPayload (
4
+ bgioState: Parameters<typeof getSteps>[0],
5
+ moveRule: Parameters<typeof getSteps>[1],
6
+ targets: unknown[],
7
+ _context: Record<string, unknown>
8
+ ) {
9
+ const argNames = getSteps(
10
+ bgioState,
11
+ moveRule
12
+ ).map((s) => s.argName);
13
+ return {
14
+ arguments: targets.reduce<Record<string, unknown>>((acc, target, i) => ({
15
+ ...acc,
16
+ [argNames[i]]: target,
17
+ }), {}),
18
+ };
19
+ }
@@ -0,0 +1,10 @@
1
+ import { deserialize } from "wackson";
2
+ import { registry } from "../registry.js";
3
+ import type { BgioResolveState } from "./bgio-resolve-types.js";
4
+
5
+ export default function deserializeBgioArguments (bgioArguments: BgioResolveState): BgioResolveState {
6
+ return {
7
+ ...bgioArguments,
8
+ G: deserialize(JSON.stringify(bgioArguments.G), registry) as Record<string, unknown>,
9
+ };
10
+ }
@@ -0,0 +1,22 @@
1
+ import type { MoveDefinition } from "../types/bagel-types.js";
2
+ import moveFactory from "../game-factory/move/move-factory.js";
3
+
4
+ export default function doMoves (
5
+ bgioArguments: { G: unknown; [k: string]: unknown },
6
+ moves: MoveDefinition[] = [],
7
+ context: { game: Record<string, unknown> } & Record<string, unknown>
8
+ ) {
9
+ if (!moves?.length) {
10
+ return bgioArguments.G;
11
+ }
12
+
13
+ moves.forEach((moveRule) => {
14
+ moveFactory(moveRule, context.game).moveInstance!.doMove(
15
+ bgioArguments,
16
+ undefined,
17
+ context
18
+ );
19
+ });
20
+
21
+ return bgioArguments.G;
22
+ }
@@ -0,0 +1,30 @@
1
+ import matches from "lodash/matches.js";
2
+ import resolveProperties from "./resolve-properties.js";
3
+ import type { BgioResolveState } from "./bgio-resolve-types.js";
4
+
5
+ function resolveMatcher (
6
+ bgioArguments: BgioResolveState,
7
+ matcher: Record<string, unknown>,
8
+ context: Record<string, unknown>
9
+ ) {
10
+ const resolvedMatcher = { ...matcher };
11
+ delete resolvedMatcher.state;
12
+ delete resolvedMatcher.stateGroups;
13
+ return resolveProperties(bgioArguments, resolvedMatcher, context);
14
+ }
15
+
16
+ function getEntityMatcher (entity: { rule: Record<string, unknown>; state?: Record<string, unknown> }) {
17
+ return {
18
+ ...entity.rule,
19
+ ...entity.state,
20
+ };
21
+ }
22
+
23
+ export default function entityMatches (
24
+ bgioArguments: BgioResolveState,
25
+ matcher: Record<string, unknown>,
26
+ entity: { rule: Record<string, unknown>; state?: Record<string, unknown> },
27
+ context: Record<string, unknown>
28
+ ): boolean {
29
+ return matches(resolveMatcher(bgioArguments, matcher, context))(getEntityMatcher(entity));
30
+ }
@@ -0,0 +1,6 @@
1
+ declare module "expr-eval" {
2
+ export class Parser {
3
+ functions: Record<string, (...args: unknown[]) => unknown>;
4
+ evaluate (expression: string, variables?: Record<string, unknown>): number;
5
+ }
6
+ }
@@ -0,0 +1,23 @@
1
+ import conditionFactory from "../game-factory/condition/condition-factory.js";
2
+ import type { Condition as ConditionRule } from "../types/bagel-types.js";
3
+
4
+ export default function findMetCondition (
5
+ bgioArguments: unknown,
6
+ conditions: ConditionRule[] = [],
7
+ payload: Record<string, unknown>,
8
+ context: Record<string, unknown>,
9
+ ) {
10
+ let success: { conditionRule: unknown; [k: string]: unknown } | undefined;
11
+ for (const conditionRule of conditions) {
12
+ const result = conditionFactory(conditionRule as ConditionRule)!
13
+ .check(bgioArguments, payload, context);
14
+ if ((result as { conditionIsMet: boolean }).conditionIsMet) {
15
+ success = {
16
+ ...result as object,
17
+ conditionRule,
18
+ };
19
+ break;
20
+ }
21
+ }
22
+ return success;
23
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Minimal shape of the boardgame.io client (or stand-in) used to resolve the active move set.
3
+ */
4
+ export interface GetCurrentMovesClient {
5
+ game: {
6
+ phases?: Record<string, unknown>;
7
+ moves?: Record<string, unknown>;
8
+ turn?: { stages?: Record<string, unknown> };
9
+ };
10
+ playerID?: string;
11
+ stageName?: string;
12
+ }
13
+
14
+ /** `state` shape expected by {@link getCurrentMoves} (boardgame.io match state). */
15
+ export interface GetCurrentMovesState {
16
+ ctx: {
17
+ phase?: string;
18
+ activePlayers?: Record<string, string>;
19
+ currentPlayer?: string;
20
+ };
21
+ }
22
+
23
+ // get the most specific set of moves for current stage/phase
24
+ // this will probably all break for complex stages with multiple active players
25
+ export default function getCurrentMoves (
26
+ state: GetCurrentMovesState,
27
+ client: GetCurrentMovesClient
28
+ ): Record<string, unknown> {
29
+ const { game, playerID, stageName } = client;
30
+ const phaseName = state.ctx.phase;
31
+
32
+ const stageNameToUse = stageName ?? state.ctx.activePlayers?.[playerID ?? state.ctx.currentPlayer ?? ""];
33
+ const phaseOrRoot =
34
+ (game as { phases?: Record<string, unknown> }).phases?.[phaseName as string] ?? game;
35
+ const stageOrPhaseOrRoot =
36
+ (phaseOrRoot as { turn?: { stages?: Record<string, unknown> } }).turn?.stages?.[stageNameToUse as string] ?? phaseOrRoot;
37
+
38
+ return (stageOrPhaseOrRoot as { moves?: Record<string, unknown> }).moves ?? {};
39
+ }
@@ -0,0 +1,30 @@
1
+ import checkConditions from "./check-conditions.js";
2
+ import resolveProperties from "./resolve-properties.js";
3
+ import type { BgioResolveState } from "./bgio-resolve-types.js";
4
+ import type { Condition } from "../types/bagel-types.js";
5
+ export default function getScenarioResults (
6
+ bgioArguments: BgioResolveState,
7
+ scenarios: unknown[]
8
+ ) {
9
+ let match: { scenario: { result?: unknown; [k: string]: unknown }; conditionResults: { results: unknown[] } } | undefined;
10
+ for (const scenario of scenarios) {
11
+ const conditionResults = checkConditions(
12
+ bgioArguments,
13
+ (scenario as { conditions?: Condition[] }).conditions
14
+ );
15
+ if (conditionResults.conditionsAreMet) {
16
+ match = { scenario: scenario as { result?: unknown }, conditionResults };
17
+ break;
18
+ }
19
+ }
20
+
21
+ if (match?.scenario?.result) {
22
+ return resolveProperties(
23
+ bgioArguments,
24
+ match.scenario.result,
25
+ { results: match.conditionResults.results }
26
+ );
27
+ } else {
28
+ return match;
29
+ }
30
+ }
@@ -0,0 +1,38 @@
1
+ import { bankOf, type BgioResolveState } from "./bgio-resolve-types.js";
2
+
3
+ // controls order of what players need to click first
4
+ const argNamesMap: Record<string, string[]> = {
5
+ PlaceNew: ["destination"],
6
+ RemoveEntity: ["entity"],
7
+ MoveEntity: ["entity", "destination"],
8
+ TakeFrom: ["source", "destination"],
9
+ SetState: ["entity", "state"],
10
+ };
11
+
12
+ // this might not be where special handling for setstate wants to live
13
+ export default function getSteps (
14
+ bgioState: BgioResolveState,
15
+ moveRule: {
16
+ moveType: string;
17
+ arguments: Record<string, { playerChoice?: boolean; possibleValues?: unknown[]; [k: string]: unknown }>;
18
+ }
19
+ ) {
20
+ const names = argNamesMap[moveRule.moveType];
21
+ if (!names) return [];
22
+ return names
23
+ .filter((argName) => moveRule.arguments[argName]?.playerChoice)
24
+ .map((argName) => ({
25
+ argName,
26
+ getClickable: argName === "state"
27
+ ? () => (moveRule.arguments[argName].possibleValues as unknown[]).map((value) => ({
28
+ abstract: true,
29
+ ...moveRule.arguments[argName],
30
+ value,
31
+ }))
32
+ : (context: Record<string, unknown>) => bankOf(bgioState).findAll(
33
+ bgioState,
34
+ moveRule.arguments[argName],
35
+ context
36
+ ),
37
+ }));
38
+ }
@@ -0,0 +1,28 @@
1
+ type PathStep = string | number | { flatten: boolean; map?: (string | number)[] };
2
+
3
+ export default function get (obj: unknown, pathArray: PathStep[]): unknown {
4
+ let current: unknown = obj;
5
+
6
+ for (const step of pathArray) {
7
+ if (current === undefined) {
8
+ return current;
9
+ }
10
+
11
+ if (step && typeof step === "object" && "flatten" in step && step.flatten) {
12
+ if (!Array.isArray(current)) {
13
+ return undefined;
14
+ }
15
+
16
+ let flat = current.flat() as unknown[];
17
+
18
+ if (step.map) {
19
+ flat = flat.map((item) => get(item, step.map!));
20
+ }
21
+ current = flat;
22
+ } else {
23
+ current = (current as Record<string | number, unknown>)[step as string | number];
24
+ }
25
+ }
26
+
27
+ return current;
28
+ }