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,94 +0,0 @@
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
- }
@@ -1,29 +0,0 @@
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
- }
@@ -1,271 +0,0 @@
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
- }
@@ -1,239 +0,0 @@
1
- import { serialize } from "wackson";
2
- import moveFactory from "./move/move-factory.js";
3
- import Bank from "./bank/bank.js";
4
- import expandGameRules from "./expand-game-rules.js";
5
- import getScenarioResults from '../utils/get-scenario-results.js'
6
- import doMoves from '../utils/do-moves.js'
7
- import deserializeBgioArguments from '../utils/deserialize-bgio-arguments.js'
8
-
9
- export default function gameFactory (gameRules, gameName) {
10
- const game = { name: gameName }
11
- const rules = expandGameRules(gameRules)
12
-
13
- game.setup = (bgioArguments) => {
14
- const { ctx } = bgioArguments
15
- const initialState = {
16
- _meta: {
17
- passedPlayers: [],
18
- previousPayloads: {},
19
- }
20
- };
21
-
22
- const entityDefinitions = expandEntityDefinitions(rules.entities, ctx)
23
- initialState.bank = new Bank(entityDefinitions)
24
- initialState.sharedBoard = initialState.bank.getOne(
25
- bgioArguments,
26
- {
27
- conditions: [{
28
- conditionType: 'Is',
29
- matcher: { name: "sharedBoard" }
30
- }]
31
- }
32
- )
33
-
34
- if (rules.personalBoard) {
35
- initialState.personalBoards = bgioArguments.ctx.playOrder.map((playerID) =>
36
- initialState.bank.getOne(
37
- bgioArguments,
38
- {
39
- conditions: [{
40
- conditionType: 'Is',
41
- matcher: {
42
- name: "personalBoard",
43
- player: playerID,
44
- }
45
- }]
46
- }
47
- )
48
- )
49
- }
50
-
51
- rules.initialMoves?.forEach((moveRule) => {
52
- moveFactory(moveRule, game).moveInstance.doMove(
53
- { ...bgioArguments, G: initialState }
54
- );
55
- })
56
- return JSON.parse(serialize(initialState));
57
- }
58
-
59
- if (rules.moves) {
60
- game.moves = createMoves(rules.moves, game)
61
- }
62
-
63
- if (rules.turn) {
64
- game.turn = createTurn(rules.turn, game)
65
- }
66
-
67
- if (rules.phases) {
68
- game.phases = Object.entries(rules.phases).reduce((acc, [name, phaseRule]) => ({
69
- ...acc,
70
- [name]: createPhase(phaseRule, game)
71
- }), {})
72
- }
73
-
74
- if (rules.endIf) {
75
- game.endIf = (bgioArguments) => {
76
- const newBgioArguments = deserializeBgioArguments(bgioArguments)
77
- return getScenarioResults(newBgioArguments, rules.endIf)
78
- }
79
- }
80
-
81
- if (!gameRules.DEBUG_DISABLE_SECRET_STATE) {
82
- game.playerView = (bgioArguments) => {
83
- const { G, playerID } = deserializeBgioArguments(bgioArguments)
84
- Object.values(G.bank.tracker).forEach(((entity) => {
85
- if (
86
- entity.rule.contentsHiddenFrom === 'All'
87
- || (
88
- entity.rule.contentsHiddenFrom === 'Others'
89
- && (
90
- playerID !== entity.rule.player
91
- || playerID == undefined
92
- )
93
- )
94
- ) {
95
- // may want to hide entities inside spaces instead?
96
- if (entity.spaces) {
97
- entity.spaces = entity.rule.hideLength
98
- ? []
99
- : entity.spaces.map(() => G.bank.createEntity())
100
- }
101
- if (entity.entities) {
102
- entity.entities = entity.rule.hideLength
103
- ? []
104
- : entity.entities.map(() => G.bank.createEntity())
105
- }
106
- }
107
- }))
108
- return JSON.parse(serialize(G))
109
- }
110
- }
111
-
112
- return game
113
- }
114
-
115
- // create a new entity for each variant
116
- function expandEntityDefinitions (entities, ctx) {
117
- return entities.reduce((acc, entity) => {
118
- const entityCopy = { ...entity }
119
-
120
- // perPlayer flag multiplies number of variants
121
- if (entityCopy.perPlayer) {
122
- delete entityCopy.perPlayer
123
- if (entityCopy.variants) {
124
- entityCopy.variants =
125
- (new Array(ctx.numPlayers)).fill().reduce((accu, _, i) => [
126
- ...accu,
127
- ...entityCopy.variants.map(variant => ({ ...variant, player: `${i}` }))
128
- ], [])
129
- } else {
130
- entityCopy.variants =
131
- (new Array(ctx.numPlayers)).fill().map((_, i) => ({ player: `${i}` }))
132
- }
133
- }
134
-
135
- // variants becomes new entitites
136
- if (entityCopy.variants) {
137
- const variants = entityCopy.variants
138
- delete entityCopy.variants
139
-
140
- return [
141
- ...acc,
142
- ...variants.map(variant => ({
143
- ...entityCopy,
144
- ...variant,
145
- }))
146
- ]
147
- } else {
148
- return [
149
- ...acc,
150
- entityCopy
151
- ]
152
- }
153
- }, [])
154
- }
155
-
156
- function createTurn (turnRule, game) {
157
- const turn = { ...turnRule }
158
-
159
- turn.onBegin = (bgioArguments) => {
160
- const newBgioArguments = deserializeBgioArguments(bgioArguments)
161
- const stageRule = turnRule.stages?.[
162
- newBgioArguments.ctx.activePlayers?.[newBgioArguments.ctx.currentPlayer]
163
- ]
164
-
165
- // not 100% sure about this logic / timing, but it seems to work so far in terms
166
- // of letting a player pass and still take a turn later if a move becomes available
167
- newBgioArguments.G._meta.passedPlayers = newBgioArguments.G._meta.passedPlayers
168
- .filter(p => p !== newBgioArguments.ctx.currentPlayer)
169
-
170
- doMoves(newBgioArguments, turnRule.initialMoves, { game })
171
- doMoves(newBgioArguments, stageRule?.initialMoves, { game })
172
-
173
- return JSON.parse(serialize(newBgioArguments.G));
174
- }
175
-
176
- if (turnRule.stages) {
177
- Object.entries(turnRule.stages).forEach(([stageName, stageRule]) => {
178
- if (stageRule.moves) {
179
- turn.stages[stageName].moves = createMoves(stageRule.moves, game)
180
- }
181
- })
182
- }
183
-
184
- if (turnRule.order?.playOrder === 'RotateFirst') {
185
- turnRule.order.first = () => 0
186
- turnRule.order.next = ({ ctx }) => (ctx.playOrderPos + 1) % ctx.numPlayers
187
- turn.order.playOrder = ({ ctx, G }) => {
188
- return G._meta.isAfterFirstPhase
189
- ? [...ctx.playOrder.slice(1), ctx.playOrder[0]]
190
- : ctx.playOrder
191
- }
192
- }
193
-
194
- return turn
195
- }
196
-
197
- function createPhase (phaseRule, game) {
198
- const phase = {...phaseRule}
199
- if (phaseRule.turn) {
200
- phase.turn = createTurn(phaseRule.turn, game)
201
- }
202
- if (phaseRule.moves) {
203
- phase.moves = createMoves(phaseRule.moves, game)
204
- }
205
-
206
- phase.onBegin = (bgioArguments) => {
207
- const newBgioArguments = deserializeBgioArguments(bgioArguments)
208
- doMoves(newBgioArguments, phaseRule.initialMoves, { game })
209
- newBgioArguments.G._meta.currentPhaseHasBeenSetUp = true
210
- newBgioArguments.G._meta.nextPhase = phaseRule.next
211
- return JSON.parse(serialize(newBgioArguments.G));
212
- }
213
-
214
- if (phaseRule.endIf) {
215
- phase.endIf = (bgioArguments) => {
216
- const newBgioArguments = deserializeBgioArguments(bgioArguments)
217
- if (newBgioArguments.G._meta.currentPhaseHasBeenSetUp) {
218
- const result = getScenarioResults(newBgioArguments, phaseRule.endIf)
219
- if (result) {
220
- return result
221
- }
222
- }
223
- }
224
- }
225
-
226
- phase.onEnd = ({ G }) => {
227
- G._meta.currentPhaseHasBeenSetUp = false
228
- G._meta.isAfterFirstPhase = true
229
- }
230
-
231
- return phase
232
- }
233
-
234
- function createMoves (moves, game) {
235
- return Object.entries(moves).reduce((acc, [name, moveDefinition]) => ({
236
- ...acc,
237
- [name]: moveFactory({ ...moveDefinition, name }, game)
238
- }), {})
239
- }
@@ -1,18 +0,0 @@
1
- import Move from "./move.js";
2
- import { getMoveInstance } from "./move-factory.js";
3
-
4
- export default class ForEach extends Move {
5
- do(bgioArguments, rule, { arguments: { targets } }, context) {
6
- targets.forEach((target) => {
7
- const loopContext = {
8
- ...context,
9
- loopTarget: target
10
- }
11
- getMoveInstance(rule.move).doMove(
12
- bgioArguments,
13
- undefined,
14
- loopContext
15
- )
16
- })
17
- }
18
- }
@@ -1,16 +0,0 @@
1
- import Move from "./move.js";
2
-
3
- export default class MoveEntity extends Move {
4
- do(bgioArguments, rule, { arguments: { entity, destination } }) {
5
- // todo: move all such things to always be multiple
6
- if (Array.isArray(entity)) {
7
- entity.forEach((e) => {
8
- bgioArguments.G.bank.findParent(e)?.remove(e)
9
- destination.placeEntity(e, rule.position)
10
- })
11
- } else {
12
- bgioArguments.G.bank.findParent(entity)?.remove(entity)
13
- destination.placeEntity(entity, rule.position)
14
- }
15
- }
16
- }