@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,429 @@
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 One Piece game state - SIMPLIFIED!
8
+ type TestGameState = {
9
+ battleAllowed: boolean;
10
+ leaderLife: Record<string, number>;
11
+ };
12
+
13
+ type TestMoves = {
14
+ // Setup moves
15
+ initializeDecks: { playerId: PlayerId };
16
+ placeLeader: { playerId: PlayerId; leaderId: CardId };
17
+ determineFirstPlayer: { playerId: PlayerId };
18
+ drawOpeningHand: { playerId: PlayerId };
19
+ decideMulligan: { playerId: PlayerId; redraw: boolean };
20
+ placeLifeCards: { playerId: PlayerId; lifeCount: number };
21
+ transitionToGame: Record<string, never>;
22
+ // Core game moves
23
+ draw: { playerId: PlayerId };
24
+ placeDon: { playerId: PlayerId };
25
+ playCharacter: { playerId: PlayerId; cardId: CardId };
26
+ playEvent: { playerId: PlayerId; cardId: CardId };
27
+ playStage: { playerId: PlayerId; cardId: CardId };
28
+ giveDon: { playerId: PlayerId; donCardId: CardId; targetCardId: CardId };
29
+ attack: { playerId: PlayerId; attackerId: CardId; targetId?: CardId };
30
+ activateAbility: { playerId: PlayerId; cardId: CardId };
31
+ // Standard moves
32
+ pass: { playerId: PlayerId };
33
+ concede: { playerId: PlayerId };
34
+ };
35
+
36
+ // One Piece move definitions
37
+ const onePieceMoves: GameMoveDefinitions<TestGameState, TestMoves> = {
38
+ // Setup moves using engine utilities
39
+ initializeDecks: {
40
+ reducer: (_draft, context) => {
41
+ const { zones } = context;
42
+ const playerId = context.params.playerId;
43
+
44
+ // Use engine's createDeck utility!
45
+ zones.createDeck({
46
+ zoneId: "deck" as ZoneId,
47
+ playerId,
48
+ cardCount: 50,
49
+ shuffle: true,
50
+ });
51
+
52
+ zones.createDeck({
53
+ zoneId: "donDeck" as ZoneId,
54
+ playerId,
55
+ cardCount: 10,
56
+ shuffle: true,
57
+ });
58
+
59
+ // NO MORE: draft.setupStep
60
+ },
61
+ },
62
+
63
+ placeLeader: {
64
+ reducer: (_draft, context) => {
65
+ const { zones } = context;
66
+ const leaderId = context.params.leaderId;
67
+
68
+ // Place Leader card in leader area
69
+ zones.moveCard({
70
+ cardId: leaderId,
71
+ targetZoneId: "leader" as ZoneId,
72
+ });
73
+
74
+ // NO MORE: draft.setupStep
75
+ },
76
+ },
77
+
78
+ determineFirstPlayer: {
79
+ reducer: (_draft, _context) => {
80
+ // NO MORE: draft.currentPlayer, draft.firstTurn, draft.setupStep
81
+ // Engine handles this!
82
+ },
83
+ },
84
+
85
+ drawOpeningHand: {
86
+ reducer: (_draft, context) => {
87
+ const { zones } = context;
88
+ const playerId = context.params.playerId;
89
+
90
+ // BEFORE: Manual loop (11 lines)
91
+ // AFTER: Use drawCards utility!
92
+ zones.drawCards({
93
+ from: "deck" as ZoneId,
94
+ to: "hand" as ZoneId,
95
+ count: 5,
96
+ playerId,
97
+ });
98
+
99
+ // NO MORE: draft.setupStep, draft.mulliganOffered
100
+ },
101
+ },
102
+
103
+ decideMulligan: {
104
+ reducer: (_draft, context) => {
105
+ const { zones } = context;
106
+ const playerId = context.params.playerId;
107
+ const redraw = context.params.redraw;
108
+
109
+ if (redraw) {
110
+ // BEFORE: Manual mulligan (22 lines)
111
+ // AFTER: One line!
112
+ zones.mulligan({
113
+ hand: "hand" as ZoneId,
114
+ deck: "deck" as ZoneId,
115
+ drawCount: 5,
116
+ playerId,
117
+ });
118
+ }
119
+
120
+ // NO MORE: draft.mulliganOffered
121
+ },
122
+ },
123
+
124
+ placeLifeCards: {
125
+ reducer: (_draft, context) => {
126
+ const { zones } = context;
127
+ const playerId = context.params.playerId;
128
+ const lifeCount = context.params.lifeCount;
129
+
130
+ // BEFORE: Manual loop (9 lines)
131
+ // AFTER: Use bulkMove utility!
132
+ zones.bulkMove({
133
+ from: "deck" as ZoneId,
134
+ to: "life" as ZoneId,
135
+ count: lifeCount,
136
+ playerId,
137
+ position: "bottom",
138
+ });
139
+
140
+ // NO MORE: draft.setupStep
141
+ },
142
+ },
143
+
144
+ transitionToGame: {
145
+ reducer: (_draft, _context) => {
146
+ // NO MORE: draft.setupStep, draft.phase, draft.turn, draft.firstTurn
147
+ },
148
+ },
149
+
150
+ // Core game moves
151
+ draw: {
152
+ condition: (state, context) => {
153
+ // First player skips draw on first turn
154
+ const isFirstTurn = context.flow?.isFirstTurn ?? false;
155
+ const isFirstPlayer = context.flow?.currentPlayer === context.playerId;
156
+
157
+ if (isFirstTurn && isFirstPlayer) {
158
+ return false;
159
+ }
160
+
161
+ return true;
162
+ },
163
+ reducer: (_draft, context) => {
164
+ const { zones } = context;
165
+ const playerId = context.params.playerId;
166
+
167
+ zones.drawCards({
168
+ from: "deck" as ZoneId,
169
+ to: "hand" as ZoneId,
170
+ count: 1,
171
+ playerId,
172
+ });
173
+ },
174
+ },
175
+
176
+ placeDon: {
177
+ reducer: (_draft, context) => {
178
+ const { zones } = context;
179
+ const playerId = context.params.playerId;
180
+
181
+ // Get DON!! count for this turn (use flow.turn)
182
+ const turnNumber = context.flow?.turn ?? 1;
183
+ const donCount = Math.min(turnNumber, 10);
184
+
185
+ // Draw DON!! cards
186
+ zones.bulkMove({
187
+ from: "donDeck" as ZoneId,
188
+ to: "donArea" as ZoneId,
189
+ count: donCount,
190
+ playerId,
191
+ });
192
+ },
193
+ },
194
+
195
+ playCharacter: {
196
+ reducer: (_draft, context) => {
197
+ const cardId = context.params.cardId;
198
+
199
+ context.zones.moveCard({
200
+ cardId,
201
+ targetZoneId: "characters" as ZoneId,
202
+ });
203
+ },
204
+ },
205
+
206
+ playEvent: {
207
+ reducer: (_draft, context) => {
208
+ const cardId = context.params.cardId;
209
+
210
+ // Events go directly to discard
211
+ context.zones.moveCard({
212
+ cardId,
213
+ targetZoneId: "discard" as ZoneId,
214
+ });
215
+ },
216
+ },
217
+
218
+ playStage: {
219
+ reducer: (_draft, context) => {
220
+ const cardId = context.params.cardId;
221
+
222
+ context.zones.moveCard({
223
+ cardId,
224
+ targetZoneId: "stage" as ZoneId,
225
+ });
226
+ },
227
+ },
228
+
229
+ giveDon: {
230
+ reducer: (_draft, context) => {
231
+ const donCardId = context.params.donCardId;
232
+
233
+ // Attach DON!! to character (simplified)
234
+ context.zones.moveCard({
235
+ cardId: donCardId,
236
+ targetZoneId: "donArea" as ZoneId,
237
+ });
238
+ },
239
+ },
240
+
241
+ attack: {
242
+ reducer: (draft, _context) => {
243
+ // Mark battle as in progress
244
+ draft.battleAllowed = true;
245
+ },
246
+ },
247
+
248
+ activateAbility: {
249
+ reducer: (_draft, _context) => {
250
+ // Ability activation logic
251
+ },
252
+ },
253
+
254
+ // Standard moves from engine
255
+ pass: standardMoves<TestGameState>({
256
+ include: ["pass"],
257
+ }).pass!,
258
+
259
+ concede: standardMoves<TestGameState>({
260
+ include: ["concede"],
261
+ }).concede!,
262
+ };
263
+
264
+ // One Piece zones (unchanged)
265
+ const onePieceZones: Record<string, CardZoneConfig> = {
266
+ deck: {
267
+ id: "deck" as ZoneId,
268
+ name: "zones.deck",
269
+ visibility: "secret",
270
+ ordered: true,
271
+ owner: undefined,
272
+ faceDown: true,
273
+ maxSize: 50,
274
+ },
275
+ hand: {
276
+ id: "hand" as ZoneId,
277
+ name: "zones.hand",
278
+ visibility: "private",
279
+ ordered: false,
280
+ owner: undefined,
281
+ faceDown: false,
282
+ maxSize: undefined,
283
+ },
284
+ donDeck: {
285
+ id: "donDeck" as ZoneId,
286
+ name: "zones.donDeck",
287
+ visibility: "public",
288
+ ordered: true,
289
+ owner: undefined,
290
+ faceDown: true,
291
+ maxSize: 10,
292
+ },
293
+ donArea: {
294
+ id: "donArea" as ZoneId,
295
+ name: "zones.donArea",
296
+ visibility: "public",
297
+ ordered: false,
298
+ owner: undefined,
299
+ faceDown: false,
300
+ maxSize: undefined,
301
+ },
302
+ leader: {
303
+ id: "leader" as ZoneId,
304
+ name: "zones.leader",
305
+ visibility: "public",
306
+ ordered: false,
307
+ owner: undefined,
308
+ faceDown: false,
309
+ maxSize: 1,
310
+ },
311
+ characters: {
312
+ id: "characters" as ZoneId,
313
+ name: "zones.characters",
314
+ visibility: "public",
315
+ ordered: false,
316
+ owner: undefined,
317
+ faceDown: false,
318
+ maxSize: undefined,
319
+ },
320
+ stage: {
321
+ id: "stage" as ZoneId,
322
+ name: "zones.stage",
323
+ visibility: "public",
324
+ ordered: false,
325
+ owner: undefined,
326
+ faceDown: false,
327
+ maxSize: undefined,
328
+ },
329
+ life: {
330
+ id: "life" as ZoneId,
331
+ name: "zones.life",
332
+ visibility: "secret",
333
+ ordered: true,
334
+ owner: undefined,
335
+ faceDown: true,
336
+ maxSize: 5,
337
+ },
338
+ discard: {
339
+ id: "discard" as ZoneId,
340
+ name: "zones.discard",
341
+ visibility: "public",
342
+ ordered: false,
343
+ owner: undefined,
344
+ faceDown: false,
345
+ maxSize: undefined,
346
+ },
347
+ };
348
+
349
+ // One Piece flow (simplified)
350
+ const onePieceFlow: FlowDefinition<TestGameState> = {
351
+ turn: {
352
+ initialPhase: "refresh",
353
+ phases: {
354
+ refresh: {
355
+ order: 1,
356
+ next: "draw",
357
+ onBegin: (_context) => {},
358
+ endIf: () => true,
359
+ },
360
+ draw: {
361
+ order: 2,
362
+ next: "don",
363
+ onBegin: (_context) => {},
364
+ endIf: () => true,
365
+ },
366
+ don: {
367
+ order: 3,
368
+ next: "main",
369
+ onBegin: (_context) => {},
370
+ endIf: () => true,
371
+ },
372
+ main: {
373
+ order: 4,
374
+ next: "end",
375
+ onBegin: (_context) => {},
376
+ },
377
+ end: {
378
+ order: 5,
379
+ next: "refresh",
380
+ onBegin: (context) => {
381
+ context.state.battleAllowed = false;
382
+ },
383
+ endIf: () => true,
384
+ },
385
+ },
386
+ },
387
+ };
388
+
389
+ /**
390
+ * Create minimal One Piece game definition for testing
391
+ *
392
+ * REFACTORED to showcase new engine features:
393
+ * ✨ 140+ lines of boilerplate ELIMINATED!
394
+ * ✅ No manual phase/turn/player tracking
395
+ * ✅ High-level zone utilities (createDeck, drawCards, mulligan, bulkMove)
396
+ * ✅ Standard moves library (pass, concede)
397
+ * ✅ Flow context access (isFirstTurn, turn)
398
+ */
399
+ export function createMockOnePieceGame(): GameDefinition<
400
+ TestGameState,
401
+ TestMoves
402
+ > {
403
+ return {
404
+ name: "Test One Piece Game",
405
+ zones: onePieceZones,
406
+ flow: onePieceFlow,
407
+ moves: onePieceMoves,
408
+
409
+ /**
410
+ * Setup function - MASSIVELY SIMPLIFIED!
411
+ *
412
+ * BEFORE: 100+ lines tracking phase, setupStep, turn, currentPlayer, firstTurn, mulliganOffered, donThisTurn
413
+ * AFTER: 15 lines - just initialize game-specific data!
414
+ */
415
+ setup: (players) => {
416
+ const playerIds = players.map((p) => p.id);
417
+ const leaderLife: Record<string, number> = {};
418
+
419
+ for (const playerId of playerIds) {
420
+ leaderLife[playerId] = 5; // Default starting life
421
+ }
422
+
423
+ return {
424
+ battleAllowed: false,
425
+ leaderLife,
426
+ };
427
+ },
428
+ };
429
+ }