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