@drmxrcy/tcg-core 0.0.0-202602060542
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/README.md +882 -0
- package/package.json +58 -0
- package/src/__tests__/alpha-clash-engine-definition.test.ts +319 -0
- package/src/__tests__/createMockAlphaClashGame.ts +462 -0
- package/src/__tests__/createMockGrandArchiveGame.ts +373 -0
- package/src/__tests__/createMockGundamGame.ts +379 -0
- package/src/__tests__/createMockLorcanaGame.ts +328 -0
- package/src/__tests__/createMockOnePieceGame.ts +429 -0
- package/src/__tests__/createMockRiftboundGame.ts +462 -0
- package/src/__tests__/grand-archive-engine-definition.test.ts +118 -0
- package/src/__tests__/gundam-engine-definition.test.ts +110 -0
- package/src/__tests__/integration-complete-game.test.ts +508 -0
- package/src/__tests__/integration-network-sync.test.ts +469 -0
- package/src/__tests__/lorcana-engine-definition.test.ts +100 -0
- package/src/__tests__/move-enumeration.test.ts +725 -0
- package/src/__tests__/multiplayer-engine.test.ts +555 -0
- package/src/__tests__/one-piece-engine-definition.test.ts +114 -0
- package/src/__tests__/riftbound-engine-definition.test.ts +124 -0
- package/src/actions/action-definition.test.ts +201 -0
- package/src/actions/action-definition.ts +122 -0
- package/src/actions/action-timing.test.ts +490 -0
- package/src/actions/action-timing.ts +257 -0
- package/src/cards/card-definition.test.ts +268 -0
- package/src/cards/card-definition.ts +27 -0
- package/src/cards/card-instance.test.ts +422 -0
- package/src/cards/card-instance.ts +49 -0
- package/src/cards/computed-properties.test.ts +530 -0
- package/src/cards/computed-properties.ts +84 -0
- package/src/cards/conditional-modifiers.test.ts +390 -0
- package/src/cards/modifiers.test.ts +286 -0
- package/src/cards/modifiers.ts +51 -0
- package/src/engine/MULTIPLAYER.md +425 -0
- package/src/engine/__tests__/rule-engine-flow.test.ts +348 -0
- package/src/engine/__tests__/rule-engine-history.test.ts +535 -0
- package/src/engine/__tests__/rule-engine-moves.test.ts +488 -0
- package/src/engine/__tests__/rule-engine.test.ts +366 -0
- package/src/engine/index.ts +14 -0
- package/src/engine/multiplayer-engine.example.ts +571 -0
- package/src/engine/multiplayer-engine.ts +409 -0
- package/src/engine/rule-engine.test.ts +286 -0
- package/src/engine/rule-engine.ts +1539 -0
- package/src/engine/tracker-system.ts +172 -0
- package/src/examples/__tests__/coin-flip-game.test.ts +641 -0
- package/src/filtering/card-filter.test.ts +230 -0
- package/src/filtering/card-filter.ts +91 -0
- package/src/filtering/card-query.test.ts +901 -0
- package/src/filtering/card-query.ts +273 -0
- package/src/filtering/filter-matching.test.ts +944 -0
- package/src/filtering/filter-matching.ts +315 -0
- package/src/flow/SERIALIZATION.md +428 -0
- package/src/flow/__tests__/flow-definition.test.ts +427 -0
- package/src/flow/__tests__/flow-manager.test.ts +756 -0
- package/src/flow/__tests__/flow-serialization.test.ts +565 -0
- package/src/flow/flow-definition.ts +453 -0
- package/src/flow/flow-manager.ts +1044 -0
- package/src/flow/index.ts +35 -0
- package/src/game-definition/__tests__/game-definition-validation.test.ts +359 -0
- package/src/game-definition/__tests__/game-definition.test.ts +291 -0
- package/src/game-definition/__tests__/move-definitions.test.ts +328 -0
- package/src/game-definition/game-definition.ts +261 -0
- package/src/game-definition/index.ts +28 -0
- package/src/game-definition/move-definitions.ts +188 -0
- package/src/game-definition/validation.ts +183 -0
- package/src/history/history-manager.test.ts +497 -0
- package/src/history/history-manager.ts +312 -0
- package/src/history/history-operations.ts +122 -0
- package/src/history/index.ts +9 -0
- package/src/history/types.ts +255 -0
- package/src/index.ts +32 -0
- package/src/logging/index.ts +27 -0
- package/src/logging/log-formatter.ts +187 -0
- package/src/logging/logger.ts +276 -0
- package/src/logging/types.ts +148 -0
- package/src/moves/create-move.test.ts +331 -0
- package/src/moves/create-move.ts +64 -0
- package/src/moves/move-enumeration.ts +228 -0
- package/src/moves/move-executor.test.ts +431 -0
- package/src/moves/move-executor.ts +195 -0
- package/src/moves/move-system.test.ts +380 -0
- package/src/moves/move-system.ts +463 -0
- package/src/moves/standard-moves.ts +231 -0
- package/src/operations/card-operations.test.ts +236 -0
- package/src/operations/card-operations.ts +116 -0
- package/src/operations/card-registry-impl.test.ts +251 -0
- package/src/operations/card-registry-impl.ts +70 -0
- package/src/operations/card-registry.test.ts +234 -0
- package/src/operations/card-registry.ts +106 -0
- package/src/operations/counter-operations.ts +152 -0
- package/src/operations/game-operations.test.ts +280 -0
- package/src/operations/game-operations.ts +140 -0
- package/src/operations/index.ts +24 -0
- package/src/operations/operations-impl.test.ts +354 -0
- package/src/operations/operations-impl.ts +468 -0
- package/src/operations/zone-operations.test.ts +295 -0
- package/src/operations/zone-operations.ts +223 -0
- package/src/rng/seeded-rng.test.ts +339 -0
- package/src/rng/seeded-rng.ts +123 -0
- package/src/targeting/index.ts +48 -0
- package/src/targeting/target-definition.test.ts +273 -0
- package/src/targeting/target-definition.ts +37 -0
- package/src/targeting/target-dsl.ts +279 -0
- package/src/targeting/target-resolver.ts +486 -0
- package/src/targeting/target-validation.test.ts +994 -0
- package/src/targeting/target-validation.ts +286 -0
- package/src/telemetry/events.ts +202 -0
- package/src/telemetry/index.ts +21 -0
- package/src/telemetry/telemetry-manager.ts +127 -0
- package/src/telemetry/types.ts +68 -0
- package/src/testing/__tests__/testing-utilities-integration.test.ts +161 -0
- package/src/testing/index.ts +88 -0
- package/src/testing/test-assertions.test.ts +341 -0
- package/src/testing/test-assertions.ts +256 -0
- package/src/testing/test-card-factory.test.ts +228 -0
- package/src/testing/test-card-factory.ts +111 -0
- package/src/testing/test-context-factory.ts +187 -0
- package/src/testing/test-end-assertions.test.ts +262 -0
- package/src/testing/test-end-assertions.ts +95 -0
- package/src/testing/test-engine-builder.test.ts +389 -0
- package/src/testing/test-engine-builder.ts +46 -0
- package/src/testing/test-flow-assertions.test.ts +284 -0
- package/src/testing/test-flow-assertions.ts +115 -0
- package/src/testing/test-player-builder.test.ts +132 -0
- package/src/testing/test-player-builder.ts +46 -0
- package/src/testing/test-replay-assertions.test.ts +356 -0
- package/src/testing/test-replay-assertions.ts +164 -0
- package/src/testing/test-rng-helpers.test.ts +260 -0
- package/src/testing/test-rng-helpers.ts +190 -0
- package/src/testing/test-state-builder.test.ts +373 -0
- package/src/testing/test-state-builder.ts +99 -0
- package/src/testing/test-zone-factory.test.ts +295 -0
- package/src/testing/test-zone-factory.ts +224 -0
- package/src/types/branded-utils.ts +54 -0
- package/src/types/branded.test.ts +175 -0
- package/src/types/branded.ts +33 -0
- package/src/types/index.ts +8 -0
- package/src/types/state.test.ts +198 -0
- package/src/types/state.ts +154 -0
- package/src/validation/card-type-guards.test.ts +242 -0
- package/src/validation/card-type-guards.ts +179 -0
- package/src/validation/index.ts +40 -0
- package/src/validation/schema-builders.test.ts +403 -0
- package/src/validation/schema-builders.ts +345 -0
- package/src/validation/type-guard-builder.test.ts +216 -0
- package/src/validation/type-guard-builder.ts +109 -0
- package/src/validation/validator-builder.test.ts +375 -0
- package/src/validation/validator-builder.ts +273 -0
- package/src/zones/index.ts +28 -0
- package/src/zones/zone-factory.test.ts +183 -0
- package/src/zones/zone-factory.ts +44 -0
- package/src/zones/zone-operations.test.ts +800 -0
- package/src/zones/zone-operations.ts +306 -0
- package/src/zones/zone-state-helpers.test.ts +337 -0
- package/src/zones/zone-state-helpers.ts +128 -0
- package/src/zones/zone-visibility.test.ts +156 -0
- package/src/zones/zone-visibility.ts +36 -0
- package/src/zones/zone.test.ts +186 -0
- package/src/zones/zone.ts +66 -0
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
import type { FlowDefinition } from "../flow";
|
|
2
|
+
import type { GameDefinition, GameMoveDefinitions } from "../game-definition";
|
|
3
|
+
import { standardMoves } from "../moves/standard-moves";
|
|
4
|
+
import type { CardId, PlayerId, ZoneId } from "../types";
|
|
5
|
+
import type { CardZoneConfig } from "../zones";
|
|
6
|
+
|
|
7
|
+
// Mock Alpha Clash game state - MASSIVELY SIMPLIFIED!
|
|
8
|
+
// The engine now handles: phase, turn, currentPlayer, setupStep, mulliganOffered
|
|
9
|
+
type TestGameState = {
|
|
10
|
+
contenderHealth: Record<string, number>;
|
|
11
|
+
resourcesAvailable: Record<string, number>;
|
|
12
|
+
clashInProgress: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type TestMoves = {
|
|
16
|
+
// Setup moves
|
|
17
|
+
placeContender: { playerId: PlayerId };
|
|
18
|
+
drawInitialHand: { playerId: PlayerId };
|
|
19
|
+
decideMulligan: { playerId: PlayerId; keepHand: boolean };
|
|
20
|
+
chooseFirstPlayer: { playerId: PlayerId };
|
|
21
|
+
transitionToPlay: Record<string, never>;
|
|
22
|
+
// Regular game moves
|
|
23
|
+
drawCard: { playerId: PlayerId };
|
|
24
|
+
playResource: { playerId: PlayerId; cardId: CardId };
|
|
25
|
+
playClashCard: { playerId: PlayerId; cardId: CardId };
|
|
26
|
+
playAction: { playerId: PlayerId; cardId: CardId };
|
|
27
|
+
setTrap: { playerId: PlayerId; cardId: CardId };
|
|
28
|
+
initiateClash: { playerId: PlayerId; attackerIds: CardId[] };
|
|
29
|
+
declareObstructors: {
|
|
30
|
+
playerId: PlayerId;
|
|
31
|
+
obstructorAssignments: Record<string, string>;
|
|
32
|
+
};
|
|
33
|
+
playClashBuff: { playerId: PlayerId; cardId: CardId };
|
|
34
|
+
// Standard moves provided by engine
|
|
35
|
+
pass: { playerId: PlayerId };
|
|
36
|
+
concede: { playerId: PlayerId };
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Alpha Clash move definitions
|
|
40
|
+
const alphaClashMoves: GameMoveDefinitions<TestGameState, TestMoves> = {
|
|
41
|
+
// Setup moves - now using engine utilities!
|
|
42
|
+
placeContender: {
|
|
43
|
+
reducer: (draft, context) => {
|
|
44
|
+
// NO MORE: if (!zones) checks - zones is guaranteed by engine!
|
|
45
|
+
const { zones } = context;
|
|
46
|
+
const playerId = context.params.playerId as PlayerId;
|
|
47
|
+
const deckCards = zones.getCardsInZone("deck" as ZoneId, playerId);
|
|
48
|
+
|
|
49
|
+
// Move first card (assumed to be Contender) to Contender zone
|
|
50
|
+
if (deckCards.length > 0) {
|
|
51
|
+
const contenderCardId = deckCards[0];
|
|
52
|
+
if (contenderCardId) {
|
|
53
|
+
zones.moveCard({
|
|
54
|
+
cardId: contenderCardId,
|
|
55
|
+
targetZoneId: "contender" as ZoneId,
|
|
56
|
+
position: "bottom",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// NO MORE: draft.setupStep - engine handles this!
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
drawInitialHand: {
|
|
66
|
+
reducer: (draft, context) => {
|
|
67
|
+
const { zones } = context;
|
|
68
|
+
const playerId = context.params.playerId as PlayerId;
|
|
69
|
+
|
|
70
|
+
// BEFORE: Manual shuffle + loop to draw cards (11 lines)
|
|
71
|
+
// AFTER: Use engine's high-level drawCards utility (3 lines!)
|
|
72
|
+
zones.shuffleZone("deck" as ZoneId, playerId);
|
|
73
|
+
zones.drawCards({
|
|
74
|
+
from: "deck" as ZoneId,
|
|
75
|
+
to: "hand" as ZoneId,
|
|
76
|
+
count: 8, // Alpha Clash standard starting hand size
|
|
77
|
+
playerId,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// NO MORE: draft.setupStep, draft.mulliganOffered - engine handles this!
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
decideMulligan: {
|
|
85
|
+
reducer: (draft, context) => {
|
|
86
|
+
const { zones } = context;
|
|
87
|
+
const playerId = context.params.playerId as PlayerId;
|
|
88
|
+
const keepHand = context.params.keepHand;
|
|
89
|
+
|
|
90
|
+
if (!keepHand) {
|
|
91
|
+
// BEFORE: Manual loop to return cards, shuffle, redraw (25 lines)
|
|
92
|
+
// AFTER: Use engine's mulligan utility (1 line!)
|
|
93
|
+
zones.mulligan({
|
|
94
|
+
hand: "hand" as ZoneId,
|
|
95
|
+
deck: "deck" as ZoneId,
|
|
96
|
+
drawCount: 8,
|
|
97
|
+
playerId,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// NO MORE: draft.mulliganOffered - engine handles this with trackers!
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
chooseFirstPlayer: {
|
|
106
|
+
reducer: (draft, context) => {
|
|
107
|
+
// NO MORE: draft.currentPlayer - engine handles this via flow!
|
|
108
|
+
// NO MORE: draft.firstPlayerChosen - engine provides context.flow.isFirstTurn!
|
|
109
|
+
// In a full implementation, we'd signal to the engine who goes first
|
|
110
|
+
// For now, this is just a placeholder
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
transitionToPlay: {
|
|
115
|
+
reducer: (draft, context) => {
|
|
116
|
+
// NO MORE: draft.setupStep, draft.phase, draft.turn - engine handles ALL of this!
|
|
117
|
+
// The game is ready to start - no manual state management needed!
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
// Regular game moves (enhanced with engine features)
|
|
122
|
+
drawCard: {
|
|
123
|
+
condition: (state, context) => {
|
|
124
|
+
// Use engine's flow context to check if it's the first turn
|
|
125
|
+
const isFirstTurn = context.flow?.isFirstTurn ?? false;
|
|
126
|
+
const isFirstPlayer = context.flow?.currentPlayer === context.playerId;
|
|
127
|
+
|
|
128
|
+
// First player skips draw on first turn (rule 103.7a)
|
|
129
|
+
if (isFirstTurn && isFirstPlayer) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return true;
|
|
134
|
+
},
|
|
135
|
+
reducer: (draft, context) => {
|
|
136
|
+
const playerId = context.params.playerId as PlayerId;
|
|
137
|
+
|
|
138
|
+
// Use engine's drawCards utility
|
|
139
|
+
context.zones.drawCards({
|
|
140
|
+
from: "deck" as ZoneId,
|
|
141
|
+
to: "hand" as ZoneId,
|
|
142
|
+
count: 1,
|
|
143
|
+
playerId,
|
|
144
|
+
});
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
playResource: {
|
|
149
|
+
condition: (state, context) => {
|
|
150
|
+
const playerId = context.params.playerId;
|
|
151
|
+
|
|
152
|
+
// BEFORE: state.hasPlayedResourceThisTurn[playerId]
|
|
153
|
+
// AFTER: Use engine's tracker system!
|
|
154
|
+
return !context.trackers?.check(
|
|
155
|
+
"hasPlayedResource",
|
|
156
|
+
playerId as PlayerId,
|
|
157
|
+
);
|
|
158
|
+
},
|
|
159
|
+
reducer: (draft, context) => {
|
|
160
|
+
const playerId = context.params.playerId as PlayerId;
|
|
161
|
+
const cardId = context.params.cardId as CardId;
|
|
162
|
+
|
|
163
|
+
// Move card to resource zone
|
|
164
|
+
context.zones.moveCard({
|
|
165
|
+
cardId,
|
|
166
|
+
targetZoneId: "resource" as ZoneId,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Increment resources
|
|
170
|
+
draft.resourcesAvailable[playerId] =
|
|
171
|
+
(draft.resourcesAvailable[playerId] || 0) + 1;
|
|
172
|
+
|
|
173
|
+
// BEFORE: draft.hasPlayedResourceThisTurn[playerId] = true
|
|
174
|
+
// AFTER: Use engine's tracker system!
|
|
175
|
+
context.trackers?.mark("hasPlayedResource", playerId);
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
playClashCard: {
|
|
180
|
+
reducer: (draft, context) => {
|
|
181
|
+
const cardId = context.params.cardId as CardId;
|
|
182
|
+
|
|
183
|
+
// Move card to clash zone
|
|
184
|
+
context.zones.moveCard({
|
|
185
|
+
cardId,
|
|
186
|
+
targetZoneId: "clash" as ZoneId,
|
|
187
|
+
});
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
playAction: {
|
|
192
|
+
reducer: (draft, context) => {
|
|
193
|
+
const cardId = context.params.cardId as CardId;
|
|
194
|
+
|
|
195
|
+
// Play action, then discard
|
|
196
|
+
context.zones.moveCard({
|
|
197
|
+
cardId,
|
|
198
|
+
targetZoneId: "discard" as ZoneId,
|
|
199
|
+
});
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
setTrap: {
|
|
204
|
+
reducer: (draft, context) => {
|
|
205
|
+
const cardId = context.params.cardId as CardId;
|
|
206
|
+
|
|
207
|
+
// Move card to accessory zone (face-down)
|
|
208
|
+
context.zones.moveCard({
|
|
209
|
+
cardId,
|
|
210
|
+
targetZoneId: "accessory" as ZoneId,
|
|
211
|
+
});
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
initiateClash: {
|
|
216
|
+
reducer: (draft, context) => {
|
|
217
|
+
draft.clashInProgress = true;
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
declareObstructors: {
|
|
222
|
+
reducer: (draft, context) => {
|
|
223
|
+
// Handle obstructor assignments
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
playClashBuff: {
|
|
228
|
+
reducer: (draft, context) => {
|
|
229
|
+
const cardId = context.params.cardId as CardId;
|
|
230
|
+
|
|
231
|
+
// Play buff during clash
|
|
232
|
+
context.zones.moveCard({
|
|
233
|
+
cardId,
|
|
234
|
+
targetZoneId: "standby" as ZoneId,
|
|
235
|
+
});
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
|
|
239
|
+
// Standard moves - using engine's standard moves library!
|
|
240
|
+
pass: standardMoves<TestGameState>({
|
|
241
|
+
include: ["pass"],
|
|
242
|
+
}).pass!,
|
|
243
|
+
|
|
244
|
+
concede: standardMoves<TestGameState>({
|
|
245
|
+
include: ["concede"],
|
|
246
|
+
}).concede!,
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// Alpha Clash zones configuration (unchanged)
|
|
250
|
+
const alphaClashZones: Record<string, CardZoneConfig> = {
|
|
251
|
+
deck: {
|
|
252
|
+
id: "deck" as ZoneId,
|
|
253
|
+
name: "zones.deck",
|
|
254
|
+
visibility: "private",
|
|
255
|
+
ordered: true,
|
|
256
|
+
owner: undefined,
|
|
257
|
+
faceDown: true,
|
|
258
|
+
maxSize: 50,
|
|
259
|
+
},
|
|
260
|
+
hand: {
|
|
261
|
+
id: "hand" as ZoneId,
|
|
262
|
+
name: "zones.hand",
|
|
263
|
+
visibility: "private",
|
|
264
|
+
ordered: false,
|
|
265
|
+
owner: undefined,
|
|
266
|
+
faceDown: false,
|
|
267
|
+
maxSize: undefined,
|
|
268
|
+
},
|
|
269
|
+
contender: {
|
|
270
|
+
id: "contender" as ZoneId,
|
|
271
|
+
name: "zones.contender",
|
|
272
|
+
visibility: "public",
|
|
273
|
+
ordered: false,
|
|
274
|
+
owner: undefined,
|
|
275
|
+
faceDown: false,
|
|
276
|
+
maxSize: 1,
|
|
277
|
+
},
|
|
278
|
+
clash: {
|
|
279
|
+
id: "clash" as ZoneId,
|
|
280
|
+
name: "zones.clash",
|
|
281
|
+
visibility: "public",
|
|
282
|
+
ordered: false,
|
|
283
|
+
owner: undefined,
|
|
284
|
+
faceDown: false,
|
|
285
|
+
maxSize: undefined,
|
|
286
|
+
},
|
|
287
|
+
clashground: {
|
|
288
|
+
id: "clashground" as ZoneId,
|
|
289
|
+
name: "zones.clashground",
|
|
290
|
+
visibility: "public",
|
|
291
|
+
ordered: false,
|
|
292
|
+
owner: undefined,
|
|
293
|
+
faceDown: false,
|
|
294
|
+
maxSize: 1,
|
|
295
|
+
},
|
|
296
|
+
accessory: {
|
|
297
|
+
id: "accessory" as ZoneId,
|
|
298
|
+
name: "zones.accessory",
|
|
299
|
+
visibility: "secret",
|
|
300
|
+
ordered: false,
|
|
301
|
+
owner: undefined,
|
|
302
|
+
faceDown: true,
|
|
303
|
+
maxSize: undefined,
|
|
304
|
+
},
|
|
305
|
+
resource: {
|
|
306
|
+
id: "resource" as ZoneId,
|
|
307
|
+
name: "zones.resource",
|
|
308
|
+
visibility: "public",
|
|
309
|
+
ordered: false,
|
|
310
|
+
owner: undefined,
|
|
311
|
+
faceDown: false,
|
|
312
|
+
maxSize: undefined,
|
|
313
|
+
},
|
|
314
|
+
discard: {
|
|
315
|
+
id: "discard" as ZoneId,
|
|
316
|
+
name: "zones.discard",
|
|
317
|
+
visibility: "public",
|
|
318
|
+
ordered: false,
|
|
319
|
+
owner: undefined,
|
|
320
|
+
faceDown: false,
|
|
321
|
+
maxSize: undefined,
|
|
322
|
+
},
|
|
323
|
+
oblivion: {
|
|
324
|
+
id: "oblivion" as ZoneId,
|
|
325
|
+
name: "zones.oblivion",
|
|
326
|
+
visibility: "public",
|
|
327
|
+
ordered: false,
|
|
328
|
+
owner: undefined,
|
|
329
|
+
faceDown: false,
|
|
330
|
+
maxSize: undefined,
|
|
331
|
+
},
|
|
332
|
+
standby: {
|
|
333
|
+
id: "standby" as ZoneId,
|
|
334
|
+
name: "zones.standby",
|
|
335
|
+
visibility: "public",
|
|
336
|
+
ordered: true,
|
|
337
|
+
owner: undefined,
|
|
338
|
+
faceDown: false,
|
|
339
|
+
maxSize: undefined,
|
|
340
|
+
},
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
// Alpha Clash flow definition (unchanged)
|
|
344
|
+
const alphaClashFlow: FlowDefinition<TestGameState> = {
|
|
345
|
+
turn: {
|
|
346
|
+
initialPhase: "startOfTurn",
|
|
347
|
+
onBegin: (_context) => {
|
|
348
|
+
// Turn begins - handle start of turn effects
|
|
349
|
+
},
|
|
350
|
+
onEnd: (_context) => {
|
|
351
|
+
// Turn cleanup
|
|
352
|
+
},
|
|
353
|
+
phases: {
|
|
354
|
+
startOfTurn: {
|
|
355
|
+
order: 0,
|
|
356
|
+
next: "expansion",
|
|
357
|
+
onBegin: (_context) => {
|
|
358
|
+
// Trigger start of turn effects
|
|
359
|
+
},
|
|
360
|
+
endIf: () => true,
|
|
361
|
+
},
|
|
362
|
+
expansion: {
|
|
363
|
+
order: 1,
|
|
364
|
+
next: "primary",
|
|
365
|
+
steps: {
|
|
366
|
+
readyStep: {
|
|
367
|
+
order: 1,
|
|
368
|
+
next: "drawStep",
|
|
369
|
+
onBegin: (_context) => {
|
|
370
|
+
// Ready all engaged cards
|
|
371
|
+
},
|
|
372
|
+
endIf: () => true,
|
|
373
|
+
},
|
|
374
|
+
drawStep: {
|
|
375
|
+
order: 2,
|
|
376
|
+
next: "resourceStep",
|
|
377
|
+
onBegin: (_context) => {
|
|
378
|
+
// Draw a card (handled by drawCard move)
|
|
379
|
+
},
|
|
380
|
+
endIf: () => true,
|
|
381
|
+
},
|
|
382
|
+
resourceStep: {
|
|
383
|
+
order: 3,
|
|
384
|
+
onBegin: (_context) => {
|
|
385
|
+
// Player may play one resource
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
primary: {
|
|
391
|
+
order: 2,
|
|
392
|
+
next: "endOfTurn",
|
|
393
|
+
onBegin: (_context) => {
|
|
394
|
+
// Primary phase - player can play cards, initiate clashes
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
endOfTurn: {
|
|
398
|
+
order: 3,
|
|
399
|
+
next: "startOfTurn",
|
|
400
|
+
onBegin: (_context) => {
|
|
401
|
+
// End of turn effects
|
|
402
|
+
},
|
|
403
|
+
endIf: (_context) => {
|
|
404
|
+
return true;
|
|
405
|
+
},
|
|
406
|
+
},
|
|
407
|
+
},
|
|
408
|
+
},
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Create minimal Alpha Clash game definition for testing
|
|
413
|
+
*
|
|
414
|
+
* REFACTORED to showcase new engine features:
|
|
415
|
+
* ✨ 100+ lines of boilerplate ELIMINATED!
|
|
416
|
+
* ✅ No manual phase/turn/player tracking
|
|
417
|
+
* ✅ High-level zone utilities (drawCards, mulligan)
|
|
418
|
+
* ✅ Tracker system for per-turn flags
|
|
419
|
+
* ✅ Standard moves library (pass, concede)
|
|
420
|
+
* ✅ Flow context access (isFirstTurn, currentPlayer)
|
|
421
|
+
* ✅ No redundant zone checks
|
|
422
|
+
*/
|
|
423
|
+
export function createMockAlphaClashGame(): GameDefinition<
|
|
424
|
+
TestGameState,
|
|
425
|
+
TestMoves
|
|
426
|
+
> {
|
|
427
|
+
return {
|
|
428
|
+
name: "Test Alpha Clash Game",
|
|
429
|
+
zones: alphaClashZones,
|
|
430
|
+
flow: alphaClashFlow,
|
|
431
|
+
moves: alphaClashMoves,
|
|
432
|
+
|
|
433
|
+
// Configure engine's tracker system for per-turn flags
|
|
434
|
+
trackers: {
|
|
435
|
+
perTurn: ["hasPlayedResource"], // Auto-resets at turn end
|
|
436
|
+
perPlayer: true, // Track separately for each player
|
|
437
|
+
},
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Setup function - MASSIVELY SIMPLIFIED!
|
|
441
|
+
*
|
|
442
|
+
* BEFORE: 60+ lines tracking phase, turn, currentPlayer, setupStep, firstPlayerChosen, mulliganOffered
|
|
443
|
+
* AFTER: 15 lines - just initialize game-specific data!
|
|
444
|
+
*/
|
|
445
|
+
setup: (players) => {
|
|
446
|
+
const playerIds = players.map((p) => p.id);
|
|
447
|
+
const contenderHealth: Record<string, number> = {};
|
|
448
|
+
const resourcesAvailable: Record<string, number> = {};
|
|
449
|
+
|
|
450
|
+
for (const playerId of playerIds) {
|
|
451
|
+
contenderHealth[playerId] = 20; // Default Contender starting health
|
|
452
|
+
resourcesAvailable[playerId] = 0;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return {
|
|
456
|
+
contenderHealth,
|
|
457
|
+
resourcesAvailable,
|
|
458
|
+
clashInProgress: false,
|
|
459
|
+
};
|
|
460
|
+
},
|
|
461
|
+
};
|
|
462
|
+
}
|