@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.
Files changed (157) hide show
  1. package/README.md +882 -0
  2. package/package.json +58 -0
  3. package/src/__tests__/alpha-clash-engine-definition.test.ts +319 -0
  4. package/src/__tests__/createMockAlphaClashGame.ts +462 -0
  5. package/src/__tests__/createMockGrandArchiveGame.ts +373 -0
  6. package/src/__tests__/createMockGundamGame.ts +379 -0
  7. package/src/__tests__/createMockLorcanaGame.ts +328 -0
  8. package/src/__tests__/createMockOnePieceGame.ts +429 -0
  9. package/src/__tests__/createMockRiftboundGame.ts +462 -0
  10. package/src/__tests__/grand-archive-engine-definition.test.ts +118 -0
  11. package/src/__tests__/gundam-engine-definition.test.ts +110 -0
  12. package/src/__tests__/integration-complete-game.test.ts +508 -0
  13. package/src/__tests__/integration-network-sync.test.ts +469 -0
  14. package/src/__tests__/lorcana-engine-definition.test.ts +100 -0
  15. package/src/__tests__/move-enumeration.test.ts +725 -0
  16. package/src/__tests__/multiplayer-engine.test.ts +555 -0
  17. package/src/__tests__/one-piece-engine-definition.test.ts +114 -0
  18. package/src/__tests__/riftbound-engine-definition.test.ts +124 -0
  19. package/src/actions/action-definition.test.ts +201 -0
  20. package/src/actions/action-definition.ts +122 -0
  21. package/src/actions/action-timing.test.ts +490 -0
  22. package/src/actions/action-timing.ts +257 -0
  23. package/src/cards/card-definition.test.ts +268 -0
  24. package/src/cards/card-definition.ts +27 -0
  25. package/src/cards/card-instance.test.ts +422 -0
  26. package/src/cards/card-instance.ts +49 -0
  27. package/src/cards/computed-properties.test.ts +530 -0
  28. package/src/cards/computed-properties.ts +84 -0
  29. package/src/cards/conditional-modifiers.test.ts +390 -0
  30. package/src/cards/modifiers.test.ts +286 -0
  31. package/src/cards/modifiers.ts +51 -0
  32. package/src/engine/MULTIPLAYER.md +425 -0
  33. package/src/engine/__tests__/rule-engine-flow.test.ts +348 -0
  34. package/src/engine/__tests__/rule-engine-history.test.ts +535 -0
  35. package/src/engine/__tests__/rule-engine-moves.test.ts +488 -0
  36. package/src/engine/__tests__/rule-engine.test.ts +366 -0
  37. package/src/engine/index.ts +14 -0
  38. package/src/engine/multiplayer-engine.example.ts +571 -0
  39. package/src/engine/multiplayer-engine.ts +409 -0
  40. package/src/engine/rule-engine.test.ts +286 -0
  41. package/src/engine/rule-engine.ts +1539 -0
  42. package/src/engine/tracker-system.ts +172 -0
  43. package/src/examples/__tests__/coin-flip-game.test.ts +641 -0
  44. package/src/filtering/card-filter.test.ts +230 -0
  45. package/src/filtering/card-filter.ts +91 -0
  46. package/src/filtering/card-query.test.ts +901 -0
  47. package/src/filtering/card-query.ts +273 -0
  48. package/src/filtering/filter-matching.test.ts +944 -0
  49. package/src/filtering/filter-matching.ts +315 -0
  50. package/src/flow/SERIALIZATION.md +428 -0
  51. package/src/flow/__tests__/flow-definition.test.ts +427 -0
  52. package/src/flow/__tests__/flow-manager.test.ts +756 -0
  53. package/src/flow/__tests__/flow-serialization.test.ts +565 -0
  54. package/src/flow/flow-definition.ts +453 -0
  55. package/src/flow/flow-manager.ts +1044 -0
  56. package/src/flow/index.ts +35 -0
  57. package/src/game-definition/__tests__/game-definition-validation.test.ts +359 -0
  58. package/src/game-definition/__tests__/game-definition.test.ts +291 -0
  59. package/src/game-definition/__tests__/move-definitions.test.ts +328 -0
  60. package/src/game-definition/game-definition.ts +261 -0
  61. package/src/game-definition/index.ts +28 -0
  62. package/src/game-definition/move-definitions.ts +188 -0
  63. package/src/game-definition/validation.ts +183 -0
  64. package/src/history/history-manager.test.ts +497 -0
  65. package/src/history/history-manager.ts +312 -0
  66. package/src/history/history-operations.ts +122 -0
  67. package/src/history/index.ts +9 -0
  68. package/src/history/types.ts +255 -0
  69. package/src/index.ts +32 -0
  70. package/src/logging/index.ts +27 -0
  71. package/src/logging/log-formatter.ts +187 -0
  72. package/src/logging/logger.ts +276 -0
  73. package/src/logging/types.ts +148 -0
  74. package/src/moves/create-move.test.ts +331 -0
  75. package/src/moves/create-move.ts +64 -0
  76. package/src/moves/move-enumeration.ts +228 -0
  77. package/src/moves/move-executor.test.ts +431 -0
  78. package/src/moves/move-executor.ts +195 -0
  79. package/src/moves/move-system.test.ts +380 -0
  80. package/src/moves/move-system.ts +463 -0
  81. package/src/moves/standard-moves.ts +231 -0
  82. package/src/operations/card-operations.test.ts +236 -0
  83. package/src/operations/card-operations.ts +116 -0
  84. package/src/operations/card-registry-impl.test.ts +251 -0
  85. package/src/operations/card-registry-impl.ts +70 -0
  86. package/src/operations/card-registry.test.ts +234 -0
  87. package/src/operations/card-registry.ts +106 -0
  88. package/src/operations/counter-operations.ts +152 -0
  89. package/src/operations/game-operations.test.ts +280 -0
  90. package/src/operations/game-operations.ts +140 -0
  91. package/src/operations/index.ts +24 -0
  92. package/src/operations/operations-impl.test.ts +354 -0
  93. package/src/operations/operations-impl.ts +468 -0
  94. package/src/operations/zone-operations.test.ts +295 -0
  95. package/src/operations/zone-operations.ts +223 -0
  96. package/src/rng/seeded-rng.test.ts +339 -0
  97. package/src/rng/seeded-rng.ts +123 -0
  98. package/src/targeting/index.ts +48 -0
  99. package/src/targeting/target-definition.test.ts +273 -0
  100. package/src/targeting/target-definition.ts +37 -0
  101. package/src/targeting/target-dsl.ts +279 -0
  102. package/src/targeting/target-resolver.ts +486 -0
  103. package/src/targeting/target-validation.test.ts +994 -0
  104. package/src/targeting/target-validation.ts +286 -0
  105. package/src/telemetry/events.ts +202 -0
  106. package/src/telemetry/index.ts +21 -0
  107. package/src/telemetry/telemetry-manager.ts +127 -0
  108. package/src/telemetry/types.ts +68 -0
  109. package/src/testing/__tests__/testing-utilities-integration.test.ts +161 -0
  110. package/src/testing/index.ts +88 -0
  111. package/src/testing/test-assertions.test.ts +341 -0
  112. package/src/testing/test-assertions.ts +256 -0
  113. package/src/testing/test-card-factory.test.ts +228 -0
  114. package/src/testing/test-card-factory.ts +111 -0
  115. package/src/testing/test-context-factory.ts +187 -0
  116. package/src/testing/test-end-assertions.test.ts +262 -0
  117. package/src/testing/test-end-assertions.ts +95 -0
  118. package/src/testing/test-engine-builder.test.ts +389 -0
  119. package/src/testing/test-engine-builder.ts +46 -0
  120. package/src/testing/test-flow-assertions.test.ts +284 -0
  121. package/src/testing/test-flow-assertions.ts +115 -0
  122. package/src/testing/test-player-builder.test.ts +132 -0
  123. package/src/testing/test-player-builder.ts +46 -0
  124. package/src/testing/test-replay-assertions.test.ts +356 -0
  125. package/src/testing/test-replay-assertions.ts +164 -0
  126. package/src/testing/test-rng-helpers.test.ts +260 -0
  127. package/src/testing/test-rng-helpers.ts +190 -0
  128. package/src/testing/test-state-builder.test.ts +373 -0
  129. package/src/testing/test-state-builder.ts +99 -0
  130. package/src/testing/test-zone-factory.test.ts +295 -0
  131. package/src/testing/test-zone-factory.ts +224 -0
  132. package/src/types/branded-utils.ts +54 -0
  133. package/src/types/branded.test.ts +175 -0
  134. package/src/types/branded.ts +33 -0
  135. package/src/types/index.ts +8 -0
  136. package/src/types/state.test.ts +198 -0
  137. package/src/types/state.ts +154 -0
  138. package/src/validation/card-type-guards.test.ts +242 -0
  139. package/src/validation/card-type-guards.ts +179 -0
  140. package/src/validation/index.ts +40 -0
  141. package/src/validation/schema-builders.test.ts +403 -0
  142. package/src/validation/schema-builders.ts +345 -0
  143. package/src/validation/type-guard-builder.test.ts +216 -0
  144. package/src/validation/type-guard-builder.ts +109 -0
  145. package/src/validation/validator-builder.test.ts +375 -0
  146. package/src/validation/validator-builder.ts +273 -0
  147. package/src/zones/index.ts +28 -0
  148. package/src/zones/zone-factory.test.ts +183 -0
  149. package/src/zones/zone-factory.ts +44 -0
  150. package/src/zones/zone-operations.test.ts +800 -0
  151. package/src/zones/zone-operations.ts +306 -0
  152. package/src/zones/zone-state-helpers.test.ts +337 -0
  153. package/src/zones/zone-state-helpers.ts +128 -0
  154. package/src/zones/zone-visibility.test.ts +156 -0
  155. package/src/zones/zone-visibility.ts +36 -0
  156. package/src/zones/zone.test.ts +186 -0
  157. package/src/zones/zone.ts +66 -0
