board-game-engine 2.0.0 → 2.1.0
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/README.md +2 -2
- 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/e2e/fixtures/bge-checkers.html +1 -2
- package/e2e/fixtures/bge-minimal.html +1 -2
- package/e2e/fixtures/bge-ttt.html +1 -2
- package/examples/index.html +1 -1
- package/package.json +9 -3
- package/playwright-report/index.html +1 -1
- package/scripts/build.mjs +2 -2
- package/src/client/client.ts +305 -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,18 @@
|
|
|
1
|
+
import Move from "./move.js";
|
|
2
|
+
|
|
3
|
+
export default class MoveEntity extends Move {
|
|
4
|
+
do (bgioArguments: unknown, rule: { position?: unknown }, resolvedPayload: unknown) {
|
|
5
|
+
const { entity, destination } = (resolvedPayload as { arguments: { entity: unknown; destination: unknown } }).arguments;
|
|
6
|
+
// todo: move all such things to always be multiple
|
|
7
|
+
const g = bgioArguments as { G: { bank: { findParent: (e: unknown) => { remove: (x: unknown) => void } | undefined } } };
|
|
8
|
+
if (Array.isArray(entity)) {
|
|
9
|
+
entity.forEach((e: unknown) => {
|
|
10
|
+
g.G.bank.findParent(e)?.remove(e);
|
|
11
|
+
(destination as { placeEntity: (e: unknown, p?: unknown) => void }).placeEntity(e, rule.position);
|
|
12
|
+
});
|
|
13
|
+
} else {
|
|
14
|
+
g.G.bank.findParent(entity)?.remove(entity);
|
|
15
|
+
(destination as { placeEntity: (e: unknown, p?: unknown) => void }).placeEntity(entity, rule.position);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { serialize, deserialize } from 'wackson'
|
|
2
|
+
import { INVALID_MOVE } from '@mnbroatch/boardgame.io/dist/cjs/core.js';
|
|
3
|
+
import { registry } from '../../registry.js'
|
|
4
|
+
import deserializeBgioArguments from '../../utils/deserialize-bgio-arguments.js'
|
|
5
|
+
import MoveEntity from "./move-entity.js";
|
|
6
|
+
import RemoveEntity from "./remove-entity.js";
|
|
7
|
+
import PlaceNew from "./place-new.js";
|
|
8
|
+
import TakeFrom from "./take-from.js";
|
|
9
|
+
import SetState from "./set-state.js";
|
|
10
|
+
import SetActivePlayers from "./set-active-players.js";
|
|
11
|
+
import EndTurn from "./end-turn.js";
|
|
12
|
+
import PassTurn from "./pass-turn.js";
|
|
13
|
+
import ForEach from "./for-each.js";
|
|
14
|
+
import Pass from "./pass.js";
|
|
15
|
+
import Shuffle from "./shuffle.js";
|
|
16
|
+
import type { MoveDefinition } from "../../types/bagel-types.js";
|
|
17
|
+
import type { BgioResolveState } from "../../utils/bgio-resolve-types.js";
|
|
18
|
+
import type Move from "./move.js";
|
|
19
|
+
|
|
20
|
+
type MoveFactoryContext = {
|
|
21
|
+
moveInstance: Move;
|
|
22
|
+
game: unknown;
|
|
23
|
+
moveConditionResults?: unknown[];
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default function moveFactory (moveRule: MoveDefinition, game: unknown) {
|
|
27
|
+
const moveInstance = getMoveInstance(moveRule);
|
|
28
|
+
if (!moveInstance) {
|
|
29
|
+
throw new Error("moveFactory: unknown moveType");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// accepts serialized G and payload, returns serialized
|
|
33
|
+
const compatibleMove = function (
|
|
34
|
+
bgioArguments: unknown,
|
|
35
|
+
serializablePayload: unknown
|
|
36
|
+
) {
|
|
37
|
+
const newBgioArguments = deserializeBgioArguments(bgioArguments as BgioResolveState);
|
|
38
|
+
const { G } = newBgioArguments;
|
|
39
|
+
const payload = revivePayload(serializablePayload, G as { bank: { locate: (id: number) => unknown } });
|
|
40
|
+
const context: MoveFactoryContext = { moveInstance, game };
|
|
41
|
+
const moveConditionResults = moveInstance.doMove(newBgioArguments, payload, context);
|
|
42
|
+
|
|
43
|
+
context.moveConditionResults = [moveConditionResults];
|
|
44
|
+
|
|
45
|
+
if (moveConditionResults !== INVALID_MOVE && moveRule.then) {
|
|
46
|
+
for (const automaticMoveRule of moveRule.then) {
|
|
47
|
+
const auto = getMoveInstance(automaticMoveRule);
|
|
48
|
+
if (!auto) continue;
|
|
49
|
+
const result = auto.doMove(
|
|
50
|
+
newBgioArguments,
|
|
51
|
+
{},
|
|
52
|
+
{ ...context } // spread here so prevArguments doesn't change for sibling
|
|
53
|
+
);
|
|
54
|
+
context.moveConditionResults!.push(result);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return JSON.parse(serialize(G));
|
|
59
|
+
};
|
|
60
|
+
compatibleMove.moveInstance = moveInstance;
|
|
61
|
+
return compatibleMove;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function revivePayload (
|
|
65
|
+
serializablePayload: unknown,
|
|
66
|
+
G: { bank: { locate: (id: number) => unknown } }
|
|
67
|
+
): { arguments?: Record<string, unknown> } | undefined {
|
|
68
|
+
if (!serializablePayload) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
const payload = deserialize(JSON.stringify(serializablePayload), registry) as {
|
|
72
|
+
arguments: Record<string, unknown>;
|
|
73
|
+
};
|
|
74
|
+
payload.arguments =
|
|
75
|
+
Object.entries(payload.arguments).reduce<Record<string, unknown>>((acc, [key, argOrEntityId]) => ({
|
|
76
|
+
...acc,
|
|
77
|
+
[key]: typeof argOrEntityId === "number" ? G.bank.locate(argOrEntityId as number) : argOrEntityId
|
|
78
|
+
}), {});
|
|
79
|
+
return payload;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function getMoveInstance (moveRule: MoveDefinition) {
|
|
83
|
+
switch (moveRule.moveType) {
|
|
84
|
+
case 'MoveEntity':
|
|
85
|
+
return new MoveEntity(moveRule);
|
|
86
|
+
case 'PlaceNew':
|
|
87
|
+
return new PlaceNew(moveRule);
|
|
88
|
+
case 'RemoveEntity':
|
|
89
|
+
return new RemoveEntity(moveRule);
|
|
90
|
+
case 'TakeFrom':
|
|
91
|
+
return new TakeFrom(moveRule);
|
|
92
|
+
case 'SetState':
|
|
93
|
+
return new SetState(moveRule);
|
|
94
|
+
case 'ForEach':
|
|
95
|
+
return new ForEach(moveRule);
|
|
96
|
+
case 'Pass':
|
|
97
|
+
return new Pass(moveRule);
|
|
98
|
+
case 'Shuffle':
|
|
99
|
+
return new Shuffle(moveRule);
|
|
100
|
+
case 'SetActivePlayers':
|
|
101
|
+
return new SetActivePlayers(moveRule);
|
|
102
|
+
case 'EndTurn':
|
|
103
|
+
return new EndTurn(moveRule);
|
|
104
|
+
case 'PassTurn':
|
|
105
|
+
return new PassTurn(moveRule);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { INVALID_MOVE } from "@mnbroatch/boardgame.io/dist/cjs/core.js";
|
|
2
|
+
import type { Condition, MoveDefinition } from "../../types/bagel-types.js";
|
|
3
|
+
import checkConditions from "../../utils/check-conditions.js";
|
|
4
|
+
import resolveProperties from "../../utils/resolve-properties.js";
|
|
5
|
+
import type { BgioResolveState } from "../../utils/bgio-resolve-types.js";
|
|
6
|
+
|
|
7
|
+
export default class Move {
|
|
8
|
+
rule: MoveDefinition;
|
|
9
|
+
|
|
10
|
+
constructor (rule: MoveDefinition) {
|
|
11
|
+
this.rule = this.transformRule(rule as Parameters<Move["transformRule"]>[0]) as MoveDefinition;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
checkValidity (bgioArguments: unknown, payload: { arguments: Record<string, unknown> }, context: Record<string, unknown>) {
|
|
15
|
+
const moveArguments =
|
|
16
|
+
"arguments" in this.rule && this.rule.arguments
|
|
17
|
+
? this.rule.arguments
|
|
18
|
+
: {};
|
|
19
|
+
const argRuleEntries = Object.entries(moveArguments) as [string, { conditions?: Condition[] }][];
|
|
20
|
+
|
|
21
|
+
if (
|
|
22
|
+
!argRuleEntries.every(([argName]) => {
|
|
23
|
+
const arg = payload.arguments[argName];
|
|
24
|
+
return arg !== undefined && (!Array.isArray(arg) || arg.length);
|
|
25
|
+
})
|
|
26
|
+
) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const argumentResults: Record<string, { results: unknown[]; conditionsAreMet: boolean }> = {};
|
|
31
|
+
|
|
32
|
+
for (let i = 0, len = argRuleEntries.length; i < len; i++) {
|
|
33
|
+
const [argName, argRule] = argRuleEntries[i];
|
|
34
|
+
const payloadArg = payload.arguments[argName];
|
|
35
|
+
const args = Array.isArray(payloadArg)
|
|
36
|
+
? payloadArg
|
|
37
|
+
: [payloadArg];
|
|
38
|
+
|
|
39
|
+
const argResults: unknown[] = [];
|
|
40
|
+
for (let j = 0, lenj = args.length; j < lenj; j++) {
|
|
41
|
+
const arg = args[j];
|
|
42
|
+
const result = checkConditions(
|
|
43
|
+
bgioArguments as BgioResolveState,
|
|
44
|
+
argRule.conditions,
|
|
45
|
+
{ target: arg },
|
|
46
|
+
{ ...context, moveArguments: payload.arguments }
|
|
47
|
+
);
|
|
48
|
+
argResults.push(result);
|
|
49
|
+
if (!result.conditionsAreMet) {
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const last = argResults[argResults.length - 1] as { conditionsAreMet: boolean } | undefined;
|
|
55
|
+
const argConditionsAreMet = last?.conditionsAreMet ?? false;
|
|
56
|
+
argumentResults[argName] = {
|
|
57
|
+
results: argResults,
|
|
58
|
+
conditionsAreMet: argConditionsAreMet,
|
|
59
|
+
};
|
|
60
|
+
if (!argConditionsAreMet) {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const moveResults = checkConditions(
|
|
66
|
+
bgioArguments as BgioResolveState,
|
|
67
|
+
(this.rule as { conditions?: Condition[] }).conditions,
|
|
68
|
+
{},
|
|
69
|
+
{ ...context, moveArguments: payload.arguments }
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
argumentResults,
|
|
74
|
+
moveResults,
|
|
75
|
+
conditionsAreMet: moveResults.conditionsAreMet
|
|
76
|
+
&& Object.values(argumentResults).every((a) => a.conditionsAreMet),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
isValid (bgioArguments: unknown, payload: { arguments: Record<string, unknown> }, context: Record<string, unknown>) {
|
|
81
|
+
const conditionResults = this.checkValidity(
|
|
82
|
+
bgioArguments,
|
|
83
|
+
payload,
|
|
84
|
+
context
|
|
85
|
+
);
|
|
86
|
+
if (conditionResults === false) return false;
|
|
87
|
+
return conditionResults.conditionsAreMet;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
doMove (
|
|
91
|
+
bgioArguments: unknown,
|
|
92
|
+
payload: { arguments?: Record<string, unknown> } | undefined,
|
|
93
|
+
context: Record<string, unknown>,
|
|
94
|
+
{ skipCheck = false } = {}
|
|
95
|
+
) {
|
|
96
|
+
const rule = resolveProperties(
|
|
97
|
+
bgioArguments as BgioResolveState,
|
|
98
|
+
this.rule,
|
|
99
|
+
context
|
|
100
|
+
) as { name?: string; arguments?: Record<string, unknown> };
|
|
101
|
+
const resolvedPayload = {
|
|
102
|
+
...payload,
|
|
103
|
+
arguments: Object.entries(rule.arguments ?? {})
|
|
104
|
+
.reduce<Record<string, unknown>>((acc, [argName, arg]) => ({
|
|
105
|
+
...acc,
|
|
106
|
+
[argName]: payload?.arguments?.[argName] ?? arg,
|
|
107
|
+
}), {}),
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
if (rule.name) {
|
|
111
|
+
(bgioArguments as { G: { _meta: { previousPayloads: Record<string, unknown> } } }).G._meta.previousPayloads[rule.name] = resolvedPayload;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let conditionResults: ReturnType<Move["checkValidity"]> | undefined;
|
|
115
|
+
if (!skipCheck) {
|
|
116
|
+
conditionResults = this.checkValidity(bgioArguments, resolvedPayload as { arguments: Record<string, unknown> }, context);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!skipCheck && conditionResults !== false && !conditionResults!.conditionsAreMet) {
|
|
120
|
+
return INVALID_MOVE;
|
|
121
|
+
} else {
|
|
122
|
+
this.do(bgioArguments, rule, resolvedPayload, context);
|
|
123
|
+
if (context) {
|
|
124
|
+
context.previousArguments = resolvedPayload.arguments;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return { conditionResults };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
do (_bgioArguments: unknown, _rule: unknown, _resolvedPayload: unknown, _context: unknown) {
|
|
132
|
+
throw new Error("Move#do must be implemented by subclass");
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
transformRule (rule: { arguments?: Record<string, { playerChoice?: boolean; resolveAsEntity?: boolean }> }) {
|
|
136
|
+
const args = rule.arguments;
|
|
137
|
+
if (args) {
|
|
138
|
+
for (const key in args) {
|
|
139
|
+
const arg = args[key];
|
|
140
|
+
if (arg && !arg.playerChoice) {
|
|
141
|
+
arg.resolveAsEntity = true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return rule;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Move from "./move.js";
|
|
2
|
+
|
|
3
|
+
export default class PassTurn extends Move {
|
|
4
|
+
do (bgioArguments: unknown) {
|
|
5
|
+
const a = bgioArguments as {
|
|
6
|
+
G: { _meta: { passedPlayers: unknown[] } };
|
|
7
|
+
ctx: { numPlayers: number; currentPlayer: string };
|
|
8
|
+
events: { pass: () => void };
|
|
9
|
+
};
|
|
10
|
+
if (a.G._meta.passedPlayers.length < a.ctx.numPlayers) {
|
|
11
|
+
a.G._meta.passedPlayers.push(a.ctx.currentPlayer);
|
|
12
|
+
a.events.pass();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { MovePlaceNew } from "../../types/bagel-types.js";
|
|
2
|
+
import type { BgioResolveState } from "../../utils/bgio-resolve-types.js";
|
|
3
|
+
import { bankOf } from "../../utils/bgio-resolve-types.js";
|
|
4
|
+
import Move from "./move.js";
|
|
5
|
+
|
|
6
|
+
type PlaceNewRule = MovePlaceNew & { count?: number; position?: unknown };
|
|
7
|
+
|
|
8
|
+
export default class PlaceNew extends Move {
|
|
9
|
+
do (bgioArguments: unknown, rule: unknown, resolvedPayload: unknown, context: Record<string, unknown>) {
|
|
10
|
+
const { destination } = (resolvedPayload as { arguments: { destination: unknown } }).arguments;
|
|
11
|
+
const bgio = bgioArguments as BgioResolveState;
|
|
12
|
+
const r = rule as PlaceNewRule;
|
|
13
|
+
const bank = bankOf(bgio);
|
|
14
|
+
const entities = r.matchMultiple
|
|
15
|
+
? bank.getMultiple(
|
|
16
|
+
bgio,
|
|
17
|
+
{
|
|
18
|
+
...r.entity,
|
|
19
|
+
conditions: [
|
|
20
|
+
...(r.entity?.conditions || []),
|
|
21
|
+
...(r.conditions || []),
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
r.count ?? 1,
|
|
25
|
+
context
|
|
26
|
+
)
|
|
27
|
+
: [bank.getOne(
|
|
28
|
+
bgio,
|
|
29
|
+
{
|
|
30
|
+
...r.entity,
|
|
31
|
+
conditions: [
|
|
32
|
+
...(r.entity?.conditions || []),
|
|
33
|
+
...(r.conditions || []),
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
context
|
|
37
|
+
)]
|
|
38
|
+
entities.forEach((entity: unknown) => {
|
|
39
|
+
(destination as { placeEntity: (e: unknown, p?: unknown) => void }).placeEntity(entity, r.position as unknown);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { BgioResolveState } from "../../utils/bgio-resolve-types.js";
|
|
2
|
+
import { bankOf } from "../../utils/bgio-resolve-types.js";
|
|
3
|
+
import Move from "./move.js";
|
|
4
|
+
|
|
5
|
+
export default class RemoveEntity extends Move {
|
|
6
|
+
do (bgioArguments: unknown, _rule: unknown, resolvedPayload: unknown) {
|
|
7
|
+
const { entity } = (resolvedPayload as { arguments: { entity: unknown } }).arguments;
|
|
8
|
+
const bgio = bgioArguments as BgioResolveState;
|
|
9
|
+
bankOf(bgio).returnToBank(bgio, entity as { entityId: number; rule: Record<string, unknown> });
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { MoveDefinition } from "../../types/bagel-types.js";
|
|
2
|
+
import type { BgioResolveState } from "../../utils/bgio-resolve-types.js";
|
|
3
|
+
import Move from "./move.js";
|
|
4
|
+
import doMoves from '../../utils/do-moves.js'
|
|
5
|
+
|
|
6
|
+
export default class SetActivePlayers extends Move {
|
|
7
|
+
do (bgioArguments: unknown, rule: Record<string, unknown>, _unused: unknown, context: Record<string, unknown>) {
|
|
8
|
+
const b = bgioArguments as { events: { setActivePlayers: (o: unknown) => void }; ctx: { phase: string } };
|
|
9
|
+
b.events.setActivePlayers((rule as { options: unknown }).options);
|
|
10
|
+
|
|
11
|
+
// this is going to need to be expanded to handle more complex things
|
|
12
|
+
// than "move current player to new stage"
|
|
13
|
+
const phaseName = b.ctx.phase;
|
|
14
|
+
const stageName = (rule.options as { currentPlayer?: { stage?: string } }).currentPlayer?.stage;
|
|
15
|
+
const phaseOrRoot = (context.game as { phases?: Record<string, unknown> }).phases?.[phaseName] ?? context.game;
|
|
16
|
+
const stage = (phaseOrRoot as { turn?: { stages?: Record<string, unknown> } })?.turn?.stages?.[stageName as string];
|
|
17
|
+
doMoves(
|
|
18
|
+
bgioArguments as BgioResolveState,
|
|
19
|
+
(stage as { initialMoves?: MoveDefinition[] } | undefined)?.initialMoves,
|
|
20
|
+
{
|
|
21
|
+
...context,
|
|
22
|
+
stageName,
|
|
23
|
+
} as unknown as Parameters<typeof doMoves>[2]
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import Move from "./move.js";
|
|
2
|
+
|
|
3
|
+
// todo: invariant conditions like "is one of the allowed values"
|
|
4
|
+
export default class SetState extends Move {
|
|
5
|
+
do (_unused: unknown, _rule: unknown, resolvedPayload: unknown) {
|
|
6
|
+
const { entity, state } = (resolvedPayload as {
|
|
7
|
+
arguments: { entity: { state?: Record<string, unknown> }; state: { property: string; value: unknown } };
|
|
8
|
+
}).arguments;
|
|
9
|
+
entity.state = {
|
|
10
|
+
...entity.state,
|
|
11
|
+
[state.property]: state.value,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import Move from "./move.js";
|
|
2
|
+
|
|
3
|
+
export default class Shuffle extends Move {
|
|
4
|
+
do (bgioArguments: unknown, _rule: unknown, resolvedPayload: unknown) {
|
|
5
|
+
const { target } = (resolvedPayload as { arguments: { target: { entities: unknown[] } } }).arguments;
|
|
6
|
+
const b = bgioArguments as { random: { Shuffle: <T>(xs: T[]) => T[] } };
|
|
7
|
+
target.entities = b.random.Shuffle(target.entities);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import Move from "./move.js";
|
|
2
|
+
|
|
3
|
+
export default class TakeFrom extends Move {
|
|
4
|
+
do (_bgioArguments: unknown, rule: { arguments: { source: { position?: unknown } } }, resolvedPayload: unknown) {
|
|
5
|
+
const { source, destination } = (resolvedPayload as { arguments: { source: unknown; destination: unknown } }).arguments;
|
|
6
|
+
(destination as { placeEntity: (e: unknown) => void }).placeEntity(
|
|
7
|
+
(source as { takeOne: (p: unknown) => unknown }).takeOne(
|
|
8
|
+
(rule as { arguments: { source: { position?: unknown } } }).arguments.source.position
|
|
9
|
+
)
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import Entity from "../entity.js";
|
|
2
|
+
|
|
3
|
+
export default class Space extends Entity {
|
|
4
|
+
entities: unknown[];
|
|
5
|
+
|
|
6
|
+
constructor (
|
|
7
|
+
options: ConstructorParameters<typeof Entity>[0],
|
|
8
|
+
rule: Record<string, unknown>,
|
|
9
|
+
id: number
|
|
10
|
+
) {
|
|
11
|
+
super(options, rule, id);
|
|
12
|
+
this.entities = [];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
placeEntity (entity: unknown, position: "Last" | "First" = "Last") {
|
|
16
|
+
if (position === "Last") {
|
|
17
|
+
this.entities.push(entity);
|
|
18
|
+
} else if (position === "First") {
|
|
19
|
+
this.entities.unshift(entity);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
remove (entity: unknown) {
|
|
24
|
+
this.entities.splice(this.entities.indexOf(entity), 1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
takeOne (position: "First" = "First") {
|
|
28
|
+
if (position === "First") {
|
|
29
|
+
return this.entities.splice(0, 1)[0];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
isEmpty () {
|
|
34
|
+
return this.entities.length === 0;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import chunk from "lodash/chunk.js";
|
|
2
|
+
import SpaceGroup from "./space-group.js";
|
|
3
|
+
|
|
4
|
+
export default class Grid extends SpaceGroup {
|
|
5
|
+
declare rule: Record<string, unknown> & { width: number; height: number };
|
|
6
|
+
|
|
7
|
+
getSpacesCount () {
|
|
8
|
+
return (this.rule.width as number) * (this.rule.height as number);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
getRows () {
|
|
12
|
+
return chunk(this.spaces, this.rule.width as number);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
getCoordinates (index: number) {
|
|
16
|
+
const { width } = this.rule;
|
|
17
|
+
return [
|
|
18
|
+
index % width,
|
|
19
|
+
Math.floor(index / width),
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
getIndex ([x, y]: [number, number]) {
|
|
24
|
+
const { width } = this.rule;
|
|
25
|
+
return y * width + x;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
override getSpace (arg: number | [number, number]) {
|
|
29
|
+
if (Array.isArray(arg)) {
|
|
30
|
+
return this.spaces[this.getIndex(arg)];
|
|
31
|
+
}
|
|
32
|
+
return this.spaces[arg];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
getRelativeCoordinates ([oldX, oldY]: [number, number], [relativeX, relativeY]: [number, number]) {
|
|
36
|
+
const newCoordinates: [number, number] = [oldX + relativeX, oldY + relativeY];
|
|
37
|
+
return this.areCoordinatesValid(newCoordinates)
|
|
38
|
+
? newCoordinates
|
|
39
|
+
: null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
areCoordinatesValid ([x, y]: [number, number]) {
|
|
43
|
+
return x >= 0
|
|
44
|
+
&& y >= 0
|
|
45
|
+
&& x < (this.rule.width as number)
|
|
46
|
+
&& y < (this.rule.height as number);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import Entity from "../entity.js";
|
|
2
|
+
|
|
3
|
+
type BankLike = { createEntity: (def: Record<string, unknown>) => unknown };
|
|
4
|
+
|
|
5
|
+
export default class SpaceGroup extends Entity {
|
|
6
|
+
spaces: unknown[];
|
|
7
|
+
|
|
8
|
+
constructor (
|
|
9
|
+
options: ConstructorParameters<typeof Entity>[0] & { bank: BankLike },
|
|
10
|
+
rule: Record<string, unknown>,
|
|
11
|
+
id: number
|
|
12
|
+
) {
|
|
13
|
+
super(options, rule, id);
|
|
14
|
+
this.spaces = this.makeSpaces(options.bank);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
makeSpaces (bank: BankLike) {
|
|
18
|
+
return Array(this.getSpacesCount()).fill(undefined)
|
|
19
|
+
.map((_, i) => bank.createEntity({ entityType: "Space", index: i }));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getEmptySpaces () {
|
|
23
|
+
return (this.spaces as { isEmpty: () => boolean }[]).filter((space) => space.isEmpty());
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getSpace (arg: number | [number, number]) {
|
|
27
|
+
if (Array.isArray(arg)) {
|
|
28
|
+
throw new Error("Numeric index only for SpaceGroup#getSpace");
|
|
29
|
+
}
|
|
30
|
+
return this.spaces[arg];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getEntities (index: number) {
|
|
34
|
+
return (this.getSpace(index) as { entities: unknown[] }).entities;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
placeEntity (index: number, entity: unknown) {
|
|
38
|
+
(this.getSpace(index) as { placeEntity: (e: unknown) => void }).placeEntity(entity);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getSpacesCount (): number {
|
|
42
|
+
throw new Error("SpaceGroup#getSpacesCount must be implemented by subclass");
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { default as gameFactory } from "./game-factory/game-factory.js";
|
|
2
|
+
export { Client } from "./client/client.js";
|
|
3
|
+
export type { ClientOptions } from "./client/client.js";
|
|
4
|
+
export type { BoardGameEngineGame, BgioArguments } from "./game-factory/game-factory.js";
|
|
5
|
+
export type * from "./types/index.js";
|