landlord-ts 1.0.2
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/LICENSE +21 -0
- package/README.md +111 -0
- package/data/all_cards.json.gz +0 -0
- package/dist/chunk-I6ETCO5F.js +803 -0
- package/dist/index.cjs +2487 -0
- package/dist/index.d.cts +504 -0
- package/dist/index.d.ts +504 -0
- package/dist/index.js +1681 -0
- package/dist/simulation-worker.cjs +208 -0
- package/dist/simulation-worker.d.cts +2 -0
- package/dist/simulation-worker.d.ts +2 -0
- package/dist/simulation-worker.js +33 -0
- package/package.json +102 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
/** Mana cost and color helpers — port of lib/src/card/mana_cost.rs */
|
|
2
|
+
type ManaCost = {
|
|
3
|
+
bits: number;
|
|
4
|
+
r: number;
|
|
5
|
+
w: number;
|
|
6
|
+
b: number;
|
|
7
|
+
u: number;
|
|
8
|
+
g: number;
|
|
9
|
+
c: number;
|
|
10
|
+
};
|
|
11
|
+
declare function manaCostFromRgbuwc(r: number, g: number, b: number, u: number, w: number, c: number): ManaCost;
|
|
12
|
+
declare function manaCostCmc(cost: ManaCost): number;
|
|
13
|
+
/** Expand a mana cost string like "{2}{R/G}" into all concrete ManaCost combinations. */
|
|
14
|
+
declare function manaCostsFromStr(manaCostStr: string): ManaCost[];
|
|
15
|
+
|
|
16
|
+
/** Internal card type — port of CardKind in lib/src/card/card.rs */
|
|
17
|
+
declare enum CardKind {
|
|
18
|
+
BasicLand = "BasicLand",
|
|
19
|
+
TapLand = "TapLand",
|
|
20
|
+
CheckLand = "CheckLand",
|
|
21
|
+
ShockLand = "ShockLand",
|
|
22
|
+
FastLand = "FastLand",
|
|
23
|
+
SlowLand = "SlowLand",
|
|
24
|
+
BattleLand = "BattleLand",
|
|
25
|
+
TurnLand = "TurnLand",
|
|
26
|
+
SurveilLand = "SurveilLand",
|
|
27
|
+
BounceLand = "BounceLand",
|
|
28
|
+
TriomeLand = "TriomeLand",
|
|
29
|
+
CyclingLand = "CyclingLand",
|
|
30
|
+
PainLand = "PainLand",
|
|
31
|
+
FetchLand = "FetchLand",
|
|
32
|
+
CanopyLand = "CanopyLand",
|
|
33
|
+
PathwayLand = "PathwayLand",
|
|
34
|
+
OtherLand = "OtherLand",
|
|
35
|
+
ForcedLand = "ForcedLand",
|
|
36
|
+
Creature = "Creature",
|
|
37
|
+
Spell = "Spell",
|
|
38
|
+
Enchantment = "Enchantment",
|
|
39
|
+
Instant = "Instant",
|
|
40
|
+
Planeswalker = "Planeswalker",
|
|
41
|
+
Sorcery = "Sorcery",
|
|
42
|
+
Artifact = "Artifact",
|
|
43
|
+
Unknown = "Unknown"
|
|
44
|
+
}
|
|
45
|
+
declare enum Rarity {
|
|
46
|
+
Common = "common",
|
|
47
|
+
Uncommon = "uncommon",
|
|
48
|
+
Rare = "rare",
|
|
49
|
+
Mythic = "mythic",
|
|
50
|
+
Special = "special",
|
|
51
|
+
Bonus = "bonus",
|
|
52
|
+
Other = "other"
|
|
53
|
+
}
|
|
54
|
+
declare enum GameFormat {
|
|
55
|
+
Standard = "standard",
|
|
56
|
+
Other = "other"
|
|
57
|
+
}
|
|
58
|
+
/** Set code stored as a string (Rust uses a large enum). */
|
|
59
|
+
type SetCode = string;
|
|
60
|
+
type Card = {
|
|
61
|
+
name: string;
|
|
62
|
+
oracleId: string;
|
|
63
|
+
manaCostString: string;
|
|
64
|
+
imageUri: string;
|
|
65
|
+
kind: CardKind;
|
|
66
|
+
/** Stable hash of the card name (FNV-1a 64-bit). */
|
|
67
|
+
hash: number;
|
|
68
|
+
turn: number;
|
|
69
|
+
manaCost: ManaCost;
|
|
70
|
+
allManaCosts: ManaCost[];
|
|
71
|
+
arenaId: number;
|
|
72
|
+
rarity: Rarity;
|
|
73
|
+
set: SetCode;
|
|
74
|
+
isFace: boolean;
|
|
75
|
+
/** Bitmask of basic land types on this card (see BasicLandType). */
|
|
76
|
+
basicLandTypes: number;
|
|
77
|
+
/** Bitmask of basic types that unlock this check land; 0 if not a check. */
|
|
78
|
+
checkTypes: number;
|
|
79
|
+
/** Mana units produced per tap (default 1); >1 for fixed-quantity lands like Ancient Tomb. */
|
|
80
|
+
manaPerTap: number;
|
|
81
|
+
};
|
|
82
|
+
declare function isLandKind(kind: CardKind): boolean;
|
|
83
|
+
declare function isLand(card: Card): boolean;
|
|
84
|
+
/** FNV-1a 64-bit — stable across runs (unlike Rust DefaultHasher). */
|
|
85
|
+
declare function hashCardName(name: string): number;
|
|
86
|
+
|
|
87
|
+
/** Bitmask for basic land types (Plains / Island / Swamp / Mountain / Forest). */
|
|
88
|
+
declare const BasicLandType: {
|
|
89
|
+
readonly Plains: number;
|
|
90
|
+
readonly Island: number;
|
|
91
|
+
readonly Swamp: number;
|
|
92
|
+
readonly Mountain: number;
|
|
93
|
+
readonly Forest: number;
|
|
94
|
+
};
|
|
95
|
+
/** Parse Plains/Island/Swamp/Mountain/Forest subtypes from a type line. */
|
|
96
|
+
declare function basicLandTypesFromTypeLine(typeLine: string): number;
|
|
97
|
+
/**
|
|
98
|
+
* Parse check-land requirements from oracle text after "unless you control".
|
|
99
|
+
* e.g. "enters tapped unless you control a Plains or an Island."
|
|
100
|
+
*/
|
|
101
|
+
declare function checkTypesFromOracleText(oracleText: string): number;
|
|
102
|
+
|
|
103
|
+
type ManaColorCount = {
|
|
104
|
+
total: number;
|
|
105
|
+
c: number;
|
|
106
|
+
w: number;
|
|
107
|
+
u: number;
|
|
108
|
+
b: number;
|
|
109
|
+
r: number;
|
|
110
|
+
g: number;
|
|
111
|
+
wu: number;
|
|
112
|
+
wb: number;
|
|
113
|
+
ub: number;
|
|
114
|
+
ur: number;
|
|
115
|
+
br: number;
|
|
116
|
+
bg: number;
|
|
117
|
+
rg: number;
|
|
118
|
+
rw: number;
|
|
119
|
+
gw: number;
|
|
120
|
+
gu: number;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
type DeckCard = {
|
|
124
|
+
card: Card;
|
|
125
|
+
count: number;
|
|
126
|
+
};
|
|
127
|
+
type Deck = {
|
|
128
|
+
title: string | null;
|
|
129
|
+
url: string | null;
|
|
130
|
+
cards: DeckCard[];
|
|
131
|
+
format: GameFormat;
|
|
132
|
+
cardCount: number;
|
|
133
|
+
};
|
|
134
|
+
declare class DeckcodeError extends Error {
|
|
135
|
+
/**
|
|
136
|
+
* All unresolved card names from this parse (set/collector stripped).
|
|
137
|
+
* Prefer this for UI lists when multiple cards are missing.
|
|
138
|
+
*/
|
|
139
|
+
readonly unknownCardNames: string[];
|
|
140
|
+
/** First unknown card name; same as `unknownCardNames[0]` when present. */
|
|
141
|
+
readonly unknownCardName?: string;
|
|
142
|
+
constructor(message: string, options?: {
|
|
143
|
+
unknownCardName?: string;
|
|
144
|
+
unknownCardNames?: string[];
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
declare function deckFromCards(cards: Iterable<Card>): Deck;
|
|
148
|
+
declare function deckFlatten(deck: Deck): Card[];
|
|
149
|
+
declare function deckFromList(list: string): Deck;
|
|
150
|
+
declare function decklist(list: string): Deck;
|
|
151
|
+
/**
|
|
152
|
+
* Non-throwing parse for UI validation (e.g. textarea before `run()`).
|
|
153
|
+
* On failure, `error.message` is human-readable; unknown cards set
|
|
154
|
+
* `error.unknownCardNames` (and `error.unknownCardName` for the first).
|
|
155
|
+
*/
|
|
156
|
+
type ParseDecklistResult = {
|
|
157
|
+
ok: true;
|
|
158
|
+
deck: Deck;
|
|
159
|
+
} | {
|
|
160
|
+
ok: false;
|
|
161
|
+
error: DeckcodeError;
|
|
162
|
+
};
|
|
163
|
+
declare function parseDecklist(list: string): ParseDecklistResult;
|
|
164
|
+
|
|
165
|
+
type Rng = {
|
|
166
|
+
/** Uniform integer in `[min, max)`. */
|
|
167
|
+
genRange(min: number, max: number): number;
|
|
168
|
+
};
|
|
169
|
+
type Mulligan = {
|
|
170
|
+
simulateHand(rng: Rng, deck: readonly Card[], draws: number): Hand;
|
|
171
|
+
};
|
|
172
|
+
/** Mulberry32 PRNG for reproducible simulations. */
|
|
173
|
+
declare function createMulberry32(seed: number): Rng;
|
|
174
|
+
|
|
175
|
+
type SimCard = {
|
|
176
|
+
hash: number;
|
|
177
|
+
kind: CardKind;
|
|
178
|
+
manaCost: ManaCost;
|
|
179
|
+
basicLandTypes: number;
|
|
180
|
+
checkTypes: number;
|
|
181
|
+
manaPerTap: number;
|
|
182
|
+
};
|
|
183
|
+
declare enum PlayOrder {
|
|
184
|
+
First = "First",
|
|
185
|
+
Second = "Second"
|
|
186
|
+
}
|
|
187
|
+
type AutoTapResult = {
|
|
188
|
+
paid: boolean;
|
|
189
|
+
cmc: boolean;
|
|
190
|
+
inOpeningHand: boolean;
|
|
191
|
+
inDrawHand: boolean;
|
|
192
|
+
};
|
|
193
|
+
type Hand = {
|
|
194
|
+
cards: SimCard[];
|
|
195
|
+
startingHandSize: number;
|
|
196
|
+
openingHandSize: number;
|
|
197
|
+
mulliganCount: number;
|
|
198
|
+
};
|
|
199
|
+
declare function handFromOpeningAndDraws(opening: readonly Card[], draws: readonly Card[], startingHandSize?: number): Hand;
|
|
200
|
+
declare function autoTapByTurn(hand: Hand, goal: Card, turn: number, playOrder: PlayOrder): AutoTapResult;
|
|
201
|
+
declare function playCmcAutoTap(hand: Hand, goal: Card): AutoTapResult;
|
|
202
|
+
declare function drawCmcAutoTap(hand: Hand, goal: Card): AutoTapResult;
|
|
203
|
+
/**
|
|
204
|
+
* Available turn for a land given board state when it is played.
|
|
205
|
+
* Always-available kinds ignore play-turn gating for Karsten parity (sources in hand).
|
|
206
|
+
* `basicsOnBoard` counts Basic-supertype lands already played (for BattleLand).
|
|
207
|
+
*/
|
|
208
|
+
declare function availableTurnForLand(card: SimCard, playTurn: number, otherLands: number, boardTypes: number, basicsOnBoard?: number): number;
|
|
209
|
+
|
|
210
|
+
type SimulationConfig = {
|
|
211
|
+
runCount: number;
|
|
212
|
+
drawCount: number;
|
|
213
|
+
deck: Deck;
|
|
214
|
+
mulligan: Mulligan;
|
|
215
|
+
onThePlay: boolean;
|
|
216
|
+
/** Optional seed for reproducible runs (tests). */
|
|
217
|
+
seed?: number;
|
|
218
|
+
/**
|
|
219
|
+
* When set, `runs` is a maximum; stop early when the Wilson half-width of the
|
|
220
|
+
* aggregate pManaGivenCmc across observed CMC opportunities is below this.
|
|
221
|
+
*/
|
|
222
|
+
epsilon?: number;
|
|
223
|
+
/** Shard Monte Carlo trials across worker threads (Node). Default: true when runCount >= 2000. */
|
|
224
|
+
parallel?: boolean;
|
|
225
|
+
/** London/Never starting hand size used when reconstructing workers. */
|
|
226
|
+
startingHandSize?: number;
|
|
227
|
+
mulliganDownTo?: number;
|
|
228
|
+
mulliganOnLands?: number[];
|
|
229
|
+
acceptableHandList?: number[][];
|
|
230
|
+
};
|
|
231
|
+
type Simulation = {
|
|
232
|
+
hands: Hand[];
|
|
233
|
+
accumulatedOpeningHandSize: number;
|
|
234
|
+
accumulatedOpeningHandLandCount: number;
|
|
235
|
+
onThePlay: boolean;
|
|
236
|
+
};
|
|
237
|
+
type Observations = {
|
|
238
|
+
mana: number;
|
|
239
|
+
cmc: number;
|
|
240
|
+
play: number;
|
|
241
|
+
inOpeningHand: number;
|
|
242
|
+
totalRuns: number;
|
|
243
|
+
};
|
|
244
|
+
declare function pMana(obs: Observations): number;
|
|
245
|
+
declare function pManaGivenCmc(obs: Observations): number;
|
|
246
|
+
declare function pPlay(obs: Observations): number;
|
|
247
|
+
/** Wilson score half-width for a binomial proportion (approx. 95% z=1.96). */
|
|
248
|
+
declare function wilsonHalfWidth(successes: number, trials: number, z?: number): number;
|
|
249
|
+
declare function simulationFromConfig(config: SimulationConfig): Simulation;
|
|
250
|
+
type SimulationProgress = {
|
|
251
|
+
completed: number;
|
|
252
|
+
total: number;
|
|
253
|
+
};
|
|
254
|
+
type SimulationAsyncOptions = {
|
|
255
|
+
/**
|
|
256
|
+
* Trials per progress tick when `epsilon` is unset (default 500).
|
|
257
|
+
* Ignored when `epsilon` is set — batches use the same size as sync adaptive (1000).
|
|
258
|
+
*/
|
|
259
|
+
batchSize?: number;
|
|
260
|
+
onProgress?: (progress: SimulationProgress) => void;
|
|
261
|
+
/** Required for Wilson early-stop when `config.epsilon` is set. */
|
|
262
|
+
cards?: readonly Card[];
|
|
263
|
+
/** When aborted, stops between batches (throws `AbortError`). */
|
|
264
|
+
signal?: AbortSignal;
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* Sequential batched hand generation with optional progress callbacks and event-loop yields.
|
|
268
|
+
* Always single-threaded (`parallel` ignored) so hosts can flush SSE between batches.
|
|
269
|
+
* Without `epsilon`, uses one continuous RNG stream (seeded runs match `simulationFromConfig` with parallel off).
|
|
270
|
+
* With `epsilon`, batch size matches sync adaptive (`EARLY_STOP_BATCH`) so seeded results match `run()`.
|
|
271
|
+
*/
|
|
272
|
+
declare function simulationFromConfigAsync(config: SimulationConfig, options?: SimulationAsyncOptions): Promise<Simulation>;
|
|
273
|
+
declare function observationsForCard(sim: Simulation, card: Card): Observations;
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* On-curve observations report builders — used to populate flattened RunOutput.
|
|
277
|
+
*/
|
|
278
|
+
|
|
279
|
+
/** Fraction of CMC opportunities that must fail color/timing to flag `colorConstrained`. */
|
|
280
|
+
declare const COLOR_CONSTRAINED_THRESHOLD = 0.15;
|
|
281
|
+
/** Fraction of mana hits that must be undrawn to flag `drawDependent`. */
|
|
282
|
+
declare const DRAW_DEPENDENT_THRESHOLD = 0.15;
|
|
283
|
+
type CardObservationsReport = {
|
|
284
|
+
name: string;
|
|
285
|
+
manaCost: string;
|
|
286
|
+
imageUri: string;
|
|
287
|
+
kind: CardKind;
|
|
288
|
+
turn: number;
|
|
289
|
+
copies: number;
|
|
290
|
+
cmc: number;
|
|
291
|
+
playedOnCurve: number;
|
|
292
|
+
notPlayedOnCurve: number;
|
|
293
|
+
totalSimulations: number;
|
|
294
|
+
pCastOnCurve: number;
|
|
295
|
+
pManaGivenCmc: number;
|
|
296
|
+
pInOpeningHand: number;
|
|
297
|
+
notEnoughLands: number;
|
|
298
|
+
colorOrTimingFail: number;
|
|
299
|
+
manaOkUndrawn: number;
|
|
300
|
+
};
|
|
301
|
+
type WeakestOnCurveEntry = {
|
|
302
|
+
name: string;
|
|
303
|
+
pCastOnCurve: number;
|
|
304
|
+
turn: number;
|
|
305
|
+
};
|
|
306
|
+
type ColorConstrainedEntry = {
|
|
307
|
+
name: string;
|
|
308
|
+
colorOrTimingFail: number;
|
|
309
|
+
cmcOpportunities: number;
|
|
310
|
+
};
|
|
311
|
+
type DrawDependentEntry = {
|
|
312
|
+
name: string;
|
|
313
|
+
manaOkUndrawn: number;
|
|
314
|
+
manaHits: number;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Public run() / runAsync() façade — Arena decklist → Monte Carlo on-curve report.
|
|
319
|
+
* Public field names use camelCase.
|
|
320
|
+
*/
|
|
321
|
+
|
|
322
|
+
/** Thrown for invalid `RunInput` (bad deckcode, empty deck, bad acceptable hands). */
|
|
323
|
+
declare class RunValidationError extends Error {
|
|
324
|
+
constructor(message: string, options?: {
|
|
325
|
+
cause?: unknown;
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
type RunInput = {
|
|
329
|
+
code: string;
|
|
330
|
+
runs: number;
|
|
331
|
+
onThePlay: boolean;
|
|
332
|
+
mulliganDownTo: number;
|
|
333
|
+
mulliganOnLands: number[];
|
|
334
|
+
acceptableHandList: string[][];
|
|
335
|
+
/** Optional RNG seed for reproducible runs. */
|
|
336
|
+
seed?: number;
|
|
337
|
+
/** Optional starting hand size (default 7). */
|
|
338
|
+
startingHandSize?: number;
|
|
339
|
+
/**
|
|
340
|
+
* Optional early-stop half-width on aggregate pManaGivenCmc.
|
|
341
|
+
* When set, `runs` is treated as a maximum.
|
|
342
|
+
*/
|
|
343
|
+
epsilon?: number;
|
|
344
|
+
/** Shard trials across worker threads (default: auto when runs >= 2000). */
|
|
345
|
+
parallel?: boolean;
|
|
346
|
+
};
|
|
347
|
+
type RunProgressPhase = 'simulating' | 'scoring';
|
|
348
|
+
type RunProgress = {
|
|
349
|
+
completed: number;
|
|
350
|
+
total: number;
|
|
351
|
+
/** `simulating` during hand batches; `scoring` once before report build. */
|
|
352
|
+
phase: RunProgressPhase;
|
|
353
|
+
};
|
|
354
|
+
type RunAsyncInput = RunInput & {
|
|
355
|
+
onProgress?: (progress: RunProgress) => void;
|
|
356
|
+
/**
|
|
357
|
+
* Trials per progress tick when `epsilon` is unset (default 500).
|
|
358
|
+
* Ignored when `epsilon` is set (uses the same 1000-trial batches as sync adaptive).
|
|
359
|
+
*/
|
|
360
|
+
batchSize?: number;
|
|
361
|
+
/** When aborted, stops between batches (throws `AbortError`). */
|
|
362
|
+
signal?: AbortSignal;
|
|
363
|
+
};
|
|
364
|
+
type LandCount = {
|
|
365
|
+
name: string;
|
|
366
|
+
manaCost: string;
|
|
367
|
+
imageUri: string;
|
|
368
|
+
kind: CardKind;
|
|
369
|
+
copies: number;
|
|
370
|
+
hash: number;
|
|
371
|
+
};
|
|
372
|
+
type RunOutput = {
|
|
373
|
+
totalSimulations: number;
|
|
374
|
+
avgOpeningHandSize: number;
|
|
375
|
+
avgOpeningLandCount: number;
|
|
376
|
+
deckSize: number;
|
|
377
|
+
deckAverageCmc: number;
|
|
378
|
+
cards: CardObservationsReport[];
|
|
379
|
+
weakestOnCurve: WeakestOnCurveEntry[];
|
|
380
|
+
colorConstrained: ColorConstrainedEntry[];
|
|
381
|
+
drawDependent: DrawDependentEntry[];
|
|
382
|
+
landCounts: LandCount[];
|
|
383
|
+
totalLandCounts: ManaColorCount;
|
|
384
|
+
basicLandCounts: ManaColorCount;
|
|
385
|
+
tapLandCounts: ManaColorCount;
|
|
386
|
+
checkLandCounts: ManaColorCount;
|
|
387
|
+
shockLandCounts: ManaColorCount;
|
|
388
|
+
fastLandCounts: ManaColorCount;
|
|
389
|
+
slowLandCounts: ManaColorCount;
|
|
390
|
+
battleLandCounts: ManaColorCount;
|
|
391
|
+
turnLandCounts: ManaColorCount;
|
|
392
|
+
surveilLandCounts: ManaColorCount;
|
|
393
|
+
bounceLandCounts: ManaColorCount;
|
|
394
|
+
triomeLandCounts: ManaColorCount;
|
|
395
|
+
cyclingLandCounts: ManaColorCount;
|
|
396
|
+
painLandCounts: ManaColorCount;
|
|
397
|
+
fetchLandCounts: ManaColorCount;
|
|
398
|
+
canopyLandCounts: ManaColorCount;
|
|
399
|
+
pathwayLandCounts: ManaColorCount;
|
|
400
|
+
otherLandCounts: ManaColorCount;
|
|
401
|
+
nonLandCounts: ManaColorCount;
|
|
402
|
+
};
|
|
403
|
+
/** SSE `data:` payload shapes for wiki Pattern A hosts (types only). */
|
|
404
|
+
type SimulateProgressEvent = {
|
|
405
|
+
type: 'progress';
|
|
406
|
+
} & RunProgress;
|
|
407
|
+
type SimulateDoneEvent = {
|
|
408
|
+
type: 'done';
|
|
409
|
+
result: RunOutput;
|
|
410
|
+
};
|
|
411
|
+
type SimulateErrorEvent = {
|
|
412
|
+
type: 'error';
|
|
413
|
+
message: string;
|
|
414
|
+
};
|
|
415
|
+
type SimulateStreamEvent = SimulateProgressEvent | SimulateDoneEvent | SimulateErrorEvent;
|
|
416
|
+
/**
|
|
417
|
+
* Run a Monte Carlo simulation for an Arena decklist.
|
|
418
|
+
* Returns a single flattened on-curve report (`cards`, insights, land tallies).
|
|
419
|
+
*/
|
|
420
|
+
declare function run(input: RunInput): RunOutput;
|
|
421
|
+
/**
|
|
422
|
+
* Async Monte Carlo run with optional progress callbacks for streaming hosts (e.g. SSE).
|
|
423
|
+
* Always sequential batches (`parallel` ignored) so the event loop can flush between ticks.
|
|
424
|
+
* Emits `phase: 'simulating'` after each hand batch, then `phase: 'scoring'` before report build.
|
|
425
|
+
*/
|
|
426
|
+
declare function runAsync(input: RunAsyncInput): Promise<RunOutput>;
|
|
427
|
+
|
|
428
|
+
type Collection = {
|
|
429
|
+
cards: Card[];
|
|
430
|
+
};
|
|
431
|
+
/** Convenience object API matching Rust Collection methods. */
|
|
432
|
+
type CollectionApi = Collection & {
|
|
433
|
+
cardFromName(name: string): Card | undefined;
|
|
434
|
+
otherFacesByName(name: string): Card[];
|
|
435
|
+
readonly length: number;
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
declare function loadCardsFromGzipBytes(bytes: Uint8Array): CollectionApi;
|
|
439
|
+
/** Lazily loaded card collection (Node). */
|
|
440
|
+
declare function getAllCards(): CollectionApi;
|
|
441
|
+
/** Replace the in-memory collection (tests / custom DBs). Pass null to clear. */
|
|
442
|
+
declare function setAllCards(collection: CollectionApi | null): void;
|
|
443
|
+
/**
|
|
444
|
+
* Proxy so `ALL_CARDS.cardFromName(...)` works like Rust lazy_static.
|
|
445
|
+
* Loads the gzipped DB on first property access.
|
|
446
|
+
*/
|
|
447
|
+
declare const ALL_CARDS: CollectionApi;
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Scryfall → landlord Card conversion.
|
|
451
|
+
* Port of landlord lib/src/scryfall.rs (feat/enters-tapped-lands)
|
|
452
|
+
* and flatten/filter from bins/scryfall2landlord (feat/jsonl-bulk-data-support).
|
|
453
|
+
*/
|
|
454
|
+
|
|
455
|
+
type ScryfallLegality = 'legal' | 'not_legal' | 'banned' | 'restricted' | string;
|
|
456
|
+
type ScryfallCard = {
|
|
457
|
+
name?: string;
|
|
458
|
+
id?: string;
|
|
459
|
+
oracle_id?: string;
|
|
460
|
+
mana_cost?: string;
|
|
461
|
+
oracle_text?: string;
|
|
462
|
+
collector_number?: string;
|
|
463
|
+
type_line?: string;
|
|
464
|
+
color_identity?: string[];
|
|
465
|
+
legalities?: Record<string, ScryfallLegality>;
|
|
466
|
+
image_uris?: Record<string, string>;
|
|
467
|
+
cmc?: number;
|
|
468
|
+
arena_id?: number;
|
|
469
|
+
card_faces?: ScryfallCard[];
|
|
470
|
+
set?: string;
|
|
471
|
+
set_type?: string;
|
|
472
|
+
rarity?: string;
|
|
473
|
+
object?: string;
|
|
474
|
+
released_at?: string;
|
|
475
|
+
lang?: string | null;
|
|
476
|
+
promo?: boolean;
|
|
477
|
+
};
|
|
478
|
+
/** Override land color sources when Scryfall color_identity is wrong. */
|
|
479
|
+
declare const SPECIAL_LANDS: ReadonlyMap<string, ManaCost>;
|
|
480
|
+
/**
|
|
481
|
+
* Classify land ETB / nickname cycle from oracle text.
|
|
482
|
+
* Order matters: conditional ETB matchers before bare TapLand; specialty untapped before Other.
|
|
483
|
+
*/
|
|
484
|
+
declare function landKindFromOracleText(oracleText: string, typeLine: string, name?: string): CardKind;
|
|
485
|
+
/** Extract the ETB clause after "enters tapped" for mining / diagnostics. */
|
|
486
|
+
declare function etbClauseFromOracle(oracleText: string): string | null;
|
|
487
|
+
declare function scryfallCardToCard(raw: ScryfallCard): Card;
|
|
488
|
+
declare function scryfallCardsToCards(cards: readonly ScryfallCard[]): Card[];
|
|
489
|
+
|
|
490
|
+
type London = {
|
|
491
|
+
startingHandSize: number;
|
|
492
|
+
mulliganDownTo: number;
|
|
493
|
+
mulliganOnLands: Set<number>;
|
|
494
|
+
acceptableHandList: Set<number>[];
|
|
495
|
+
};
|
|
496
|
+
declare function londonNever(): London;
|
|
497
|
+
declare function asLondonMulligan(london: London): Mulligan;
|
|
498
|
+
|
|
499
|
+
type Never = {
|
|
500
|
+
startingHandSize: number;
|
|
501
|
+
};
|
|
502
|
+
declare function asNeverMulligan(n?: Never): Mulligan;
|
|
503
|
+
|
|
504
|
+
export { ALL_CARDS, BasicLandType, COLOR_CONSTRAINED_THRESHOLD, type Card, CardKind, type CardObservationsReport, type ColorConstrainedEntry, DRAW_DEPENDENT_THRESHOLD, type Deck, type DeckCard, DeckcodeError, type DrawDependentEntry, type LandCount, type ManaColorCount, type ManaCost, type Observations, type ParseDecklistResult, PlayOrder, Rarity, type RunAsyncInput, type RunInput, type RunOutput, type RunProgress, type RunProgressPhase, RunValidationError, SPECIAL_LANDS, type ScryfallCard, type SimulateDoneEvent, type SimulateErrorEvent, type SimulateProgressEvent, type SimulateStreamEvent, type Simulation, type SimulationAsyncOptions, type SimulationProgress, type WeakestOnCurveEntry, asLondonMulligan, asNeverMulligan, autoTapByTurn, availableTurnForLand, basicLandTypesFromTypeLine, checkTypesFromOracleText, createMulberry32, deckFlatten, deckFromCards, deckFromList, decklist, drawCmcAutoTap, etbClauseFromOracle, getAllCards, handFromOpeningAndDraws, hashCardName, isLand, isLandKind, landKindFromOracleText, loadCardsFromGzipBytes, londonNever, manaCostCmc, manaCostFromRgbuwc, manaCostsFromStr, observationsForCard, pMana, pManaGivenCmc, pPlay, parseDecklist, playCmcAutoTap, run, runAsync, scryfallCardToCard, scryfallCardsToCards, setAllCards, simulationFromConfig, simulationFromConfigAsync, wilsonHalfWidth };
|