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
@@ -1,18 +1,17 @@
1
1
  import _matches from "lodash/matches.js";
2
- import type { Condition as ConditionRule } from "../../types/bagel-types.js";
3
2
  import Condition from "../condition/condition.js";
4
3
  import checkConditions from "../../utils/check-conditions.js";
5
4
 
6
5
  export default class ContainsCondition extends Condition {
7
- checkCondition (bgioArguments: unknown, rule: unknown, payload: Record<string, unknown>, context: Record<string, unknown>) {
8
- const target = payload.target as { entities?: unknown[]; spaces?: unknown[] } | undefined;
6
+ checkCondition(bgioArguments, rule, payload, context) {
7
+ const { target } = payload
9
8
  if (!target) {
10
9
  return { matches: [], conditionIsMet: false }
11
10
  } else {
12
11
  const candidates = target.entities ?? target.spaces
13
- const matches = candidates?.filter((entity: unknown) => checkConditions(
12
+ const matches = candidates?.filter(entity => checkConditions(
14
13
  bgioArguments,
15
- (rule as { conditions?: ConditionRule[] }).conditions,
14
+ rule,
16
15
  { target: entity },
17
16
  context
18
17
  ).conditionsAreMet) ?? []
@@ -3,24 +3,21 @@ import conditionFactory from "./condition-factory.js";
3
3
  import Condition from "./condition.js";
4
4
 
5
5
  export default class ContainsSame extends Condition {
6
- checkCondition (bgioArguments: unknown, rule: unknown, conditionPayload: Record<string, unknown>, _newContext: Record<string, unknown>) {
7
- const { targets } = conditionPayload as { targets: { entities?: unknown[]; rule?: unknown }[] };
6
+ checkCondition (bgioArguments, rule, { targets }) {
8
7
  if (targets.length === 1 && targets[0].entities?.length) {
9
8
  return { conditionIsMet: true }
10
9
  }
11
10
 
12
11
  const [ first, ...restEntities ] = targets;
13
- const conditionIsMet = (first.entities ?? []).some((entity: unknown) => {
14
- const e = entity as { rule?: unknown };
12
+ const conditionIsMet = first.entities.some(entity => {
15
13
  const condition = conditionFactory({
16
14
  conditionType: "Contains",
17
15
  conditions: [{
18
16
  conditionType: 'Is',
19
- matcher: pick(e.rule as object, (rule as { properties: unknown }).properties as never)
17
+ matcher: pick(entity.rule, rule.properties)
20
18
  }]
21
- });
22
- if (!condition) return false;
23
- return restEntities.every((ent: unknown) => {
19
+ })
20
+ return restEntities.every(ent => {
24
21
  return condition.isMet(bgioArguments, { target: ent })
25
22
  })
26
23
  })
@@ -1,17 +1,16 @@
1
1
  import _matches from "lodash/matches.js";
2
2
  import Condition from "../condition/condition.js";
3
3
  import resolveExpression from "../../utils/resolve-expression.js";
4
- import type { BgioResolveState } from "../../utils/bgio-resolve-types.js";
5
4
 
6
5
  export default class Evaluate extends Condition {
7
- checkCondition (bgioArguments: unknown, rule: unknown, payload: Record<string, unknown>, context: Record<string, unknown>) {
6
+ checkCondition(bgioArguments, rule, payload, context) {
8
7
  const newContext = { ...context }
9
8
  if (payload?.target) {
10
9
  newContext.target = payload.target
11
10
  }
12
11
  const result = resolveExpression(
13
- bgioArguments as BgioResolveState,
14
- rule as { expression: string; arguments?: unknown },
12
+ bgioArguments,
13
+ rule,
15
14
  newContext
16
15
  )
17
16
  return { result, conditionIsMet: !!result }
@@ -0,0 +1,25 @@
1
+ import Condition from "./condition.js";
2
+ import checkConditions from "../../utils/check-conditions.js";
3
+
4
+ export default class EveryCondition extends Condition {
5
+ checkCondition(bgioArguments, rule, { target: targets }, context) {
6
+ const results = targets.map((target) => {
7
+ const loopContext = {
8
+ ...context,
9
+ loopTarget: target
10
+ }
11
+
12
+ return checkConditions(
13
+ bgioArguments,
14
+ rule,
15
+ undefined,
16
+ loopContext
17
+ )
18
+ })
19
+
20
+ return {
21
+ conditionIsMet: results.every(r => r.conditionsAreMet),
22
+ results
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,14 @@
1
+ import Condition from "./condition.js";
2
+ import gridContainsSequence from "../../utils/grid-contains-sequence.js";
3
+
4
+ export default class HasLineCondition extends Condition {
5
+ checkCondition(bgioArguments, rule, payload, context) {
6
+ const { matches } = gridContainsSequence(
7
+ bgioArguments,
8
+ payload.target,
9
+ rule.sequence,
10
+ context
11
+ );
12
+ return { matches, conditionIsMet: !!matches.length };
13
+ }
14
+ }
@@ -0,0 +1,19 @@
1
+ import Condition from "./condition.js";
2
+ import gridContainsSequence from "../../utils/grid-contains-sequence.js";
3
+
4
+
5
+ export default class InLineCondition extends Condition {
6
+ checkCondition(bgioArguments, rule, payload, context) {
7
+ const { G } = bgioArguments;
8
+ const { target } = payload;
9
+ const parent = G.bank.findParent(payload.target);
10
+
11
+ const { matches: allMatches } = gridContainsSequence(bgioArguments, parent, rule.sequence, context);
12
+
13
+ const matches = allMatches.filter(sequence =>
14
+ sequence.some(space => space === target)
15
+ );
16
+
17
+ return { matches, conditionIsMet: !!matches.length };
18
+ }
19
+ }
@@ -0,0 +1,23 @@
1
+ import Condition from "./condition.js";
2
+ import entityMatches from '../../utils/entity-matches.js'
3
+
4
+ export default class Is extends Condition {
5
+ checkCondition(bgioArguments, rule, { target }, context) {
6
+ if (this.rule.entity && target !== rule.entity) {
7
+ return {
8
+ target,
9
+ conditionIsMet: false,
10
+ }
11
+ }
12
+
13
+ return {
14
+ target,
15
+ conditionIsMet: entityMatches(
16
+ bgioArguments,
17
+ rule.matcher,
18
+ target,
19
+ context
20
+ )
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,9 @@
1
+ import Condition from "./condition.js";
2
+
3
+ export default class IsFull extends Condition {
4
+ checkCondition(bgioArguments, rule, payload, context) {
5
+ return {
6
+ conditionIsMet: payload.target.spaces.every(space => space?.entities.length)
7
+ };
8
+ }
9
+ }
@@ -1,14 +1,13 @@
1
1
  import Condition from "./condition.js";
2
2
  import areThereValidMoves from "../../utils/any-valid-moves.js";
3
3
  import getCurrentMoves from "../../utils/get-current-moves.js";
4
- import type { GetCurrentMovesClient, GetCurrentMovesState } from "../../utils/get-current-moves.js";
5
4
 
6
5
  export default class NoPossibleMoves extends Condition {
7
- checkCondition (bgioArguments: unknown, _unused: unknown, _payload: unknown, context: Record<string, unknown>) {
6
+ checkCondition(bgioArguments, _, __, context) {
8
7
  return {
9
8
  conditionIsMet: !areThereValidMoves(
10
9
  bgioArguments,
11
- getCurrentMoves(bgioArguments as GetCurrentMovesState, context as unknown as GetCurrentMovesClient),
10
+ getCurrentMoves(bgioArguments, context),
12
11
  )
13
12
  }
14
13
  }
@@ -1,12 +1,11 @@
1
- import type { Condition as ConditionRule } from "../../types/bagel-types.js";
2
1
  import Condition from "./condition.js";
3
2
  import checkConditions from "../../utils/check-conditions.js";
4
3
 
5
4
  export default class NotCondition extends Condition {
6
- checkCondition (bgioArguments: unknown, rule: unknown, payload: Record<string, unknown>, context: Record<string, unknown>) {
5
+ checkCondition(bgioArguments, rule, payload, context) {
7
6
  const result = checkConditions(
8
7
  bgioArguments,
9
- (rule as { conditions?: ConditionRule[] }).conditions,
8
+ rule,
10
9
  payload,
11
10
  context
12
11
  )
@@ -1,12 +1,11 @@
1
- import type { Condition as ConditionRule } from "../../types/bagel-types.js";
2
1
  import Condition from "./condition.js";
3
2
  import findMetCondition from "../../utils/find-met-condition.js";
4
3
 
5
4
  export default class Or extends Condition {
6
- checkCondition (bgioArguments: unknown, rule: unknown, payload: Record<string, unknown>, context: Record<string, unknown>) {
5
+ checkCondition(bgioArguments, rule, payload, context) {
7
6
  const result = findMetCondition(
8
7
  bgioArguments,
9
- (rule as { conditions?: ConditionRule[] }).conditions,
8
+ rule,
10
9
  payload,
11
10
  context
12
11
  )
@@ -0,0 +1,12 @@
1
+ import Condition from "./condition.js";
2
+
3
+ export default class Position extends Condition {
4
+ checkCondition(bgioArguments, rule, { target }) {
5
+ const parent = bgioArguments.G.bank.findParent(target)
6
+ let conditionIsMet
7
+ if (rule.position === 'First') {
8
+ conditionIsMet = parent.entities.indexOf(target) === 0
9
+ }
10
+ return { conditionIsMet }
11
+ }
12
+ }
@@ -1,18 +1,16 @@
1
- import type { Condition as ConditionRule } from "../../types/bagel-types.js";
2
1
  import Condition from "./condition.js";
3
2
  import checkConditions from "../../utils/check-conditions.js";
4
3
 
5
4
  export default class SomeCondition extends Condition {
6
- checkCondition (bgioArguments: unknown, rule: unknown, conditionPayload: Record<string, unknown>, context: Record<string, unknown>) {
7
- const targets = conditionPayload.target as unknown[];
8
- const result = targets.find((target: unknown) => {
5
+ checkCondition(bgioArguments, rule, { target: targets }, context) {
6
+ const result = targets.find((target) => {
9
7
  const loopContext = {
10
8
  ...context,
11
9
  loopTarget: target
12
10
  }
13
11
  return checkConditions(
14
12
  bgioArguments,
15
- (rule as { conditions?: ConditionRule[] }).conditions,
13
+ rule,
16
14
  undefined,
17
15
  loopContext
18
16
  ).conditionsAreMet
@@ -0,0 +1,94 @@
1
+ import Condition from "./condition.js";
2
+ import checkConditions from "../../utils/check-conditions.js";
3
+ import simulateMove from "../../utils/simulate-move.js";
4
+
5
+ // relying on target order is not perfect;
6
+ // I think we'll want to switch to named arguments
7
+ const argNameMap = {
8
+ PlaceNew: ['destination'],
9
+ RemoveEntity: ['entity'],
10
+ MoveEntity: ['entity', 'destination'],
11
+ TakeFrom: ['source', 'destination'],
12
+ SetState: ['entity', 'state'],
13
+ }
14
+
15
+ export default class WouldCondition extends Condition {
16
+ checkCondition(bgioArguments, rule, { target, targets = [target] }, context) {
17
+ const payload = {
18
+ arguments: targets.reduce((acc, target, i) => ({
19
+ ...acc,
20
+ [argNameMap[context.moveInstance.rule.moveType][i]]: target
21
+ }), {})
22
+ }
23
+
24
+ const simulatedG = simulateMove(
25
+ bgioArguments,
26
+ payload,
27
+ context
28
+ )
29
+
30
+ let simulatedConditionsPayload = {}
31
+ if (target) {
32
+ simulatedConditionsPayload = {
33
+ target: simulatedG.bank.locate(target.entityId)
34
+ }
35
+ } else if (targets) {
36
+ simulatedConditionsPayload = {
37
+ targets: targets.map(t => simulatedG.bank.locate(t.entityId))
38
+ }
39
+ }
40
+
41
+ const conditionResults = checkConditions(
42
+ {
43
+ ...bgioArguments,
44
+ G: simulatedG
45
+ },
46
+ rule,
47
+ simulatedConditionsPayload,
48
+ context
49
+ )
50
+
51
+ const conditionIsMet = conditionResults.conditionsAreMet
52
+
53
+ // optimization: don't bother restoring on failure
54
+ const results = conditionIsMet
55
+ ? restoreReferences(
56
+ conditionResults.results,
57
+ entityId => bgioArguments.G.bank.locate(entityId)
58
+ )
59
+ : conditionResults.results
60
+
61
+ return {
62
+ results,
63
+ conditionIsMet
64
+ }
65
+ }
66
+ }
67
+
68
+ // references to simulated object are useless
69
+ function restoreReferences(obj, getOriginalEntity, seen = new WeakSet()) {
70
+ if (typeof obj !== 'object' || obj === null) {
71
+ return obj;
72
+ }
73
+
74
+ if (seen.has(obj)) {
75
+ return obj;
76
+ }
77
+ seen.add(obj);
78
+
79
+ if (obj.entityId !== undefined) {
80
+ return getOriginalEntity(obj.entityId);
81
+ }
82
+
83
+ if (Array.isArray(obj)) {
84
+ return obj.map(item => restoreReferences(item, getOriginalEntity, seen));
85
+ } else {
86
+ const restored = {};
87
+ for (const key in obj) {
88
+ if (obj.hasOwnProperty(key)) {
89
+ restored[key] = restoreReferences(obj[key], getOriginalEntity, seen);
90
+ }
91
+ }
92
+ return restored;
93
+ }
94
+ }
@@ -0,0 +1,29 @@
1
+ export default class Entity {
2
+ constructor (options, rule, id) {
3
+ if (!options?.fromBank) {
4
+ throw new Error(`Do not create entities directly. Go through the Bank. rule: ${JSON.stringify(rule)}`)
5
+ }
6
+ this.rule = rule
7
+ this.entityId = id
8
+ this.state = {}
9
+ if (this.rule.stateGroups) {
10
+ Object.entries(this.rule.stateGroups)
11
+ .forEach(([stateGroupName, stateGroupValues]) => {
12
+ const stateGroupValueName = options?.initialStateGroups?.[stateGroupName]
13
+ ?? Object.keys(stateGroupValues)[0]
14
+ Object.assign(this.state, stateGroupValues[stateGroupValueName])
15
+ })
16
+ }
17
+ if (this.rule.state) {
18
+ Object.assign(this.state, this.rule.state)
19
+ }
20
+ }
21
+
22
+ get attributes () {
23
+ return {
24
+ ...this.rule,
25
+ ...this,
26
+ ...this.state
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,271 @@
1
+ import cloneDeep from "lodash/cloneDeep.js";
2
+ import find from "lodash/find.js";
3
+ import transformJSON from "../utils/json-transformer.js";
4
+
5
+ // for later when we implement deep replacement
6
+ // { type: 'IsEmpty' } = { type: 'not', conditions: [{ type: 'Contains' }],
7
+ // { matcher: {...blah} } => conditions.push({type: "Is", matcher: {...blah} })
8
+
9
+ // put somewhere
10
+ // const invariantConditionMappings = [
11
+ // {
12
+ // rule: {
13
+ // type: 'BankHasEnough',
14
+ // entity: rule.entity
15
+ // }
16
+ // },
17
+ // ]
18
+
19
+
20
+ // Things we always want, don't need to configure, and
21
+ // want to treat as first-class citizens
22
+ const invariantEntities = [
23
+ {
24
+ entityType: "Space",
25
+ count: "Infinity",
26
+ },
27
+ {
28
+ entityType: "Board",
29
+ name: 'sharedBoard'
30
+ },
31
+ {
32
+ name: "playerMarker",
33
+ perPlayer: true,
34
+ count: "Infinity"
35
+ }
36
+ ]
37
+
38
+ function expandEntities (rules) {
39
+ rules.entities = [
40
+ ...invariantEntities,
41
+ ...(rules.entities || [])
42
+ ]
43
+ }
44
+
45
+ function expandInitialPlacements (rules, entities) {
46
+ if (rules.sharedBoard) {
47
+ const sharedBoardPlacements = rules.sharedBoard.map(matcher => ({ entity: matcher, destination: { name: 'sharedBoard' } }))
48
+ if (!rules.initialPlacements) rules.initialPlacements = []
49
+ rules.initialPlacements.unshift(...sharedBoardPlacements)
50
+ }
51
+
52
+ if (rules.personalBoard) {
53
+ entities.push({
54
+ entityType: "Board",
55
+ name: 'personalBoard',
56
+ perPlayer: true
57
+ })
58
+ const personalBoardPlacements = rules.personalBoard.map(matcher => ({
59
+ entity: matcher,
60
+ destination: {
61
+ name: 'personalBoard'
62
+ }
63
+ }))
64
+ if (!rules.initialPlacements) rules.initialPlacements = []
65
+ rules.initialPlacements.unshift(...personalBoardPlacements)
66
+ }
67
+
68
+ if (rules.initialPlacements) {
69
+ const initialPlacementMoves = rules.initialPlacements.map(placement => {
70
+
71
+ // probably going to need to separate this even in the shorthand. maybe
72
+ // combine, then search entity rule and extract state variables instead?
73
+ const { state, ...matcher } = placement.entity
74
+ const entityDefinition = find(entities, matcher)
75
+
76
+ if (placement.destination.name === 'personalBoard') {
77
+ return {
78
+ moveType: 'ForEach',
79
+ arguments: {
80
+ targets: {
81
+ type: 'ctxPath',
82
+ path: ['playOrder']
83
+ }
84
+ },
85
+ move: {
86
+ moveType: 'PlaceNew',
87
+ entity: {
88
+ state,
89
+ conditions: [{
90
+ conditionType: 'Is',
91
+ matcher: {
92
+ ...matcher,
93
+ ...(entityDefinition.perPlayer
94
+ ? {
95
+ player: {
96
+ type: 'contextPath',
97
+ path: ['loopTarget']
98
+ }
99
+ }
100
+ : {}
101
+ )
102
+ },
103
+ }]
104
+ },
105
+ arguments: {
106
+ destination: {
107
+ conditions: [{
108
+ conditionType: 'Is',
109
+ matcher: {
110
+ ...placement.destination,
111
+ player: {
112
+ type: 'contextPath',
113
+ path: ['loopTarget']
114
+ }
115
+ }
116
+ }]
117
+ },
118
+ }
119
+ }
120
+ }
121
+ } else {
122
+ return {
123
+ moveType: 'PlaceNew',
124
+ entity: {
125
+ state,
126
+ conditions: [{
127
+ conditionType: 'Is',
128
+ matcher,
129
+ }]
130
+ },
131
+ arguments: {
132
+ destination: {
133
+ conditions: [{
134
+ conditionType: 'Is',
135
+ matcher: placement.destination
136
+ }]
137
+ },
138
+ }
139
+ }
140
+ }
141
+ })
142
+ if (!rules.initialMoves) rules.initialMoves = []
143
+ rules.initialMoves.unshift(...initialPlacementMoves)
144
+ delete rules.initialPlacements
145
+ }
146
+ }
147
+
148
+ const keyMappings = []
149
+
150
+ const simpleReplacements = [
151
+ [
152
+ 'isCurrentPlayer',
153
+ {
154
+ conditionType: 'Is',
155
+ matcher: {
156
+ player: {
157
+ type: 'ctxPath',
158
+ path: ['currentPlayer']
159
+ }
160
+ }
161
+ }
162
+ ],
163
+ [
164
+ 'isEmpty',
165
+ {
166
+ conditionType: 'Not',
167
+ conditions: [{conditionType: 'Contains'}]
168
+ }
169
+ ],
170
+ [
171
+ 'ownerOfFirstResultEntity', // might have to more tightly couple this to HasLine condition
172
+ {
173
+ "type": "contextPath",
174
+ "path": ["results", 0, "matches", 0, 0, "entities", 0, "attributes", "player"]
175
+ }
176
+ ]
177
+ ]
178
+
179
+ const transformationRules = [
180
+ {
181
+ test: val => val && typeof val === 'object',
182
+ replace: (val) => {
183
+ keyMappings.forEach(([oldKey, newKey]) => {
184
+ if (val.hasOwnProperty(oldKey)) {
185
+ val[newKey] = val[oldKey]
186
+ delete val[oldKey]
187
+ }
188
+ })
189
+ return val
190
+ }
191
+ },
192
+ {
193
+ test: val => typeof val === 'string',
194
+ replace: (val) => {
195
+ for (let i = 0, len = simpleReplacements.length; i < len; i++) {
196
+ if (val === simpleReplacements[i][0]) {
197
+ return simpleReplacements[i][1]
198
+ }
199
+ }
200
+ return val
201
+ }
202
+ },
203
+ {
204
+ test: val => val?.conditions,
205
+ replace: (val) => {
206
+ if (!Array.isArray(val.conditions)) {
207
+ val.conditions = [val.conditions]
208
+ }
209
+ return val
210
+ }
211
+ },
212
+ {
213
+ test: val => val?.conditions,
214
+ replace: (val) => {
215
+ // make "Is" the default condition
216
+ for (let i = 0, len = val.conditions.length; i < len; i++) {
217
+ if (!val.conditions[i].conditionType) {
218
+ val.conditions[i] = {
219
+ conditionType: 'Is',
220
+ matcher: val.conditions[i]
221
+ }
222
+ }
223
+ }
224
+ return val
225
+ }
226
+ },
227
+ {
228
+ test: val => typeof val?.target === 'string',
229
+ replace: val => ({
230
+ ...val,
231
+ target: {
232
+ conditions: [{
233
+ conditionType: 'Is',
234
+ matcher: {
235
+ name: val.target
236
+ }
237
+ }]
238
+ }
239
+ })
240
+ }
241
+ ]
242
+
243
+ export default function expandGameRules (gameRules) {
244
+ const rules = transformJSON(gameRules, transformationRules)
245
+
246
+ if (!rules.sharedBoard) {
247
+ rules.sharedBoard = rules.entities
248
+ }
249
+
250
+ if (!rules.turn) {
251
+ rules.turn = {
252
+ minMoves: 1,
253
+ maxMoves: 1
254
+ }
255
+ }
256
+
257
+ expandEntities(rules)
258
+ expandInitialPlacements(rules, rules.entities)
259
+
260
+ if (rules.phases) {
261
+ Object.entries(rules.phases).forEach((phaseRule) => {
262
+ expandInitialPlacements(phaseRule, rules.entities)
263
+ })
264
+ }
265
+
266
+ if (gameRules.numPlayers) {
267
+ gameRules.minPlayers = gameRules.maxPlayers = gameRules.numPlayers
268
+ }
269
+
270
+ return rules
271
+ }