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.
- package/.github/workflows/ci.yml +33 -0
- package/dist/board-game-engine.cjs +463 -349
- package/dist/board-game-engine.js +463 -349
- package/dist/board-game-engine.min.js +22 -22
- package/dist/board-game-engine.mjs +461 -348
- package/dist/client/client.d.ts +76 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/game-factory/bank/bank-slot.d.ts +30 -0
- package/dist/game-factory/bank/bank-slot.d.ts.map +1 -0
- package/dist/game-factory/bank/bank.d.ts +34 -0
- package/dist/game-factory/bank/bank.d.ts.map +1 -0
- package/dist/game-factory/board.d.ts +4 -0
- package/dist/game-factory/board.d.ts.map +1 -0
- package/dist/game-factory/condition/condition-factory.d.ts +4 -0
- package/dist/game-factory/condition/condition-factory.d.ts.map +1 -0
- package/dist/game-factory/condition/condition.d.ts +13 -0
- package/dist/game-factory/condition/condition.d.ts.map +1 -0
- package/dist/game-factory/condition/contains-condition.d.ts +8 -0
- package/dist/game-factory/condition/contains-condition.d.ts.map +1 -0
- package/dist/game-factory/condition/contains-same-condition.d.ts +7 -0
- package/dist/game-factory/condition/contains-same-condition.d.ts.map +1 -0
- package/dist/game-factory/condition/evaluate-condition.d.ts +8 -0
- package/dist/game-factory/condition/evaluate-condition.d.ts.map +1 -0
- package/dist/game-factory/condition/every-condition.d.ts +12 -0
- package/dist/game-factory/condition/every-condition.d.ts.map +1 -0
- package/dist/game-factory/condition/has-line-condition.d.ts +8 -0
- package/dist/game-factory/condition/has-line-condition.d.ts.map +1 -0
- package/dist/game-factory/condition/in-line-condition.d.ts +8 -0
- package/dist/game-factory/condition/in-line-condition.d.ts.map +1 -0
- package/dist/game-factory/condition/is-condition.d.ts +8 -0
- package/dist/game-factory/condition/is-condition.d.ts.map +1 -0
- package/dist/game-factory/condition/is-full-condition.d.ts +7 -0
- package/dist/game-factory/condition/is-full-condition.d.ts.map +1 -0
- package/dist/game-factory/condition/no-possible-moves-condition.d.ts +7 -0
- package/dist/game-factory/condition/no-possible-moves-condition.d.ts.map +1 -0
- package/dist/game-factory/condition/not-condition.d.ts +7 -0
- package/dist/game-factory/condition/not-condition.d.ts.map +1 -0
- package/dist/game-factory/condition/or-condition.d.ts +7 -0
- package/dist/game-factory/condition/or-condition.d.ts.map +1 -0
- package/dist/game-factory/condition/position-condition.d.ts +7 -0
- package/dist/game-factory/condition/position-condition.d.ts.map +1 -0
- package/dist/game-factory/condition/some-condition.d.ts +8 -0
- package/dist/game-factory/condition/some-condition.d.ts.map +1 -0
- package/dist/game-factory/condition/would-condition.d.ts +8 -0
- package/dist/game-factory/condition/would-condition.d.ts.map +1 -0
- package/dist/game-factory/entity.d.ts +13 -0
- package/dist/game-factory/entity.d.ts.map +1 -0
- package/dist/game-factory/expand-game-rules.d.ts +3 -0
- package/dist/game-factory/expand-game-rules.d.ts.map +1 -0
- package/dist/game-factory/game-factory.d.ts +10 -0
- package/dist/game-factory/game-factory.d.ts.map +1 -0
- package/{src/game-factory/move/end-turn.js → dist/game-factory/move/end-turn.d.ts} +2 -4
- package/dist/game-factory/move/end-turn.d.ts.map +1 -0
- package/dist/game-factory/move/for-each.d.ts +5 -0
- package/dist/game-factory/move/for-each.d.ts.map +1 -0
- package/dist/game-factory/move/index.d.ts +6 -0
- package/dist/game-factory/move/index.d.ts.map +1 -0
- package/dist/game-factory/move/move-entity.d.ts +7 -0
- package/dist/game-factory/move/move-entity.d.ts.map +1 -0
- package/dist/game-factory/move/move-factory.d.ts +18 -0
- package/dist/game-factory/move/move-factory.d.ts.map +1 -0
- package/dist/game-factory/move/move.d.ts +54 -0
- package/dist/game-factory/move/move.d.ts.map +1 -0
- package/dist/game-factory/move/pass-turn.d.ts +5 -0
- package/dist/game-factory/move/pass-turn.d.ts.map +1 -0
- package/{src/game-factory/move/pass.js → dist/game-factory/move/pass.d.ts} +2 -4
- package/dist/game-factory/move/pass.d.ts.map +1 -0
- package/dist/game-factory/move/place-new.d.ts +5 -0
- package/dist/game-factory/move/place-new.d.ts.map +1 -0
- package/dist/game-factory/move/remove-entity.d.ts +5 -0
- package/dist/game-factory/move/remove-entity.d.ts.map +1 -0
- package/dist/game-factory/move/set-active-players.d.ts +5 -0
- package/dist/game-factory/move/set-active-players.d.ts.map +1 -0
- package/dist/game-factory/move/set-state.d.ts +5 -0
- package/dist/game-factory/move/set-state.d.ts.map +1 -0
- package/dist/game-factory/move/shuffle.d.ts +5 -0
- package/dist/game-factory/move/shuffle.d.ts.map +1 -0
- package/dist/game-factory/move/take-from.d.ts +11 -0
- package/dist/game-factory/move/take-from.d.ts.map +1 -0
- package/dist/game-factory/space/space.d.ts +10 -0
- package/dist/game-factory/space/space.d.ts.map +1 -0
- package/dist/game-factory/space-group/grid.d.ts +15 -0
- package/dist/game-factory/space-group/grid.d.ts.map +1 -0
- package/dist/game-factory/space-group/space-group.d.ts +20 -0
- package/dist/game-factory/space-group/space-group.d.ts.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/registry.d.ts +17 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/types/bagel-types.d.ts +339 -0
- package/dist/types/bagel-types.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/rule-with-conditions.d.ts +9 -0
- package/dist/types/rule-with-conditions.d.ts.map +1 -0
- package/dist/utils/any-valid-moves.d.ts +2 -0
- package/dist/utils/any-valid-moves.d.ts.map +1 -0
- package/dist/utils/bgio-resolve-types.d.ts +25 -0
- package/dist/utils/bgio-resolve-types.d.ts.map +1 -0
- package/dist/utils/check-conditions.d.ts +7 -0
- package/dist/utils/check-conditions.d.ts.map +1 -0
- package/dist/utils/create-payload.d.ts +5 -0
- package/dist/utils/create-payload.d.ts.map +1 -0
- package/dist/utils/deserialize-bgio-arguments.d.ts +3 -0
- package/dist/utils/deserialize-bgio-arguments.d.ts.map +1 -0
- package/dist/utils/do-moves.d.ts +8 -0
- package/dist/utils/do-moves.d.ts.map +1 -0
- package/dist/utils/entity-matches.d.ts +6 -0
- package/dist/utils/entity-matches.d.ts.map +1 -0
- package/dist/utils/find-met-condition.d.ts +6 -0
- package/dist/utils/find-met-condition.d.ts.map +1 -0
- package/dist/utils/get-current-moves.d.ts +24 -0
- package/dist/utils/get-current-moves.d.ts.map +1 -0
- package/dist/utils/get-scenario-results.d.ts +3 -0
- package/dist/utils/get-scenario-results.d.ts.map +1 -0
- package/dist/utils/get-steps.d.ts +13 -0
- package/dist/utils/get-steps.d.ts.map +1 -0
- package/dist/utils/get.d.ts +7 -0
- package/dist/utils/get.d.ts.map +1 -0
- package/dist/utils/grid-contains-sequence.d.ts +27 -0
- package/dist/utils/grid-contains-sequence.d.ts.map +1 -0
- package/dist/utils/json-transformer.d.ts +8 -0
- package/dist/utils/json-transformer.d.ts.map +1 -0
- package/dist/utils/prepare-payload.d.ts +2 -0
- package/dist/utils/prepare-payload.d.ts.map +1 -0
- package/dist/utils/resolve-entity.d.ts +3 -0
- package/dist/utils/resolve-entity.d.ts.map +1 -0
- package/dist/utils/resolve-expression.d.ts +6 -0
- package/dist/utils/resolve-expression.d.ts.map +1 -0
- package/dist/utils/resolve-properties.d.ts +4 -0
- package/dist/utils/resolve-properties.d.ts.map +1 -0
- package/dist/utils/simulate-move.d.ts +16 -0
- package/dist/utils/simulate-move.d.ts.map +1 -0
- package/examples/checkers.json +2 -2
- package/examples/connect-four.json +1 -1
- package/examples/eights.json +15 -15
- package/package.json +9 -3
- package/playwright-report/index.html +1 -1
- package/scripts/build.mjs +2 -2
- package/src/client/client.ts +306 -0
- package/src/game-factory/bank/bank-slot.ts +81 -0
- package/src/game-factory/bank/bank.ts +125 -0
- package/src/game-factory/{board.js → board.ts} +1 -1
- package/src/game-factory/condition/condition-factory.ts +59 -0
- package/src/game-factory/condition/condition.ts +50 -0
- package/src/game-factory/condition/{contains-condition.js → contains-condition.ts} +5 -4
- package/src/game-factory/condition/{contains-same-condition.js → contains-same-condition.ts} +8 -5
- package/src/game-factory/condition/{evaluate-condition.js → evaluate-condition.ts} +4 -3
- package/src/game-factory/condition/every-condition.ts +27 -0
- package/src/game-factory/condition/has-line-condition.ts +15 -0
- package/src/game-factory/condition/in-line-condition.ts +25 -0
- package/src/game-factory/condition/is-condition.ts +24 -0
- package/src/game-factory/condition/is-full-condition.ts +10 -0
- package/src/game-factory/condition/{no-possible-moves-condition.js → no-possible-moves-condition.ts} +3 -2
- package/src/game-factory/condition/{not-condition.js → not-condition.ts} +3 -2
- package/src/game-factory/condition/{or-condition.js → or-condition.ts} +3 -2
- package/src/game-factory/condition/position-condition.ts +13 -0
- package/src/game-factory/condition/{some-condition.js → some-condition.ts} +5 -3
- package/src/game-factory/condition/would-condition.ts +104 -0
- package/src/game-factory/entity.ts +37 -0
- package/src/game-factory/expand-game-rules.ts +263 -0
- package/src/game-factory/game-factory.ts +263 -0
- package/src/game-factory/move/end-turn.ts +7 -0
- package/src/game-factory/move/for-each.ts +20 -0
- package/src/game-factory/move/move-entity.ts +18 -0
- package/src/game-factory/move/move-factory.ts +107 -0
- package/src/game-factory/move/move.ts +147 -0
- package/src/game-factory/move/pass-turn.ts +15 -0
- package/src/game-factory/move/pass.ts +7 -0
- package/src/game-factory/move/place-new.ts +42 -0
- package/src/game-factory/move/remove-entity.ts +11 -0
- package/src/game-factory/move/set-active-players.ts +26 -0
- package/src/game-factory/move/set-state.ts +14 -0
- package/src/game-factory/move/shuffle.ts +9 -0
- package/src/game-factory/move/take-from.ts +12 -0
- package/src/game-factory/space/space.ts +36 -0
- package/src/game-factory/space-group/grid.ts +48 -0
- package/src/game-factory/space-group/space-group.ts +44 -0
- package/src/index.ts +5 -0
- package/src/types/bagel-types.ts +449 -0
- package/src/types/boardgame-io-core.d.ts +7 -0
- package/src/types/index.ts +70 -0
- package/src/types/rule-with-conditions.ts +9 -0
- package/src/utils/{any-valid-moves.js → any-valid-moves.ts} +54 -49
- package/src/utils/bgio-resolve-types.ts +27 -0
- package/src/utils/check-conditions.ts +28 -0
- package/src/utils/create-payload.ts +19 -0
- package/src/utils/deserialize-bgio-arguments.ts +10 -0
- package/src/utils/do-moves.ts +22 -0
- package/src/utils/entity-matches.ts +30 -0
- package/src/utils/expr-eval.d.ts +6 -0
- package/src/utils/find-met-condition.ts +23 -0
- package/src/utils/get-current-moves.ts +39 -0
- package/src/utils/get-scenario-results.ts +30 -0
- package/src/utils/get-steps.ts +38 -0
- package/src/utils/get.ts +28 -0
- package/src/utils/{grid-contains-sequence.js → grid-contains-sequence.ts} +71 -33
- package/src/utils/json-transformer.ts +17 -0
- package/src/utils/prepare-payload.ts +20 -0
- package/src/utils/resolve-entity.ts +15 -0
- package/src/utils/resolve-expression.ts +16 -0
- package/src/utils/resolve-properties.ts +172 -0
- package/src/utils/simulate-move.ts +32 -0
- package/src/wackson.d.ts +4 -0
- package/tsconfig.build.json +14 -0
- package/tsconfig.json +21 -0
- package/src/client/client.js +0 -224
- package/src/game-factory/bank/bank-slot.js +0 -69
- package/src/game-factory/bank/bank.js +0 -114
- package/src/game-factory/condition/condition-factory.js +0 -52
- package/src/game-factory/condition/condition.js +0 -39
- package/src/game-factory/condition/every-condition.js +0 -25
- package/src/game-factory/condition/has-line-condition.js +0 -14
- package/src/game-factory/condition/in-line-condition.js +0 -19
- package/src/game-factory/condition/is-condition.js +0 -23
- package/src/game-factory/condition/is-full-condition.js +0 -9
- package/src/game-factory/condition/position-condition.js +0 -12
- package/src/game-factory/condition/would-condition.js +0 -94
- package/src/game-factory/entity.js +0 -29
- package/src/game-factory/expand-game-rules.js +0 -271
- package/src/game-factory/game-factory.js +0 -239
- package/src/game-factory/move/for-each.js +0 -18
- package/src/game-factory/move/move-entity.js +0 -16
- package/src/game-factory/move/move-factory.js +0 -89
- package/src/game-factory/move/move.js +0 -131
- package/src/game-factory/move/pass-turn.js +0 -10
- package/src/game-factory/move/place-new.js +0 -33
- package/src/game-factory/move/remove-entity.js +0 -7
- package/src/game-factory/move/set-active-players.js +0 -23
- package/src/game-factory/move/set-state.js +0 -11
- package/src/game-factory/move/shuffle.js +0 -7
- package/src/game-factory/move/take-from.js +0 -7
- package/src/game-factory/space/space.js +0 -30
- package/src/game-factory/space-group/grid.js +0 -43
- package/src/game-factory/space-group/space-group.js +0 -29
- package/src/index.js +0 -2
- package/src/utils/check-conditions.js +0 -28
- package/src/utils/create-payload.js +0 -16
- package/src/utils/deserialize-bgio-arguments.js +0 -8
- package/src/utils/do-moves.js +0 -18
- package/src/utils/entity-matches.js +0 -20
- package/src/utils/find-met-condition.js +0 -22
- package/src/utils/get-current-moves.js +0 -12
- package/src/utils/get-scenario-results.js +0 -23
- package/src/utils/get-steps.js +0 -29
- package/src/utils/get.js +0 -25
- package/src/utils/json-transformer.js +0 -12
- package/src/utils/prepare-payload.js +0 -16
- package/src/utils/resolve-entity.js +0 -9
- package/src/utils/resolve-expression.js +0 -10
- package/src/utils/resolve-properties.js +0 -149
- package/src/utils/simulate-move.js +0 -25
- /package/src/game-factory/move/{index.js → index.ts} +0 -0
- /package/src/{registry.js → registry.ts} +0 -0
|
@@ -1,20 +1,37 @@
|
|
|
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";
|
|
3
4
|
import checkConditions from "./check-conditions.js";
|
|
4
5
|
|
|
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
|
+
|
|
5
22
|
// We'll check reverse directions along each line
|
|
6
|
-
const directions = [
|
|
23
|
+
const directions: [number, number][] = [
|
|
7
24
|
[1, 0], // horizontal
|
|
8
25
|
[0, 1], // vertical
|
|
9
26
|
[1, 1], // diagonal down-right
|
|
10
27
|
[-1, 1], // diagonal down-left
|
|
11
28
|
];
|
|
12
29
|
|
|
13
|
-
const sequenceCache = new WeakMap();
|
|
30
|
+
const sequenceCache = new WeakMap<object, Map<string, { stateKey: string; result: unknown }>>();
|
|
14
31
|
|
|
15
|
-
function getSequenceKey(sequencePattern, context) {
|
|
32
|
+
function getSequenceKey (sequencePattern: unknown, context: Record<string, unknown>) {
|
|
16
33
|
const contextKey = {
|
|
17
|
-
moveInstance: context.moveInstance?.id,
|
|
34
|
+
moveInstance: (context.moveInstance as { id?: unknown } | undefined)?.id,
|
|
18
35
|
moveArguments: context.moveArguments,
|
|
19
36
|
// Add other context properties that conditions might use
|
|
20
37
|
};
|
|
@@ -22,17 +39,17 @@ function getSequenceKey(sequencePattern, context) {
|
|
|
22
39
|
}
|
|
23
40
|
|
|
24
41
|
// todo: use stable hash library that we're using for game rules hash
|
|
25
|
-
function getGridStateKey(grid) {
|
|
42
|
+
function getGridStateKey (grid: GridLike) {
|
|
26
43
|
const spaces = grid.entities || [];
|
|
27
|
-
|
|
28
|
-
return spaces.map(space => {
|
|
44
|
+
|
|
45
|
+
return spaces.map((space) => {
|
|
29
46
|
const entities = space.entities || [];
|
|
30
|
-
if (entities.length === 0) return
|
|
31
|
-
|
|
32
|
-
return entities.map(entity => {
|
|
47
|
+
if (entities.length === 0) return "empty";
|
|
48
|
+
|
|
49
|
+
return entities.map((entity) => {
|
|
33
50
|
const sortedKeys = Object.keys(entity).sort();
|
|
34
|
-
const stateObj = {};
|
|
35
|
-
sortedKeys.forEach(key => {
|
|
51
|
+
const stateObj: Record<string, unknown> = {};
|
|
52
|
+
sortedKeys.forEach((key) => {
|
|
36
53
|
stateObj[key] = entity[key];
|
|
37
54
|
});
|
|
38
55
|
return JSON.stringify(stateObj);
|
|
@@ -40,8 +57,15 @@ function getGridStateKey(grid) {
|
|
|
40
57
|
}).join(',');
|
|
41
58
|
}
|
|
42
59
|
|
|
43
|
-
function findSequencesInLine(
|
|
44
|
-
|
|
60
|
+
function findSequencesInLine (
|
|
61
|
+
bgioArguments: unknown,
|
|
62
|
+
lineSpaces: unknown[],
|
|
63
|
+
sequencePattern: SequenceChunk[],
|
|
64
|
+
minSequenceLength: number,
|
|
65
|
+
context: Record<string, unknown>,
|
|
66
|
+
reverse = false
|
|
67
|
+
) {
|
|
68
|
+
const matches: unknown[][] = [];
|
|
45
69
|
|
|
46
70
|
// Use original array or iterate in reverse without creating new array
|
|
47
71
|
const length = lineSpaces.length;
|
|
@@ -68,9 +92,9 @@ function findSequencesInLine(bgioArguments, lineSpaces, sequencePattern, minSequ
|
|
|
68
92
|
return matches;
|
|
69
93
|
}
|
|
70
94
|
|
|
71
|
-
function getLineStartingPoints(grid, dx, dy) {
|
|
95
|
+
function getLineStartingPoints (grid: GridLike, dx: number, dy: number) {
|
|
72
96
|
const { width, height } = grid.attributes;
|
|
73
|
-
const starts = [];
|
|
97
|
+
const starts: [number, number][] = [];
|
|
74
98
|
|
|
75
99
|
if (dx === 1 && dy === 0) {
|
|
76
100
|
// Horizontal: start at leftmost column
|
|
@@ -91,8 +115,8 @@ function getLineStartingPoints(grid, dx, dy) {
|
|
|
91
115
|
return starts;
|
|
92
116
|
}
|
|
93
117
|
|
|
94
|
-
function getLineSpaces(grid, startX, startY, dx, dy) {
|
|
95
|
-
const spaces = [];
|
|
118
|
+
function getLineSpaces (grid: GridLike, startX: number, startY: number, dx: number, dy: number) {
|
|
119
|
+
const spaces: unknown[] = [];
|
|
96
120
|
let [x, y] = [startX, startY];
|
|
97
121
|
|
|
98
122
|
while (grid.areCoordinatesValid([x, y])) {
|
|
@@ -103,9 +127,16 @@ function getLineSpaces(grid, startX, startY, dx, dy) {
|
|
|
103
127
|
return spaces;
|
|
104
128
|
}
|
|
105
129
|
|
|
106
|
-
function tryMatchSequence(
|
|
130
|
+
function tryMatchSequence (
|
|
131
|
+
bgioArguments: unknown,
|
|
132
|
+
lineSpaces: unknown[],
|
|
133
|
+
startIndex: number,
|
|
134
|
+
sequencePattern: SequenceChunk[],
|
|
135
|
+
context: Record<string, unknown>,
|
|
136
|
+
reverse = false
|
|
137
|
+
) {
|
|
107
138
|
let spaceIndex = startIndex;
|
|
108
|
-
const matchedSpaces = [];
|
|
139
|
+
const matchedSpaces: unknown[] = [];
|
|
109
140
|
const length = lineSpaces.length;
|
|
110
141
|
|
|
111
142
|
for (const chunk of sequencePattern) {
|
|
@@ -122,7 +153,7 @@ function tryMatchSequence(bgioArguments, lineSpaces, startIndex, sequencePattern
|
|
|
122
153
|
}
|
|
123
154
|
|
|
124
155
|
let matchedCount = 0;
|
|
125
|
-
const chunkMatches = [];
|
|
156
|
+
const chunkMatches: unknown[] = [];
|
|
126
157
|
|
|
127
158
|
// Greedy: try to match as many as possible up to max
|
|
128
159
|
while (matchedCount < max && spaceIndex < length) {
|
|
@@ -152,15 +183,16 @@ function tryMatchSequence(bgioArguments, lineSpaces, startIndex, sequencePattern
|
|
|
152
183
|
return matchedSpaces.length > 0 ? matchedSpaces : null;
|
|
153
184
|
}
|
|
154
185
|
|
|
155
|
-
function checkSpaceConditions(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
186
|
+
function checkSpaceConditions (
|
|
187
|
+
bgioArguments: unknown,
|
|
188
|
+
space: unknown,
|
|
189
|
+
conditions: Condition[] | undefined,
|
|
190
|
+
chunkMatches: unknown[] = [],
|
|
191
|
+
context?: Record<string, unknown>
|
|
192
|
+
) {
|
|
161
193
|
return checkConditions(
|
|
162
194
|
bgioArguments,
|
|
163
|
-
|
|
195
|
+
conditions,
|
|
164
196
|
{
|
|
165
197
|
target: space,
|
|
166
198
|
targets: [space, ...chunkMatches] // for ContainsSame, other group conditions
|
|
@@ -169,7 +201,12 @@ function checkSpaceConditions(bgioArguments, space, conditions, chunkMatches = [
|
|
|
169
201
|
).conditionsAreMet
|
|
170
202
|
}
|
|
171
203
|
|
|
172
|
-
export default function gridContainsSequence(
|
|
204
|
+
export default function gridContainsSequence (
|
|
205
|
+
bgioArguments: unknown,
|
|
206
|
+
grid: GridLike,
|
|
207
|
+
sequencePattern: SequenceChunk[],
|
|
208
|
+
context: Record<string, unknown>
|
|
209
|
+
) {
|
|
173
210
|
const cacheKey = getSequenceKey(sequencePattern, context);
|
|
174
211
|
let gridCache = sequenceCache.get(grid);
|
|
175
212
|
|
|
@@ -185,10 +222,11 @@ export default function gridContainsSequence(bgioArguments, grid, sequencePatter
|
|
|
185
222
|
return cacheEntry.result;
|
|
186
223
|
}
|
|
187
224
|
|
|
188
|
-
const matches = [];
|
|
189
|
-
|
|
190
|
-
const minSequenceLength = sequencePattern.reduce(
|
|
191
|
-
sum + (chunk.minCount || chunk.count || 1),
|
|
225
|
+
const matches: unknown[][] = [];
|
|
226
|
+
|
|
227
|
+
const minSequenceLength = sequencePattern.reduce(
|
|
228
|
+
(sum: number, chunk: SequenceChunk) => sum + (chunk.minCount || chunk.count || 1),
|
|
229
|
+
0
|
|
192
230
|
);
|
|
193
231
|
|
|
194
232
|
// For each direction, scan each row/column/diagonal once
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type TransformRule = {
|
|
2
|
+
test: (val: unknown) => boolean;
|
|
3
|
+
replace: (val: unknown) => unknown;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
/** Recurse and replace. Circular references not allowed. */
|
|
7
|
+
export default function transformJSON (data: unknown, rules: TransformRule[]): unknown {
|
|
8
|
+
return JSON.parse(JSON.stringify(data), (_key, value: unknown) => {
|
|
9
|
+
let result = value;
|
|
10
|
+
for (const rule of rules) {
|
|
11
|
+
if (rule.test(result)) {
|
|
12
|
+
result = rule.replace(result);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return result;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { serialize } from "wackson";
|
|
2
|
+
|
|
3
|
+
// todo: remember why reducing to id was preferred?
|
|
4
|
+
export default function preparePayload (payload: unknown): unknown {
|
|
5
|
+
const p = payload as {
|
|
6
|
+
arguments?: Record<string, { abstract?: boolean; entityId?: unknown }>;
|
|
7
|
+
} | null | undefined;
|
|
8
|
+
if (p?.arguments) {
|
|
9
|
+
const payloadCopy = {
|
|
10
|
+
...p,
|
|
11
|
+
arguments: Object.entries(p.arguments).reduce<Record<string, unknown>>((acc, [key, argument]) => ({
|
|
12
|
+
...acc,
|
|
13
|
+
[key]: argument.abstract ? argument : argument.entityId,
|
|
14
|
+
}), {}),
|
|
15
|
+
};
|
|
16
|
+
return JSON.parse(serialize(payloadCopy, { deduplicateInstances: false }));
|
|
17
|
+
} else {
|
|
18
|
+
return payload;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import isPlainObject from "lodash/isPlainObject.js";
|
|
2
|
+
import { bankOf, type BgioResolveState } from "./bgio-resolve-types.js";
|
|
3
|
+
|
|
4
|
+
const abstractTargetNames = ["state"];
|
|
5
|
+
|
|
6
|
+
export default function resolveEntity (
|
|
7
|
+
bgioArguments: BgioResolveState,
|
|
8
|
+
target: unknown,
|
|
9
|
+
context: unknown,
|
|
10
|
+
targetName: string | undefined
|
|
11
|
+
): unknown {
|
|
12
|
+
return !abstractTargetNames.includes(targetName ?? "") && isPlainObject(target)
|
|
13
|
+
? bankOf(bgioArguments).find(bgioArguments, target, context)
|
|
14
|
+
: target;
|
|
15
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Parser } from "expr-eval";
|
|
2
|
+
import resolveProperties from "./resolve-properties.js";
|
|
3
|
+
import type { BgioResolveState } from "./bgio-resolve-types.js";
|
|
4
|
+
|
|
5
|
+
const parser = new Parser();
|
|
6
|
+
(parser.functions as Record<string, (...args: unknown[]) => unknown>).sum = (...args: unknown[]) =>
|
|
7
|
+
(args[0] as number[]).reduce((acc, val) => acc + val, 0);
|
|
8
|
+
|
|
9
|
+
export default function resolveExpression (
|
|
10
|
+
bgioArguments: BgioResolveState,
|
|
11
|
+
rule: { expression: string; arguments?: unknown },
|
|
12
|
+
context: Record<string, unknown>
|
|
13
|
+
): unknown {
|
|
14
|
+
const args = resolveProperties(bgioArguments, rule.arguments, context) as Record<string, unknown>;
|
|
15
|
+
return parser.evaluate(rule.expression, args);
|
|
16
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import isPlainObject from "lodash/isPlainObject.js";
|
|
2
|
+
import pick from "lodash/pick.js";
|
|
3
|
+
import get from "./get.js";
|
|
4
|
+
import resolveExpression from "./resolve-expression.js";
|
|
5
|
+
import resolveEntity from "./resolve-entity.js";
|
|
6
|
+
import { bankOf, type BgioResolveState } from "./bgio-resolve-types.js";
|
|
7
|
+
|
|
8
|
+
export type { BgioResolveState };
|
|
9
|
+
|
|
10
|
+
const resolutionTerminators = [
|
|
11
|
+
"conditions",
|
|
12
|
+
"move",
|
|
13
|
+
"then",
|
|
14
|
+
"mapping",
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
export default function resolveProperties (
|
|
18
|
+
bgioArguments: BgioResolveState,
|
|
19
|
+
obj: unknown,
|
|
20
|
+
context: Record<string, unknown> = {},
|
|
21
|
+
key?: string
|
|
22
|
+
): unknown {
|
|
23
|
+
if (!isPlainObject(obj) && !Array.isArray(obj)) {
|
|
24
|
+
return obj;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let resolvedProperties: Record<string, unknown> | unknown[] = Array.isArray(obj)
|
|
28
|
+
? [...obj]
|
|
29
|
+
: { ...(obj as Record<string, unknown>) };
|
|
30
|
+
|
|
31
|
+
Object.entries(obj as Record<string, unknown>).forEach(([k, value]) => {
|
|
32
|
+
if (!resolutionTerminators.includes(k)) {
|
|
33
|
+
(resolvedProperties as Record<string, unknown>)[k] = resolveProperties(bgioArguments, value, context, k);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const resolved = resolveProperty(bgioArguments, resolvedProperties, context);
|
|
38
|
+
|
|
39
|
+
const resolveAsEntity = (resolved as { resolveAsEntity?: boolean } | null)?.resolveAsEntity
|
|
40
|
+
|| key === "target"
|
|
41
|
+
|| key === "targets";
|
|
42
|
+
|
|
43
|
+
return resolveAsEntity
|
|
44
|
+
? resolveEntity(
|
|
45
|
+
bgioArguments,
|
|
46
|
+
resolved,
|
|
47
|
+
context,
|
|
48
|
+
key
|
|
49
|
+
)
|
|
50
|
+
: resolved;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function resolveProperty (
|
|
54
|
+
bgioArguments: BgioResolveState,
|
|
55
|
+
value: unknown,
|
|
56
|
+
context: Record<string, unknown>
|
|
57
|
+
): unknown {
|
|
58
|
+
const v = value as Record<string, unknown> | null;
|
|
59
|
+
if (v?.type === "expression") {
|
|
60
|
+
const expr = v as { expression: string; arguments?: unknown };
|
|
61
|
+
return resolveExpression(
|
|
62
|
+
bgioArguments,
|
|
63
|
+
{
|
|
64
|
+
...expr,
|
|
65
|
+
arguments: resolveProperties(bgioArguments, expr.arguments, context, "arguments"),
|
|
66
|
+
},
|
|
67
|
+
context
|
|
68
|
+
);
|
|
69
|
+
} else if (v?.type === "count") {
|
|
70
|
+
return bankOf(bgioArguments).findAll(
|
|
71
|
+
bgioArguments,
|
|
72
|
+
value,
|
|
73
|
+
context
|
|
74
|
+
).length;
|
|
75
|
+
} else if (v?.type === "contextPath") {
|
|
76
|
+
return get(context, v.path as Parameters<typeof get>[1]);
|
|
77
|
+
} else if (v?.type === "ctxPath") {
|
|
78
|
+
return get(bgioArguments.ctx, v.path as Parameters<typeof get>[1]);
|
|
79
|
+
} else if (v?.type === "gamePath") {
|
|
80
|
+
return get(bgioArguments.G, v.path as Parameters<typeof get>[1]);
|
|
81
|
+
} else if (v?.type === "relativePath" || v?.type === "RelativePath") {
|
|
82
|
+
const target = resolveProperties(bgioArguments, v.target, context, "target");
|
|
83
|
+
return get((target as { attributes?: unknown })?.attributes, v.path as Parameters<typeof get>[1]) ?? null;
|
|
84
|
+
} else if (v?.type === "parent" || v?.type === "Parent") {
|
|
85
|
+
const originalTarget = v.target
|
|
86
|
+
? resolveProperties(bgioArguments, v.target, context, "target")
|
|
87
|
+
: context.originalTarget;
|
|
88
|
+
return bankOf(bgioArguments).findParent(originalTarget) ?? null;
|
|
89
|
+
} else if (v?.type === "map") {
|
|
90
|
+
return getMappedTargets(
|
|
91
|
+
bgioArguments,
|
|
92
|
+
v.targets,
|
|
93
|
+
v.mapping,
|
|
94
|
+
context
|
|
95
|
+
).map((mappedTarget) => mappedTarget.value);
|
|
96
|
+
} else if (v?.type === "mapMax") {
|
|
97
|
+
const mappedTargets = getMappedTargets(
|
|
98
|
+
bgioArguments,
|
|
99
|
+
v.targets,
|
|
100
|
+
v.mapping,
|
|
101
|
+
context
|
|
102
|
+
);
|
|
103
|
+
let maxValue: number | undefined;
|
|
104
|
+
const maxTargets: unknown[] = [];
|
|
105
|
+
for (let i = 0, len = mappedTargets.length; i < len; i++) {
|
|
106
|
+
const { target, value: val } = mappedTargets[i];
|
|
107
|
+
if (maxValue === undefined || (val as number) > maxValue) {
|
|
108
|
+
maxValue = val as number;
|
|
109
|
+
maxTargets.length = 0;
|
|
110
|
+
maxTargets.push(target);
|
|
111
|
+
} else if (val === maxValue) {
|
|
112
|
+
maxTargets.push(target);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return maxTargets;
|
|
116
|
+
} else if (v?.type === "pick" || v?.type === "Pick") {
|
|
117
|
+
const target = resolveProperties(bgioArguments, v.target, context, "target");
|
|
118
|
+
return pick(
|
|
119
|
+
resolveProperties(
|
|
120
|
+
bgioArguments,
|
|
121
|
+
(target as { attributes?: unknown })?.attributes,
|
|
122
|
+
context,
|
|
123
|
+
"attributes"
|
|
124
|
+
) as object,
|
|
125
|
+
v.properties as string[]
|
|
126
|
+
);
|
|
127
|
+
} else if (v?.type === "coordinates" || v?.type === "Coordinates") {
|
|
128
|
+
const originalTarget = v.target
|
|
129
|
+
? resolveProperties(bgioArguments, v.target, context, "target")
|
|
130
|
+
: context.originalTarget;
|
|
131
|
+
const parent = bankOf(bgioArguments).findParent(originalTarget) as { getCoordinates: (i: unknown) => unknown };
|
|
132
|
+
return parent.getCoordinates((originalTarget as { rule: { index: unknown } }).rule.index);
|
|
133
|
+
} else if (v?.type === "relativeCoordinates") {
|
|
134
|
+
const originalTarget = v.target
|
|
135
|
+
? resolveProperties(bgioArguments, v.target, context, "target")
|
|
136
|
+
: context.originalTarget;
|
|
137
|
+
const parent = bankOf(bgioArguments).findParent(originalTarget) as {
|
|
138
|
+
getCoordinates: (i: unknown) => unknown;
|
|
139
|
+
getRelativeCoordinates: (a: unknown, b: unknown) => unknown;
|
|
140
|
+
spaces: unknown[];
|
|
141
|
+
getIndex: (c: unknown) => number;
|
|
142
|
+
};
|
|
143
|
+
const oldCoordinates =
|
|
144
|
+
parent.getCoordinates((originalTarget as { rule: { index: unknown } }).rule.index);
|
|
145
|
+
const newCoordinates =
|
|
146
|
+
parent.getRelativeCoordinates(
|
|
147
|
+
oldCoordinates,
|
|
148
|
+
resolveProperties(bgioArguments, v.location, context, "location")
|
|
149
|
+
);
|
|
150
|
+
return (newCoordinates && parent.spaces[parent.getIndex(newCoordinates)]) ?? null;
|
|
151
|
+
} else {
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function getMappedTargets (
|
|
157
|
+
bgioArguments: BgioResolveState,
|
|
158
|
+
targetsRule: unknown,
|
|
159
|
+
mapping: unknown,
|
|
160
|
+
context: Record<string, unknown>
|
|
161
|
+
): Array<{ target: unknown; value: unknown }> {
|
|
162
|
+
(targetsRule as { resolveAsEntity?: boolean }).resolveAsEntity = true;
|
|
163
|
+
const resolved = resolveProperties(bgioArguments, targetsRule, context) as unknown[] | undefined;
|
|
164
|
+
return resolved?.map((target) => ({
|
|
165
|
+
target,
|
|
166
|
+
value: resolveProperties(
|
|
167
|
+
bgioArguments,
|
|
168
|
+
mapping,
|
|
169
|
+
{ ...context, loopTarget: target },
|
|
170
|
+
),
|
|
171
|
+
})) ?? [];
|
|
172
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { serialize, deserialize } from "wackson";
|
|
2
|
+
import { registry } from "../registry.js";
|
|
3
|
+
import type { BgioResolveState } from "./bgio-resolve-types.js";
|
|
4
|
+
|
|
5
|
+
export default function simulateMove (
|
|
6
|
+
bgioArguments: BgioResolveState,
|
|
7
|
+
payload: { arguments: Record<string, { abstract?: boolean; entityId?: unknown } | number> },
|
|
8
|
+
context: { moveInstance: { doMove: (...args: unknown[]) => unknown } }
|
|
9
|
+
) {
|
|
10
|
+
const simulatedG = deserialize(serialize(bgioArguments.G) as string, registry) as {
|
|
11
|
+
bank: { locate: (id: unknown) => unknown };
|
|
12
|
+
};
|
|
13
|
+
const newBgioArguments = {
|
|
14
|
+
...bgioArguments,
|
|
15
|
+
G: simulatedG,
|
|
16
|
+
};
|
|
17
|
+
const simulatedPayload = { ...payload, arguments: {} as Record<string, unknown> };
|
|
18
|
+
Object.entries(payload.arguments).forEach(([argName, arg]) => {
|
|
19
|
+
simulatedPayload.arguments[argName] = (arg as { abstract?: boolean }).abstract
|
|
20
|
+
? arg
|
|
21
|
+
: simulatedG.bank.locate(typeof arg === "number" ? arg : (arg as { entityId: unknown }).entityId);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
context.moveInstance.doMove(
|
|
25
|
+
newBgioArguments,
|
|
26
|
+
simulatedPayload,
|
|
27
|
+
context,
|
|
28
|
+
{ skipCheck: true }
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
return simulatedG;
|
|
32
|
+
}
|
package/src/wackson.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"noEmit": false,
|
|
5
|
+
"emitDeclarationOnly": true,
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"declarationMap": true,
|
|
8
|
+
"outDir": "dist",
|
|
9
|
+
"rootDir": "src",
|
|
10
|
+
"stripInternal": true
|
|
11
|
+
},
|
|
12
|
+
"include": ["src/**/*.ts"],
|
|
13
|
+
"exclude": ["node_modules", "dist", "**/*.spec.ts", "e2e"]
|
|
14
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"lib": ["ES2020", "DOM"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noImplicitAny": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"noEmit": true,
|
|
11
|
+
"allowJs": false,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
|
+
"noUnusedLocals": true,
|
|
16
|
+
"noUnusedParameters": true,
|
|
17
|
+
"rootDir": "."
|
|
18
|
+
},
|
|
19
|
+
"include": ["src/**/*.ts", "src/**/*.d.ts"],
|
|
20
|
+
"exclude": ["node_modules", "dist"]
|
|
21
|
+
}
|