board-game-engine 2.0.1 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/board-game-engine.cjs +5509 -5613
- package/dist/board-game-engine.js +5509 -5613
- package/dist/board-game-engine.min.js +22 -22
- package/dist/board-game-engine.mjs +5508 -5611
- package/package.json +4 -10
- package/playwright-report/index.html +1 -1
- package/scripts/build.mjs +2 -2
- package/src/client/client.js +224 -0
- package/src/game-factory/bank/bank-slot.js +69 -0
- package/src/game-factory/bank/bank.js +114 -0
- package/src/game-factory/{board.ts → board.js} +1 -1
- package/src/game-factory/condition/condition-factory.js +52 -0
- package/src/game-factory/condition/condition.js +39 -0
- package/src/game-factory/condition/{contains-condition.ts → contains-condition.js} +4 -5
- package/src/game-factory/condition/{contains-same-condition.ts → contains-same-condition.js} +5 -8
- package/src/game-factory/condition/{evaluate-condition.ts → evaluate-condition.js} +3 -4
- package/src/game-factory/condition/every-condition.js +25 -0
- package/src/game-factory/condition/has-line-condition.js +14 -0
- package/src/game-factory/condition/in-line-condition.js +19 -0
- package/src/game-factory/condition/is-condition.js +23 -0
- package/src/game-factory/condition/is-full-condition.js +9 -0
- package/src/game-factory/condition/{no-possible-moves-condition.ts → no-possible-moves-condition.js} +2 -3
- package/src/game-factory/condition/{not-condition.ts → not-condition.js} +2 -3
- package/src/game-factory/condition/{or-condition.ts → or-condition.js} +2 -3
- package/src/game-factory/condition/position-condition.js +12 -0
- package/src/game-factory/condition/{some-condition.ts → some-condition.js} +3 -5
- package/src/game-factory/condition/would-condition.js +94 -0
- package/src/game-factory/entity.js +29 -0
- package/src/game-factory/expand-game-rules.js +271 -0
- package/src/game-factory/game-factory.js +240 -0
- package/{dist/game-factory/move/end-turn.d.ts → src/game-factory/move/end-turn.js} +4 -2
- package/src/game-factory/move/for-each.js +18 -0
- package/src/game-factory/move/move-entity.js +16 -0
- package/src/game-factory/move/move-factory.js +89 -0
- package/src/game-factory/move/move.js +131 -0
- package/src/game-factory/move/pass-turn.js +10 -0
- package/{dist/game-factory/move/pass.d.ts → src/game-factory/move/pass.js} +4 -2
- package/src/game-factory/move/place-new.js +33 -0
- package/src/game-factory/move/remove-entity.js +7 -0
- package/src/game-factory/move/set-active-players.js +23 -0
- package/src/game-factory/move/set-state.js +11 -0
- package/src/game-factory/move/shuffle.js +7 -0
- package/src/game-factory/move/take-from.js +7 -0
- package/src/game-factory/space/space.js +30 -0
- package/src/game-factory/space-group/grid.js +43 -0
- package/src/game-factory/space-group/space-group.js +29 -0
- package/src/index.js +2 -0
- package/src/utils/{any-valid-moves.ts → any-valid-moves.js} +49 -54
- package/src/utils/check-conditions.js +28 -0
- package/src/utils/create-payload.js +16 -0
- package/src/utils/deserialize-bgio-arguments.js +8 -0
- package/src/utils/do-moves.js +18 -0
- package/src/utils/entity-matches.js +20 -0
- package/src/utils/find-met-condition.js +22 -0
- package/src/utils/get-current-moves.js +12 -0
- package/src/utils/get-scenario-results.js +23 -0
- package/src/utils/get-steps.js +29 -0
- package/src/utils/get.js +25 -0
- package/src/utils/{grid-contains-sequence.ts → grid-contains-sequence.js} +33 -71
- package/src/utils/json-transformer.js +12 -0
- package/src/utils/prepare-payload.js +17 -0
- package/src/utils/resolve-entity.js +9 -0
- package/src/utils/resolve-expression.js +10 -0
- package/src/utils/resolve-properties.js +149 -0
- package/src/utils/simulate-move.js +25 -0
- package/.github/workflows/ci.yml +0 -33
- package/dist/client/client.d.ts +0 -76
- package/dist/client/client.d.ts.map +0 -1
- package/dist/game-factory/bank/bank-slot.d.ts +0 -30
- package/dist/game-factory/bank/bank-slot.d.ts.map +0 -1
- package/dist/game-factory/bank/bank.d.ts +0 -34
- package/dist/game-factory/bank/bank.d.ts.map +0 -1
- package/dist/game-factory/board.d.ts +0 -4
- package/dist/game-factory/board.d.ts.map +0 -1
- package/dist/game-factory/condition/condition-factory.d.ts +0 -4
- package/dist/game-factory/condition/condition-factory.d.ts.map +0 -1
- package/dist/game-factory/condition/condition.d.ts +0 -13
- package/dist/game-factory/condition/condition.d.ts.map +0 -1
- package/dist/game-factory/condition/contains-condition.d.ts +0 -8
- package/dist/game-factory/condition/contains-condition.d.ts.map +0 -1
- package/dist/game-factory/condition/contains-same-condition.d.ts +0 -7
- package/dist/game-factory/condition/contains-same-condition.d.ts.map +0 -1
- package/dist/game-factory/condition/evaluate-condition.d.ts +0 -8
- package/dist/game-factory/condition/evaluate-condition.d.ts.map +0 -1
- package/dist/game-factory/condition/every-condition.d.ts +0 -12
- package/dist/game-factory/condition/every-condition.d.ts.map +0 -1
- package/dist/game-factory/condition/has-line-condition.d.ts +0 -8
- package/dist/game-factory/condition/has-line-condition.d.ts.map +0 -1
- package/dist/game-factory/condition/in-line-condition.d.ts +0 -8
- package/dist/game-factory/condition/in-line-condition.d.ts.map +0 -1
- package/dist/game-factory/condition/is-condition.d.ts +0 -8
- package/dist/game-factory/condition/is-condition.d.ts.map +0 -1
- package/dist/game-factory/condition/is-full-condition.d.ts +0 -7
- package/dist/game-factory/condition/is-full-condition.d.ts.map +0 -1
- package/dist/game-factory/condition/no-possible-moves-condition.d.ts +0 -7
- package/dist/game-factory/condition/no-possible-moves-condition.d.ts.map +0 -1
- package/dist/game-factory/condition/not-condition.d.ts +0 -7
- package/dist/game-factory/condition/not-condition.d.ts.map +0 -1
- package/dist/game-factory/condition/or-condition.d.ts +0 -7
- package/dist/game-factory/condition/or-condition.d.ts.map +0 -1
- package/dist/game-factory/condition/position-condition.d.ts +0 -7
- package/dist/game-factory/condition/position-condition.d.ts.map +0 -1
- package/dist/game-factory/condition/some-condition.d.ts +0 -8
- package/dist/game-factory/condition/some-condition.d.ts.map +0 -1
- package/dist/game-factory/condition/would-condition.d.ts +0 -8
- package/dist/game-factory/condition/would-condition.d.ts.map +0 -1
- package/dist/game-factory/entity.d.ts +0 -13
- package/dist/game-factory/entity.d.ts.map +0 -1
- package/dist/game-factory/expand-game-rules.d.ts +0 -3
- package/dist/game-factory/expand-game-rules.d.ts.map +0 -1
- package/dist/game-factory/game-factory.d.ts +0 -10
- package/dist/game-factory/game-factory.d.ts.map +0 -1
- package/dist/game-factory/move/end-turn.d.ts.map +0 -1
- package/dist/game-factory/move/for-each.d.ts +0 -5
- package/dist/game-factory/move/for-each.d.ts.map +0 -1
- package/dist/game-factory/move/index.d.ts +0 -6
- package/dist/game-factory/move/index.d.ts.map +0 -1
- package/dist/game-factory/move/move-entity.d.ts +0 -7
- package/dist/game-factory/move/move-entity.d.ts.map +0 -1
- package/dist/game-factory/move/move-factory.d.ts +0 -18
- package/dist/game-factory/move/move-factory.d.ts.map +0 -1
- package/dist/game-factory/move/move.d.ts +0 -54
- package/dist/game-factory/move/move.d.ts.map +0 -1
- package/dist/game-factory/move/pass-turn.d.ts +0 -5
- package/dist/game-factory/move/pass-turn.d.ts.map +0 -1
- package/dist/game-factory/move/pass.d.ts.map +0 -1
- package/dist/game-factory/move/place-new.d.ts +0 -5
- package/dist/game-factory/move/place-new.d.ts.map +0 -1
- package/dist/game-factory/move/remove-entity.d.ts +0 -5
- package/dist/game-factory/move/remove-entity.d.ts.map +0 -1
- package/dist/game-factory/move/set-active-players.d.ts +0 -5
- package/dist/game-factory/move/set-active-players.d.ts.map +0 -1
- package/dist/game-factory/move/set-state.d.ts +0 -5
- package/dist/game-factory/move/set-state.d.ts.map +0 -1
- package/dist/game-factory/move/shuffle.d.ts +0 -5
- package/dist/game-factory/move/shuffle.d.ts.map +0 -1
- package/dist/game-factory/move/take-from.d.ts +0 -11
- package/dist/game-factory/move/take-from.d.ts.map +0 -1
- package/dist/game-factory/space/space.d.ts +0 -10
- package/dist/game-factory/space/space.d.ts.map +0 -1
- package/dist/game-factory/space-group/grid.d.ts +0 -15
- package/dist/game-factory/space-group/grid.d.ts.map +0 -1
- package/dist/game-factory/space-group/space-group.d.ts +0 -20
- package/dist/game-factory/space-group/space-group.d.ts.map +0 -1
- package/dist/index.d.ts +0 -6
- package/dist/index.d.ts.map +0 -1
- package/dist/registry.d.ts +0 -17
- package/dist/registry.d.ts.map +0 -1
- package/dist/types/bagel-types.d.ts +0 -339
- package/dist/types/bagel-types.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -3
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/rule-with-conditions.d.ts +0 -9
- package/dist/types/rule-with-conditions.d.ts.map +0 -1
- package/dist/utils/any-valid-moves.d.ts +0 -2
- package/dist/utils/any-valid-moves.d.ts.map +0 -1
- package/dist/utils/bgio-resolve-types.d.ts +0 -25
- package/dist/utils/bgio-resolve-types.d.ts.map +0 -1
- package/dist/utils/check-conditions.d.ts +0 -7
- package/dist/utils/check-conditions.d.ts.map +0 -1
- package/dist/utils/create-payload.d.ts +0 -5
- package/dist/utils/create-payload.d.ts.map +0 -1
- package/dist/utils/deserialize-bgio-arguments.d.ts +0 -3
- package/dist/utils/deserialize-bgio-arguments.d.ts.map +0 -1
- package/dist/utils/do-moves.d.ts +0 -8
- package/dist/utils/do-moves.d.ts.map +0 -1
- package/dist/utils/entity-matches.d.ts +0 -6
- package/dist/utils/entity-matches.d.ts.map +0 -1
- package/dist/utils/find-met-condition.d.ts +0 -6
- package/dist/utils/find-met-condition.d.ts.map +0 -1
- package/dist/utils/get-current-moves.d.ts +0 -24
- package/dist/utils/get-current-moves.d.ts.map +0 -1
- package/dist/utils/get-scenario-results.d.ts +0 -3
- package/dist/utils/get-scenario-results.d.ts.map +0 -1
- package/dist/utils/get-steps.d.ts +0 -13
- package/dist/utils/get-steps.d.ts.map +0 -1
- package/dist/utils/get.d.ts +0 -7
- package/dist/utils/get.d.ts.map +0 -1
- package/dist/utils/grid-contains-sequence.d.ts +0 -27
- package/dist/utils/grid-contains-sequence.d.ts.map +0 -1
- package/dist/utils/json-transformer.d.ts +0 -8
- package/dist/utils/json-transformer.d.ts.map +0 -1
- package/dist/utils/prepare-payload.d.ts +0 -2
- package/dist/utils/prepare-payload.d.ts.map +0 -1
- package/dist/utils/resolve-entity.d.ts +0 -3
- package/dist/utils/resolve-entity.d.ts.map +0 -1
- package/dist/utils/resolve-expression.d.ts +0 -6
- package/dist/utils/resolve-expression.d.ts.map +0 -1
- package/dist/utils/resolve-properties.d.ts +0 -4
- package/dist/utils/resolve-properties.d.ts.map +0 -1
- package/dist/utils/simulate-move.d.ts +0 -16
- package/dist/utils/simulate-move.d.ts.map +0 -1
- package/src/client/client.ts +0 -306
- package/src/game-factory/bank/bank-slot.ts +0 -81
- package/src/game-factory/bank/bank.ts +0 -125
- package/src/game-factory/condition/condition-factory.ts +0 -59
- package/src/game-factory/condition/condition.ts +0 -50
- package/src/game-factory/condition/every-condition.ts +0 -27
- package/src/game-factory/condition/has-line-condition.ts +0 -15
- package/src/game-factory/condition/in-line-condition.ts +0 -25
- package/src/game-factory/condition/is-condition.ts +0 -24
- package/src/game-factory/condition/is-full-condition.ts +0 -10
- package/src/game-factory/condition/position-condition.ts +0 -13
- package/src/game-factory/condition/would-condition.ts +0 -104
- package/src/game-factory/entity.ts +0 -37
- package/src/game-factory/expand-game-rules.ts +0 -263
- package/src/game-factory/game-factory.ts +0 -263
- package/src/game-factory/move/end-turn.ts +0 -7
- package/src/game-factory/move/for-each.ts +0 -20
- package/src/game-factory/move/move-entity.ts +0 -18
- package/src/game-factory/move/move-factory.ts +0 -107
- package/src/game-factory/move/move.ts +0 -147
- package/src/game-factory/move/pass-turn.ts +0 -15
- package/src/game-factory/move/pass.ts +0 -7
- package/src/game-factory/move/place-new.ts +0 -42
- package/src/game-factory/move/remove-entity.ts +0 -11
- package/src/game-factory/move/set-active-players.ts +0 -26
- package/src/game-factory/move/set-state.ts +0 -14
- package/src/game-factory/move/shuffle.ts +0 -9
- package/src/game-factory/move/take-from.ts +0 -12
- package/src/game-factory/space/space.ts +0 -36
- package/src/game-factory/space-group/grid.ts +0 -48
- package/src/game-factory/space-group/space-group.ts +0 -44
- package/src/index.ts +0 -5
- package/src/types/bagel-types.ts +0 -449
- package/src/types/boardgame-io-core.d.ts +0 -7
- package/src/types/index.ts +0 -70
- package/src/types/rule-with-conditions.ts +0 -9
- package/src/utils/bgio-resolve-types.ts +0 -27
- package/src/utils/check-conditions.ts +0 -28
- package/src/utils/create-payload.ts +0 -19
- package/src/utils/deserialize-bgio-arguments.ts +0 -10
- package/src/utils/do-moves.ts +0 -22
- package/src/utils/entity-matches.ts +0 -30
- package/src/utils/expr-eval.d.ts +0 -6
- package/src/utils/find-met-condition.ts +0 -23
- package/src/utils/get-current-moves.ts +0 -39
- package/src/utils/get-scenario-results.ts +0 -30
- package/src/utils/get-steps.ts +0 -38
- package/src/utils/get.ts +0 -28
- package/src/utils/json-transformer.ts +0 -17
- package/src/utils/prepare-payload.ts +0 -20
- package/src/utils/resolve-entity.ts +0 -15
- package/src/utils/resolve-expression.ts +0 -16
- package/src/utils/resolve-properties.ts +0 -172
- package/src/utils/simulate-move.ts +0 -32
- package/src/wackson.d.ts +0 -4
- package/tsconfig.build.json +0 -14
- package/tsconfig.json +0 -21
- /package/src/game-factory/move/{index.ts → index.js} +0 -0
- /package/src/{registry.ts → registry.js} +0 -0
package/package.json
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "board-game-engine",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "wip board game engine",
|
|
5
5
|
"main": "dist/board-game-engine.cjs",
|
|
6
6
|
"module": "dist/board-game-engine.mjs",
|
|
7
|
-
"types": "dist/index.d.ts",
|
|
8
7
|
"exports": {
|
|
9
8
|
".": {
|
|
10
|
-
"types": "./dist/index.d.ts",
|
|
11
9
|
"import": "./dist/board-game-engine.mjs",
|
|
12
10
|
"require": "./dist/board-game-engine.cjs"
|
|
13
11
|
}
|
|
@@ -21,16 +19,12 @@
|
|
|
21
19
|
"test:e2e:install": "playwright install firefox",
|
|
22
20
|
"serve": "http-server . -p 5174 -c-1",
|
|
23
21
|
"lint": "eslint .",
|
|
24
|
-
"build": "node scripts/build.mjs
|
|
25
|
-
"build:types": "tsc -p tsconfig.build.json",
|
|
26
|
-
"typecheck": "tsc --noEmit",
|
|
22
|
+
"build": "node scripts/build.mjs",
|
|
27
23
|
"prepublishOnly": "npm run build"
|
|
28
24
|
},
|
|
29
25
|
"author": "Matthew Broatch",
|
|
30
26
|
"license": "ISC",
|
|
31
27
|
"devDependencies": {
|
|
32
|
-
"@playwright/test": "^1.49.0",
|
|
33
|
-
"@types/lodash": "^4.17.24",
|
|
34
28
|
"cross-env": "^7.0.3",
|
|
35
29
|
"esbuild": "^0.24.0",
|
|
36
30
|
"esbuild-plugin-istanbul": "^0.3.0",
|
|
@@ -40,12 +34,12 @@
|
|
|
40
34
|
"http-server": "^14.1.1",
|
|
41
35
|
"nyc": "^15.1.0",
|
|
42
36
|
"standard": "^16.0.4",
|
|
43
|
-
"
|
|
37
|
+
"@playwright/test": "^1.49.0"
|
|
44
38
|
},
|
|
45
39
|
"dependencies": {
|
|
46
40
|
"@mnbroatch/boardgame.io": "0.0.1",
|
|
47
41
|
"expr-eval": "^2.0.2",
|
|
48
|
-
"wackson": "^
|
|
42
|
+
"wackson": "^2.0.0"
|
|
49
43
|
},
|
|
50
44
|
"repository": {
|
|
51
45
|
"type": "git",
|
|
@@ -82,4 +82,4 @@ Error generating stack: `+a.message+`
|
|
|
82
82
|
<div id='root'></div>
|
|
83
83
|
</body>
|
|
84
84
|
</html>
|
|
85
|
-
<script id="playwrightReportBase64" type="application/zip">data:application/zip;base64,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</script>
|
|
85
|
+
<script id="playwrightReportBase64" type="application/zip">data:application/zip;base64,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</script>
|
package/scripts/build.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as esbuild from 'esbuild'
|
|
2
2
|
import { esbuildPluginIstanbul } from 'esbuild-plugin-istanbul'
|
|
3
3
|
|
|
4
|
-
const entry = 'src/index.
|
|
4
|
+
const entry = 'src/index.js'
|
|
5
5
|
const outdir = 'dist'
|
|
6
6
|
const globalName = 'BoardGameEngine'
|
|
7
7
|
const coverage = process.env.COVERAGE === '1'
|
|
@@ -24,7 +24,7 @@ if (coverage) {
|
|
|
24
24
|
esbuildPluginIstanbul({
|
|
25
25
|
name: 'istanbul',
|
|
26
26
|
filter: /\.(js|ts)$/,
|
|
27
|
-
include: ['src/**/*.
|
|
27
|
+
include: ['src/**/*.js'],
|
|
28
28
|
exclude: ['**/*.spec.js', '**/node_modules/**'],
|
|
29
29
|
}),
|
|
30
30
|
],
|
|
@@ -0,0 +1,224 @@
|
|
|
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 { registry } from '../registry.js';
|
|
7
|
+
import simulateMove from '../utils/simulate-move.js';
|
|
8
|
+
import getCurrentMoves from '../utils/get-current-moves.js';
|
|
9
|
+
import resolveProperties from '../utils/resolve-properties.js';
|
|
10
|
+
import checkConditions from '../utils/check-conditions.js';
|
|
11
|
+
import preparePayload from '../utils/prepare-payload.js';
|
|
12
|
+
import getSteps from '../utils/get-steps.js';
|
|
13
|
+
import createPayload from '../utils/create-payload.js';
|
|
14
|
+
|
|
15
|
+
export class Client {
|
|
16
|
+
constructor (options) {
|
|
17
|
+
this.options = options
|
|
18
|
+
this.game = options.boardgameIOGame
|
|
19
|
+
|| gameFactory(JSON.parse(options.gameRules), options.gameName)
|
|
20
|
+
|
|
21
|
+
if (!options.boardgameIOGame) {
|
|
22
|
+
this.moveBuilder = { targets: [], stepIndex: 0, eliminatedMoves: [] }
|
|
23
|
+
this.optimisticWinner = null
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
connect () {
|
|
28
|
+
const {
|
|
29
|
+
server,
|
|
30
|
+
numPlayers,
|
|
31
|
+
debug = {
|
|
32
|
+
collapseOnLoad: true,
|
|
33
|
+
impl: Debug,
|
|
34
|
+
},
|
|
35
|
+
matchID,
|
|
36
|
+
playerID,
|
|
37
|
+
credentials,
|
|
38
|
+
multiplayer = SocketIO({ server, socketOpts: { transports: ['websocket', 'polling'] } }),
|
|
39
|
+
} = this.options
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const clientOptions = !credentials
|
|
43
|
+
? { game: this.game, numPlayers, debug }
|
|
44
|
+
: {
|
|
45
|
+
game: this.game,
|
|
46
|
+
multiplayer,
|
|
47
|
+
matchID,
|
|
48
|
+
playerID,
|
|
49
|
+
credentials,
|
|
50
|
+
numPlayers,
|
|
51
|
+
debug,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this.client = BoardgameIOClient(clientOptions)
|
|
55
|
+
this.client.subscribe(() => this.update())
|
|
56
|
+
this.client.start()
|
|
57
|
+
return this
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error('Failed to join game:', error?.message ?? error)
|
|
60
|
+
if (error?.stack) console.error(error.stack)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
update () {
|
|
65
|
+
this.options.onClientUpdate?.()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
getState () {
|
|
69
|
+
const bgioState = this.client?.getState()
|
|
70
|
+
if (!bgioState) return {}
|
|
71
|
+
|
|
72
|
+
const state = this.options.boardgameIOGame
|
|
73
|
+
? bgioState
|
|
74
|
+
: {
|
|
75
|
+
...bgioState,
|
|
76
|
+
G: deserialize(JSON.stringify(bgioState.G), registry),
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const gameover = this.optimisticWinner ?? state?.ctx?.gameover
|
|
80
|
+
|
|
81
|
+
const currentMoves = gameover
|
|
82
|
+
? []
|
|
83
|
+
: getCurrentMoves(state, this.client)
|
|
84
|
+
|
|
85
|
+
if (this.options.boardgameIOGame) {
|
|
86
|
+
return {
|
|
87
|
+
state,
|
|
88
|
+
gameover,
|
|
89
|
+
moves: this.client.moves,
|
|
90
|
+
currentMoves
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const _wrappedMoves = Object.entries(currentMoves)
|
|
95
|
+
.reduce((acc, [moveName, rawMove]) => {
|
|
96
|
+
const move = (payload) => {
|
|
97
|
+
this.client.moves[moveName](preparePayload(payload))
|
|
98
|
+
}
|
|
99
|
+
move.moveInstance = rawMove.moveInstance
|
|
100
|
+
return { ...acc, [moveName]: move }
|
|
101
|
+
}, {})
|
|
102
|
+
|
|
103
|
+
const { allClickable, _possibleMoveMeta } = getPossibleMoves(state, _wrappedMoves, this.moveBuilder)
|
|
104
|
+
|
|
105
|
+
return { state, gameover, allClickable, _wrappedMoves, _possibleMoveMeta }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
doStep (_target) {
|
|
109
|
+
if (this.options.boardgameIOGame) return
|
|
110
|
+
|
|
111
|
+
const { state, _wrappedMoves, _possibleMoveMeta } = this.getState()
|
|
112
|
+
|
|
113
|
+
const target = _target.abstract
|
|
114
|
+
? _target
|
|
115
|
+
: state.G.bank.locate(_target.entityId)
|
|
116
|
+
|
|
117
|
+
const newEliminated = Object.entries(_possibleMoveMeta)
|
|
118
|
+
.filter(([_, meta]) => !hasTarget(meta.clickableForMove, target))
|
|
119
|
+
.map(([name]) => name)
|
|
120
|
+
.concat(this.moveBuilder.eliminatedMoves);
|
|
121
|
+
|
|
122
|
+
if (newEliminated.length === Object.keys(_wrappedMoves).length) {
|
|
123
|
+
console.error('invalid move with target:', target?.rule);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const remainingMoveEntries = Object.entries(_possibleMoveMeta)
|
|
128
|
+
.filter(([name]) => !newEliminated.includes(name))
|
|
129
|
+
|
|
130
|
+
if (isMoveCompleted(state, _wrappedMoves, remainingMoveEntries, this.moveBuilder.stepIndex)) {
|
|
131
|
+
const [moveName] = remainingMoveEntries[0]
|
|
132
|
+
const move = _wrappedMoves[moveName]
|
|
133
|
+
const payload = createPayload(
|
|
134
|
+
state,
|
|
135
|
+
move.moveInstance.rule,
|
|
136
|
+
[...this.moveBuilder.targets, target],
|
|
137
|
+
{ moveInstance: move.moveInstance }
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
this.optimisticWinner = getWinnerAfterMove(state, this.game, move.moveInstance, payload);
|
|
141
|
+
move(payload);
|
|
142
|
+
this.moveBuilder = { targets: [], stepIndex: 0, eliminatedMoves: [] };
|
|
143
|
+
} else {
|
|
144
|
+
this.moveBuilder = {
|
|
145
|
+
eliminatedMoves: newEliminated,
|
|
146
|
+
stepIndex: this.moveBuilder.stepIndex + 1,
|
|
147
|
+
targets: [...this.moveBuilder.targets, target]
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
this.update()
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
reset () {
|
|
155
|
+
if (this.options.boardgameIOGame) return
|
|
156
|
+
this.moveBuilder = { targets: [], stepIndex: 0, eliminatedMoves: [] };
|
|
157
|
+
this.optimisticWinner = null
|
|
158
|
+
this.update()
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
undoStep () {
|
|
162
|
+
if (this.options.boardgameIOGame) return
|
|
163
|
+
if (this.moveBuilder.targets.length) {
|
|
164
|
+
this.moveBuilder = {
|
|
165
|
+
targets: this.moveBuilder.targets.slice(0, -1),
|
|
166
|
+
stepIndex: Math.max(0, this.moveBuilder.stepIndex - 1),
|
|
167
|
+
eliminatedMoves: []
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
this.update()
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function hasTarget(clickableSet, target) {
|
|
175
|
+
if (!target.abstract) return clickableSet.has(target);
|
|
176
|
+
return [...clickableSet].some(item => item.abstract && item.value === target.value);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function getPossibleMoves(bgioState, moves, moveBuilder) {
|
|
180
|
+
const { eliminatedMoves, stepIndex } = moveBuilder;
|
|
181
|
+
const _possibleMoveMeta = {};
|
|
182
|
+
const allClickable = new Set();
|
|
183
|
+
|
|
184
|
+
Object.entries(moves)
|
|
185
|
+
.filter(([moveName]) => !eliminatedMoves.includes(moveName))
|
|
186
|
+
.forEach(([moveName, move]) => {
|
|
187
|
+
const moveRule = resolveProperties(bgioState, { ...move.moveInstance.rule, moveName })
|
|
188
|
+
|
|
189
|
+
const context = {
|
|
190
|
+
moveInstance: move.moveInstance,
|
|
191
|
+
moveArguments: moveRule.arguments
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const targets = moveBuilder.targets.map(t =>
|
|
195
|
+
t.abstract ? t : bgioState.G.bank.locate(t.entityId)
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
const payload = createPayload(bgioState, moveRule, targets, context);
|
|
199
|
+
|
|
200
|
+
context.moveArguments = { ...context.moveArguments, ...payload.arguments }
|
|
201
|
+
|
|
202
|
+
const moveIsAllowed = checkConditions(bgioState, moveRule, {}, context).conditionsAreMet;
|
|
203
|
+
const moveSteps = getSteps(bgioState, moveRule);
|
|
204
|
+
|
|
205
|
+
const clickableForMove = new Set(
|
|
206
|
+
(moveIsAllowed && moveSteps?.[stepIndex]?.getClickable(context)) || []
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
_possibleMoveMeta[moveName] = { clickableForMove };
|
|
210
|
+
clickableForMove.forEach(entity => allClickable.add(entity));
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
return { _possibleMoveMeta, allClickable };
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function isMoveCompleted(state, moves, remainingMoveEntries, stepIndex) {
|
|
217
|
+
return remainingMoveEntries.length === 1 &&
|
|
218
|
+
getSteps(state, moves[remainingMoveEntries[0][0]].moveInstance.rule).length === stepIndex + 1;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function getWinnerAfterMove (state, game, moveInstance, movePayload) {
|
|
222
|
+
const simulatedG = simulateMove(state, preparePayload(movePayload), { moveInstance })
|
|
223
|
+
return game.endIf?.({ ...state, G: JSON.parse(serialize(simulatedG, { registry })) })
|
|
224
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import resolveProperties from '../../utils/resolve-properties.js'
|
|
2
|
+
|
|
3
|
+
// lazily create entities as needed, and also function as an index of entities created
|
|
4
|
+
class BankSlot {
|
|
5
|
+
constructor (rule, bank) {
|
|
6
|
+
this.bank = bank
|
|
7
|
+
this.rule = rule
|
|
8
|
+
this.pool = []
|
|
9
|
+
this.remaining = +rule.count || 1
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
getOne (bgioArguments, options, context) {
|
|
13
|
+
return this.getMultiple(bgioArguments, 1, options, context)[0]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
getMultiple (bgioArguments, count = Infinity, options = {}, context) {
|
|
17
|
+
const toReturn = []
|
|
18
|
+
|
|
19
|
+
if (this.remaining === Infinity && count === Infinity) {
|
|
20
|
+
throw new Error(`Cannot get infinite pieces from slot with infinite remaining: ${this.rule.name}`)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (count !== Infinity && count > this.remaining) {
|
|
24
|
+
throw new Error(`Requested ${count} pieces but only ${this.remaining} available in slot: ${this.rule.name}`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Determine actual count to fetch
|
|
28
|
+
const actualCount = count === Infinity ? this.remaining : count
|
|
29
|
+
|
|
30
|
+
if (this.remaining !== Infinity) {
|
|
31
|
+
this.remaining -= actualCount
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const fromPool = Math.min(actualCount, this.pool.length)
|
|
35
|
+
toReturn.push(...this.pool.splice(0, fromPool))
|
|
36
|
+
|
|
37
|
+
const remainder = actualCount - fromPool
|
|
38
|
+
if (remainder > 0) {
|
|
39
|
+
toReturn.push(
|
|
40
|
+
...Array.from(new Array(remainder)).map(() =>
|
|
41
|
+
this.bank.createEntity(this.rule)
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (options.state) {
|
|
47
|
+
const newState = resolveProperties(bgioArguments, options.state, context)
|
|
48
|
+
toReturn.forEach(entity => {
|
|
49
|
+
entity.state = { ...entity.state, ...newState }
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return toReturn
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
returnToBank (entity) {
|
|
57
|
+
if (entity.rule.state) {
|
|
58
|
+
entity.state = entity.rule.state
|
|
59
|
+
} else {
|
|
60
|
+
delete entity.state
|
|
61
|
+
}
|
|
62
|
+
if (this.remaining !== undefined) {
|
|
63
|
+
this.remaining += 1
|
|
64
|
+
}
|
|
65
|
+
this.pool.push(entity)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default BankSlot
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import find from 'lodash/find.js'
|
|
2
|
+
import filter from 'lodash/filter.js'
|
|
3
|
+
import checkConditions from '../../utils/check-conditions.js'
|
|
4
|
+
import { registry } from '../../registry.js'
|
|
5
|
+
import BankSlot from './bank-slot.js'
|
|
6
|
+
|
|
7
|
+
class Bank {
|
|
8
|
+
constructor (entityRules) {
|
|
9
|
+
this.currentEntityId = 0
|
|
10
|
+
this.tracker = {}
|
|
11
|
+
this.slots = entityRules.map(rule => new BankSlot(rule, this))
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
createEntity (definition = {}, options) {
|
|
15
|
+
const entity = new (registry[definition.entityType || 'Entity'])(
|
|
16
|
+
{
|
|
17
|
+
bank: this,
|
|
18
|
+
fromBank: true,
|
|
19
|
+
...options
|
|
20
|
+
},
|
|
21
|
+
definition,
|
|
22
|
+
this.currentEntityId++
|
|
23
|
+
)
|
|
24
|
+
this.track(entity)
|
|
25
|
+
return entity
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
track (entity) {
|
|
29
|
+
this.tracker[entity.entityId] = entity
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
locate (entityId) {
|
|
33
|
+
return this.tracker[entityId]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
findAll (bgioArguments, rule, context) {
|
|
37
|
+
if (!rule.conditions) {
|
|
38
|
+
throw new Error (`Cannot find entity with no conditions. Rule: ${JSON.stringify(rule)}`)
|
|
39
|
+
}
|
|
40
|
+
return filter(
|
|
41
|
+
Object.values(this.tracker),
|
|
42
|
+
entity => checkConditions(
|
|
43
|
+
bgioArguments,
|
|
44
|
+
rule,
|
|
45
|
+
{ target: entity },
|
|
46
|
+
context
|
|
47
|
+
).conditionsAreMet
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
findOne (bgioArguments, rule, context) {
|
|
52
|
+
return this.findAll(bgioArguments, rule, context)[0]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
find (bgioArguments, rule, context) {
|
|
56
|
+
return rule.matchMultiple
|
|
57
|
+
? this.findAll(bgioArguments, rule, context)
|
|
58
|
+
: this.findOne(bgioArguments, rule, context)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
findParent (entity) {
|
|
62
|
+
return find(this.tracker, ent =>
|
|
63
|
+
ent.entities?.includes(entity)
|
|
64
|
+
|| ent.spaces?.includes(entity)
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
getOne (bgioArguments, rule, context) {
|
|
69
|
+
const slot = this.getSlot(bgioArguments, rule, context)
|
|
70
|
+
if (!slot) {
|
|
71
|
+
console.error(`No matching slot for ${JSON.stringify(rule)}`)
|
|
72
|
+
}
|
|
73
|
+
return slot.getOne(bgioArguments, { state: rule.state }, context)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
getMultiple (bgioArguments, rule, count, context) {
|
|
77
|
+
const slots = this.getSlots(bgioArguments, rule, context)
|
|
78
|
+
if (!slots.length) {
|
|
79
|
+
console.error(`No matching slots for ${JSON.stringify(rule)}`)
|
|
80
|
+
}
|
|
81
|
+
return slots.reduce((acc, slot) => [
|
|
82
|
+
...acc,
|
|
83
|
+
...slot.getMultiple(bgioArguments, count, { state: rule.state })
|
|
84
|
+
], [])
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
getSlot (bgioArguments, rule, context) {
|
|
88
|
+
return this.slots.find(slot => checkConditions(
|
|
89
|
+
bgioArguments,
|
|
90
|
+
rule,
|
|
91
|
+
{ target: slot },
|
|
92
|
+
context
|
|
93
|
+
).conditionsAreMet
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
getSlots (bgioArguments, rule, context) {
|
|
98
|
+
return this.slots.filter(slot => checkConditions(
|
|
99
|
+
bgioArguments,
|
|
100
|
+
rule,
|
|
101
|
+
{ target: slot },
|
|
102
|
+
context
|
|
103
|
+
).conditionsAreMet
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
returnToBank (bgioArguments, entity) {
|
|
108
|
+
this.findParent(entity).remove(entity)
|
|
109
|
+
this.getSlot(bgioArguments, entity.rule).returnToBank(entity)
|
|
110
|
+
delete this.tracker[entity.entityId]
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export default Bank
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import Is from "./is-condition.js";
|
|
2
|
+
import Not from "./not-condition.js";
|
|
3
|
+
import Or from "./or-condition.js";
|
|
4
|
+
import Some from "./some-condition.js";
|
|
5
|
+
import Every from "./every-condition.js";
|
|
6
|
+
import ContainsCondition from "./contains-condition.js";
|
|
7
|
+
import ContainsSameCondition from "./contains-same-condition.js";
|
|
8
|
+
import InLine from "./in-line-condition.js";
|
|
9
|
+
import HasLine from "./has-line-condition.js";
|
|
10
|
+
import IsFull from "./is-full-condition.js";
|
|
11
|
+
import Would from "./would-condition.js";
|
|
12
|
+
import NoPossibleMoves from "./no-possible-moves-condition.js";
|
|
13
|
+
import Evaluate from "./evaluate-condition.js";
|
|
14
|
+
import Position from "./position-condition.js";
|
|
15
|
+
// import BingoCondition from "./bingo-condition.js";
|
|
16
|
+
// import RelativeMoveCondition from "./relative-move-condition.js";
|
|
17
|
+
|
|
18
|
+
export default function conditionFactory(rule) {
|
|
19
|
+
if (rule.conditionType === "Is") {
|
|
20
|
+
return new Is(rule);
|
|
21
|
+
} else if (rule.conditionType === "Not") {
|
|
22
|
+
return new Not(rule);
|
|
23
|
+
} else if (rule.conditionType === "Or") {
|
|
24
|
+
return new Or(rule);
|
|
25
|
+
} else if (rule.conditionType === "Some") {
|
|
26
|
+
return new Some(rule);
|
|
27
|
+
} else if (rule.conditionType === "Contains") {
|
|
28
|
+
return new ContainsCondition(rule);
|
|
29
|
+
} else if (rule.conditionType === "ContainsSame") {
|
|
30
|
+
return new ContainsSameCondition(rule);
|
|
31
|
+
} else if (rule.conditionType === "Every") {
|
|
32
|
+
return new Every(rule);
|
|
33
|
+
} else if (rule.conditionType === "InLine") {
|
|
34
|
+
return new InLine(rule);
|
|
35
|
+
} else if (rule.conditionType === "HasLine") {
|
|
36
|
+
return new HasLine(rule);
|
|
37
|
+
} else if (rule.conditionType === "IsFull") {
|
|
38
|
+
return new IsFull(rule);
|
|
39
|
+
} else if (rule.conditionType === "Would") {
|
|
40
|
+
return new Would(rule);
|
|
41
|
+
} else if (rule.conditionType === "NoPossibleMoves") {
|
|
42
|
+
return new NoPossibleMoves(rule);
|
|
43
|
+
} else if (rule.conditionType === "Evaluate") {
|
|
44
|
+
return new Evaluate(rule);
|
|
45
|
+
} else if (rule.conditionType === "Position") {
|
|
46
|
+
return new Position(rule);
|
|
47
|
+
// } else if (rule.conditionType === "bingo") {
|
|
48
|
+
// return new BingoCondition(rule);
|
|
49
|
+
// } else if (rule.conditionType === "relativeMove") {
|
|
50
|
+
// return new RelativeMoveCondition(rule);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import resolveProperties from "../../utils/resolve-properties.js";
|
|
2
|
+
|
|
3
|
+
export default class Condition {
|
|
4
|
+
constructor (rule) {
|
|
5
|
+
this.rule = rule
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
check (bgioArguments, payload, context) {
|
|
9
|
+
const conditionPayload = { ...payload }
|
|
10
|
+
const newContext = { ...context }
|
|
11
|
+
|
|
12
|
+
if (conditionPayload.target) {
|
|
13
|
+
newContext.originalTarget = conditionPayload.target
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const rule = resolveProperties(
|
|
17
|
+
bgioArguments,
|
|
18
|
+
this.rule,
|
|
19
|
+
newContext
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
// We don't simply defer to payload target because of parent and relativePath
|
|
23
|
+
// target types, for instance, which retarget to another entity
|
|
24
|
+
if (rule.target !== undefined) {
|
|
25
|
+
conditionPayload.target = rule.target
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Nonexistent entities never fulfill conditions (including "Not" conditions!)
|
|
29
|
+
if (this.rule.target !== undefined && !conditionPayload.target) {
|
|
30
|
+
return { conditionIsMet: false }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return this.checkCondition(bgioArguments, rule, conditionPayload, newContext)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
isMet(...args) {
|
|
37
|
+
return this.check(...args).conditionIsMet
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import _matches from "lodash/matches.js";
|
|
2
|
-
import type { Condition as ConditionRule } from "../../types/bagel-types.js";
|
|
3
2
|
import Condition from "../condition/condition.js";
|
|
4
3
|
import checkConditions from "../../utils/check-conditions.js";
|
|
5
4
|
|
|
6
5
|
export default class ContainsCondition extends Condition {
|
|
7
|
-
checkCondition
|
|
8
|
-
const
|
|
6
|
+
checkCondition(bgioArguments, rule, payload, context) {
|
|
7
|
+
const { target } = payload
|
|
9
8
|
if (!target) {
|
|
10
9
|
return { matches: [], conditionIsMet: false }
|
|
11
10
|
} else {
|
|
12
11
|
const candidates = target.entities ?? target.spaces
|
|
13
|
-
const matches = candidates?.filter(
|
|
12
|
+
const matches = candidates?.filter(entity => checkConditions(
|
|
14
13
|
bgioArguments,
|
|
15
|
-
|
|
14
|
+
rule,
|
|
16
15
|
{ target: entity },
|
|
17
16
|
context
|
|
18
17
|
).conditionsAreMet) ?? []
|