@@ -0,0 +1,373 @@
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 Grand Archive game state - SIMPLIFIED!
8
+ // Engine now handles: phase, turn, currentPlayer, setupStep
9
+ type TestGameState = {
10
+ opportunityPlayer: PlayerId | null; // Who has Opportunity to act
11
+ champions: Record<
12
+ string,
13
+ {
14
+ id: string;
15
+ level: number;
16
+ damage: number;
17
+ }
18
+ >;
19
+ };
20
+
21
+ type TestMoves = {
22
+ // Setup moves
23
+ initializeGame: { playerId: PlayerId };
24
+ chooseFirstPlayer: { playerId: PlayerId };
25
+ shuffleDecks: { playerId: PlayerId };
26
+ drawStartingHand: { playerId: PlayerId; count: number };
27
+ // Gameplay moves
28
+ materializeCard: { cardId: CardId };
29
+ playCard: { cardId: CardId; targets?: CardId[] };
30
+ declareAttack: { attackerId: CardId; targetId: CardId };
31
+ declareRetaliation: { defenderId: CardId };
32
+ activateAbility: { cardId: CardId; abilityIndex?: number };
33
+ passOpportunity: Record<string, never>;
34
+ endPhase: Record<string, never>;
35
+ // Standard moves
36
+ concede: { playerId: PlayerId };
37
+ };
38
+
39
+ // Grand Archive move definitions
40
+ const grandArchiveMoves: GameMoveDefinitions<TestGameState, TestMoves> = {
41
+ // Setup moves - using engine utilities!
42
+ initializeGame: {
43
+ reducer: (_draft, context) => {
44
+ const { zones } = context;
45
+ const playerId = context.params.playerId;
46
+
47
+ // Use engine's createDeck utility (instead of manual loop)
48
+ zones.createDeck({
49
+ zoneId: "mainDeck" as ZoneId,
50
+ playerId,
51
+ cardCount: 40,
52
+ shuffle: false,
53
+ });
54
+
55
+ zones.createDeck({
56
+ zoneId: "materialDeck" as ZoneId,
57
+ playerId,
58
+ cardCount: 15,
59
+ shuffle: false,
60
+ });
61
+ },
62
+ },
63
+
64
+ chooseFirstPlayer: {
65
+ reducer: (_draft, context) => {
66
+ // NO MORE: draft.currentPlayer, draft.phase, draft.turn
67
+ // Engine handles this via flow!
68
+ },
69
+ },
70
+
71
+ shuffleDecks: {
72
+ reducer: (_draft, context) => {
73
+ const { zones } = context;
74
+ const playerId = context.params.playerId;
75
+
76
+ // Shuffle both decks
77
+ zones.shuffleZone("mainDeck" as ZoneId, playerId);
78
+ zones.shuffleZone("materialDeck" as ZoneId, playerId);
79
+ },
80
+ },
81
+
82
+ drawStartingHand: {
83
+ reducer: (_draft, context) => {
84
+ const { zones } = context;
85
+ const playerId = context.params.playerId;
86
+ const count = context.params.count;
87
+
88
+ // BEFORE: Manual loop (11 lines)
89
+ // AFTER: Use engine's drawCards utility!
90
+ zones.drawCards({
91
+ from: "mainDeck" as ZoneId,
92
+ to: "hand" as ZoneId,
93
+ count,
94
+ playerId,
95
+ });
96
+ },
97
+ },
98
+
99
+ // Gameplay moves enhanced with engine features
100
+ materializeCard: {
101
+ condition: (state, context) => {
102
+ const playerId = context.playerId;
103
+ // Use engine's tracker system!
104
+ return !context.trackers?.check("hasMaterialized", playerId);
105
+ },
106
+ reducer: (draft, context) => {
107
+ const cardId = context.params.cardId;
108
+ const playerId = context.playerId;
109
+
110
+ // Move from material deck to memory
111
+ context.zones.moveCard({
112
+ cardId,
113
+ targetZoneId: "memory" as ZoneId,
114
+ });
115
+
116
+ // Mark as materialized this turn
117
+ context.trackers?.mark("hasMaterialized", playerId);
118
+ },
119
+ },
120
+
121
+ playCard: {
122
+ reducer: (_draft, context) => {
123
+ const cardId = context.params.cardId;
124
+
125
+ // Play card to field
126
+ context.zones.moveCard({
127
+ cardId,
128
+ targetZoneId: "field" as ZoneId,
129
+ });
130
+ },
131
+ },
132
+
133
+ declareAttack: {
134
+ reducer: (_draft, _context) => {
135
+ // Attack logic
136
+ },
137
+ },
138
+
139
+ declareRetaliation: {
140
+ reducer: (_draft, _context) => {
141
+ // Retaliation logic
142
+ },
143
+ },
144
+
145
+ activateAbility: {
146
+ reducer: (_draft, _context) => {
147
+ // Ability activation logic
148
+ },
149
+ },
150
+
151
+ passOpportunity: {
152
+ reducer: (draft, _context) => {
153
+ // Pass opportunity to next player
154
+ draft.opportunityPlayer = null;
155
+ },
156
+ },
157
+
158
+ endPhase: {
159
+ reducer: (draft, _context) => {
160
+ // End current phase
161
+ draft.opportunityPlayer = null;
162
+ },
163
+ },
164
+
165
+ // Standard moves from engine library
166
+ concede: standardMoves<TestGameState>({
167
+ include: ["concede"],
168
+ }).concede!,
169
+ };
170
+
171
+ // Grand Archive zones configuration (unchanged)
172
+ const grandArchiveZones: Record<string, CardZoneConfig> = {
173
+ hand: {
174
+ id: "hand" as ZoneId,
175
+ name: "zones.hand",
176
+ visibility: "private",
177
+ ordered: false,
178
+ owner: undefined,
179
+ faceDown: false,
180
+ maxSize: undefined,
181
+ },
182
+ mainDeck: {
183
+ id: "mainDeck" as ZoneId,
184
+ name: "zones.mainDeck",
185
+ visibility: "secret",
186
+ ordered: true,
187
+ owner: undefined,
188
+ faceDown: true,
189
+ maxSize: 40,
190
+ },
191
+ materialDeck: {
192
+ id: "materialDeck" as ZoneId,
193
+ name: "zones.materialDeck",
194
+ visibility: "secret",
195
+ ordered: true,
196
+ owner: undefined,
197
+ faceDown: true,
198
+ maxSize: 15,
199
+ },
200
+ memory: {
201
+ id: "memory" as ZoneId,
202
+ name: "zones.memory",
203
+ visibility: "private",
204
+ ordered: false,
205
+ owner: undefined,
206
+ faceDown: false,
207
+ maxSize: undefined,
208
+ },
209
+ field: {
210
+ id: "field" as ZoneId,
211
+ name: "zones.field",
212
+ visibility: "public",
213
+ ordered: false,
214
+ owner: undefined,
215
+ faceDown: false,
216
+ maxSize: undefined,
217
+ },
218
+ graveyard: {
219
+ id: "graveyard" as ZoneId,
220
+ name: "zones.graveyard",
221
+ visibility: "public",
222
+ ordered: false,
223
+ owner: undefined,
224
+ faceDown: false,
225
+ maxSize: undefined,
226
+ },
227
+ banishment: {
228
+ id: "banishment" as ZoneId,
229
+ name: "zones.banishment",
230
+ visibility: "public",
231
+ ordered: false,
232
+ owner: undefined,
233
+ faceDown: false,
234
+ maxSize: undefined,
235
+ },
236
+ effectsStack: {
237
+ id: "effectsStack" as ZoneId,
238
+ name: "zones.effectsStack",
239
+ visibility: "public",
240
+ ordered: true,
241
+ owner: undefined,
242
+ faceDown: false,
243
+ maxSize: undefined,
244
+ },
245
+ intent: {
246
+ id: "intent" as ZoneId,
247
+ name: "zones.intent",
248
+ visibility: "public",
249
+ ordered: false,
250
+ owner: undefined,
251
+ faceDown: false,
252
+ maxSize: undefined,
253
+ },
254
+ };
255
+
256
+ // Grand Archive flow definition (simplified)
257
+ const grandArchiveFlow: FlowDefinition<TestGameState> = {
258
+ turn: {
259
+ initialPhase: "wakeUp",
260
+ onBegin: (_context) => {},
261
+ onEnd: (_context) => {},
262
+ phases: {
263
+ wakeUp: {
264
+ order: 1,
265
+ next: "materialize",
266
+ onBegin: (context) => {
267
+ context.state.opportunityPlayer = null;
268
+ },
269
+ endIf: () => true,
270
+ },
271
+ materialize: {
272
+ order: 2,
273
+ next: "recollection",
274
+ onBegin: (context) => {
275
+ context.state.opportunityPlayer = null;
276
+ },
277
+ endIf: () => true,
278
+ },
279
+ recollection: {
280
+ order: 3,
281
+ next: "draw",
282
+ onBegin: (context) => {
283
+ // Grant Opportunity using flow context!
284
+ const currentPlayer = context.getCurrentPlayer();
285
+ context.state.opportunityPlayer = currentPlayer as PlayerId;
286
+ },
287
+ },
288
+ draw: {
289
+ order: 4,
290
+ next: "main",
291
+ onBegin: (context) => {
292
+ context.state.opportunityPlayer = null;
293
+ },
294
+ endIf: () => true,
295
+ },
296
+ main: {
297
+ order: 5,
298
+ next: "end",
299
+ onBegin: (context) => {
300
+ const currentPlayer = context.getCurrentPlayer();
301
+ context.state.opportunityPlayer = currentPlayer as PlayerId;
302
+ },
303
+ },
304
+ end: {
305
+ order: 6,
306
+ next: "wakeUp",
307
+ onBegin: (context) => {
308
+ const currentPlayer = context.getCurrentPlayer();
309
+ context.state.opportunityPlayer = currentPlayer as PlayerId;
310
+ },
311
+ endIf: (_context) => {
312
+ return true;
313
+ },
314
+ },
315
+ },
316
+ },
317
+ };
318
+
319
+ /**
320
+ * Create minimal Grand Archive game definition for testing
321
+ *
322
+ * REFACTORED to showcase new engine features:
323
+ * ✨ 70+ lines of boilerplate ELIMINATED!
324
+ * ✅ No manual phase/turn/player tracking
325
+ * ✅ High-level zone utilities (createDeck, drawCards)
326
+ * ✅ Tracker system for per-turn flags (hasMaterialized, hasDrawn)
327
+ * ✅ Standard moves library (concede)
328
+ * ✅ Flow context access in phase hooks
329
+ */
330
+ export function createMockGrandArchiveGame(): GameDefinition<
331
+ TestGameState,
332
+ TestMoves
333
+ > {
334
+ return {
335
+ name: "Test Grand Archive Game",
336
+ zones: grandArchiveZones,
337
+ flow: grandArchiveFlow,
338
+ moves: grandArchiveMoves,
339
+
340
+ // Configure engine's tracker system
341
+ trackers: {
342
+ perTurn: ["hasMaterialized", "hasDrawn"],
343
+ perPlayer: true,
344
+ },
345
+
346
+ /**
347
+ * Setup function - MASSIVELY SIMPLIFIED!
348
+ *
349
+ * BEFORE: 60+ lines tracking phase, turn, currentPlayer, hasDrawnThisTurn, hasMaterializedThisTurn
350
+ * AFTER: 20 lines - just initialize game-specific data!
351
+ */
352
+ setup: (players) => {
353
+ const playerIds = players.map((p) => p.id);
354
+ const champions: Record<
355
+ string,
356
+ { id: string; level: number; damage: number }
357
+ > = {};
358
+
359
+ for (const playerId of playerIds) {
360
+ champions[playerId] = {
361
+ id: `${playerId}-champion`,
362
+ level: 0,
363
+ damage: 0,
364
+ };
365
+ }
366
+
367
+ return {
368
+ opportunityPlayer: null,
369
+ champions,
370
+ };
371
+ },
372
+ };
373
+ }