board-game-engine 0.0.2 → 0.0.3
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/board-game-engine.test.js +2 -41
- package/dist/board-game-engine.js +32556 -5074
- package/dist/board-game-engine.min.js +2 -1
- package/dist/board-game-engine.min.js.LICENSE.txt +14 -0
- package/package.json +6 -3
- package/patch-bgio.cjs +23 -0
- package/src/client/client.js +287 -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.js +3 -0
- 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.js +21 -0
- package/src/game-factory/condition/contains-same-condition.js +27 -0
- package/src/game-factory/condition/evaluate-condition.js +18 -0
- 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.js +14 -0
- package/src/game-factory/condition/not-condition.js +14 -0
- package/src/game-factory/condition/or-condition.js +15 -0
- package/src/game-factory/condition/position-condition.js +12 -0
- package/src/game-factory/condition/some-condition.js +24 -0
- 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 +276 -0
- package/src/game-factory/game-factory.js +239 -0
- package/src/game-factory/move/end-turn.js +7 -0
- package/src/game-factory/move/for-each.js +18 -0
- package/src/game-factory/move/index.js +7 -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/src/game-factory/move/pass.js +7 -0
- 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 +13 -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/registry.js +17 -0
- package/src/utils/any-valid-moves.js +157 -0
- 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 +28 -0
- package/src/utils/get.js +25 -0
- package/src/utils/grid-contains-sequence.js +226 -0
- package/src/utils/json-transformer.js +12 -0
- package/src/utils/prepare-payload.js +16 -0
- package/src/utils/resolve-entity.js +9 -0
- package/src/utils/resolve-expression.js +10 -0
- package/src/utils/resolve-properties.js +157 -0
- package/src/utils/simulate-move.js +25 -0
- package/webpack.config.js +4 -1
- package/src/action/action-factory.js +0 -13
- package/src/action/action.js +0 -34
- package/src/action/move-piece-action.js +0 -11
- package/src/action/select-piece-action.js +0 -23
- package/src/action/swap-action.js +0 -14
- package/src/board/board-factory.js +0 -12
- package/src/board/board-group.js +0 -9
- package/src/board/board.js +0 -11
- package/src/board/grid.js +0 -52
- package/src/board/stack.js +0 -16
- package/src/condition/action-type-matches-condition.js +0 -7
- package/src/condition/bingo-condition.js +0 -50
- package/src/condition/blackout-condition.js +0 -9
- package/src/condition/condition-factory.js +0 -31
- package/src/condition/condition.js +0 -9
- package/src/condition/contains-condition.js +0 -14
- package/src/condition/does-not-contain-condition.js +0 -15
- package/src/condition/is-valid-player-condition.js +0 -7
- package/src/condition/piece-matches-condition.js +0 -23
- package/src/condition/relative-move-condition.js +0 -16
- package/src/condition/some-condition.js +0 -7
- package/src/game/game.ts +0 -362
- package/src/index.ts +0 -1
- package/src/piece/piece-factory.js +0 -5
- package/src/piece/piece.ts +0 -25
- package/src/piece/pile.js +0 -70
- package/src/player/player.ts +0 -13
- package/src/registry.ts +0 -51
- package/src/round/round-factory.js +0 -7
- package/src/round/round.js +0 -41
- package/src/round/sequential-player-turn.js +0 -18
- package/src/space/space.ts +0 -22
- package/src/utils/find-value-path.js +0 -37
- package/src/utils/resolve-board.ts +0 -38
- package/src/utils/resolve-piece.ts +0 -43
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// recurse and replace. circular references not allowed
|
|
2
|
+
export default function transformJSON(data, rules) {
|
|
3
|
+
return JSON.parse(JSON.stringify(data), (key, value) => {
|
|
4
|
+
let result = value;
|
|
5
|
+
for (const rule of rules) {
|
|
6
|
+
if (rule.test(result)) {
|
|
7
|
+
result = rule.replace(result);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return result;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { serialize } from "wackson";
|
|
2
|
+
|
|
3
|
+
// todo: remember why reducing to id was preferred?
|
|
4
|
+
export default function preparePayload (payload) {
|
|
5
|
+
if (payload?.arguments) {
|
|
6
|
+
const payloadCopy = { ...payload }
|
|
7
|
+
payloadCopy.arguments =
|
|
8
|
+
Object.entries(payloadCopy.arguments).reduce((acc, [key, argument]) => ({
|
|
9
|
+
...acc,
|
|
10
|
+
[key]: argument.abstract ? argument : argument.entityId
|
|
11
|
+
}), {})
|
|
12
|
+
return JSON.parse(serialize(payloadCopy, { deduplicateInstances: false }))
|
|
13
|
+
} else {
|
|
14
|
+
return payload
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import isPlainObject from "lodash/isPlainObject.js";
|
|
2
|
+
|
|
3
|
+
const abstractTargetNames = ['state']
|
|
4
|
+
|
|
5
|
+
export default function resolveEntity (bgioArguments, target, context, targetName) {
|
|
6
|
+
return !abstractTargetNames.includes(targetName) && isPlainObject(target)
|
|
7
|
+
? bgioArguments.G.bank.find(bgioArguments, target, context)
|
|
8
|
+
: target
|
|
9
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Parser } from 'expr-eval'
|
|
2
|
+
import resolveProperties from "../utils/resolve-properties.js";
|
|
3
|
+
|
|
4
|
+
const parser = new Parser();
|
|
5
|
+
parser.functions.sum = array => array.reduce((acc, val) => acc + val, 0)
|
|
6
|
+
|
|
7
|
+
export default function resolveExpression (bgioArguments, rule, context) {
|
|
8
|
+
const args = resolveProperties(bgioArguments, rule.arguments, context)
|
|
9
|
+
return parser.evaluate(rule.expression, args)
|
|
10
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import isPlainObject from "lodash/isPlainObject.js";
|
|
2
|
+
import pick from "lodash/pick.js";
|
|
3
|
+
import get from "./get.js";
|
|
4
|
+
import resolveExpression from "./resolve-expression.js";
|
|
5
|
+
import resolveEntity from "./resolve-entity.js";
|
|
6
|
+
|
|
7
|
+
// some keys only contain things that will be the root of a later resolution
|
|
8
|
+
const resolutionTerminators = [
|
|
9
|
+
'conditions',
|
|
10
|
+
'move',
|
|
11
|
+
'then',
|
|
12
|
+
'mapping',
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
export default function resolveProperties (bgioArguments, obj, context, key) {
|
|
16
|
+
if (!isPlainObject(obj) && !Array.isArray(obj)) {
|
|
17
|
+
return obj
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let resolvedProperties = Array.isArray(obj)
|
|
21
|
+
? [...obj]
|
|
22
|
+
: { ...obj }
|
|
23
|
+
|
|
24
|
+
Object.entries(obj).forEach(([key, value]) => {
|
|
25
|
+
if (!resolutionTerminators.includes(key)) {
|
|
26
|
+
resolvedProperties[key] = resolveProperties(bgioArguments, value, context, key)
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const resolved = resolveProperty(bgioArguments, resolvedProperties, context)
|
|
31
|
+
|
|
32
|
+
const resolveAsEntity = resolved?.resolveAsEntity
|
|
33
|
+
|| key === 'target'
|
|
34
|
+
|| key === 'targets'
|
|
35
|
+
|
|
36
|
+
return resolveAsEntity
|
|
37
|
+
? resolveEntity(
|
|
38
|
+
bgioArguments,
|
|
39
|
+
resolved,
|
|
40
|
+
context,
|
|
41
|
+
key
|
|
42
|
+
)
|
|
43
|
+
: resolved
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function resolveProperty (bgioArguments, value, context) {
|
|
47
|
+
if (value?.type === 'expression') {
|
|
48
|
+
return resolveExpression(
|
|
49
|
+
bgioArguments,
|
|
50
|
+
{
|
|
51
|
+
...value,
|
|
52
|
+
arguments: resolveProperties(bgioArguments, value.arguments, context, 'arguments')
|
|
53
|
+
},
|
|
54
|
+
context
|
|
55
|
+
)
|
|
56
|
+
} else if (value?.type === 'count') {
|
|
57
|
+
return bgioArguments.G.bank.findAll(
|
|
58
|
+
bgioArguments,
|
|
59
|
+
value,
|
|
60
|
+
context
|
|
61
|
+
).length
|
|
62
|
+
} else if (value?.type === 'contextPath') {
|
|
63
|
+
return get(context, value.path)
|
|
64
|
+
} else if (value?.type === 'ctxPath') {
|
|
65
|
+
return get(bgioArguments.ctx, value.path)
|
|
66
|
+
} else if (value?.type === 'gamePath') {
|
|
67
|
+
return get(bgioArguments.G, value.path)
|
|
68
|
+
} else if (value?.type === 'RelativePath') {
|
|
69
|
+
const target = resolveProperties(bgioArguments, value.target, context, 'target')
|
|
70
|
+
return get(target.attributes, value.path) ?? null
|
|
71
|
+
} else if (value?.type === 'Parent') {
|
|
72
|
+
const originalTarget = value.target
|
|
73
|
+
? resolveProperties(bgioArguments, value.target, context, 'target')
|
|
74
|
+
: context.originalTarget
|
|
75
|
+
return bgioArguments.G.bank.findParent(originalTarget) ?? null
|
|
76
|
+
} else if (value?.type === 'map') {
|
|
77
|
+
return getMappedTargets(
|
|
78
|
+
bgioArguments,
|
|
79
|
+
value.targets,
|
|
80
|
+
value.mapping,
|
|
81
|
+
context
|
|
82
|
+
).map(mappedTarget => mappedTarget.value)
|
|
83
|
+
} else if (value?.type === 'mapMax') {
|
|
84
|
+
const mappedTargets = getMappedTargets(
|
|
85
|
+
bgioArguments,
|
|
86
|
+
value.targets,
|
|
87
|
+
value.mapping,
|
|
88
|
+
context
|
|
89
|
+
)
|
|
90
|
+
let maxValue
|
|
91
|
+
const maxTargets = []
|
|
92
|
+
for (let i = 0, len = mappedTargets.length; i < len; i++) {
|
|
93
|
+
const { target, value: val } = mappedTargets[i]
|
|
94
|
+
if (maxValue === undefined || val > maxValue) {
|
|
95
|
+
maxValue = val
|
|
96
|
+
maxTargets.length = 0
|
|
97
|
+
maxTargets.push(target)
|
|
98
|
+
} else if (val === maxValue) {
|
|
99
|
+
maxTargets.push(target)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return maxTargets
|
|
103
|
+
} else if (value?.type === 'Pick') {
|
|
104
|
+
const target = resolveProperties(bgioArguments, value.target, context, 'target')
|
|
105
|
+
if (target !== undefined) {
|
|
106
|
+
console.log('target', target)
|
|
107
|
+
console.log('target.attributes', target.attributes)
|
|
108
|
+
const x = pick(
|
|
109
|
+
resolveProperties(
|
|
110
|
+
bgioArguments,
|
|
111
|
+
target.attributes,
|
|
112
|
+
context,
|
|
113
|
+
'attributes'
|
|
114
|
+
),
|
|
115
|
+
value.properties
|
|
116
|
+
)
|
|
117
|
+
console.log('x', x)
|
|
118
|
+
return x
|
|
119
|
+
} else {
|
|
120
|
+
console.log('8888target', target)
|
|
121
|
+
}
|
|
122
|
+
} else if (value?.type === 'Coordinates') {
|
|
123
|
+
const originalTarget = value.target
|
|
124
|
+
? resolveProperties(bgioArguments, value.target, context, 'target')
|
|
125
|
+
: context.originalTarget
|
|
126
|
+
const parent = bgioArguments.G.bank.findParent(originalTarget)
|
|
127
|
+
return parent.getCoordinates(originalTarget.rule.index)
|
|
128
|
+
} else if (value?.type === 'relativeCoordinates') {
|
|
129
|
+
const originalTarget = value.target
|
|
130
|
+
? resolveProperties(bgioArguments, value.target, context, 'target')
|
|
131
|
+
: context.originalTarget
|
|
132
|
+
const parent = bgioArguments.G.bank.findParent(originalTarget)
|
|
133
|
+
const oldCoordinates =
|
|
134
|
+
parent.getCoordinates(originalTarget.rule.index)
|
|
135
|
+
const newCoordinates =
|
|
136
|
+
parent.getRelativeCoordinates(
|
|
137
|
+
oldCoordinates,
|
|
138
|
+
resolveProperties(bgioArguments, value.location, context, 'location')
|
|
139
|
+
)
|
|
140
|
+
return (newCoordinates && parent.spaces[parent.getIndex(newCoordinates)]) ?? null
|
|
141
|
+
} else {
|
|
142
|
+
return value
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function getMappedTargets (bgioArguments, targetsRule, mapping, context) {
|
|
147
|
+
targetsRule.resolveAsEntity = true
|
|
148
|
+
return resolveProperties(bgioArguments, targetsRule, context)?.map(target => ({
|
|
149
|
+
target,
|
|
150
|
+
value: resolveProperties(
|
|
151
|
+
bgioArguments,
|
|
152
|
+
mapping,
|
|
153
|
+
{ ...context, loopTarget: target },
|
|
154
|
+
)
|
|
155
|
+
})) ?? []
|
|
156
|
+
}
|
|
157
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { serialize, deserialize } from 'wackson'
|
|
2
|
+
import { registry } from '../registry.js'
|
|
3
|
+
|
|
4
|
+
export default function simulateMove (bgioArguments, payload, context) {
|
|
5
|
+
const simulatedG = deserialize(serialize(bgioArguments.G), registry)
|
|
6
|
+
const newBgioArguments = {
|
|
7
|
+
...bgioArguments,
|
|
8
|
+
G: simulatedG,
|
|
9
|
+
}
|
|
10
|
+
const simulatedPayload = { ...payload, arguments: {} }
|
|
11
|
+
Object.entries(payload.arguments).forEach(([argName, arg]) => {
|
|
12
|
+
simulatedPayload.arguments[argName] = arg.abstract
|
|
13
|
+
? arg
|
|
14
|
+
: simulatedG.bank.locate(typeof arg === 'number' ? arg : arg.entityId)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
context.moveInstance.doMove(
|
|
18
|
+
newBgioArguments,
|
|
19
|
+
simulatedPayload,
|
|
20
|
+
context,
|
|
21
|
+
{ skipCheck: true }
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
return simulatedG
|
|
25
|
+
}
|
package/webpack.config.js
CHANGED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import MovePieceAction from "./move-piece-action.js";
|
|
2
|
-
import SwapAction from "./swap-action.js";
|
|
3
|
-
import SelectPieceAction from "./select-piece-action.js";
|
|
4
|
-
|
|
5
|
-
export default function actionFactory(actionPayload, game) {
|
|
6
|
-
if (actionPayload.type === "movePiece") {
|
|
7
|
-
return new MovePieceAction(actionPayload, game);
|
|
8
|
-
} else if (actionPayload.type === "swap") {
|
|
9
|
-
return new SwapAction(actionPayload, game);
|
|
10
|
-
} else if (actionPayload.type === "selectPiece") {
|
|
11
|
-
return new SelectPieceAction(actionPayload, game);
|
|
12
|
-
}
|
|
13
|
-
}
|
package/src/action/action.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import conditionFactory from '../condition/condition-factory.js'
|
|
2
|
-
|
|
3
|
-
export default class Action {
|
|
4
|
-
constructor (rules, game) {
|
|
5
|
-
this.game = game
|
|
6
|
-
this.rules = rules
|
|
7
|
-
this.id = `${Math.random()}`
|
|
8
|
-
|
|
9
|
-
const invariantConditionRules = [
|
|
10
|
-
{ type: 'actionTypeMatches', actionRule: this.rules },
|
|
11
|
-
{ type: 'pieceMatches', actionRule: this.rules },
|
|
12
|
-
{ type: 'isValidPlayer' }
|
|
13
|
-
]
|
|
14
|
-
|
|
15
|
-
this.conditions = [
|
|
16
|
-
...invariantConditionRules,
|
|
17
|
-
...(this.rules.conditions || [])
|
|
18
|
-
].map((conditionRule) => conditionFactory(conditionRule, game))
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
assertIsValid (actionPayload) {
|
|
22
|
-
const unmetConditions = this.conditions.filter(
|
|
23
|
-
(condition) => !condition.isMet(actionPayload)
|
|
24
|
-
)
|
|
25
|
-
if (unmetConditions.length) {
|
|
26
|
-
console.log('==================')
|
|
27
|
-
console.log('unmetConditions', unmetConditions)
|
|
28
|
-
console.log('actionPayload', actionPayload)
|
|
29
|
-
throw new Error('conditions not met ^')
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
do () {}
|
|
34
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import Action from "./action.js";
|
|
2
|
-
import resolveBoard from "../utils/resolve-board.ts";
|
|
3
|
-
import resolvePiece from "../utils/resolve-piece.ts";
|
|
4
|
-
|
|
5
|
-
export default class MovePieceAction extends Action {
|
|
6
|
-
do(actionPayload) {
|
|
7
|
-
const piece = resolvePiece(actionPayload.piece, this.game);
|
|
8
|
-
const board = resolveBoard(actionPayload.board, this.game)
|
|
9
|
-
board.placePiece(actionPayload.target, piece);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import Action from "./action.js";
|
|
2
|
-
|
|
3
|
-
export default class SelectPieceAction extends Action {
|
|
4
|
-
constructor(actionPayload, game) {
|
|
5
|
-
super(actionPayload, game);
|
|
6
|
-
}
|
|
7
|
-
do(actionPayload) {
|
|
8
|
-
let piece;
|
|
9
|
-
if (actionPayload.piece?.id) {
|
|
10
|
-
piece = this.game.getPiece({
|
|
11
|
-
id: actionPayload.piece?.id,
|
|
12
|
-
});
|
|
13
|
-
} else if (actionPayload.from === "player") {
|
|
14
|
-
piece = this.game.players
|
|
15
|
-
.find((player) => player.id === actionPayload.playerId)
|
|
16
|
-
.pieces.find((piece) => piece.name === actionPayload.piece.name)
|
|
17
|
-
.getOne();
|
|
18
|
-
}
|
|
19
|
-
this.game.context.selectedPiece = piece;
|
|
20
|
-
|
|
21
|
-
// do the "then"
|
|
22
|
-
}
|
|
23
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import Action from "./action.js";
|
|
2
|
-
|
|
3
|
-
export default class SwapAction extends Action {
|
|
4
|
-
do(actionPayload) {
|
|
5
|
-
let piece;
|
|
6
|
-
if (actionPayload.from === "player") {
|
|
7
|
-
piece = this.game.players
|
|
8
|
-
.find((player) => player.id === actionPayload.playerId)
|
|
9
|
-
.pieces.find((piece) => piece.name === actionPayload.piece.name)
|
|
10
|
-
.getOne();
|
|
11
|
-
}
|
|
12
|
-
this.game.get(actionPayload.board).placePiece(actionPayload.target, piece);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import Grid from "./grid.js";
|
|
2
|
-
import Stack from "./stack.js";
|
|
3
|
-
|
|
4
|
-
export default function boardFactory(boardRule, options) {
|
|
5
|
-
if (boardRule.type === "grid") {
|
|
6
|
-
return new Grid(boardRule, options);
|
|
7
|
-
} else if (boardRule.type === "stack") {
|
|
8
|
-
return new Stack(boardRule, options);
|
|
9
|
-
} else {
|
|
10
|
-
console.log("missing board type:", boardRule);
|
|
11
|
-
}
|
|
12
|
-
}
|
package/src/board/board-group.js
DELETED
package/src/board/board.js
DELETED
package/src/board/grid.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import get from "lodash/get.js";
|
|
2
|
-
import Board from "./board.js";
|
|
3
|
-
import Space from "../space/space.ts";
|
|
4
|
-
|
|
5
|
-
export default class Grid extends Board {
|
|
6
|
-
constructor(boardRule, options) {
|
|
7
|
-
super(boardRule, options);
|
|
8
|
-
this.grid = makeGrid(boardRule);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
getEmptySpaces() {
|
|
12
|
-
const emptySpaces = [];
|
|
13
|
-
for (const row of this.grid) {
|
|
14
|
-
for (const space of row) {
|
|
15
|
-
if (space.isEmpty()) {
|
|
16
|
-
emptySpaces.push(space);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return emptySpaces;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
getSpace(target) {
|
|
24
|
-
return get(this.grid, target);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
getPieces(target) {
|
|
28
|
-
return this.getSpace(target).pieces;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
placePiece(target, piece) {
|
|
32
|
-
this.getSpace(target).placePiece(piece);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function makeGrid(boardRule) {
|
|
37
|
-
const x = boardRule.width;
|
|
38
|
-
const y = boardRule.height;
|
|
39
|
-
if (!x || !y) {
|
|
40
|
-
throw new Error("No size provided for grid");
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const grid = [];
|
|
44
|
-
for (let i = 0; i < y; i++) {
|
|
45
|
-
const row = [];
|
|
46
|
-
for (let j = 0; j < x; j++) {
|
|
47
|
-
row.push(new Space([i, j]));
|
|
48
|
-
}
|
|
49
|
-
grid.push(row);
|
|
50
|
-
}
|
|
51
|
-
return grid;
|
|
52
|
-
}
|
package/src/board/stack.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import Board from "./board.js";
|
|
2
|
-
|
|
3
|
-
export default class Stack extends Board {
|
|
4
|
-
constructor(boardRule, options) {
|
|
5
|
-
super(boardRule, options);
|
|
6
|
-
this.stack = [];
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
placePiece(target, piece) {
|
|
10
|
-
if (target) {
|
|
11
|
-
// insert by index?
|
|
12
|
-
} else {
|
|
13
|
-
this.stack.push(piece);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import Condition from "../condition/condition.js";
|
|
2
|
-
import resolveBoard from "../utils/resolve-board.ts";
|
|
3
|
-
|
|
4
|
-
export default class BingoCondition extends Condition {
|
|
5
|
-
isMet() {
|
|
6
|
-
const grid = resolveBoard(this.rules.boardPath, this.game).grid;
|
|
7
|
-
|
|
8
|
-
// TODO: handle rectangles in addition to squares
|
|
9
|
-
const size = grid.length;
|
|
10
|
-
|
|
11
|
-
// Check rows
|
|
12
|
-
for (let i = 0; i < size; i++) {
|
|
13
|
-
if (this.checkLine(grid[i])) {
|
|
14
|
-
return true;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Check columns
|
|
19
|
-
for (let i = 0; i < size; i++) {
|
|
20
|
-
const column = [];
|
|
21
|
-
for (let j = 0; j < size; j++) {
|
|
22
|
-
column.push(grid[j][i]);
|
|
23
|
-
}
|
|
24
|
-
if (this.checkLine(column)) {
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Check diagonals
|
|
30
|
-
const diagonal1 = [];
|
|
31
|
-
const diagonal2 = [];
|
|
32
|
-
for (let i = 0; i < size; i++) {
|
|
33
|
-
diagonal1.push(grid[i][i]);
|
|
34
|
-
diagonal2.push(grid[i][size - 1 - i]);
|
|
35
|
-
}
|
|
36
|
-
if (this.checkLine(diagonal1) || this.checkLine(diagonal2)) {
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
checkLine(line) {
|
|
44
|
-
return line.every((space) =>
|
|
45
|
-
space.pieces.some((piece) => {
|
|
46
|
-
return piece.doesRuleMatch(this.rules.piece);
|
|
47
|
-
}),
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import Condition from "../condition/condition.js";
|
|
2
|
-
import resolveBoard from "../utils/resolve-board.ts";
|
|
3
|
-
|
|
4
|
-
export default class BlackoutCondition extends Condition {
|
|
5
|
-
isMet() {
|
|
6
|
-
const grid = resolveBoard(this.rules.boardPath, this.game).grid;
|
|
7
|
-
return grid.every((row) => row.every((space) => !space.isEmpty()));
|
|
8
|
-
}
|
|
9
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import DoesNotContainCondition from "./does-not-contain-condition.js";
|
|
2
|
-
import ContainsCondition from "./contains-condition.js";
|
|
3
|
-
import BingoCondition from "./bingo-condition.js";
|
|
4
|
-
import BlackoutCondition from "./blackout-condition.js";
|
|
5
|
-
import SomeCondition from "./some-condition.js";
|
|
6
|
-
import RelativeMoveCondition from "./relative-move-condition.js";
|
|
7
|
-
import ActionTypeMatchesCondition from "./action-type-matches-condition.js";
|
|
8
|
-
import IsValidPlayerCondition from "./is-valid-player-condition.js";
|
|
9
|
-
import PieceMatchesCondition from "./piece-matches-condition.js";
|
|
10
|
-
|
|
11
|
-
export default function conditionFactory(conditionRule, game) {
|
|
12
|
-
if (conditionRule.type === "contains") {
|
|
13
|
-
return new ContainsCondition(conditionRule, game);
|
|
14
|
-
} else if (conditionRule.type === "doesNotContain") {
|
|
15
|
-
return new DoesNotContainCondition(conditionRule, game);
|
|
16
|
-
} else if (conditionRule.type === "bingo") {
|
|
17
|
-
return new BingoCondition(conditionRule, game);
|
|
18
|
-
} else if (conditionRule.type === "blackout") {
|
|
19
|
-
return new BlackoutCondition(conditionRule, game);
|
|
20
|
-
} else if (conditionRule.type === "some") {
|
|
21
|
-
return new SomeCondition(conditionRule, game);
|
|
22
|
-
} else if (conditionRule.type === "relativeMove") {
|
|
23
|
-
return new RelativeMoveCondition(conditionRule, game);
|
|
24
|
-
} else if (conditionRule.type === "actionTypeMatches") {
|
|
25
|
-
return new ActionTypeMatchesCondition(conditionRule, game);
|
|
26
|
-
} else if (conditionRule.type === "isValidPlayer") {
|
|
27
|
-
return new IsValidPlayerCondition(conditionRule, game);
|
|
28
|
-
} else if (conditionRule.type === "pieceMatches") {
|
|
29
|
-
return new PieceMatchesCondition(conditionRule, game);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import matches from "lodash/matches.js";
|
|
2
|
-
import Condition from "../condition/condition.js";
|
|
3
|
-
|
|
4
|
-
export default class ContainsCondition extends Condition {
|
|
5
|
-
isMet(actionPayload) {
|
|
6
|
-
const board = this.game.get(actionPayload.board);
|
|
7
|
-
const pieces = board.getPieces(actionPayload.target);
|
|
8
|
-
return !!pieces.filter(filterPieces).length;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
filterPieces(piece) {
|
|
12
|
-
return this.rules.piece === "any" || matches(this.rules.piece)(piece);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import matches from "lodash/matches.js";
|
|
2
|
-
import Condition from "../condition/condition.js";
|
|
3
|
-
import resolveBoard from "../utils/resolve-board.ts";
|
|
4
|
-
|
|
5
|
-
export default class DoesNotContainCondition extends Condition {
|
|
6
|
-
isMet(actionPayload) {
|
|
7
|
-
const board = resolveBoard(actionPayload.board, this.game);
|
|
8
|
-
const pieces = board.getPieces(actionPayload.target);
|
|
9
|
-
return !pieces.filter(this.filterPieces.bind(this)).length;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
filterPieces(piece) {
|
|
13
|
-
return this.rules.piece === "any" || matches(piece, this.rules.piece || {});
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import matches from "lodash/matches.js";
|
|
2
|
-
import Condition from "../condition/condition.js";
|
|
3
|
-
import resolvePiece from "../utils/resolve-piece.ts";
|
|
4
|
-
|
|
5
|
-
export default class PieceMatchesCondition extends Condition {
|
|
6
|
-
isMet(actionPayload) {
|
|
7
|
-
const piece = resolvePiece(actionPayload.piece, this.game);
|
|
8
|
-
|
|
9
|
-
if (this.rules.actionRule?.piece && !piece) {
|
|
10
|
-
console.error("no piece found");
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
if (this.rules.actionRule?.piece) {
|
|
15
|
-
const matcher = {
|
|
16
|
-
...this.rules.actionRule.piece,
|
|
17
|
-
};
|
|
18
|
-
return matches(matcher)(piece.rule);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return true;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import matches from "lodash/matches.js";
|
|
2
|
-
import Condition from "../condition/condition.js";
|
|
3
|
-
|
|
4
|
-
export default class RelativeMoveCondition extends Condition {
|
|
5
|
-
isMet(actionPayload) {
|
|
6
|
-
const board = this.game.get(actionPayload.board);
|
|
7
|
-
const pieces = board.getPieces(actionPayload.target);
|
|
8
|
-
return !pieces.filter(this.filterPieces.bind(this)).length;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
filterPieces(piece) {
|
|
12
|
-
return (
|
|
13
|
-
this.rules.piece === "any" || matches(piece, (this.rules.piece = {}))
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
}
|