@yipe/dice 0.1.6 → 0.2.1
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/dist/builder/index.cjs +3465 -0
- package/dist/builder/index.cjs.map +1 -0
- package/dist/builder/index.d.cts +255 -0
- package/dist/builder/index.d.ts +255 -0
- package/dist/builder/index.js +3447 -0
- package/dist/builder/index.js.map +1 -0
- package/dist/index.d.cts +3 -883
- package/dist/index.d.ts +3 -883
- package/dist/pmf-DIegvlyA.d.cts +884 -0
- package/dist/pmf-DIegvlyA.d.ts +884 -0
- package/package.json +11 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,885 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*/
|
|
4
|
-
declare class LRUCache<K, V> {
|
|
5
|
-
private readonly maxSize;
|
|
6
|
-
private cache;
|
|
7
|
-
constructor(maxSize?: number);
|
|
8
|
-
get(key: K): V | undefined;
|
|
9
|
-
delete(key: K): void;
|
|
10
|
-
set(key: K, value: V): this;
|
|
11
|
-
clear(): void;
|
|
12
|
-
get size(): number;
|
|
13
|
-
has(key: K): boolean;
|
|
14
|
-
keys(): IterableIterator<K>;
|
|
15
|
-
values(): IterableIterator<V>;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/** Mapping from outcome label to probability mass or damage attribution. */
|
|
19
|
-
type OutcomeLabelMap = Partial<Record<string, number>>;
|
|
20
|
-
/** Computational epsilon for pruning negligible probabilities. */
|
|
21
|
-
declare const EPS = 1e-12;
|
|
22
|
-
/** A probability bin for a specific damage value. */
|
|
23
|
-
interface Bin {
|
|
24
|
-
/** Total probability mass at this damage value. */
|
|
25
|
-
p: number;
|
|
26
|
-
/** Per-outcome probability mass contributions at this damage. */
|
|
27
|
-
count: OutcomeLabelMap;
|
|
28
|
-
/** Optional per-outcome damage attribution at this damage. */
|
|
29
|
-
attr?: OutcomeLabelMap;
|
|
30
|
-
}
|
|
31
|
-
/** Simple mapping from damage value to probability. */
|
|
32
|
-
type DamageDistribution = Record<number, number>;
|
|
33
|
-
/** Canonical outcome labels supported by the query helpers. */
|
|
34
|
-
type OutcomeType = "crit" | "hit" | "missNone" | "missDamage" | "saveHalf" | "saveFail" | "pc";
|
|
35
|
-
type Rounding = "none" | "floor" | "round" | "ceil";
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Query interface for analyzing dice roll probability distributions.
|
|
39
|
-
*
|
|
40
|
-
* Combines multiple attack PMFs and provides statistical analysis methods for:
|
|
41
|
-
* - Basic statistics (mean, variance, min/max, percentiles)
|
|
42
|
-
* - Probability queries (hit chances, success rates, exact counts)
|
|
43
|
-
* - Damage analysis (ranges by outcome type, expected values)
|
|
44
|
-
* - Data export (charts, tables, visualizations)
|
|
45
|
-
*
|
|
46
|
-
*/
|
|
47
|
-
declare class DiceQuery {
|
|
48
|
-
readonly singles: PMF[];
|
|
49
|
-
readonly combined: PMF;
|
|
50
|
-
constructor(singles: PMF | PMF[], combined?: PMF, eps?: number);
|
|
51
|
-
private static readonly DEFAULT_OUTCOMES;
|
|
52
|
-
/**
|
|
53
|
-
* Returns the expected damage across all possible outcomes.
|
|
54
|
-
*
|
|
55
|
-
* Example: `query.mean()` → 12.5
|
|
56
|
-
* Use case: "What's my average damage per round?"
|
|
57
|
-
*/
|
|
58
|
-
mean(): number;
|
|
59
|
-
/**
|
|
60
|
-
* Returns the variance of the damage distribution.
|
|
61
|
-
*
|
|
62
|
-
* Example: `query.variance()` → 45.2
|
|
63
|
-
* Use case: "How much does my damage vary from the average?"
|
|
64
|
-
* High variance means higher risk/reward. Lower variance means more consistent damage.
|
|
65
|
-
*/
|
|
66
|
-
variance(): number;
|
|
67
|
-
/**
|
|
68
|
-
* Returns the standard deviation of the damage distribution.
|
|
69
|
-
*
|
|
70
|
-
* Example: `query.stdev()` → 6.7
|
|
71
|
-
* Use case: "What's the typical spread around my average damage?"
|
|
72
|
-
* Used to determine how consistent the damage is.
|
|
73
|
-
*/
|
|
74
|
-
stddev(): number;
|
|
75
|
-
/**
|
|
76
|
-
* Returns the Cumulative Distribution Function.
|
|
77
|
-
*/
|
|
78
|
-
cdf(x: number): number;
|
|
79
|
-
/**
|
|
80
|
-
* Returns the probability of dealing X damage or less.
|
|
81
|
-
* In statistics, this is called the cumulative distribution function (CDF).
|
|
82
|
-
* Example: `query.cdf(20)` → 0.75
|
|
83
|
-
* Use case: "What's the chance I deal 20 damage or less?"
|
|
84
|
-
*/
|
|
85
|
-
probTotalAtMost(x: number): number;
|
|
86
|
-
/**
|
|
87
|
-
* Returns the Complementary Cumulative Distribution Function.
|
|
88
|
-
*/
|
|
89
|
-
ccdf(x: number): number;
|
|
90
|
-
/**
|
|
91
|
-
* Returns the probability of dealing at least X damage.
|
|
92
|
-
*
|
|
93
|
-
* Example: `query.probTotalAtLeast(25)` → 0.35
|
|
94
|
-
* Use case: "What's the chance I deal at least 25 damage to finish the enemy?"
|
|
95
|
-
*/
|
|
96
|
-
probTotalAtLeast(threshold: number): number;
|
|
97
|
-
/**
|
|
98
|
-
* Returns damage values at specific percentiles.
|
|
99
|
-
*
|
|
100
|
-
* Example: `query.percentiles([0.25, 0.5, 0.75])` → [8, 12, 18]
|
|
101
|
-
* Use case: "What are my 25th, 50th, and 75th percentile damage values?"
|
|
102
|
-
*/
|
|
103
|
-
percentiles(percentileValues: number[]): number[];
|
|
104
|
-
/**
|
|
105
|
-
* Returns the minimum possible damage.
|
|
106
|
-
*
|
|
107
|
-
* Example: `query.min()` → 0
|
|
108
|
-
* Use case: "What's the worst-case damage if everything misses?"
|
|
109
|
-
*/
|
|
110
|
-
min(): number;
|
|
111
|
-
/**
|
|
112
|
-
* Returns the maximum possible damage.
|
|
113
|
-
*
|
|
114
|
-
* Example: `query.max()` → 56
|
|
115
|
-
* Use case: "What's the best-case damage if everything crits and rolls max?"
|
|
116
|
-
*/
|
|
117
|
-
max(): number;
|
|
118
|
-
private singleProb;
|
|
119
|
-
probAtLeastK(labels: OutcomeType | OutcomeType[], k: number): number;
|
|
120
|
-
/**
|
|
121
|
-
* Returns the probability that at least one attack has the specified outcome(s).
|
|
122
|
-
* - This is the complement of probAtMostK(labels, 0)
|
|
123
|
-
*
|
|
124
|
-
* Examples:
|
|
125
|
-
* - `query.probAtLeastOne('hit')` → 0.88 (88% chance at least one attack hits)
|
|
126
|
-
* - `query.probAtLeastOne(['hit', 'crit'])` → 0.96 (96% chance at least one succeeds)
|
|
127
|
-
*
|
|
128
|
-
* Use cases:
|
|
129
|
-
* - "What's the chance at least one of my attacks connects?"
|
|
130
|
-
*
|
|
131
|
-
* Note:
|
|
132
|
-
*
|
|
133
|
-
* - You have to pass in an array of labels to avoid double-counting if you are
|
|
134
|
-
* using multiple labels. You cannot just add them.
|
|
135
|
-
*/
|
|
136
|
-
probAtLeastOne(labels: OutcomeType | OutcomeType[]): number;
|
|
137
|
-
/**
|
|
138
|
-
* Computes binomial probabilities for exactly 0, 1, 2, ..., maxK occurrences of a label.
|
|
139
|
-
*
|
|
140
|
-
* Uses dynamic programming to efficiently calculate the probability distribution
|
|
141
|
-
* of how many attacks will have the specified outcome, accounting for different
|
|
142
|
-
* success probabilities across individual attacks.
|
|
143
|
-
*
|
|
144
|
-
* Example: For 3 attacks with 50% hit chance each, returns:
|
|
145
|
-
* [0.125, 0.375, 0.375, 0.125] = [P(0 hits), P(1 hit), P(2 hits), P(3 hits)]
|
|
146
|
-
*
|
|
147
|
-
* @param label - The outcome type to count
|
|
148
|
-
* @param maxK - Maximum number of occurrences to calculate (usually number of attacks)
|
|
149
|
-
* @returns Array where index K contains P(exactly K attacks have the label)
|
|
150
|
-
*/
|
|
151
|
-
private computeBinomialProbabilities;
|
|
152
|
-
/**
|
|
153
|
-
* Returns the probability that exactly K attacks result in the specified outcome(s).
|
|
154
|
-
*
|
|
155
|
-
* Single label examples:
|
|
156
|
-
* - probExactlyK('hit', 2) = probability exactly 2 attacks hit
|
|
157
|
-
* - probExactlyK('crit', 1) = probability exactly 1 attack crits
|
|
158
|
-
* - probExactlyK('crit', 0) = probability no attacks crit
|
|
159
|
-
*
|
|
160
|
-
* Array examples:
|
|
161
|
-
* - probExactlyK(['hit', 'crit'], 2) = probability exactly 2 attacks succeed
|
|
162
|
-
* - probExactlyK(['hit', 'crit'], 1) = probability exactly 1 attack succeeds
|
|
163
|
-
* - probExactlyK(['miss', 'missNone'], 0) = probability no attacks miss
|
|
164
|
-
*
|
|
165
|
-
* Use cases:
|
|
166
|
-
* - "What's the chance exactly one of my attacks hits?"
|
|
167
|
-
* - "How likely am I to get exactly 2 successes out of 3 attacks?"
|
|
168
|
-
* - "What's the probability that exactly half my attacks succeed?"
|
|
169
|
-
*
|
|
170
|
-
* Note: For arrays, an attack counts as a "success" if it has any of the specified labels.
|
|
171
|
-
* This is different from probAtMostK, which counts an attack as a "success" if it has ALL of the specified labels.
|
|
172
|
-
*/
|
|
173
|
-
probExactlyK(labels: OutcomeType | OutcomeType[], k: number): number;
|
|
174
|
-
/**
|
|
175
|
-
* Returns the probability that AT MOST K attacks result in the specified outcome(s).
|
|
176
|
-
*
|
|
177
|
-
* Single label examples:
|
|
178
|
-
* - probAtMostK('hit', 1) = probability 0 or 1 attacks hit (at most 1)
|
|
179
|
-
* - probAtMostK('crit', 0) = probability no attacks crit
|
|
180
|
-
* - probAtMostK('miss', 2) = probability at most 2 attacks miss
|
|
181
|
-
*
|
|
182
|
-
* Array examples:
|
|
183
|
-
* - probAtMostK(['hit', 'crit'], 1) = probability at most 1 attack succeeds
|
|
184
|
-
* - probAtMostK(['hit', 'crit'], 0) = probability no attacks succeed (all miss)
|
|
185
|
-
*
|
|
186
|
-
* Use cases:
|
|
187
|
-
* - "What's the chance that at most one attack hits?" (rest miss)
|
|
188
|
-
* - "How likely am I to have mostly failures?" (at most 1 success)
|
|
189
|
-
* - "What's the probability of a really bad turn?" (at most 0 successes)
|
|
190
|
-
*
|
|
191
|
-
*/
|
|
192
|
-
probAtMostK(labels: OutcomeType | OutcomeType[], k: number): number;
|
|
193
|
-
/**
|
|
194
|
-
* Returns the expected damage attributed to specific outcome types.
|
|
195
|
-
*
|
|
196
|
-
* Single label examples:
|
|
197
|
-
* - expectedDamageFrom('hit') = expected damage from hit components
|
|
198
|
-
* - expectedDamageFrom('crit') = expected damage from crit components
|
|
199
|
-
*
|
|
200
|
-
* Array examples:
|
|
201
|
-
* - expectedDamageFrom(['hit', 'crit']) = expected damage from any success
|
|
202
|
-
* - expectedDamageFrom(['missDamage', 'missNone']) = expected damage from misses
|
|
203
|
-
*
|
|
204
|
-
* Use cases:
|
|
205
|
-
* - "How much damage do I expect from successful attacks?"
|
|
206
|
-
* - "What's the damage contribution from critical hits specifically?"
|
|
207
|
-
* - "How much damage comes from miss effects (like save-for-half spells)?"
|
|
208
|
-
*/
|
|
209
|
-
expectedDamageFrom(labels: OutcomeType | OutcomeType[]): number;
|
|
210
|
-
/**
|
|
211
|
-
* Returns damage statistics for scenarios where AT LEAST ONE attack results in
|
|
212
|
-
* the specified outcome(s).
|
|
213
|
-
*
|
|
214
|
-
* This method answers "What happens when things go reasonably well?" rather than
|
|
215
|
-
* "What's the theoretical maximum?" It includes mixed scenarios which are more
|
|
216
|
-
* common and tactically relevant than pure scenarios.
|
|
217
|
-
*
|
|
218
|
-
* Single label examples:
|
|
219
|
-
* - damageStatsFrom('hit') = damage range when at least one attack hits
|
|
220
|
-
* - damageStatsFrom('crit') = damage range when at least one attack crits
|
|
221
|
-
*
|
|
222
|
-
* Array examples:
|
|
223
|
-
* - damageStatsFrom(['hit', 'crit']) = damage range when at least one attack succeeds
|
|
224
|
-
* - damageStatsFrom(['miss', 'missNone']) = damage range when at least one attack misses
|
|
225
|
-
*
|
|
226
|
-
* Tactical Use Cases:
|
|
227
|
-
* - "Given that I don't completely whiff (99% of turns), what damage should I expect?"
|
|
228
|
-
* - "When planning to kill a 60 HP enemy, what's my damage range on successful turns?"
|
|
229
|
-
* - "Should I use this risky spell if it has good damage when it works?"
|
|
230
|
-
* - "What's my damage potential when something goes right?" (vs pure failure)
|
|
231
|
-
*
|
|
232
|
-
* Combat Planning Examples:
|
|
233
|
-
* - 4 attacks with 90% hit chance: "96% of the time you'll do 25-150 damage, avg 52"
|
|
234
|
-
* (Much more useful than "You average 50 damage including complete misses")
|
|
235
|
-
* - Risk assessment: "80% of successful turns do 40-80 damage, but 20% do 80-150"
|
|
236
|
-
* - Resource management: "If I hit anything, I'll likely finish this enemy"
|
|
237
|
-
*
|
|
238
|
-
* Statistical Note:
|
|
239
|
-
* This includes mixed scenarios (2 hits + 1 crit, 3 hits + 1 miss, etc.) which
|
|
240
|
-
* occur far more frequently than pure scenarios. For pure scenarios, use combinedDamageStats.
|
|
241
|
-
*
|
|
242
|
-
* @example
|
|
243
|
-
* // High-level tactical planning
|
|
244
|
-
* const successStats = query.damageStatsFrom('hit')
|
|
245
|
-
* const successChance = query.probAtLeastOne('hit')
|
|
246
|
-
* console.log(`${(successChance*100).toFixed(1)}% chance to do ${successStats.min}-${successStats.max} damage`)
|
|
247
|
-
*/
|
|
248
|
-
damageStatsFrom(labels: OutcomeType | OutcomeType[]): {
|
|
249
|
-
min: number;
|
|
250
|
-
max: number;
|
|
251
|
-
avg: number;
|
|
252
|
-
count: number;
|
|
253
|
-
};
|
|
254
|
-
/**
|
|
255
|
-
* Returns damage statistics for scenarios where ALL attacks result in the specified
|
|
256
|
-
* outcome, calculated by leveraging the pure partition of singles.
|
|
257
|
-
*
|
|
258
|
-
* This method answers "What's the theoretical best/worst case?" and "What are the
|
|
259
|
-
* clean mathematical boundaries?" It provides pure scenarios without mixing outcomes.
|
|
260
|
-
*
|
|
261
|
-
* Examples:
|
|
262
|
-
* - combinedDamageStats('hit') = damage range when all attacks hit (none crit, none miss)
|
|
263
|
-
* - combinedDamageStats('crit') = damage range when all attacks crit (none just hit)
|
|
264
|
-
*
|
|
265
|
-
* UI and Display Use Cases:
|
|
266
|
-
* - Statistics panels showing "MAX Hit Damage" (users expect pure hits, not mixed)
|
|
267
|
-
* - "Best case scenario" vs "worst case scenario" analysis
|
|
268
|
-
* - Mathematical verification: "Does our hit damage calculation match manual math?"
|
|
269
|
-
* - Clean damage type attribution: "How much comes from base hits vs crits?"
|
|
270
|
-
*
|
|
271
|
-
* Design and Balance Use Cases:
|
|
272
|
-
* - Game designers: "What's the damage ceiling if someone gets lucky?"
|
|
273
|
-
* - Character optimization: "What's my absolute maximum potential?"
|
|
274
|
-
* - Ability comparison: "Which build has higher crit ceiling?"
|
|
275
|
-
* - Minimum guaranteed damage: "What's the worst I can do if everything hits?"
|
|
276
|
-
*
|
|
277
|
-
* Mathematical Use Cases:
|
|
278
|
-
* - Validating complex calculations against simple manual math
|
|
279
|
-
* - Understanding damage component contributions in isolation
|
|
280
|
-
* - Separating luck (crit variance) from consistency (hit variance)
|
|
281
|
-
* - Building intuition about damage sources
|
|
282
|
-
*
|
|
283
|
-
* When to Use This vs damageStatsFrom():
|
|
284
|
-
* - Use THIS for: UI max/min displays, theoretical limits, clean comparisons
|
|
285
|
-
* - Use damageStatsFrom() for: tactical planning, realistic expectations, mixed scenarios
|
|
286
|
-
*
|
|
287
|
-
* Statistical Note:
|
|
288
|
-
* Pure scenarios (all hits, all crits) are rare but represent clear mathematical
|
|
289
|
-
* boundaries. These stats help understand the "shape" of your damage potential.
|
|
290
|
-
*
|
|
291
|
-
* @example
|
|
292
|
-
* // UI display logic
|
|
293
|
-
* const pureHitMax = query.combinedDamageStats('hit').max // Clean "MAX Hit Damage: 90"
|
|
294
|
-
* const pureCritMax = query.combinedDamageStats('crit').max // Clean "MAX Crit Damage: 168"
|
|
295
|
-
*
|
|
296
|
-
* // vs tactical planning (use damageStatsFrom instead)
|
|
297
|
-
* const realisticRange = query.damageStatsFrom('hit') // Includes mixed scenarios
|
|
298
|
-
*/
|
|
299
|
-
combinedDamageStats(targetLabel: OutcomeType): {
|
|
300
|
-
min: number;
|
|
301
|
-
max: number;
|
|
302
|
-
avg: number;
|
|
303
|
-
count: number;
|
|
304
|
-
};
|
|
305
|
-
/**
|
|
306
|
-
* Returns the probability that a result includes ANY of the specified labels.
|
|
307
|
-
*
|
|
308
|
-
* Examples:
|
|
309
|
-
* - `query.probabilityOf('hit')` → 0.88 (probability at least one hit occurs)
|
|
310
|
-
* - `query.probabilityOf(['hit', 'crit'])` → 0.96 (probability of any success)
|
|
311
|
-
*
|
|
312
|
-
* Use cases:
|
|
313
|
-
* - "What's the chance my resolution includes a success label?"
|
|
314
|
-
* - "How likely am I to get any hits or crits across all attacks?"
|
|
315
|
-
*/
|
|
316
|
-
probabilityOf(labels: OutcomeType | OutcomeType[]): number;
|
|
317
|
-
/**
|
|
318
|
-
* Returns the probability of missing (any type of miss).
|
|
319
|
-
*
|
|
320
|
-
* Example: `query.missChance()` → 0.04
|
|
321
|
-
* Use case: "What's the chance I miss completely this turn?"
|
|
322
|
-
*/
|
|
323
|
-
missChance(): number;
|
|
324
|
-
/**
|
|
325
|
-
* Returns data formatted for plotting damage probability distribution.
|
|
326
|
-
*
|
|
327
|
-
* Example: `query.toChartSeries()` → [{x: 0, y: 0.04}, {x: 6, y: 0.1}, ...]
|
|
328
|
-
* Use case: "I want to visualize my damage distribution in a chart."
|
|
329
|
-
*/
|
|
330
|
-
toChartSeries(): Array<{
|
|
331
|
-
x: number;
|
|
332
|
-
y: number;
|
|
333
|
-
}>;
|
|
334
|
-
/**
|
|
335
|
-
* Returns tabular data showing damage values and their probability breakdowns.
|
|
336
|
-
*
|
|
337
|
-
* Example: `query.toLabeledTable(['hit', 'crit'])` →
|
|
338
|
-
* [{damage: 6, total: 0.01, hit: 0.008, crit: 0}, ...]
|
|
339
|
-
*
|
|
340
|
-
* Use case: "I want to see exactly how hit/crit probabilities contribute to each damage value."
|
|
341
|
-
*/
|
|
342
|
-
toLabeledTable(labels?: OutcomeType[]): Array<{
|
|
343
|
-
damage: number;
|
|
344
|
-
total: number;
|
|
345
|
-
} & Record<string, number>>;
|
|
346
|
-
/**
|
|
347
|
-
* Returns data for stacked charts with unconditional per-label probability mass per damage.
|
|
348
|
-
*
|
|
349
|
-
* - Each dataset value equals the unconditional probability mass for that label at that damage
|
|
350
|
-
* (i.e., `bin.count[label]`).
|
|
351
|
-
* - Column sums may be less than the total probability `bin.p` when you omit labels or when
|
|
352
|
-
* there is unlabeled mass. Include all relevant outcome labels if you need the sum to match.
|
|
353
|
-
* - This behavior matches tests that expect raw per-label mass (not proportional scaling).
|
|
354
|
-
* - NOTE: This implementation may break dprcalc.com chart binning at large n, need to test it more.
|
|
355
|
-
*
|
|
356
|
-
* @example
|
|
357
|
-
* query.toStackedChartData(['hit', 'crit'])
|
|
358
|
-
* // → {labels: [0, 6, 12, ...], datasets: [{label: 'hit', data: [0, 0.03, ...]}, ...]}
|
|
359
|
-
*/
|
|
360
|
-
toStackedChartData(labels?: OutcomeType[], epsilon?: number): {
|
|
361
|
-
labels: number[];
|
|
362
|
-
datasets: Array<{
|
|
363
|
-
label: string;
|
|
364
|
-
data: number[];
|
|
365
|
-
}>;
|
|
366
|
-
};
|
|
367
|
-
/**
|
|
368
|
-
* Returns pure mathematical data for attribution charts showing outcome contributions.
|
|
369
|
-
*
|
|
370
|
-
* Automatically discovers all outcome types present in the PMF, applies filtering rules,
|
|
371
|
-
* and returns proportional data suitable for stacked visualization.
|
|
372
|
-
*
|
|
373
|
-
* @param options Configuration options
|
|
374
|
-
* @param options.stackOrder Preferred order for outcome types (unknowns placed at end)
|
|
375
|
-
* @param options.filterRules Function to determine if outcome should be included for a given damage value
|
|
376
|
-
* @param options.asPercentages Whether to return percentages (0-100) or probabilities (0-1)
|
|
377
|
-
* @returns Pure data structure with support, outcomes, and proportional data
|
|
378
|
-
*
|
|
379
|
-
* @example
|
|
380
|
-
* query.toAttributionChartSeries()
|
|
381
|
-
* // → {support: [0, 6, 12], outcomes: ['hit', 'crit'], data: {hit: [5.2, 8.1, ...], crit: [0, 2.3, ...]}}
|
|
382
|
-
*/
|
|
383
|
-
toAttributionChartSeries(options?: {
|
|
384
|
-
stackOrder?: string[];
|
|
385
|
-
filterRules?: (outcome: string, damage: number) => boolean;
|
|
386
|
-
asPercentages?: boolean;
|
|
387
|
-
}): {
|
|
388
|
-
support: number[];
|
|
389
|
-
outcomes: string[];
|
|
390
|
-
data: {
|
|
391
|
-
[outcome: string]: number[];
|
|
392
|
-
};
|
|
393
|
-
};
|
|
394
|
-
/**
|
|
395
|
-
* Returns pure mathematical data for damage attribution charts showing damage contribution
|
|
396
|
-
* from each outcome type at each damage value.
|
|
397
|
-
*
|
|
398
|
-
* Similar to toAttributionChartSeries() but uses bin.attr (damage attribution) instead of
|
|
399
|
-
* bin.count (probability attribution).
|
|
400
|
-
*
|
|
401
|
-
* @param options Configuration options
|
|
402
|
-
* @param options.stackOrder Preferred order for outcome types (unknowns placed at end)
|
|
403
|
-
* @param options.filterRules Function to determine if outcome should be included for a given damage value
|
|
404
|
-
* @param options.asPercentages Whether to return percentages (0-100) or raw damage values (0+)
|
|
405
|
-
* @returns Pure data structure with support, outcomes, and damage attribution data
|
|
406
|
-
*
|
|
407
|
-
* @example
|
|
408
|
-
* query.toDamageAttributionChartSeries()
|
|
409
|
-
* // → {support: [0, 6, 12], outcomes: ['hit', 'crit'], data: {hit: [3.2, 5.1, ...], crit: [0, 1.8, ...]}}
|
|
410
|
-
*/
|
|
411
|
-
toDamageAttributionChartSeries(options?: {
|
|
412
|
-
stackOrder?: string[];
|
|
413
|
-
filterRules?: (outcome: string, damage: number) => boolean;
|
|
414
|
-
asPercentages?: boolean;
|
|
415
|
-
}): {
|
|
416
|
-
support: number[];
|
|
417
|
-
outcomes: string[];
|
|
418
|
-
data: {
|
|
419
|
-
[outcome: string]: number[];
|
|
420
|
-
};
|
|
421
|
-
};
|
|
422
|
-
/**
|
|
423
|
-
* Returns pure mathematical data for outcome attribution charts showing which
|
|
424
|
-
* attack outcome combinations can produce each damage value.
|
|
425
|
-
*
|
|
426
|
-
* Unlike toDamageAttributionChartSeries() which tracks damage sources, this tracks
|
|
427
|
-
* outcome combinations - answering "what attack outcomes produced this damage?"
|
|
428
|
-
*
|
|
429
|
-
* @param options Configuration options
|
|
430
|
-
* @param options.stackOrder Preferred order for outcome types (unknowns placed at end)
|
|
431
|
-
* @param options.filterRules Function to determine if outcome should be included for a given damage value
|
|
432
|
-
* @param options.asPercentages Whether to return percentages (0-100) or probabilities (0-1)
|
|
433
|
-
* @returns Pure data structure with support, outcomes, and outcome combination probabilities
|
|
434
|
-
*
|
|
435
|
-
* @example
|
|
436
|
-
* query.toOutcomeAttributionChartSeries()
|
|
437
|
-
* // → {support: [0, 6, 12], outcomes: ['all_miss', 'mixed', 'all_hit'], data: {all_miss: [15, 0, 0], mixed: [60, 80, 20], all_hit: [25, 20, 80]}}
|
|
438
|
-
*/
|
|
439
|
-
toOutcomeAttributionChartSeries(options?: {
|
|
440
|
-
stackOrder?: string[];
|
|
441
|
-
filterRules?: (outcome: string, damage: number) => boolean;
|
|
442
|
-
asPercentages?: boolean;
|
|
443
|
-
}): {
|
|
444
|
-
support: number[];
|
|
445
|
-
outcomes: string[];
|
|
446
|
-
data: {
|
|
447
|
-
[outcome: string]: number[];
|
|
448
|
-
};
|
|
449
|
-
};
|
|
450
|
-
/**
|
|
451
|
-
* Returns pure mathematical data for cumulative distribution function (CDF).
|
|
452
|
-
* Shows P(X ≤ x) - the probability of getting at most x damage.
|
|
453
|
-
*
|
|
454
|
-
* @param asPercentages Whether to return percentages (0-100) or probabilities (0-1)
|
|
455
|
-
* @returns Pure data structure with support and cumulative probabilities
|
|
456
|
-
*
|
|
457
|
-
* @example
|
|
458
|
-
* query.toCDFSeries()
|
|
459
|
-
* // → {support: [0, 6, 12], data: [5.2, 18.3, 45.1]}
|
|
460
|
-
*/
|
|
461
|
-
toCDFSeries(asPercentages?: boolean): {
|
|
462
|
-
support: number[];
|
|
463
|
-
data: number[];
|
|
464
|
-
};
|
|
465
|
-
/**
|
|
466
|
-
* Returns pure mathematical data for complementary cumulative distribution function (CCDF).
|
|
467
|
-
* Shows P(X ≥ x) - the probability of getting at least x damage.
|
|
468
|
-
*
|
|
469
|
-
* @param asPercentages Whether to return percentages (0-100) or probabilities (0-1)
|
|
470
|
-
* @returns Pure data structure with support and complementary cumulative probabilities
|
|
471
|
-
*
|
|
472
|
-
* @example
|
|
473
|
-
* query.toCCDFSeries()
|
|
474
|
-
* // → {support: [0, 6, 12], data: [100, 94.8, 81.7]}
|
|
475
|
-
*/
|
|
476
|
-
toCCDFSeries(asPercentages?: boolean): {
|
|
477
|
-
support: number[];
|
|
478
|
-
data: number[];
|
|
479
|
-
};
|
|
480
|
-
/** Probability of doing strictly more than threshold damage (default >0). */
|
|
481
|
-
probDamageGreaterThan(threshold?: number): number;
|
|
482
|
-
/** All outcome keys actually present (typed & ordered if you pass an order). */
|
|
483
|
-
outcomeKeys(order?: OutcomeType[]): OutcomeType[];
|
|
484
|
-
/** Total probability per outcome across the PMF. */
|
|
485
|
-
outcomeTotals(outcomes?: OutcomeType[]): Map<OutcomeType, number>;
|
|
486
|
-
/** Conditional damage range per outcome (min/avg/max of X | outcome). */
|
|
487
|
-
outcomeDamageRanges(outcomes?: OutcomeType[]): Map<OutcomeType, {
|
|
488
|
-
min: number;
|
|
489
|
-
avg: number;
|
|
490
|
-
max: number;
|
|
491
|
-
}>;
|
|
492
|
-
/**
|
|
493
|
-
* Snapshot of the distribution in the exact shape the UI consumes.
|
|
494
|
-
* - outcome probabilities are "at least one" (and equal to "all" for a single PMF)
|
|
495
|
-
* - damageRange is conditional on the outcome occurring
|
|
496
|
-
*/
|
|
497
|
-
snapshot(order?: readonly OutcomeType[]): Snapshot;
|
|
498
|
-
/**
|
|
499
|
-
* PMF Transformation Methods
|
|
500
|
-
*
|
|
501
|
-
* These methods provide a fluent API for transforming dice queries by wrapping
|
|
502
|
-
* the underlying PMF transformation methods. All operations work on the combined
|
|
503
|
-
* PMF and return new DiceQuery instances.
|
|
504
|
-
*/
|
|
505
|
-
/**
|
|
506
|
-
* Returns a new DiceQuery with normalized probabilities (ensuring they sum to 1.0).
|
|
507
|
-
*
|
|
508
|
-
* @returns New DiceQuery with normalized combined PMF
|
|
509
|
-
*/
|
|
510
|
-
normalize(): DiceQuery;
|
|
511
|
-
/**
|
|
512
|
-
* Returns a new DiceQuery with low-probability outcomes removed.
|
|
513
|
-
*
|
|
514
|
-
* @param eps Minimum probability threshold (defaults to PMF epsilon)
|
|
515
|
-
* @param keepFinalBin Whether to keep the highest damage bin regardless of probability
|
|
516
|
-
* @returns New DiceQuery with compacted combined PMF
|
|
517
|
-
*/
|
|
518
|
-
compact(eps?: number, keepFinalBin?: boolean): DiceQuery;
|
|
519
|
-
/**
|
|
520
|
-
* Returns a new DiceQuery with an additional scaled branch added.
|
|
521
|
-
* Useful for conditional outcomes like "30% chance of opportunity attack".
|
|
522
|
-
*
|
|
523
|
-
* @param branch DiceQuery to add as a scaled branch
|
|
524
|
-
* @param probability Probability of the branch occurring (0-1)
|
|
525
|
-
* @returns New DiceQuery combining this query with the scaled branch
|
|
526
|
-
*
|
|
527
|
-
* @example
|
|
528
|
-
* const baseAttack = parse("(d20 + 5 AC 15) * (2d6 + 3)");
|
|
529
|
-
* const opportunityAttack = parse("(d20 + 5 AC 15) * (1d8 + 3)");
|
|
530
|
-
* const withOpportunity = baseAttack.addScaled(opportunityAttack, 0.3);
|
|
531
|
-
*/
|
|
532
|
-
addScaled(branch: DiceQuery, probability: number): DiceQuery;
|
|
533
|
-
/**
|
|
534
|
-
* Returns a new DiceQuery with all probabilities scaled by a factor.
|
|
535
|
-
* Used for conditional scenarios where the entire outcome has reduced probability.
|
|
536
|
-
*
|
|
537
|
-
* @param factor Scaling factor for probabilities
|
|
538
|
-
* @returns New DiceQuery with scaled probabilities
|
|
539
|
-
*
|
|
540
|
-
* @example
|
|
541
|
-
* const fullAttack = parse("(d20 + 5 AC 15) * (2d6 + 3)");
|
|
542
|
-
* const conditionalAttack = fullAttack.scaleMass(0.3); // 30% chance scenario
|
|
543
|
-
*/
|
|
544
|
-
scaleMass(factor: number): DiceQuery;
|
|
545
|
-
totalMass(): number;
|
|
546
|
-
/**
|
|
547
|
-
* Returns a new DiceQuery with damage values transformed by a function.
|
|
548
|
-
* Useful for applying modifiers, resistances, or other damage transformations.
|
|
549
|
-
*
|
|
550
|
-
* @param damageTransformFunction Function to transform each damage value
|
|
551
|
-
* @returns New DiceQuery with transformed damage values
|
|
552
|
-
*
|
|
553
|
-
* @example
|
|
554
|
-
* const baseAttack = parse("2d6 + 3");
|
|
555
|
-
* const withResistance = baseAttack.mapDamage(dmg => Math.floor(dmg / 2)); // Half damage
|
|
556
|
-
* const withBonus = baseAttack.mapDamage(dmg => dmg + 5); // +5 damage
|
|
557
|
-
*/
|
|
558
|
-
mapDamage(damageTransformFunction: (damageValue: number) => number): DiceQuery;
|
|
559
|
-
/**
|
|
560
|
-
* Returns a new DiceQuery with damage values scaled by a factor.
|
|
561
|
-
* Convenient wrapper around mapDamage for multiplicative scaling.
|
|
562
|
-
*
|
|
563
|
-
* @param factor Scaling factor for damage values
|
|
564
|
-
* @param rounding Rounding method: "floor" (default), "round", or "ceil"
|
|
565
|
-
* @returns New DiceQuery with scaled damage values
|
|
566
|
-
*
|
|
567
|
-
* @example
|
|
568
|
-
* const baseAttack = parse("2d6 + 3");
|
|
569
|
-
* const doubled = baseAttack.scaleDamage(2); // Double damage
|
|
570
|
-
* const halfDamage = baseAttack.scaleDamage(0.5, "round"); // Half damage, rounded
|
|
571
|
-
*/
|
|
572
|
-
scaleDamage(factor: number, rounding?: "floor" | "round" | "ceil"): DiceQuery;
|
|
573
|
-
/**
|
|
574
|
-
* Returns a new DiceQuery combining this query with another via convolution.
|
|
575
|
-
* Equivalent to rolling both queries independently and adding results.
|
|
576
|
-
* It is important to use this rather than combing()ing the PMFs directly!
|
|
577
|
-
* This method maintains the provenance of the PMFs which is needed for damage attribution.
|
|
578
|
-
* Combining the .combined PMFs directly is still valid for DPR calculations but
|
|
579
|
-
* is not statistically sound for queries.
|
|
580
|
-
*
|
|
581
|
-
* @param other DiceQuery to combine with
|
|
582
|
-
* @param eps Optional epsilon for precision control
|
|
583
|
-
* @returns New DiceQuery representing the combined outcome
|
|
584
|
-
*
|
|
585
|
-
* @example
|
|
586
|
-
* const mainAttack = parse("(d20 + 5 AC 15) * (2d6 + 3)");
|
|
587
|
-
* const bonusAttack = parse("(d20 + 3 AC 15) * (1d6 + 1)");
|
|
588
|
-
* const bothAttacks = mainAttack.convolve(bonusAttack);
|
|
589
|
-
*/
|
|
590
|
-
convolve(other: DiceQuery): DiceQuery;
|
|
591
|
-
/**
|
|
592
|
-
* First-success split over an ordered list of DISTINCT single-swing PMFs.
|
|
593
|
-
* Each PMF may have different success/subset probabilities (from labels).
|
|
594
|
-
*
|
|
595
|
-
* successOutcome: e.g., ["success"] or ["hit", "crit"]
|
|
596
|
-
* subsetOutcome: e.g., ["subset"] or ["crit"] where subset ⊆ success
|
|
597
|
-
*
|
|
598
|
-
* Returns tuple: [pFirstNonSubset, pFirstSubset, pAnySuccess, pNone]
|
|
599
|
-
*/
|
|
600
|
-
firstSuccessSplit(successOutcome: string | string[], subsetOutcome: string | string[], eps?: number): readonly [pSuccess: number, pSubset: number, pAny: number, pNone: number];
|
|
601
|
-
}
|
|
602
|
-
type OutcomeSnapshot = {
|
|
603
|
-
atLeastOneProbability: number;
|
|
604
|
-
allProbability: number;
|
|
605
|
-
damageRange: {
|
|
606
|
-
min: number;
|
|
607
|
-
avg: number;
|
|
608
|
-
max: number;
|
|
609
|
-
};
|
|
610
|
-
};
|
|
611
|
-
type Snapshot = {
|
|
612
|
-
averageDPR: number;
|
|
613
|
-
damageChance: number;
|
|
614
|
-
percentiles: {
|
|
615
|
-
p25: number;
|
|
616
|
-
p50: number;
|
|
617
|
-
p75: number;
|
|
618
|
-
};
|
|
619
|
-
outcomes: Map<OutcomeType, OutcomeSnapshot>;
|
|
620
|
-
};
|
|
621
|
-
|
|
622
|
-
declare const pmfCache: LRUCache<string, PMF>;
|
|
623
|
-
/**
|
|
624
|
-
* Probability Mass Function for discrete damage distributions.
|
|
625
|
-
*/
|
|
626
|
-
declare class PMF {
|
|
627
|
-
readonly map: Map<number, Bin>;
|
|
628
|
-
readonly epsilon: number;
|
|
629
|
-
readonly normalized: boolean;
|
|
630
|
-
readonly identifier: string;
|
|
631
|
-
private _preservedProvenance;
|
|
632
|
-
private static __anonIdCounter;
|
|
633
|
-
private _support?;
|
|
634
|
-
private _min?;
|
|
635
|
-
private _max?;
|
|
636
|
-
private _totalMass?;
|
|
637
|
-
private _mean?;
|
|
638
|
-
private _variance?;
|
|
639
|
-
private _stdev?;
|
|
640
|
-
constructor(map?: Map<number, Bin>, epsilon?: number, normalized?: boolean, identifier?: string, _preservedProvenance?: boolean);
|
|
641
|
-
static empty(epsilon?: number, identifier?: string): PMF;
|
|
642
|
-
static zero(epsilon?: number): PMF;
|
|
643
|
-
static delta(value: number, epsilon?: number): PMF;
|
|
644
|
-
static emptyMass(): PMF;
|
|
645
|
-
[Symbol.iterator](): IterableIterator<[number, Bin]>;
|
|
646
|
-
static clearCache(): void;
|
|
647
|
-
/**
|
|
648
|
-
* Creates a conditional PMF from two branches (success and failure) and a probability.
|
|
649
|
-
* This is the core logic for modeling any probabilistic event where there are two
|
|
650
|
-
* distinct outcomes.
|
|
651
|
-
*/
|
|
652
|
-
static branch(successPMF: PMF, failurePMF: PMF, successProbability: number): PMF;
|
|
653
|
-
/**
|
|
654
|
-
* withProbability()
|
|
655
|
-
*
|
|
656
|
-
* A convenience wrapper around branch() for the common case where the "failure" branch is always zero().
|
|
657
|
-
*
|
|
658
|
-
* Think of this as a shortcut for:
|
|
659
|
-
* pmf.gate(p, PMF.zero())
|
|
660
|
-
*
|
|
661
|
-
* Use this to model a *single* Bernoulli event — an outcome that either happens or doesn't,
|
|
662
|
-
* like an opportunity attack that occurs with probability p, or a single attack that either hits or misses.
|
|
663
|
-
*
|
|
664
|
-
* This is **not** for combining multiple independent attacks or mutually exclusive multi-outcome scenarios.
|
|
665
|
-
* - For multiple independent swings, use DiceQuery with separate PMFs for each attack.
|
|
666
|
-
* - For modeling "first success" logic across multiple attacks (like Sneak Attack or Smite)
|
|
667
|
-
* use query.firstSuccessSplit() to get the exact probabilities.
|
|
668
|
-
* - For scenarios with several mutually exclusive outcomes (like crit vs hit vs none), use PMF.exclusive().
|
|
669
|
-
*
|
|
670
|
-
*/
|
|
671
|
-
static withProbability(successPMF: PMF, probability: number): PMF;
|
|
672
|
-
/**
|
|
673
|
-
* gate()
|
|
674
|
-
*
|
|
675
|
-
* A conditional wrapper around branch() that applies this PMF with probability `p`,
|
|
676
|
-
* and applies a provided fallback PMF otherwise.
|
|
677
|
-
*
|
|
678
|
-
* This is useful for modeling a binary choice between two outcomes:
|
|
679
|
-
* - The "success" outcome (this PMF) happens with probability `p`.
|
|
680
|
-
* - The "failure" outcome (fallback PMF) happens with probability `1 - p`.
|
|
681
|
-
*
|
|
682
|
-
* Examples:
|
|
683
|
-
* - 25% chance to include an opportunity attack, otherwise nothing:
|
|
684
|
-
* attackPMF.gate(0.25, PMF.zero())
|
|
685
|
-
*
|
|
686
|
-
* - 50% chance to deal fireball damage, otherwise cone of cold damage:
|
|
687
|
-
* fireballPMF.gate(0.5, coneOfColdPMF)
|
|
688
|
-
*
|
|
689
|
-
* Relationship to other helpers:
|
|
690
|
-
* - **withProbability()** is a shortcut for the common case where the fallback is `PMF.zero()`.
|
|
691
|
-
* - **exclusive()** is for three or more mutually exclusive outcomes (e.g., crit vs hit vs none).
|
|
692
|
-
*
|
|
693
|
-
* @param p Probability of applying this PMF (between 0 and 1).
|
|
694
|
-
* @param fallback PMF to apply when this PMF is *not* selected.
|
|
695
|
-
* @returns A new PMF representing the weighted mixture of this PMF and the fallback.
|
|
696
|
-
*/
|
|
697
|
-
gate(p: number, zero: PMF): PMF;
|
|
698
|
-
/**
|
|
699
|
-
* PMF.exclusive()
|
|
700
|
-
*
|
|
701
|
-
* Builds a single PMF from a set of mutually exclusive weighted outcomes.
|
|
702
|
-
* Exactly one of the provided options will occur.
|
|
703
|
-
*
|
|
704
|
-
* Each option has:
|
|
705
|
-
* - A PMF representing its outcome (e.g., damage dice).
|
|
706
|
-
* - A weight representing its probability of being selected.
|
|
707
|
-
*
|
|
708
|
-
* This is useful for modeling situations like:
|
|
709
|
-
* - Sneak Attack: 6d6 if first hit is a crit, 3d6 if first hit is non-crit, 0 otherwise.
|
|
710
|
-
* - Multiple exclusive spells: Fireball vs Cone of Cold vs nothing.
|
|
711
|
-
*
|
|
712
|
-
* Notes:
|
|
713
|
-
* - If the total weight is less than 1, a zero PMF will automatically be added to
|
|
714
|
-
* make up the remaining probability.
|
|
715
|
-
* - Throws an error if the total weight is greater than 1 (invalid probability sum).
|
|
716
|
-
*
|
|
717
|
-
* @param options Array of `{ pmf, weight }` objects, each representing an outcome and its probability.
|
|
718
|
-
* @param label Optional name for debugging or charting.
|
|
719
|
-
* @param eps Optional tolerance for floating point rounding
|
|
720
|
-
* @returns A single PMF representing the exclusive mixture of all options.
|
|
721
|
-
*/
|
|
722
|
-
static exclusive(options: Array<{
|
|
723
|
-
pmf: PMF;
|
|
724
|
-
weight: number;
|
|
725
|
-
} | [PMF, number]>, eps?: number): PMF;
|
|
726
|
-
/**
|
|
727
|
-
* General-purpose N-way mixture.
|
|
728
|
-
* weights: Array of [weight, PMF].
|
|
729
|
-
*
|
|
730
|
-
* Example: PMF.mixN([
|
|
731
|
-
* [pMiss, zero],
|
|
732
|
-
* [pHit, hitPMF],
|
|
733
|
-
* [pCrit, critPMF],
|
|
734
|
-
* ]);
|
|
735
|
-
*/
|
|
736
|
-
static mixN(weights: [number, PMF][], eps?: number): PMF;
|
|
737
|
-
private setPreservedProvenance;
|
|
738
|
-
preservedProvenance(): boolean;
|
|
739
|
-
private getPowerCacheKey;
|
|
740
|
-
/**
|
|
741
|
-
* Efficiently computes this PMF convolved with itself `n` times.
|
|
742
|
-
* Uses exponentiation by squaring to reduce total convolutions.
|
|
743
|
-
* n must be a positive integer.
|
|
744
|
-
* *
|
|
745
|
-
* * NOTE: This folds multiple independent attacks into a single PMF.
|
|
746
|
-
* As a result, The power() method causes a loss of data provenance.
|
|
747
|
-
* This is ONLY SAFE if you are trying to calculate masses.
|
|
748
|
-
* If you want to query any atLeast probabilities, you should use the DiceQuery class instead without power().
|
|
749
|
-
*/
|
|
750
|
-
power(n: number, eps?: number): PMF;
|
|
751
|
-
replicate(n: number): PMF[];
|
|
752
|
-
mass(): number;
|
|
753
|
-
outcomeMass(outcome: string): number;
|
|
754
|
-
faceTotal(): number;
|
|
755
|
-
normalize(): PMF;
|
|
756
|
-
/**
|
|
757
|
-
* Returns a copy with negligible probabilities removed (p < eps).
|
|
758
|
-
* If keepFinalBin is true, the bin with the largest key is always kept,
|
|
759
|
-
* even if its probability is below eps. count/attr submaps are still cleaned.
|
|
760
|
-
*/
|
|
761
|
-
compact(eps?: number, keepFinalBin?: boolean): PMF;
|
|
762
|
-
support(): number[];
|
|
763
|
-
min(): number;
|
|
764
|
-
max(): number;
|
|
765
|
-
/**
|
|
766
|
-
* Returns the expected (mean) damage value.
|
|
767
|
-
* Cached for performance since this requires iterating through all bins.
|
|
768
|
-
*/
|
|
769
|
-
mean(): number;
|
|
770
|
-
/**
|
|
771
|
-
* Returns the variance of the damage distribution.
|
|
772
|
-
* Cached for performance since this requires mean calculation plus iteration.
|
|
773
|
-
*/
|
|
774
|
-
variance(): number;
|
|
775
|
-
/**
|
|
776
|
-
* Returns the standard deviation of the damage distribution.
|
|
777
|
-
*/
|
|
778
|
-
stdev(): number;
|
|
779
|
-
private static mergeInto;
|
|
780
|
-
add(other: PMF): PMF;
|
|
781
|
-
/**
|
|
782
|
-
* Returns a new PMF with a scaled branch added to this one.
|
|
783
|
-
* The branch PMF is scaled by the given probability before merging
|
|
784
|
-
* This will be very useful for conditional effects and for being
|
|
785
|
-
* able to model "I can probably have this opportunity attack 40% of rounds"
|
|
786
|
-
* Example: `pmf.addScaled(critBranch, 0.05)` → PMF including 5% crit outcomes
|
|
787
|
-
*/
|
|
788
|
-
addScaled(branch: PMF, probability: number): PMF;
|
|
789
|
-
scaleMass(factor: number): PMF;
|
|
790
|
-
mapDamage(damageTransformFunction: (damageValue: number) => number): PMF;
|
|
791
|
-
scaleDamage(factor: number, rounding?: "floor" | "round" | "ceil"): PMF;
|
|
792
|
-
private getPMFCombineCacheKey;
|
|
793
|
-
convolve(other: PMF, eps?: number, raw?: boolean): PMF;
|
|
794
|
-
combineRaw(other: PMF, eps?: number): PMF;
|
|
795
|
-
private static reduceConvolveLeft;
|
|
796
|
-
/**
|
|
797
|
-
* Convolves multiple PMFs using linear convolution with automatic caching.
|
|
798
|
-
* Uses a left-to-right accumulation approach for maximum cache reuse.
|
|
799
|
-
* Each convolve() call automatically uses the convolution cache for performance.
|
|
800
|
-
*
|
|
801
|
-
* This linear approach provides better cache hits than pairwise because:
|
|
802
|
-
* - Intermediate results are more predictable and stable
|
|
803
|
-
* - Similar PMF lists share common prefixes (A+B, (A+B)+C, etc.)
|
|
804
|
-
* - Order-independent cache keys work better with consistent build patterns
|
|
805
|
-
*/
|
|
806
|
-
static convolveMany(pmfList: PMF[], eps?: number): PMF;
|
|
807
|
-
toJSON(): string;
|
|
808
|
-
static fromJSON(jsonData: {
|
|
809
|
-
bins: Array<[number, Bin]>;
|
|
810
|
-
normalized?: boolean;
|
|
811
|
-
identifier?: string;
|
|
812
|
-
}): PMF;
|
|
813
|
-
/**
|
|
814
|
-
* Relative pruning with optional top-K floor.
|
|
815
|
-
* Keeps bins with p >= epsRel * peak, always keeps min and max damage,
|
|
816
|
-
* optionally guarantees at least `minBins` survivors by adding top-K.
|
|
817
|
-
* Returns a new, non-normalized PMF.
|
|
818
|
-
*/
|
|
819
|
-
prune(epsRel: number, minBins?: number): PMF;
|
|
820
|
-
/** NEW - REVIEW IF THESE ARE USEFUL OR DUPLCIATIVE? */
|
|
821
|
-
/** Probability mass at exactly x. */
|
|
822
|
-
pAt(x: number): number;
|
|
823
|
-
/** Dense integer support from min..max (inclusive).
|
|
824
|
-
* Useful for showing empty bars in charts.
|
|
825
|
-
*/
|
|
826
|
-
denseSupport(): number[];
|
|
827
|
-
/** CDF at x: P(X ≤ x). */
|
|
828
|
-
cdfAt(x: number): number;
|
|
829
|
-
/** Quantile / inverse CDF for p in [0,1]. Returns smallest x with CDF ≥ p. */
|
|
830
|
-
quantile(p: number): number;
|
|
831
|
-
/** Get outcome probability at specific damage value. */
|
|
832
|
-
outcomeAt(damage: number, outcome: string): number;
|
|
833
|
-
/** Get all outcome types present in this PMF. */
|
|
834
|
-
outcomes(): string[];
|
|
835
|
-
/** Get total probability of an outcome across all damage values. */
|
|
836
|
-
outcomeProbability(outcome: string): number;
|
|
837
|
-
/** Get damage attribution for an outcome at specific damage value. */
|
|
838
|
-
outcomeAttributionAt(damage: number, outcome: string): number;
|
|
839
|
-
/** Get all outcome data at specific damage value. */
|
|
840
|
-
binAt(damage: number): {
|
|
841
|
-
p: number;
|
|
842
|
-
count: Record<string, number>;
|
|
843
|
-
attr?: Record<string, number>;
|
|
844
|
-
} | null;
|
|
845
|
-
/** Check if outcome exists in this PMF. */
|
|
846
|
-
hasOutcome(outcome: string): boolean;
|
|
847
|
-
tailProbGE(t: number): number;
|
|
848
|
-
tailProbGT(t: number): number;
|
|
849
|
-
/**
|
|
850
|
-
* Returns a new PMF containing only bins where the specified outcome has non-zero probability.
|
|
851
|
-
* This creates a marginal distribution for the given outcome type, with probabilities
|
|
852
|
-
* scaled to represent the unconditional mass attributable to that outcome.
|
|
853
|
-
*/
|
|
854
|
-
filterOutcome(outcome: string): PMF;
|
|
855
|
-
/**
|
|
856
|
-
* Calculates probabilities for first-success outcomes across n independent attempts.
|
|
857
|
-
*
|
|
858
|
-
* @param pSuccess - Total probability of any success on a single attempt.
|
|
859
|
-
* @param pSpecial - Probability of a specific subset of successes (e.g., critical success).
|
|
860
|
-
* @param n - Number of independent attempts.
|
|
861
|
-
*
|
|
862
|
-
* Returns:
|
|
863
|
-
* - pSpecificSuccess: Probability that the first success was of the "special" type
|
|
864
|
-
* - pGeneralSuccess: Probability that the first success was of the non-special type
|
|
865
|
-
* - pNone: Probability that no successes occurred
|
|
866
|
-
* - pAny: Probability that at least one success occurred
|
|
867
|
-
*/
|
|
868
|
-
static firstSuccessWeights(pSuccess: number, pSpecial: number, n: number): {
|
|
869
|
-
pSpecificSuccess: number;
|
|
870
|
-
pGeneralSuccess: number;
|
|
871
|
-
pNone: number;
|
|
872
|
-
pAny: number;
|
|
873
|
-
};
|
|
874
|
-
mapValues(f: (v: number) => number, eps?: number, opts?: {
|
|
875
|
-
rounding?: Rounding;
|
|
876
|
-
preserveCounts?: boolean;
|
|
877
|
-
}): PMF;
|
|
878
|
-
static fromMap(m: Map<number, number>, eps?: number, { requireIntegerValues }?: {
|
|
879
|
-
requireIntegerValues?: boolean;
|
|
880
|
-
}): PMF;
|
|
881
|
-
query(): DiceQuery;
|
|
882
|
-
}
|
|
1
|
+
import { P as PMF } from './pmf-DIegvlyA.js';
|
|
2
|
+
export { B as Bin, D as DamageDistribution, b as DiceQuery, E as EPS, L as LRUCache, O as OutcomeLabelMap, c as OutcomeSnapshot, a as OutcomeType, R as Rounding, S as Snapshot, p as pmfCache } from './pmf-DIegvlyA.js';
|
|
883
3
|
|
|
884
4
|
/** Enable or disable the internal parse cache. */
|
|
885
5
|
declare function setCachingEnabled(enabled: boolean): void;
|
|
@@ -930,4 +50,4 @@ declare class Mixture<L extends string = string> {
|
|
|
930
50
|
static mix<L extends string = string>(items: Array<[label: L, pmf: PMF, weight: number]>, eps?: number): PMF;
|
|
931
51
|
}
|
|
932
52
|
|
|
933
|
-
export {
|
|
53
|
+
export { Mixture, PMF, clearParserCache, getCachingEnabled, parse, setCachingEnabled };
|