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
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { Client as BoardgameIOClient } from "@mnbroatch/boardgame.io/client";
|
|
2
|
+
import { Debug } from "@mnbroatch/boardgame.io/debug";
|
|
3
|
+
import { SocketIO } from "@mnbroatch/boardgame.io/multiplayer";
|
|
4
|
+
import { serialize, deserialize } from "wackson";
|
|
5
|
+
import gameFactory from "../game-factory/game-factory.js";
|
|
6
|
+
import type { BoardGameEngineGame, BgioArguments } from "../game-factory/game-factory.js";
|
|
7
|
+
import type { Condition, GameFactoryInput } from "../types/bagel-types.js";
|
|
8
|
+
import { registry } from "../registry.js";
|
|
9
|
+
import simulateMove from "../utils/simulate-move.js";
|
|
10
|
+
import getCurrentMoves from "../utils/get-current-moves.js";
|
|
11
|
+
import type { GetCurrentMovesClient, GetCurrentMovesState } from "../utils/get-current-moves.js";
|
|
12
|
+
import resolveProperties from "../utils/resolve-properties.js";
|
|
13
|
+
import type { BgioResolveState } from "../utils/bgio-resolve-types.js";
|
|
14
|
+
import checkConditions from "../utils/check-conditions.js";
|
|
15
|
+
import preparePayload from "../utils/prepare-payload.js";
|
|
16
|
+
import getSteps from "../utils/get-steps.js";
|
|
17
|
+
import createPayload from "../utils/create-payload.js";
|
|
18
|
+
|
|
19
|
+
export interface ClientOptions {
|
|
20
|
+
boardgameIOGame?: BoardGameEngineGame;
|
|
21
|
+
/** JSON string of a {@link GameFactoryInput} rule object */
|
|
22
|
+
gameRules?: string;
|
|
23
|
+
gameName?: string;
|
|
24
|
+
server?: string;
|
|
25
|
+
numPlayers?: number;
|
|
26
|
+
debug?: {
|
|
27
|
+
collapseOnLoad?: boolean;
|
|
28
|
+
impl?: typeof Debug;
|
|
29
|
+
};
|
|
30
|
+
matchID?: string;
|
|
31
|
+
playerID?: string | null;
|
|
32
|
+
credentials?: string;
|
|
33
|
+
multiplayer?: ReturnType<typeof SocketIO>;
|
|
34
|
+
onClientUpdate?: () => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface MoveBuilder {
|
|
38
|
+
targets: unknown[];
|
|
39
|
+
stepIndex: number;
|
|
40
|
+
eliminatedMoves: string[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class Client {
|
|
44
|
+
options: ClientOptions;
|
|
45
|
+
game: BoardGameEngineGame;
|
|
46
|
+
client?: ReturnType<typeof BoardgameIOClient>;
|
|
47
|
+
moveBuilder?: MoveBuilder;
|
|
48
|
+
optimisticWinner?: unknown | null;
|
|
49
|
+
|
|
50
|
+
constructor (options: ClientOptions) {
|
|
51
|
+
this.options = options;
|
|
52
|
+
this.game = options.boardgameIOGame
|
|
53
|
+
|| gameFactory(JSON.parse(options.gameRules as string) as GameFactoryInput, options.gameName ?? "");
|
|
54
|
+
|
|
55
|
+
if (!options.boardgameIOGame) {
|
|
56
|
+
this.moveBuilder = { targets: [], stepIndex: 0, eliminatedMoves: [] };
|
|
57
|
+
this.optimisticWinner = null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
connect () {
|
|
62
|
+
const {
|
|
63
|
+
server,
|
|
64
|
+
numPlayers,
|
|
65
|
+
debug = {
|
|
66
|
+
collapseOnLoad: true,
|
|
67
|
+
impl: Debug,
|
|
68
|
+
},
|
|
69
|
+
matchID,
|
|
70
|
+
playerID,
|
|
71
|
+
credentials,
|
|
72
|
+
multiplayer = SocketIO({ server, socketOpts: { transports: ["websocket", "polling"] } }),
|
|
73
|
+
} = this.options;
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const clientOptions = !credentials
|
|
77
|
+
? { game: this.game, numPlayers, debug }
|
|
78
|
+
: {
|
|
79
|
+
game: this.game,
|
|
80
|
+
multiplayer,
|
|
81
|
+
matchID,
|
|
82
|
+
playerID: playerID ?? undefined,
|
|
83
|
+
credentials,
|
|
84
|
+
numPlayers,
|
|
85
|
+
debug,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
this.client = BoardgameIOClient(clientOptions as Parameters<typeof BoardgameIOClient>[0]);
|
|
89
|
+
this.client.subscribe(() => this.update());
|
|
90
|
+
this.client.start();
|
|
91
|
+
return this;
|
|
92
|
+
} catch (error: unknown) {
|
|
93
|
+
const err = error as { message?: string; stack?: string };
|
|
94
|
+
console.error("Failed to join game:", err?.message ?? error);
|
|
95
|
+
if (err?.stack) console.error(err.stack);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
update () {
|
|
100
|
+
this.options.onClientUpdate?.();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
getState () {
|
|
104
|
+
const bgioState = this.client?.getState();
|
|
105
|
+
if (!bgioState) return {};
|
|
106
|
+
|
|
107
|
+
const state = this.options.boardgameIOGame
|
|
108
|
+
? bgioState
|
|
109
|
+
: {
|
|
110
|
+
...bgioState,
|
|
111
|
+
G: deserialize(JSON.stringify(bgioState.G), registry),
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const gameover = this.optimisticWinner ?? state?.ctx?.gameover;
|
|
115
|
+
|
|
116
|
+
const currentMoves = gameover
|
|
117
|
+
? []
|
|
118
|
+
: getCurrentMoves(state as GetCurrentMovesState, this.client as GetCurrentMovesClient);
|
|
119
|
+
|
|
120
|
+
if (this.options.boardgameIOGame) {
|
|
121
|
+
return {
|
|
122
|
+
state,
|
|
123
|
+
gameover,
|
|
124
|
+
moves: this.client!.moves,
|
|
125
|
+
currentMoves,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const _wrappedMoves = Object.entries(currentMoves)
|
|
130
|
+
.reduce<Record<string, unknown>>((acc, [moveName, rawMove]) => {
|
|
131
|
+
const move = (payload: unknown) => {
|
|
132
|
+
this.client!.moves[moveName](preparePayload(payload));
|
|
133
|
+
};
|
|
134
|
+
(move as { moveInstance?: unknown }).moveInstance = (rawMove as { moveInstance: unknown }).moveInstance;
|
|
135
|
+
return { ...acc, [moveName]: move };
|
|
136
|
+
}, {});
|
|
137
|
+
|
|
138
|
+
const { allClickable, _possibleMoveMeta } = getPossibleMoves(state, _wrappedMoves, this.moveBuilder!);
|
|
139
|
+
|
|
140
|
+
return { state, gameover, allClickable, _wrappedMoves, _possibleMoveMeta };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
doStep (_target: unknown) {
|
|
144
|
+
if (this.options.boardgameIOGame) return;
|
|
145
|
+
|
|
146
|
+
const { state, _wrappedMoves, _possibleMoveMeta } = this.getState() as {
|
|
147
|
+
state: { G: { bank: { locate: (id: unknown) => unknown } } };
|
|
148
|
+
_wrappedMoves: Record<string, { (p: unknown): void; moveInstance: unknown }>;
|
|
149
|
+
_possibleMoveMeta: Record<string, { clickableForMove: Set<unknown> }>;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const target = (_target as { abstract?: boolean; entityId?: unknown; value?: unknown }).abstract
|
|
153
|
+
? _target
|
|
154
|
+
: state.G.bank.locate((_target as { entityId: unknown }).entityId);
|
|
155
|
+
|
|
156
|
+
const newEliminated = Object.entries(_possibleMoveMeta)
|
|
157
|
+
.filter(([_, meta]) => !hasTarget(meta.clickableForMove, target))
|
|
158
|
+
.map(([name]) => name)
|
|
159
|
+
.concat(this.moveBuilder!.eliminatedMoves);
|
|
160
|
+
|
|
161
|
+
if (newEliminated.length === Object.keys(_wrappedMoves).length) {
|
|
162
|
+
console.error("invalid move with target:", (target as { rule?: unknown })?.rule);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const remainingMoveEntries = Object.entries(_possibleMoveMeta)
|
|
167
|
+
.filter(([name]) => !newEliminated.includes(name));
|
|
168
|
+
|
|
169
|
+
if (isMoveCompleted(
|
|
170
|
+
state,
|
|
171
|
+
_wrappedMoves as Record<string, { moveInstance: { rule: unknown } }>,
|
|
172
|
+
remainingMoveEntries,
|
|
173
|
+
this.moveBuilder!.stepIndex
|
|
174
|
+
)) {
|
|
175
|
+
const [moveName] = remainingMoveEntries[0];
|
|
176
|
+
const move = _wrappedMoves[moveName];
|
|
177
|
+
const payload = createPayload(
|
|
178
|
+
state as unknown as BgioResolveState,
|
|
179
|
+
(move as { moveInstance: { rule: Parameters<typeof getSteps>[1] } }).moveInstance.rule,
|
|
180
|
+
[...this.moveBuilder!.targets, target],
|
|
181
|
+
{ moveInstance: (move as { moveInstance: unknown }).moveInstance }
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
this.optimisticWinner = getWinnerAfterMove(state, this.game, (move as { moveInstance: unknown }).moveInstance, payload);
|
|
185
|
+
move(payload);
|
|
186
|
+
this.moveBuilder = { targets: [], stepIndex: 0, eliminatedMoves: [] };
|
|
187
|
+
} else {
|
|
188
|
+
this.moveBuilder = {
|
|
189
|
+
eliminatedMoves: newEliminated,
|
|
190
|
+
stepIndex: this.moveBuilder!.stepIndex + 1,
|
|
191
|
+
targets: [...this.moveBuilder!.targets, target],
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
this.update();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
reset () {
|
|
199
|
+
if (this.options.boardgameIOGame) return;
|
|
200
|
+
this.moveBuilder = { targets: [], stepIndex: 0, eliminatedMoves: [] };
|
|
201
|
+
this.optimisticWinner = null;
|
|
202
|
+
this.update();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
undoStep () {
|
|
206
|
+
if (this.options.boardgameIOGame) return;
|
|
207
|
+
if (this.moveBuilder!.targets.length) {
|
|
208
|
+
this.moveBuilder = {
|
|
209
|
+
targets: this.moveBuilder!.targets.slice(0, -1),
|
|
210
|
+
stepIndex: Math.max(0, this.moveBuilder!.stepIndex - 1),
|
|
211
|
+
eliminatedMoves: [],
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
this.update();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function hasTarget (clickableSet: Set<unknown>, target: unknown) {
|
|
219
|
+
if (!(target as { abstract?: boolean }).abstract) return clickableSet.has(target);
|
|
220
|
+
return [...clickableSet].some((item) => (item as { abstract?: boolean; value?: unknown }).abstract && (item as { value: unknown }).value === (target as { value: unknown }).value);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function getPossibleMoves (
|
|
224
|
+
bgioState: unknown,
|
|
225
|
+
moves: Record<string, unknown>,
|
|
226
|
+
moveBuilder: MoveBuilder
|
|
227
|
+
) {
|
|
228
|
+
const { eliminatedMoves, stepIndex } = moveBuilder;
|
|
229
|
+
const _possibleMoveMeta: Record<string, { clickableForMove: Set<unknown> }> = {};
|
|
230
|
+
const allClickable = new Set<unknown>();
|
|
231
|
+
|
|
232
|
+
Object.entries(moves)
|
|
233
|
+
.filter(([moveName]) => !eliminatedMoves.includes(moveName))
|
|
234
|
+
.forEach(([moveName, move]) => {
|
|
235
|
+
const moveRule = resolveProperties(bgioState as BgioResolveState, {
|
|
236
|
+
...(move as { moveInstance: { rule: Record<string, unknown> } }).moveInstance.rule,
|
|
237
|
+
moveName,
|
|
238
|
+
}) as { arguments?: Record<string, unknown> };
|
|
239
|
+
|
|
240
|
+
const context = {
|
|
241
|
+
moveInstance: (move as { moveInstance: unknown }).moveInstance,
|
|
242
|
+
moveArguments: moveRule.arguments,
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
const targets = moveBuilder.targets.map((t) =>
|
|
246
|
+
(t as { abstract?: boolean }).abstract ? t : (bgioState as { G: { bank: { locate: (id: unknown) => unknown } } }).G.bank.locate((t as { entityId: unknown }).entityId)
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
const payload = createPayload(
|
|
250
|
+
bgioState as BgioResolveState,
|
|
251
|
+
moveRule as Parameters<typeof getSteps>[1],
|
|
252
|
+
targets,
|
|
253
|
+
context
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
context.moveArguments = { ...context.moveArguments, ...payload.arguments };
|
|
257
|
+
|
|
258
|
+
const moveIsAllowed = checkConditions(
|
|
259
|
+
bgioState as BgioResolveState,
|
|
260
|
+
(moveRule as { conditions?: Condition[] }).conditions,
|
|
261
|
+
{},
|
|
262
|
+
context
|
|
263
|
+
).conditionsAreMet;
|
|
264
|
+
const moveSteps = getSteps(
|
|
265
|
+
bgioState as BgioResolveState,
|
|
266
|
+
moveRule as Parameters<typeof getSteps>[1]
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
const clickableForMove = new Set(
|
|
270
|
+
(moveIsAllowed && moveSteps?.[stepIndex]?.getClickable(context)) || []
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
_possibleMoveMeta[moveName] = { clickableForMove };
|
|
274
|
+
clickableForMove.forEach((entity) => allClickable.add(entity));
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
return { _possibleMoveMeta, allClickable };
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function isMoveCompleted (
|
|
281
|
+
state: unknown,
|
|
282
|
+
moves: Record<string, { moveInstance: { rule: unknown } }>,
|
|
283
|
+
remainingMoveEntries: [string, unknown][],
|
|
284
|
+
stepIndex: number
|
|
285
|
+
) {
|
|
286
|
+
return remainingMoveEntries.length === 1 &&
|
|
287
|
+
getSteps(
|
|
288
|
+
state as BgioResolveState,
|
|
289
|
+
moves[remainingMoveEntries[0][0]].moveInstance.rule as Parameters<typeof getSteps>[1]
|
|
290
|
+
).length === stepIndex + 1;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function getWinnerAfterMove (
|
|
294
|
+
state: unknown,
|
|
295
|
+
game: BoardGameEngineGame,
|
|
296
|
+
moveInstance: unknown,
|
|
297
|
+
movePayload: unknown
|
|
298
|
+
) {
|
|
299
|
+
const simulatedG = simulateMove(
|
|
300
|
+
state as unknown as BgioResolveState,
|
|
301
|
+
preparePayload(movePayload) as { arguments: Record<string, number | { abstract?: boolean; entityId?: unknown }> },
|
|
302
|
+
{ moveInstance: moveInstance as { doMove: (...args: unknown[]) => unknown } }
|
|
303
|
+
);
|
|
304
|
+
const endIf = game.endIf as ((ctx: BgioArguments) => unknown) | undefined;
|
|
305
|
+
return endIf?.({ ...state as object, G: JSON.parse(serialize(simulatedG)) } as BgioArguments);
|
|
306
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import resolveProperties from "../../utils/resolve-properties.js";
|
|
2
|
+
import type { BgioResolveState } from "../../utils/bgio-resolve-types.js";
|
|
3
|
+
|
|
4
|
+
class BankSlot {
|
|
5
|
+
bank: { createEntity: (rule: Record<string, unknown>) => unknown };
|
|
6
|
+
rule: Record<string, unknown> & { count?: number | string; name?: string };
|
|
7
|
+
pool: unknown[];
|
|
8
|
+
remaining: number;
|
|
9
|
+
|
|
10
|
+
constructor (rule: Record<string, unknown> & { count?: number | string; name?: string }, bank: BankSlot["bank"]) {
|
|
11
|
+
this.bank = bank;
|
|
12
|
+
this.rule = rule;
|
|
13
|
+
this.pool = [];
|
|
14
|
+
this.remaining = +((rule.count as number | string) || 1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
getOne (bgioArguments: BgioResolveState, options: { state?: unknown }, context: Record<string, unknown>) {
|
|
18
|
+
return this.getMultiple(bgioArguments, 1, options, context)[0];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
getMultiple (
|
|
22
|
+
bgioArguments: BgioResolveState,
|
|
23
|
+
count: number = Infinity,
|
|
24
|
+
options: { state?: unknown } = {},
|
|
25
|
+
context: Record<string, unknown> = {}
|
|
26
|
+
) {
|
|
27
|
+
const toReturn: unknown[] = [];
|
|
28
|
+
|
|
29
|
+
if (this.remaining === Infinity && count === Infinity) {
|
|
30
|
+
throw new Error(`Cannot get infinite pieces from slot with infinite remaining: ${this.rule.name}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (count !== Infinity && count > this.remaining) {
|
|
34
|
+
throw new Error(`Requested ${count} pieces but only ${this.remaining} available in slot: ${this.rule.name}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const actualCount = count === Infinity ? this.remaining : count;
|
|
38
|
+
|
|
39
|
+
if (this.remaining !== Infinity) {
|
|
40
|
+
this.remaining -= actualCount;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const fromPool = Math.min(actualCount, this.pool.length);
|
|
44
|
+
toReturn.push(...this.pool.splice(0, fromPool));
|
|
45
|
+
|
|
46
|
+
const remainder = actualCount - fromPool;
|
|
47
|
+
if (remainder > 0) {
|
|
48
|
+
toReturn.push(
|
|
49
|
+
...Array.from(new Array(remainder)).map(() =>
|
|
50
|
+
this.bank.createEntity(this.rule)
|
|
51
|
+
)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (options.state) {
|
|
56
|
+
const newState = resolveProperties(bgioArguments, options.state, context);
|
|
57
|
+
toReturn.forEach((entity) => {
|
|
58
|
+
(entity as { state: Record<string, unknown> }).state = {
|
|
59
|
+
...(entity as { state: Record<string, unknown> }).state,
|
|
60
|
+
...newState as Record<string, unknown>,
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return toReturn;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
returnToBank (entity: { rule: { state?: unknown }; state?: unknown }) {
|
|
69
|
+
if (entity.rule.state) {
|
|
70
|
+
entity.state = entity.rule.state;
|
|
71
|
+
} else {
|
|
72
|
+
delete entity.state;
|
|
73
|
+
}
|
|
74
|
+
if (this.remaining !== undefined) {
|
|
75
|
+
this.remaining += 1;
|
|
76
|
+
}
|
|
77
|
+
this.pool.push(entity);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default BankSlot;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import find from "lodash/find.js";
|
|
2
|
+
import filter from "lodash/filter.js";
|
|
3
|
+
import checkConditions from "../../utils/check-conditions.js";
|
|
4
|
+
import type { RuleWithConditions } from "../../types/rule-with-conditions.js";
|
|
5
|
+
import { registry } from "../../registry.js";
|
|
6
|
+
import BankSlot from "./bank-slot.js";
|
|
7
|
+
import type { BgioResolveState } from "../../utils/bgio-resolve-types.js";
|
|
8
|
+
|
|
9
|
+
class Bank {
|
|
10
|
+
currentEntityId: number;
|
|
11
|
+
tracker: Record<number, unknown>;
|
|
12
|
+
slots: InstanceType<typeof BankSlot>[];
|
|
13
|
+
|
|
14
|
+
constructor (entityRules: Record<string, unknown>[]) {
|
|
15
|
+
this.currentEntityId = 0;
|
|
16
|
+
this.tracker = {};
|
|
17
|
+
this.slots = entityRules.map((rule) => new BankSlot(rule, this));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
createEntity (definition: Record<string, unknown> = {}, options?: Record<string, unknown>) {
|
|
21
|
+
const Ctor = registry[(definition.entityType || "Entity") as keyof typeof registry] as new (
|
|
22
|
+
a: unknown,
|
|
23
|
+
b: Record<string, unknown>,
|
|
24
|
+
c: number
|
|
25
|
+
) => unknown;
|
|
26
|
+
const entity = new Ctor(
|
|
27
|
+
{
|
|
28
|
+
bank: this,
|
|
29
|
+
fromBank: true,
|
|
30
|
+
...options,
|
|
31
|
+
},
|
|
32
|
+
definition,
|
|
33
|
+
this.currentEntityId++
|
|
34
|
+
);
|
|
35
|
+
this.track(entity as { entityId: number });
|
|
36
|
+
return entity;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
track (entity: { entityId: number }) {
|
|
40
|
+
this.tracker[entity.entityId] = entity;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
locate (entityId: unknown) {
|
|
44
|
+
return this.tracker[entityId as number];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
findAll (bgioArguments: BgioResolveState, rule: RuleWithConditions, context: Record<string, unknown>) {
|
|
48
|
+
if (!rule.conditions) {
|
|
49
|
+
throw new Error(`Cannot find entity with no conditions. Rule: ${JSON.stringify(rule)}`);
|
|
50
|
+
}
|
|
51
|
+
return filter(
|
|
52
|
+
Object.values(this.tracker),
|
|
53
|
+
(entity) => checkConditions(
|
|
54
|
+
bgioArguments,
|
|
55
|
+
rule.conditions,
|
|
56
|
+
{ target: entity },
|
|
57
|
+
context
|
|
58
|
+
).conditionsAreMet
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
findOne (bgioArguments: BgioResolveState, rule: RuleWithConditions, context: Record<string, unknown>) {
|
|
63
|
+
return this.findAll(bgioArguments, rule, context)[0];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
find (bgioArguments: BgioResolveState, rule: RuleWithConditions & { matchMultiple?: boolean }, context: Record<string, unknown>) {
|
|
67
|
+
return rule.matchMultiple
|
|
68
|
+
? this.findAll(bgioArguments, rule, context)
|
|
69
|
+
: this.findOne(bgioArguments, rule, context);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
findParent (entity: unknown) {
|
|
73
|
+
return find(this.tracker, (ent) =>
|
|
74
|
+
(ent as { entities?: unknown[] }).entities?.includes(entity)
|
|
75
|
+
|| (ent as { spaces?: unknown[] }).spaces?.includes(entity)
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
getOne (bgioArguments: BgioResolveState, rule: RuleWithConditions & { state?: unknown }, context: Record<string, unknown>) {
|
|
80
|
+
const slot = this.getSlot(bgioArguments, rule, context);
|
|
81
|
+
if (!slot) {
|
|
82
|
+
console.error(`No matching slot for ${JSON.stringify(rule)}`);
|
|
83
|
+
}
|
|
84
|
+
return slot!.getOne(bgioArguments, { state: rule.state }, context);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
getMultiple (bgioArguments: BgioResolveState, rule: RuleWithConditions & { state?: unknown }, count: number, context: Record<string, unknown>) {
|
|
88
|
+
const slots = this.getSlots(bgioArguments, rule, context);
|
|
89
|
+
if (!slots.length) {
|
|
90
|
+
console.error(`No matching slots for ${JSON.stringify(rule)}`);
|
|
91
|
+
}
|
|
92
|
+
return slots.reduce<unknown[]>((acc, slot) => [
|
|
93
|
+
...acc,
|
|
94
|
+
...slot.getMultiple(bgioArguments, count, { state: rule.state }),
|
|
95
|
+
], []);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
getSlot (bgioArguments: BgioResolveState, rule: RuleWithConditions, context: Record<string, unknown>) {
|
|
99
|
+
return this.slots.find((slot) => checkConditions(
|
|
100
|
+
bgioArguments,
|
|
101
|
+
rule.conditions,
|
|
102
|
+
{ target: slot },
|
|
103
|
+
context
|
|
104
|
+
).conditionsAreMet
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
getSlots (bgioArguments: BgioResolveState, rule: RuleWithConditions, context: Record<string, unknown>) {
|
|
109
|
+
return this.slots.filter((slot) => checkConditions(
|
|
110
|
+
bgioArguments,
|
|
111
|
+
rule.conditions,
|
|
112
|
+
{ target: slot },
|
|
113
|
+
context
|
|
114
|
+
).conditionsAreMet
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
returnToBank (bgioArguments: BgioResolveState, entity: { entityId: number; rule: Record<string, unknown> }) {
|
|
119
|
+
(this.findParent(entity) as { remove: (e: unknown) => void }).remove(entity);
|
|
120
|
+
this.getSlot(bgioArguments, entity.rule as RuleWithConditions, {})!.returnToBank(entity);
|
|
121
|
+
delete this.tracker[entity.entityId];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export default Bank;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Condition as ConditionRule } from "../../types/bagel-types.js";
|
|
2
|
+
import type ConditionBase from "./condition.js";
|
|
3
|
+
import Is from "./is-condition.js";
|
|
4
|
+
import Not from "./not-condition.js";
|
|
5
|
+
import Or from "./or-condition.js";
|
|
6
|
+
import Some from "./some-condition.js";
|
|
7
|
+
import Every from "./every-condition.js";
|
|
8
|
+
import ContainsCondition from "./contains-condition.js";
|
|
9
|
+
import ContainsSameCondition from "./contains-same-condition.js";
|
|
10
|
+
import InLine from "./in-line-condition.js";
|
|
11
|
+
import HasLine from "./has-line-condition.js";
|
|
12
|
+
import IsFull from "./is-full-condition.js";
|
|
13
|
+
import Would from "./would-condition.js";
|
|
14
|
+
import NoPossibleMoves from "./no-possible-moves-condition.js";
|
|
15
|
+
import Evaluate from "./evaluate-condition.js";
|
|
16
|
+
import Position from "./position-condition.js";
|
|
17
|
+
// import BingoCondition from "./bingo-condition.js";
|
|
18
|
+
// import RelativeMoveCondition from "./relative-move-condition.js";
|
|
19
|
+
|
|
20
|
+
export default function conditionFactory (rule: ConditionRule): ConditionBase | undefined {
|
|
21
|
+
if (typeof rule !== "object" || rule === null || !("conditionType" in rule)) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
const r = rule as { conditionType: string; [k: string]: unknown };
|
|
25
|
+
if (r.conditionType === "Is") {
|
|
26
|
+
return new Is(r);
|
|
27
|
+
} else if (r.conditionType === "Not") {
|
|
28
|
+
return new Not(r);
|
|
29
|
+
} else if (r.conditionType === "Or") {
|
|
30
|
+
return new Or(r);
|
|
31
|
+
} else if (r.conditionType === "Some") {
|
|
32
|
+
return new Some(r);
|
|
33
|
+
} else if (r.conditionType === "Contains") {
|
|
34
|
+
return new ContainsCondition(r);
|
|
35
|
+
} else if (r.conditionType === "ContainsSame") {
|
|
36
|
+
return new ContainsSameCondition(r);
|
|
37
|
+
} else if (r.conditionType === "Every") {
|
|
38
|
+
return new Every(r);
|
|
39
|
+
} else if (r.conditionType === "InLine") {
|
|
40
|
+
return new InLine(r);
|
|
41
|
+
} else if (r.conditionType === "HasLine") {
|
|
42
|
+
return new HasLine(r);
|
|
43
|
+
} else if (r.conditionType === "IsFull") {
|
|
44
|
+
return new IsFull(r);
|
|
45
|
+
} else if (r.conditionType === "Would") {
|
|
46
|
+
return new Would(r);
|
|
47
|
+
} else if (r.conditionType === "NoPossibleMoves") {
|
|
48
|
+
return new NoPossibleMoves(r);
|
|
49
|
+
} else if (r.conditionType === "Evaluate") {
|
|
50
|
+
return new Evaluate(r);
|
|
51
|
+
} else if (r.conditionType === "Position") {
|
|
52
|
+
return new Position(r);
|
|
53
|
+
// } else if (rule.conditionType === "bingo") {
|
|
54
|
+
// return new BingoCondition(rule);
|
|
55
|
+
// } else if (rule.conditionType === "relativeMove") {
|
|
56
|
+
// return new RelativeMoveCondition(rule);
|
|
57
|
+
}
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import resolveProperties from "../../utils/resolve-properties.js";
|
|
2
|
+
import type { BgioResolveState } from "../../utils/bgio-resolve-types.js";
|
|
3
|
+
|
|
4
|
+
export default abstract class Condition {
|
|
5
|
+
rule: unknown;
|
|
6
|
+
|
|
7
|
+
constructor (rule: unknown) {
|
|
8
|
+
this.rule = rule;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
check (bgioArguments: unknown, payload: Record<string, unknown>, context: Record<string, unknown>) {
|
|
12
|
+
const conditionPayload = { ...payload };
|
|
13
|
+
const newContext = { ...context };
|
|
14
|
+
|
|
15
|
+
if (conditionPayload.target) {
|
|
16
|
+
newContext.originalTarget = conditionPayload.target;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const rule = resolveProperties(
|
|
20
|
+
bgioArguments as BgioResolveState,
|
|
21
|
+
this.rule,
|
|
22
|
+
newContext
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
if ((rule as { target?: unknown }).target !== undefined) {
|
|
26
|
+
conditionPayload.target = (rule as { target: unknown }).target;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if ((this.rule as { target?: unknown }).target !== undefined && !conditionPayload.target) {
|
|
30
|
+
return { conditionIsMet: false };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return this.checkCondition(bgioArguments, rule, conditionPayload, newContext);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
abstract checkCondition (
|
|
37
|
+
bgioArguments: unknown,
|
|
38
|
+
rule: unknown,
|
|
39
|
+
conditionPayload: Record<string, unknown>,
|
|
40
|
+
newContext: Record<string, unknown>
|
|
41
|
+
): { conditionIsMet: boolean; [k: string]: unknown };
|
|
42
|
+
|
|
43
|
+
isMet (...args: unknown[]) {
|
|
44
|
+
return (this.check as (a: unknown, b: Record<string, unknown>, c: Record<string, unknown>) => { conditionIsMet: boolean })(
|
|
45
|
+
args[0],
|
|
46
|
+
(args[1] as Record<string, unknown>) ?? {},
|
|
47
|
+
(args[2] as Record<string, unknown>) ?? {}
|
|
48
|
+
).conditionIsMet;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import _matches from "lodash/matches.js";
|
|
2
|
+
import type { Condition as ConditionRule } from "../../types/bagel-types.js";
|
|
2
3
|
import Condition from "../condition/condition.js";
|
|
3
4
|
import checkConditions from "../../utils/check-conditions.js";
|
|
4
5
|
|
|
5
6
|
export default class ContainsCondition extends Condition {
|
|
6
|
-
checkCondition(bgioArguments, rule, payload, context) {
|
|
7
|
-
const
|
|
7
|
+
checkCondition (bgioArguments: unknown, rule: unknown, payload: Record<string, unknown>, context: Record<string, unknown>) {
|
|
8
|
+
const target = payload.target as { entities?: unknown[]; spaces?: unknown[] } | undefined;
|
|
8
9
|
if (!target) {
|
|
9
10
|
return { matches: [], conditionIsMet: false }
|
|
10
11
|
} else {
|
|
11
12
|
const candidates = target.entities ?? target.spaces
|
|
12
|
-
const matches = candidates?.filter(entity => checkConditions(
|
|
13
|
+
const matches = candidates?.filter((entity: unknown) => checkConditions(
|
|
13
14
|
bgioArguments,
|
|
14
|
-
rule,
|
|
15
|
+
(rule as { conditions?: ConditionRule[] }).conditions,
|
|
15
16
|
{ target: entity },
|
|
16
17
|
context
|
|
17
18
|
).conditionsAreMet) ?? []
|
package/src/game-factory/condition/{contains-same-condition.js → contains-same-condition.ts}
RENAMED
|
@@ -3,21 +3,24 @@ import conditionFactory from "./condition-factory.js";
|
|
|
3
3
|
import Condition from "./condition.js";
|
|
4
4
|
|
|
5
5
|
export default class ContainsSame extends Condition {
|
|
6
|
-
checkCondition (bgioArguments, rule,
|
|
6
|
+
checkCondition (bgioArguments: unknown, rule: unknown, conditionPayload: Record<string, unknown>, _newContext: Record<string, unknown>) {
|
|
7
|
+
const { targets } = conditionPayload as { targets: { entities?: unknown[]; rule?: unknown }[] };
|
|
7
8
|
if (targets.length === 1 && targets[0].entities?.length) {
|
|
8
9
|
return { conditionIsMet: true }
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
const [ first, ...restEntities ] = targets;
|
|
12
|
-
const conditionIsMet = first.entities.some(entity => {
|
|
13
|
+
const conditionIsMet = (first.entities ?? []).some((entity: unknown) => {
|
|
14
|
+
const e = entity as { rule?: unknown };
|
|
13
15
|
const condition = conditionFactory({
|
|
14
16
|
conditionType: "Contains",
|
|
15
17
|
conditions: [{
|
|
16
18
|
conditionType: 'Is',
|
|
17
|
-
matcher: pick(
|
|
19
|
+
matcher: pick(e.rule as object, (rule as { properties: unknown }).properties as never)
|
|
18
20
|
}]
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
+
});
|
|
22
|
+
if (!condition) return false;
|
|
23
|
+
return restEntities.every((ent: unknown) => {
|
|
21
24
|
return condition.isMet(bgioArguments, { target: ent })
|
|
22
25
|
})
|
|
23
26
|
})
|