@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,295 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { createCardId, createPlayerId } from "../types";
|
|
3
|
+
import type { Zone } from "../zones/zone";
|
|
4
|
+
import {
|
|
5
|
+
createTestDeck,
|
|
6
|
+
createTestGraveyard,
|
|
7
|
+
createTestHand,
|
|
8
|
+
createTestPlayArea,
|
|
9
|
+
createTestZone,
|
|
10
|
+
} from "./test-zone-factory";
|
|
11
|
+
|
|
12
|
+
describe("test-zone-factory", () => {
|
|
13
|
+
describe("createTestZone", () => {
|
|
14
|
+
it("should create zone with default values", () => {
|
|
15
|
+
const zone = createTestZone();
|
|
16
|
+
|
|
17
|
+
expect(zone.config.id).toBeDefined();
|
|
18
|
+
expect(zone.config.name).toBeDefined();
|
|
19
|
+
expect(zone.config.visibility).toBeDefined();
|
|
20
|
+
expect(zone.config.ordered).toBeDefined();
|
|
21
|
+
expect(zone.cards).toEqual([]);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should override config properties", () => {
|
|
25
|
+
const zone = createTestZone({
|
|
26
|
+
name: "Custom Zone",
|
|
27
|
+
visibility: "secret",
|
|
28
|
+
ordered: true,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
expect(zone.config.name).toBe("Custom Zone");
|
|
32
|
+
expect(zone.config.visibility).toBe("secret");
|
|
33
|
+
expect(zone.config.ordered).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should include initial cards", () => {
|
|
37
|
+
const cards = [
|
|
38
|
+
createCardId("card1"),
|
|
39
|
+
createCardId("card2"),
|
|
40
|
+
createCardId("card3"),
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
const zone = createTestZone({}, cards);
|
|
44
|
+
|
|
45
|
+
expect(zone.cards).toEqual(cards);
|
|
46
|
+
expect(zone.cards.length).toBe(3);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("should generate unique zone IDs", () => {
|
|
50
|
+
const zone1 = createTestZone();
|
|
51
|
+
const zone2 = createTestZone();
|
|
52
|
+
const zone3 = createTestZone();
|
|
53
|
+
|
|
54
|
+
expect(zone1.config.id).not.toBe(zone2.config.id);
|
|
55
|
+
expect(zone2.config.id).not.toBe(zone3.config.id);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("should support maxSize", () => {
|
|
59
|
+
const zone = createTestZone({ maxSize: 10 });
|
|
60
|
+
|
|
61
|
+
expect(zone.config.maxSize).toBe(10);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("should support owner", () => {
|
|
65
|
+
const playerId = createPlayerId("p1");
|
|
66
|
+
const zone = createTestZone({ owner: playerId });
|
|
67
|
+
|
|
68
|
+
expect(zone.config.owner).toBe(playerId);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should support faceDown", () => {
|
|
72
|
+
const zone = createTestZone({ faceDown: true });
|
|
73
|
+
|
|
74
|
+
expect(zone.config.faceDown).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("should create valid Zone type", () => {
|
|
78
|
+
const zone = createTestZone();
|
|
79
|
+
|
|
80
|
+
// TypeScript type check
|
|
81
|
+
const validate = (z: Zone) => z;
|
|
82
|
+
expect(() => validate(zone)).not.toThrow();
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe("createTestDeck", () => {
|
|
87
|
+
it("should create deck zone with appropriate defaults", () => {
|
|
88
|
+
const deck = createTestDeck();
|
|
89
|
+
|
|
90
|
+
expect(deck.config.name).toContain("Deck");
|
|
91
|
+
expect(deck.config.visibility).toBe("secret");
|
|
92
|
+
expect(deck.config.ordered).toBe(true);
|
|
93
|
+
expect(deck.config.faceDown).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("should include cards when provided", () => {
|
|
97
|
+
const cards = [
|
|
98
|
+
createCardId("card1"),
|
|
99
|
+
createCardId("card2"),
|
|
100
|
+
createCardId("card3"),
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
const deck = createTestDeck(cards);
|
|
104
|
+
|
|
105
|
+
expect(deck.cards).toEqual(cards);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should support owner", () => {
|
|
109
|
+
const playerId = createPlayerId("p1");
|
|
110
|
+
const deck = createTestDeck([], playerId);
|
|
111
|
+
|
|
112
|
+
expect(deck.config.owner).toBe(playerId);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("should maintain card order", () => {
|
|
116
|
+
const cards = [
|
|
117
|
+
createCardId("card1"),
|
|
118
|
+
createCardId("card2"),
|
|
119
|
+
createCardId("card3"),
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
const deck = createTestDeck(cards);
|
|
123
|
+
|
|
124
|
+
// Order should be preserved
|
|
125
|
+
expect(deck.cards[0]).toBe(cards[0]);
|
|
126
|
+
expect(deck.cards[1]).toBe(cards[1]);
|
|
127
|
+
expect(deck.cards[2]).toBe(cards[2]);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe("createTestHand", () => {
|
|
132
|
+
it("should create hand zone with appropriate defaults", () => {
|
|
133
|
+
const hand = createTestHand();
|
|
134
|
+
|
|
135
|
+
expect(hand.config.name).toContain("Hand");
|
|
136
|
+
expect(hand.config.visibility).toBe("private");
|
|
137
|
+
expect(hand.config.ordered).toBe(false);
|
|
138
|
+
expect(hand.config.faceDown).toBe(false);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("should include cards when provided", () => {
|
|
142
|
+
const cards = [createCardId("card1"), createCardId("card2")];
|
|
143
|
+
|
|
144
|
+
const hand = createTestHand(cards);
|
|
145
|
+
|
|
146
|
+
expect(hand.cards).toEqual(cards);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("should support owner", () => {
|
|
150
|
+
const playerId = createPlayerId("p1");
|
|
151
|
+
const hand = createTestHand([], playerId);
|
|
152
|
+
|
|
153
|
+
expect(hand.config.owner).toBe(playerId);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe("createTestPlayArea", () => {
|
|
158
|
+
it("should create play area with appropriate defaults", () => {
|
|
159
|
+
const playArea = createTestPlayArea();
|
|
160
|
+
|
|
161
|
+
expect(playArea.config.name).toContain("Play Area");
|
|
162
|
+
expect(playArea.config.visibility).toBe("public");
|
|
163
|
+
expect(playArea.config.ordered).toBe(false);
|
|
164
|
+
expect(playArea.config.faceDown).toBe(false);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("should include cards when provided", () => {
|
|
168
|
+
const cards = [createCardId("card1"), createCardId("card2")];
|
|
169
|
+
|
|
170
|
+
const playArea = createTestPlayArea(cards);
|
|
171
|
+
|
|
172
|
+
expect(playArea.cards).toEqual(cards);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("should support owner", () => {
|
|
176
|
+
const playerId = createPlayerId("p1");
|
|
177
|
+
const playArea = createTestPlayArea([], playerId);
|
|
178
|
+
|
|
179
|
+
expect(playArea.config.owner).toBe(playerId);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
describe("createTestGraveyard", () => {
|
|
184
|
+
it("should create graveyard with appropriate defaults", () => {
|
|
185
|
+
const graveyard = createTestGraveyard();
|
|
186
|
+
|
|
187
|
+
expect(graveyard.config.name).toContain("Graveyard");
|
|
188
|
+
expect(graveyard.config.visibility).toBe("public");
|
|
189
|
+
expect(graveyard.config.ordered).toBe(true);
|
|
190
|
+
expect(graveyard.config.faceDown).toBe(false);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it("should include cards when provided", () => {
|
|
194
|
+
const cards = [createCardId("card1"), createCardId("card2")];
|
|
195
|
+
|
|
196
|
+
const graveyard = createTestGraveyard(cards);
|
|
197
|
+
|
|
198
|
+
expect(graveyard.cards).toEqual(cards);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("should support owner", () => {
|
|
202
|
+
const playerId = createPlayerId("p1");
|
|
203
|
+
const graveyard = createTestGraveyard([], playerId);
|
|
204
|
+
|
|
205
|
+
expect(graveyard.config.owner).toBe(playerId);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("should maintain card order", () => {
|
|
209
|
+
const cards = [
|
|
210
|
+
createCardId("card1"),
|
|
211
|
+
createCardId("card2"),
|
|
212
|
+
createCardId("card3"),
|
|
213
|
+
];
|
|
214
|
+
|
|
215
|
+
const graveyard = createTestGraveyard(cards);
|
|
216
|
+
|
|
217
|
+
// Order should be preserved (cards go on top)
|
|
218
|
+
expect(graveyard.cards[0]).toBe(cards[0]);
|
|
219
|
+
expect(graveyard.cards[1]).toBe(cards[1]);
|
|
220
|
+
expect(graveyard.cards[2]).toBe(cards[2]);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
describe("integration", () => {
|
|
225
|
+
it("should create complete player zone setup", () => {
|
|
226
|
+
const playerId = createPlayerId("p1");
|
|
227
|
+
|
|
228
|
+
// Create all zones for a player
|
|
229
|
+
const deckCards = [
|
|
230
|
+
createCardId("card1"),
|
|
231
|
+
createCardId("card2"),
|
|
232
|
+
createCardId("card3"),
|
|
233
|
+
];
|
|
234
|
+
const handCards = [createCardId("card4"), createCardId("card5")];
|
|
235
|
+
|
|
236
|
+
const deck = createTestDeck(deckCards, playerId);
|
|
237
|
+
const hand = createTestHand(handCards, playerId);
|
|
238
|
+
const playArea = createTestPlayArea([], playerId);
|
|
239
|
+
const graveyard = createTestGraveyard([], playerId);
|
|
240
|
+
|
|
241
|
+
// Verify all zones created correctly
|
|
242
|
+
expect(deck.config.owner).toBe(playerId);
|
|
243
|
+
expect(hand.config.owner).toBe(playerId);
|
|
244
|
+
expect(playArea.config.owner).toBe(playerId);
|
|
245
|
+
expect(graveyard.config.owner).toBe(playerId);
|
|
246
|
+
|
|
247
|
+
// Verify zones have correct visibility
|
|
248
|
+
expect(deck.config.visibility).toBe("secret");
|
|
249
|
+
expect(hand.config.visibility).toBe("private");
|
|
250
|
+
expect(playArea.config.visibility).toBe("public");
|
|
251
|
+
expect(graveyard.config.visibility).toBe("public");
|
|
252
|
+
|
|
253
|
+
// Verify cards distributed correctly
|
|
254
|
+
expect(deck.cards.length).toBe(3);
|
|
255
|
+
expect(hand.cards.length).toBe(2);
|
|
256
|
+
expect(playArea.cards.length).toBe(0);
|
|
257
|
+
expect(graveyard.cards.length).toBe(0);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it("should work with zone operations", () => {
|
|
261
|
+
const deck = createTestDeck([
|
|
262
|
+
createCardId("card1"),
|
|
263
|
+
createCardId("card2"),
|
|
264
|
+
createCardId("card3"),
|
|
265
|
+
]);
|
|
266
|
+
|
|
267
|
+
// Test that zone factory creates zones compatible with zone operations
|
|
268
|
+
expect(deck.cards.length).toBe(3);
|
|
269
|
+
expect(deck.config.ordered).toBe(true);
|
|
270
|
+
|
|
271
|
+
// Simulate drawing a card
|
|
272
|
+
const drawnCard = deck.cards.pop();
|
|
273
|
+
expect(drawnCard).toBe(createCardId("card3"));
|
|
274
|
+
expect(deck.cards.length).toBe(2);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it("should create zones for multiple players", () => {
|
|
278
|
+
const p1 = createPlayerId("p1");
|
|
279
|
+
const p2 = createPlayerId("p2");
|
|
280
|
+
|
|
281
|
+
const p1Deck = createTestDeck(
|
|
282
|
+
[createCardId("p1-card1"), createCardId("p1-card2")],
|
|
283
|
+
p1,
|
|
284
|
+
);
|
|
285
|
+
const p2Deck = createTestDeck(
|
|
286
|
+
[createCardId("p2-card1"), createCardId("p2-card2")],
|
|
287
|
+
p2,
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
expect(p1Deck.config.owner).toBe(p1);
|
|
291
|
+
expect(p2Deck.config.owner).toBe(p2);
|
|
292
|
+
expect(p1Deck.config.id).not.toBe(p2Deck.config.id);
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
});
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import type { CardId, PlayerId } from "../types";
|
|
2
|
+
import { createZoneId } from "../types";
|
|
3
|
+
import type { CardZoneConfig, Zone } from "../zones/zone";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Test Zone Factory
|
|
7
|
+
*
|
|
8
|
+
* Factory functions for creating test zones
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
let zoneCounter = 0;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create a test zone with optional configuration and cards
|
|
15
|
+
*
|
|
16
|
+
* Generates a zone with sensible defaults that can be customized.
|
|
17
|
+
* Each zone gets a unique ID automatically.
|
|
18
|
+
*
|
|
19
|
+
* @param configOverrides - Optional config properties to override
|
|
20
|
+
* @param cards - Optional initial cards
|
|
21
|
+
* @returns Zone for testing
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* // Create default zone
|
|
26
|
+
* const zone = createTestZone();
|
|
27
|
+
*
|
|
28
|
+
* // Create zone with cards
|
|
29
|
+
* const deck = createTestZone(
|
|
30
|
+
* { name: 'Deck', visibility: 'secret', ordered: true },
|
|
31
|
+
* ['card1', 'card2', 'card3']
|
|
32
|
+
* );
|
|
33
|
+
*
|
|
34
|
+
* // Create player-owned zone
|
|
35
|
+
* const hand = createTestZone({
|
|
36
|
+
* name: 'Hand',
|
|
37
|
+
* owner: 'player1',
|
|
38
|
+
* visibility: 'private'
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export function createTestZone(
|
|
43
|
+
configOverrides?: Partial<CardZoneConfig>,
|
|
44
|
+
cards: CardId[] = [],
|
|
45
|
+
): Zone {
|
|
46
|
+
const id = createZoneId(`test-zone-${zoneCounter++}`);
|
|
47
|
+
|
|
48
|
+
const config: CardZoneConfig = {
|
|
49
|
+
id,
|
|
50
|
+
name: `Test Zone ${zoneCounter}`,
|
|
51
|
+
visibility: "public",
|
|
52
|
+
ordered: false,
|
|
53
|
+
...configOverrides,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
config,
|
|
58
|
+
cards: [...cards],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Create a test deck zone
|
|
64
|
+
*
|
|
65
|
+
* Creates a zone with typical deck properties:
|
|
66
|
+
* - Secret visibility (no one can see cards)
|
|
67
|
+
* - Ordered (card order matters)
|
|
68
|
+
* - Face down
|
|
69
|
+
*
|
|
70
|
+
* @param cards - Optional initial cards
|
|
71
|
+
* @param owner - Optional owner player ID
|
|
72
|
+
* @returns Deck zone
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const deck = createTestDeck(
|
|
77
|
+
* ['card1', 'card2', 'card3'],
|
|
78
|
+
* 'player1'
|
|
79
|
+
* );
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export function createTestDeck(cards: CardId[] = [], owner?: PlayerId): Zone {
|
|
83
|
+
const id = createZoneId(`test-deck-${zoneCounter++}`);
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
config: {
|
|
87
|
+
id,
|
|
88
|
+
name: owner ? `${owner} Deck` : "Test Deck",
|
|
89
|
+
visibility: "secret",
|
|
90
|
+
ordered: true,
|
|
91
|
+
faceDown: true,
|
|
92
|
+
owner,
|
|
93
|
+
},
|
|
94
|
+
cards: [...cards],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Create a test hand zone
|
|
100
|
+
*
|
|
101
|
+
* Creates a zone with typical hand properties:
|
|
102
|
+
* - Private visibility (owner can see, opponents cannot)
|
|
103
|
+
* - Unordered (card order doesn't matter)
|
|
104
|
+
* - Face up
|
|
105
|
+
*
|
|
106
|
+
* @param cards - Optional initial cards
|
|
107
|
+
* @param owner - Optional owner player ID
|
|
108
|
+
* @returns Hand zone
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* const hand = createTestHand(
|
|
113
|
+
* ['card1', 'card2'],
|
|
114
|
+
* 'player1'
|
|
115
|
+
* );
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
export function createTestHand(cards: CardId[] = [], owner?: PlayerId): Zone {
|
|
119
|
+
const id = createZoneId(`test-hand-${zoneCounter++}`);
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
config: {
|
|
123
|
+
id,
|
|
124
|
+
name: owner ? `${owner} Hand` : "Test Hand",
|
|
125
|
+
visibility: "private",
|
|
126
|
+
ordered: false,
|
|
127
|
+
faceDown: false,
|
|
128
|
+
owner,
|
|
129
|
+
},
|
|
130
|
+
cards: [...cards],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Create a test play area zone
|
|
136
|
+
*
|
|
137
|
+
* Creates a zone with typical play area properties:
|
|
138
|
+
* - Public visibility (everyone can see)
|
|
139
|
+
* - Unordered (card order doesn't matter)
|
|
140
|
+
* - Face up
|
|
141
|
+
*
|
|
142
|
+
* @param cards - Optional initial cards
|
|
143
|
+
* @param owner - Optional owner player ID
|
|
144
|
+
* @returns Play area zone
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```typescript
|
|
148
|
+
* const playArea = createTestPlayArea(
|
|
149
|
+
* ['creature1', 'creature2'],
|
|
150
|
+
* 'player1'
|
|
151
|
+
* );
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
export function createTestPlayArea(
|
|
155
|
+
cards: CardId[] = [],
|
|
156
|
+
owner?: PlayerId,
|
|
157
|
+
): Zone {
|
|
158
|
+
const id = createZoneId(`test-play-area-${zoneCounter++}`);
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
config: {
|
|
162
|
+
id,
|
|
163
|
+
name: owner ? `${owner} Play Area` : "Test Play Area",
|
|
164
|
+
visibility: "public",
|
|
165
|
+
ordered: false,
|
|
166
|
+
faceDown: false,
|
|
167
|
+
owner,
|
|
168
|
+
},
|
|
169
|
+
cards: [...cards],
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Create a test graveyard zone
|
|
175
|
+
*
|
|
176
|
+
* Creates a zone with typical graveyard properties:
|
|
177
|
+
* - Public visibility (everyone can see)
|
|
178
|
+
* - Ordered (card order matters - cards go on top)
|
|
179
|
+
* - Face up
|
|
180
|
+
*
|
|
181
|
+
* @param cards - Optional initial cards
|
|
182
|
+
* @param owner - Optional owner player ID
|
|
183
|
+
* @returns Graveyard zone
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```typescript
|
|
187
|
+
* const graveyard = createTestGraveyard(
|
|
188
|
+
* ['dead-card1', 'dead-card2'],
|
|
189
|
+
* 'player1'
|
|
190
|
+
* );
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
export function createTestGraveyard(
|
|
194
|
+
cards: CardId[] = [],
|
|
195
|
+
owner?: PlayerId,
|
|
196
|
+
): Zone {
|
|
197
|
+
const id = createZoneId(`test-graveyard-${zoneCounter++}`);
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
config: {
|
|
201
|
+
id,
|
|
202
|
+
name: owner ? `${owner} Graveyard` : "Test Graveyard",
|
|
203
|
+
visibility: "public",
|
|
204
|
+
ordered: true,
|
|
205
|
+
faceDown: false,
|
|
206
|
+
owner,
|
|
207
|
+
},
|
|
208
|
+
cards: [...cards],
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Reset the zone counter (useful for deterministic test IDs)
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```typescript
|
|
217
|
+
* resetZoneCounter();
|
|
218
|
+
* const zone1 = createTestZone(); // test-zone-0
|
|
219
|
+
* const zone2 = createTestZone(); // test-zone-1
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
export function resetZoneCounter(): void {
|
|
223
|
+
zoneCounter = 0;
|
|
224
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { nanoid } from "nanoid";
|
|
2
|
+
import type { CardId, GameId, PlayerId, ZoneId } from "./branded";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a CardId from a string or generates a new unique ID
|
|
6
|
+
* @param id - Optional ID string. If not provided, generates a new unique ID
|
|
7
|
+
* @returns A branded CardId
|
|
8
|
+
*/
|
|
9
|
+
export function createCardId(): CardId;
|
|
10
|
+
export function createCardId(id: string): CardId;
|
|
11
|
+
export function createCardId(id?: string): CardId {
|
|
12
|
+
// Type assertion is acceptable here as this is the only way to create branded types
|
|
13
|
+
// biome-ignore lint/suspicious/noExplicitAny: Required for branded type creation
|
|
14
|
+
return (id ?? nanoid()) as any;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Creates a PlayerId from a string or generates a new unique ID
|
|
19
|
+
* @param id - Optional ID string. If not provided, generates a new unique ID
|
|
20
|
+
* @returns A branded PlayerId
|
|
21
|
+
*/
|
|
22
|
+
export function createPlayerId(): PlayerId;
|
|
23
|
+
export function createPlayerId(id: string): PlayerId;
|
|
24
|
+
export function createPlayerId(id?: string): PlayerId {
|
|
25
|
+
// Type assertion is acceptable here as this is the only way to create branded types
|
|
26
|
+
// biome-ignore lint/suspicious/noExplicitAny: Required for branded type creation
|
|
27
|
+
return (id ?? nanoid()) as any;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Creates a GameId from a string or generates a new unique ID
|
|
32
|
+
* @param id - Optional ID string. If not provided, generates a new unique ID
|
|
33
|
+
* @returns A branded GameId
|
|
34
|
+
*/
|
|
35
|
+
export function createGameId(): GameId;
|
|
36
|
+
export function createGameId(id: string): GameId;
|
|
37
|
+
export function createGameId(id?: string): GameId {
|
|
38
|
+
// Type assertion is acceptable here as this is the only way to create branded types
|
|
39
|
+
// biome-ignore lint/suspicious/noExplicitAny: Required for branded type creation
|
|
40
|
+
return (id ?? nanoid()) as any;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Creates a ZoneId from a string or generates a new unique ID
|
|
45
|
+
* @param id - Optional ID string. If not provided, generates a new unique ID
|
|
46
|
+
* @returns A branded ZoneId
|
|
47
|
+
*/
|
|
48
|
+
export function createZoneId(): ZoneId;
|
|
49
|
+
export function createZoneId(id: string): ZoneId;
|
|
50
|
+
export function createZoneId(id?: string): ZoneId {
|
|
51
|
+
// Type assertion is acceptable here as this is the only way to create branded types
|
|
52
|
+
// biome-ignore lint/suspicious/noExplicitAny: Required for branded type creation
|
|
53
|
+
return (id ?? nanoid()) as any;
|
|
54
|
+
}
|