@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,280 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import { createPlayerId } from "../types";
3
+ import type { InternalState } from "../types/state";
4
+ import { createGameOperations } from "./operations-impl";
5
+
6
+ // Helper to create PlayerId for tests
7
+ const playerId = createPlayerId;
8
+
9
+ describe("GameOperations", () => {
10
+ const createTestState = (): InternalState => ({
11
+ zones: {},
12
+ cards: {},
13
+ cardMetas: {},
14
+ otp: undefined,
15
+ pendingMulligan: undefined,
16
+ });
17
+
18
+ describe("OTP Operations", () => {
19
+ it("should set OTP player", () => {
20
+ const state = createTestState();
21
+ const ops = createGameOperations(state);
22
+
23
+ ops.setOTP(playerId("player-1"));
24
+
25
+ expect(state.otp).toBe(playerId("player-1"));
26
+ });
27
+
28
+ it("should get OTP player", () => {
29
+ const state = createTestState();
30
+ state.otp = playerId("player-2");
31
+ const ops = createGameOperations(state);
32
+
33
+ const otp = ops.getOTP();
34
+
35
+ expect(otp).toBe(playerId("player-2"));
36
+ });
37
+
38
+ it("should return undefined when OTP not set", () => {
39
+ const state = createTestState();
40
+ const ops = createGameOperations(state);
41
+
42
+ const otp = ops.getOTP();
43
+
44
+ expect(otp).toBeUndefined();
45
+ });
46
+
47
+ it("should overwrite existing OTP", () => {
48
+ const state = createTestState();
49
+ state.otp = playerId("player-1");
50
+ const ops = createGameOperations(state);
51
+
52
+ ops.setOTP(playerId("player-2"));
53
+
54
+ expect(state.otp).toBe(playerId("player-2"));
55
+ });
56
+ });
57
+
58
+ describe("Pending Mulligan Operations", () => {
59
+ it("should set pending mulligan list", () => {
60
+ const state = createTestState();
61
+ const ops = createGameOperations(state);
62
+
63
+ ops.setPendingMulligan([playerId("player-1"), playerId("player-2")]);
64
+
65
+ expect(state.pendingMulligan).toEqual([
66
+ playerId("player-1"),
67
+ playerId("player-2"),
68
+ ]);
69
+ });
70
+
71
+ it("should get pending mulligan list", () => {
72
+ const state = createTestState();
73
+ state.pendingMulligan = [playerId("player-1"), playerId("player-2")];
74
+ const ops = createGameOperations(state);
75
+
76
+ const pending = ops.getPendingMulligan();
77
+
78
+ expect(pending).toEqual([playerId("player-1"), playerId("player-2")]);
79
+ });
80
+
81
+ it("should return copy of pending mulligan list to prevent mutation", () => {
82
+ const state = createTestState();
83
+ state.pendingMulligan = [playerId("player-1")];
84
+ const ops = createGameOperations(state);
85
+
86
+ const pending = ops.getPendingMulligan();
87
+ pending.push(playerId("player-2"));
88
+
89
+ expect(state.pendingMulligan).toEqual([playerId("player-1")]);
90
+ });
91
+
92
+ it("should return empty array when pending mulligan not set", () => {
93
+ const state = createTestState();
94
+ const ops = createGameOperations(state);
95
+
96
+ const pending = ops.getPendingMulligan();
97
+
98
+ expect(pending).toEqual([]);
99
+ });
100
+
101
+ it("should add player to pending mulligan list", () => {
102
+ const state = createTestState();
103
+ state.pendingMulligan = [playerId("player-1")];
104
+ const ops = createGameOperations(state);
105
+
106
+ ops.addPendingMulligan(playerId("player-2"));
107
+
108
+ expect(state.pendingMulligan).toEqual([
109
+ playerId("player-1"),
110
+ playerId("player-2"),
111
+ ]);
112
+ });
113
+
114
+ it("should not add duplicate player to pending mulligan list", () => {
115
+ const state = createTestState();
116
+ state.pendingMulligan = [playerId("player-1")];
117
+ const ops = createGameOperations(state);
118
+
119
+ ops.addPendingMulligan(playerId("player-1"));
120
+
121
+ expect(state.pendingMulligan).toEqual([playerId("player-1")]);
122
+ });
123
+
124
+ it("should initialize list when adding to undefined pending mulligan", () => {
125
+ const state = createTestState();
126
+ const ops = createGameOperations(state);
127
+
128
+ ops.addPendingMulligan(playerId("player-1"));
129
+
130
+ expect(state.pendingMulligan).toEqual([playerId("player-1")]);
131
+ });
132
+
133
+ it("should remove player from pending mulligan list", () => {
134
+ const state = createTestState();
135
+ state.pendingMulligan = [
136
+ playerId("player-1"),
137
+ playerId("player-2"),
138
+ playerId("player-3"),
139
+ ];
140
+ const ops = createGameOperations(state);
141
+
142
+ ops.removePendingMulligan(playerId("player-2"));
143
+
144
+ expect(state.pendingMulligan).toEqual([
145
+ playerId("player-1"),
146
+ playerId("player-3"),
147
+ ]);
148
+ });
149
+
150
+ it("should handle removing player not in list", () => {
151
+ const state = createTestState();
152
+ state.pendingMulligan = [playerId("player-1")];
153
+ const ops = createGameOperations(state);
154
+
155
+ ops.removePendingMulligan(playerId("player-2"));
156
+
157
+ expect(state.pendingMulligan).toEqual([playerId("player-1")]);
158
+ });
159
+
160
+ it("should handle removing from empty list", () => {
161
+ const state = createTestState();
162
+ state.pendingMulligan = [];
163
+ const ops = createGameOperations(state);
164
+
165
+ ops.removePendingMulligan(playerId("player-1"));
166
+
167
+ expect(state.pendingMulligan).toEqual([]);
168
+ });
169
+
170
+ it("should handle removing from undefined list", () => {
171
+ const state = createTestState();
172
+ const ops = createGameOperations(state);
173
+
174
+ ops.removePendingMulligan(playerId("player-1"));
175
+
176
+ expect(state.pendingMulligan).toBeUndefined();
177
+ });
178
+
179
+ it("should replace entire list with setPendingMulligan", () => {
180
+ const state = createTestState();
181
+ state.pendingMulligan = [playerId("player-1"), playerId("player-2")];
182
+ const ops = createGameOperations(state);
183
+
184
+ ops.setPendingMulligan([playerId("player-3"), playerId("player-4")]);
185
+
186
+ expect(state.pendingMulligan).toEqual([
187
+ playerId("player-3"),
188
+ playerId("player-4"),
189
+ ]);
190
+ });
191
+ });
192
+
193
+ describe("Choosing First Player Operations", () => {
194
+ it("should set choosing first player", () => {
195
+ const state = createTestState();
196
+ const ops = createGameOperations(state);
197
+
198
+ ops.setChoosingFirstPlayer(playerId("player-1"));
199
+
200
+ expect(state.choosingFirstPlayer).toBe(playerId("player-1"));
201
+ });
202
+
203
+ it("should get choosing first player", () => {
204
+ const state = createTestState();
205
+ state.choosingFirstPlayer = playerId("player-2");
206
+ const ops = createGameOperations(state);
207
+
208
+ const chooser = ops.getChoosingFirstPlayer();
209
+
210
+ expect(chooser).toBe(playerId("player-2"));
211
+ });
212
+
213
+ it("should return undefined when choosing first player not set", () => {
214
+ const state = createTestState();
215
+ const ops = createGameOperations(state);
216
+
217
+ const chooser = ops.getChoosingFirstPlayer();
218
+
219
+ expect(chooser).toBeUndefined();
220
+ });
221
+
222
+ it("should overwrite existing choosing first player", () => {
223
+ const state = createTestState();
224
+ state.choosingFirstPlayer = playerId("player-1");
225
+ const ops = createGameOperations(state);
226
+
227
+ ops.setChoosingFirstPlayer(playerId("player-2"));
228
+
229
+ expect(state.choosingFirstPlayer).toBe(playerId("player-2"));
230
+ });
231
+ });
232
+
233
+ describe("Integration", () => {
234
+ it("should handle typical game setup flow", () => {
235
+ const state = createTestState();
236
+ const ops = createGameOperations(state);
237
+
238
+ // Choose first player
239
+ ops.setOTP(playerId("player-1"));
240
+
241
+ // Set all players pending mulligan
242
+ ops.setPendingMulligan([playerId("player-1"), playerId("player-2")]);
243
+
244
+ // Verify state
245
+ expect(ops.getOTP()).toBe(playerId("player-1"));
246
+ expect(ops.getPendingMulligan()).toEqual([
247
+ playerId("player-1"),
248
+ playerId("player-2"),
249
+ ]);
250
+
251
+ // Player 1 decides to keep
252
+ ops.removePendingMulligan(playerId("player-1"));
253
+ expect(ops.getPendingMulligan()).toEqual([playerId("player-2")]);
254
+
255
+ // Player 2 decides to keep
256
+ ops.removePendingMulligan(playerId("player-2"));
257
+ expect(ops.getPendingMulligan()).toEqual([]);
258
+ });
259
+
260
+ it("should handle complete first player selection flow", () => {
261
+ const state = createTestState();
262
+ const ops = createGameOperations(state);
263
+
264
+ // 1. Randomly pick who gets to choose (simulated)
265
+ ops.setChoosingFirstPlayer(playerId("player-1"));
266
+ expect(ops.getChoosingFirstPlayer()).toBe(playerId("player-1"));
267
+
268
+ // 2. That player chooses who goes first
269
+ ops.setOTP(playerId("player-2"));
270
+ expect(ops.getOTP()).toBe(playerId("player-2"));
271
+
272
+ // 3. All players mulligan
273
+ ops.setPendingMulligan([playerId("player-1"), playerId("player-2")]);
274
+ expect(ops.getPendingMulligan()).toEqual([
275
+ playerId("player-1"),
276
+ playerId("player-2"),
277
+ ]);
278
+ });
279
+ });
280
+ });
@@ -0,0 +1,140 @@
1
+ import type { PlayerId } from "../types";
2
+
3
+ /**
4
+ * Game Operations
5
+ *
6
+ * Provides controlled access to game-level internal state:
7
+ * - OTP (On The Play): The player who goes first
8
+ * - Pending Mulligan: Players who need to decide on mulligan
9
+ *
10
+ * These are universal TCG concepts that apply across all card games.
11
+ */
12
+ export type GameOperations = {
13
+ /**
14
+ * Set the player who is "on the play" (goes first)
15
+ *
16
+ * This is a universal TCG concept. The player marked as OTP
17
+ * typically goes first and may have different rules apply
18
+ * (e.g., no card draw on first turn in some games).
19
+ *
20
+ * @param playerId - Player to mark as on the play
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * // In a choose first player move:
25
+ * context.game.setOTP('player-1');
26
+ * ```
27
+ */
28
+ setOTP(playerId: PlayerId): void;
29
+
30
+ /**
31
+ * Get the player who is on the play
32
+ *
33
+ * @returns Player ID of OTP, or undefined if not yet set
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * const firstPlayer = context.game.getOTP();
38
+ * if (firstPlayer === context.playerId) {
39
+ * // Current player goes first
40
+ * }
41
+ * ```
42
+ */
43
+ getOTP(): PlayerId | undefined;
44
+
45
+ /**
46
+ * Set the player who gets to choose the first player
47
+ *
48
+ * In games like Lorcana, one player is randomly designated to choose
49
+ * who will be the starting player (OTP). This is distinct from OTP itself.
50
+ *
51
+ * @param playerId - Player designated to make the choice
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * // In game setup, randomly choose who gets to pick:
56
+ * const chooser = context.rng.choice(['player-1', 'player-2']);
57
+ * context.game.setChoosingFirstPlayer(chooser);
58
+ * ```
59
+ */
60
+ setChoosingFirstPlayer(playerId: PlayerId): void;
61
+
62
+ /**
63
+ * Get the player designated to choose the first player
64
+ *
65
+ * @returns Player ID of chooser, or undefined if not yet set
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * // In chooseFirstPlayer move condition:
70
+ * const chooser = context.game.getChoosingFirstPlayer();
71
+ * if (context.playerId !== chooser) {
72
+ * return { reason: "Only the designated player can choose", errorCode: "NOT_CHOOSER" };
73
+ * }
74
+ * ```
75
+ */
76
+ getChoosingFirstPlayer(): PlayerId | undefined;
77
+
78
+ /**
79
+ * Set the list of players who need to decide on mulligan
80
+ *
81
+ * Replaces the entire pending mulligan list.
82
+ * Typically called during game setup to initialize the list.
83
+ *
84
+ * @param playerIds - Array of player IDs pending mulligan
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * // After choosing first player, all players can mulligan:
89
+ * context.game.setPendingMulligan(['player-1', 'player-2']);
90
+ * ```
91
+ */
92
+ setPendingMulligan(playerIds: PlayerId[]): void;
93
+
94
+ /**
95
+ * Get the list of players pending mulligan
96
+ *
97
+ * @returns Array of player IDs (copy to prevent mutation)
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * const pending = context.game.getPendingMulligan();
102
+ * if (pending.includes(context.playerId)) {
103
+ * // Current player can still mulligan
104
+ * }
105
+ * ```
106
+ */
107
+ getPendingMulligan(): PlayerId[];
108
+
109
+ /**
110
+ * Add a player to the pending mulligan list
111
+ *
112
+ * Use this to mark a player as needing to decide on mulligan.
113
+ * Has no effect if player is already in the list.
114
+ *
115
+ * @param playerId - Player to add to mulligan list
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * // Allow a player to mulligan again (game-specific rule):
120
+ * context.game.addPendingMulligan('player-1');
121
+ * ```
122
+ */
123
+ addPendingMulligan(playerId: PlayerId): void;
124
+
125
+ /**
126
+ * Remove a player from the pending mulligan list
127
+ *
128
+ * Use this when a player completes their mulligan decision.
129
+ * Has no effect if player is not in the list.
130
+ *
131
+ * @param playerId - Player to remove from mulligan list
132
+ *
133
+ * @example
134
+ * ```typescript
135
+ * // After player decides to keep or mulligan:
136
+ * context.game.removePendingMulligan(context.playerId);
137
+ * ```
138
+ */
139
+ removePendingMulligan(playerId: PlayerId): void;
140
+ };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Operations API
3
+ *
4
+ * Provides controlled access to internal game state through specialized operations interfaces:
5
+ * - ZoneOperations: Manage card zones and card movement
6
+ * - CardOperations: Manage card metadata and state
7
+ * - GameOperations: Manage game-level state (OTP, mulligan)
8
+ * - CounterOperations: Manage counters and flags on cards
9
+ * - CardRegistry: Access static card definitions
10
+ */
11
+
12
+ export type { CardOperations } from "./card-operations";
13
+ export type { CardRegistry } from "./card-registry";
14
+ export { createCardRegistry } from "./card-registry-impl";
15
+ export type { CounterOperations } from "./counter-operations";
16
+ export type { GameOperations } from "./game-operations";
17
+
18
+ export {
19
+ createCardOperations,
20
+ createCounterOperations,
21
+ createGameOperations,
22
+ createZoneOperations,
23
+ } from "./operations-impl";
24
+ export type { ZoneOperations } from "./zone-operations";