@yipe/dice 0.2.23 → 0.4.0
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/.claude/worktrees/amazing-matsumoto-27220c/LICENSE +21 -0
- package/.claude/worktrees/amazing-matsumoto-27220c/README.md +518 -0
- package/.claude/worktrees/vibrant-lovelace-0cc9e7/LICENSE +21 -0
- package/.claude/worktrees/vibrant-lovelace-0cc9e7/README.md +518 -0
- package/.claude/worktrees/wizardly-mclean-e375de/LICENSE +21 -0
- package/.claude/worktrees/wizardly-mclean-e375de/README.md +518 -0
- package/CHANGELOG.md +224 -0
- package/README.md +17 -0
- package/dist/builder/index.cjs +555 -295
- package/dist/builder/index.cjs.map +1 -1
- package/dist/builder/index.d.cts +9 -10
- package/dist/builder/index.d.ts +9 -10
- package/dist/builder/index.js +555 -295
- package/dist/builder/index.js.map +1 -1
- package/dist/index.cjs +619 -256
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -3
- package/dist/index.d.ts +61 -3
- package/dist/index.js +613 -257
- package/dist/index.js.map +1 -1
- package/dist/{pmf-BC1poIqF.d.cts → pmf-D5VRghZI.d.cts} +204 -10
- package/dist/{pmf-BC1poIqF.d.ts → pmf-D5VRghZI.d.ts} +204 -10
- package/package.json +12 -14
|
@@ -36,6 +36,41 @@ type DamageDistribution = Record<number, number>;
|
|
|
36
36
|
/** Canonical outcome labels supported by the query helpers. */
|
|
37
37
|
type OutcomeType = "crit" | "hit" | "missNone" | "missDamage" | "saveHalf" | "saveFail" | "pc";
|
|
38
38
|
type Rounding = "none" | "floor" | "round" | "ceil";
|
|
39
|
+
/** How a d20 attack roll resolves: single die, keep-highest of 2/3, or keep-lowest of 2. */
|
|
40
|
+
type RollType = "flat" | "advantage" | "disadvantage" | "elven accuracy";
|
|
41
|
+
/**
|
|
42
|
+
* P(critical hit) for the given crit window and d20 {@link RollType}.
|
|
43
|
+
*
|
|
44
|
+
* `critRange` is the number of top faces that crit (1 for a natural 20, 2 for
|
|
45
|
+
* 19–20, …), so a single die crits with probability `critRange / 20`. Advantage
|
|
46
|
+
* rolls two d20s / elven accuracy three, keeping the best; disadvantage keeps
|
|
47
|
+
* the worst of two.
|
|
48
|
+
*/
|
|
49
|
+
declare function critProbability(critRange: number, rollType?: RollType): number;
|
|
50
|
+
/**
|
|
51
|
+
* The canonical "clean miss" outcome — a point of zero damage with no rider.
|
|
52
|
+
* This is the {@link OutcomeType} that attribution charts and outcome stats key
|
|
53
|
+
* on, and is distinct from the builder's attack-resolution `miss` weight label.
|
|
54
|
+
*/
|
|
55
|
+
declare const MISS_NONE_OUTCOME: OutcomeType;
|
|
56
|
+
/**
|
|
57
|
+
* All outcome types in canonical severity order — clean miss → crit. This is
|
|
58
|
+
* also the natural stacking order for attribution charts (least- to
|
|
59
|
+
* most-impactful, bottom → top). Enumerates every {@link OutcomeType} exactly
|
|
60
|
+
* once; use it instead of hand-maintained per-consumer outcome tables.
|
|
61
|
+
*/
|
|
62
|
+
declare const ALL_OUTCOME_TYPES: OutcomeType[];
|
|
63
|
+
/**
|
|
64
|
+
* Outcome types in display order for stats / breakdown rows — most prominent
|
|
65
|
+
* first (crit, hit, …) down to the clean miss.
|
|
66
|
+
*/
|
|
67
|
+
declare const OUTCOME_DISPLAY_ORDER: OutcomeType[];
|
|
68
|
+
/**
|
|
69
|
+
* Sort outcome labels by a canonical order (defaults to {@link ALL_OUTCOME_TYPES}).
|
|
70
|
+
* Labels not present in `order` sort after known ones, alphabetically — so
|
|
71
|
+
* ad-hoc/test labels outside the {@link OutcomeType} union stay stable.
|
|
72
|
+
*/
|
|
73
|
+
declare function sortOutcomes<T extends string>(outcomes: Iterable<T>, order?: readonly string[]): T[];
|
|
39
74
|
declare const onAnyHit: OutcomeType[];
|
|
40
75
|
declare const onCritOnly: OutcomeType[];
|
|
41
76
|
declare const onHitOnly: OutcomeType[];
|
|
@@ -57,9 +92,20 @@ declare const onPotentCantripOnly: OutcomeType[];
|
|
|
57
92
|
*/
|
|
58
93
|
declare class DiceQuery {
|
|
59
94
|
readonly singles: PMF[];
|
|
60
|
-
readonly
|
|
95
|
+
private readonly _eps;
|
|
96
|
+
private readonly _combinedProvided;
|
|
97
|
+
private _combined?;
|
|
61
98
|
private _combinedWithAttr?;
|
|
62
99
|
constructor(singles: PMF | PMF[], combined?: PMF, eps?: number);
|
|
100
|
+
/**
|
|
101
|
+
* The combined damage distribution of all single PMFs (their convolution),
|
|
102
|
+
* normalized to total probability 1.
|
|
103
|
+
*
|
|
104
|
+
* Computed lazily on first access and cached. Queries that only need
|
|
105
|
+
* additive statistics — {@link DiceQuery.mean}, {@link DiceQuery.variance},
|
|
106
|
+
* {@link DiceQuery.stddev} — never trigger this convolution.
|
|
107
|
+
*/
|
|
108
|
+
get combined(): PMF;
|
|
63
109
|
private static readonly DEFAULT_OUTCOMES;
|
|
64
110
|
/**
|
|
65
111
|
* Returns a new PMF with damage attribution metadata populated.
|
|
@@ -81,6 +127,21 @@ declare class DiceQuery {
|
|
|
81
127
|
* // Now pmf can be used with toDamageAttributionChartSeries()
|
|
82
128
|
*/
|
|
83
129
|
combinedWithAttribution(): PMF;
|
|
130
|
+
/**
|
|
131
|
+
* Per-label `damage value → probability mass` series for the combined,
|
|
132
|
+
* attribution-carrying distribution — the provenance core of the stacked
|
|
133
|
+
* damage-attribution chart. Convenience for
|
|
134
|
+
* `combinedWithAttribution().attributionByValue()`; see
|
|
135
|
+
* {@link PMF.attributionByValue}.
|
|
136
|
+
*/
|
|
137
|
+
attributionByValue(): Map<string, Map<number, number>>;
|
|
138
|
+
/**
|
|
139
|
+
* How many of the independent single PMFs can produce the given outcome
|
|
140
|
+
* label. Useful for "all of them succeeded" style probabilities where the
|
|
141
|
+
* exponent is the number of contributing attacks (see
|
|
142
|
+
* {@link DiceQuery.probExactlyK}).
|
|
143
|
+
*/
|
|
144
|
+
countSinglesWith(label: string): number;
|
|
84
145
|
/**
|
|
85
146
|
* Returns the expected damage across all possible outcomes.
|
|
86
147
|
*
|
|
@@ -104,6 +165,8 @@ declare class DiceQuery {
|
|
|
104
165
|
* Used to determine how consistent the damage is.
|
|
105
166
|
*/
|
|
106
167
|
stddev(): number;
|
|
168
|
+
/** Alias of {@link DiceQuery.stddev}, matching {@link PMF.stdev}. */
|
|
169
|
+
stdev(): number;
|
|
107
170
|
/**
|
|
108
171
|
* Returns the Cumulative Distribution Function.
|
|
109
172
|
*/
|
|
@@ -148,6 +211,18 @@ declare class DiceQuery {
|
|
|
148
211
|
*/
|
|
149
212
|
max(): number;
|
|
150
213
|
private singleProb;
|
|
214
|
+
/**
|
|
215
|
+
* Full count distribution [P(0), P(1), …, P(n)] for "an attack succeeds if it
|
|
216
|
+
* carries ANY of `labels`", over the n independent singles.
|
|
217
|
+
*
|
|
218
|
+
* Each single's per-event success probability is the Poisson-binomial
|
|
219
|
+
* marginal P(≥1 of labels) from {@link probabilityOf} (i.e. probAtLeastOne),
|
|
220
|
+
* computed exactly once. The binomial DP then runs once to produce the whole
|
|
221
|
+
* distribution, so the array-label paths of probExactlyK / probAtLeastK /
|
|
222
|
+
* probAtMostK can slice or sum from it instead of rebuilding a DiceQuery and
|
|
223
|
+
* re-running the DP per requested k.
|
|
224
|
+
*/
|
|
225
|
+
private countDistribution;
|
|
151
226
|
probAtLeastK(labels: OutcomeType | OutcomeType[], k: number): number;
|
|
152
227
|
/**
|
|
153
228
|
* Returns the probability that at least one attack has the specified outcome(s).
|
|
@@ -192,7 +267,7 @@ declare class DiceQuery {
|
|
|
192
267
|
* Array examples:
|
|
193
268
|
* - probExactlyK(['hit', 'crit'], 2) = probability exactly 2 attacks succeed
|
|
194
269
|
* - probExactlyK(['hit', 'crit'], 1) = probability exactly 1 attack succeeds
|
|
195
|
-
* - probExactlyK(['
|
|
270
|
+
* - probExactlyK(['missDamage', 'missNone'], 0) = probability no attacks miss
|
|
196
271
|
*
|
|
197
272
|
* Use cases:
|
|
198
273
|
* - "What's the chance exactly one of my attacks hits?"
|
|
@@ -209,7 +284,7 @@ declare class DiceQuery {
|
|
|
209
284
|
* Single label examples:
|
|
210
285
|
* - probAtMostK('hit', 1) = probability 0 or 1 attacks hit (at most 1)
|
|
211
286
|
* - probAtMostK('crit', 0) = probability no attacks crit
|
|
212
|
-
* - probAtMostK('
|
|
287
|
+
* - probAtMostK('missDamage', 2) = probability at most 2 attacks miss
|
|
213
288
|
*
|
|
214
289
|
* Array examples:
|
|
215
290
|
* - probAtMostK(['hit', 'crit'], 1) = probability at most 1 attack succeeds
|
|
@@ -253,7 +328,7 @@ declare class DiceQuery {
|
|
|
253
328
|
*
|
|
254
329
|
* Array examples:
|
|
255
330
|
* - damageStatsFrom(['hit', 'crit']) = damage range when at least one attack succeeds
|
|
256
|
-
* - damageStatsFrom(['
|
|
331
|
+
* - damageStatsFrom(['missDamage', 'missNone']) = damage range when at least one attack misses
|
|
257
332
|
*
|
|
258
333
|
* Tactical Use Cases:
|
|
259
334
|
* - "Given that I don't completely whiff (99% of turns), what damage should I expect?"
|
|
@@ -271,6 +346,12 @@ declare class DiceQuery {
|
|
|
271
346
|
* This includes mixed scenarios (2 hits + 1 crit, 3 hits + 1 miss, etc.) which
|
|
272
347
|
* occur far more frequently than pure scenarios. For pure scenarios, use combinedDamageStats.
|
|
273
348
|
*
|
|
349
|
+
* KNOWN LIMITATION (multi-attack, single label): the returned `count` is an
|
|
350
|
+
* EXPECTED COUNT (E[#label], so > 1 for N≥2 attacks, not a probability), and
|
|
351
|
+
* `avg` is the size-biased conditional mean E[dmg·#label]/E[#label] rather than
|
|
352
|
+
* E[dmg | the label occurs]. For a single attack both are the plain
|
|
353
|
+
* conditional figures. Use {@link probAtLeastOne} for the scenario probability.
|
|
354
|
+
*
|
|
274
355
|
* @example
|
|
275
356
|
* // High-level tactical planning
|
|
276
357
|
* const successStats = query.damageStatsFrom('hit')
|
|
@@ -335,7 +416,8 @@ declare class DiceQuery {
|
|
|
335
416
|
count: number;
|
|
336
417
|
};
|
|
337
418
|
/**
|
|
338
|
-
* Returns the probability that
|
|
419
|
+
* Returns the probability that at least one attack carries ANY of the
|
|
420
|
+
* specified labels (the marginal P(≥1) across the independent attacks).
|
|
339
421
|
*
|
|
340
422
|
* Examples:
|
|
341
423
|
* - `query.probabilityOf('hit')` → 0.88 (probability at least one hit occurs)
|
|
@@ -344,6 +426,12 @@ declare class DiceQuery {
|
|
|
344
426
|
* Use cases:
|
|
345
427
|
* - "What's the chance my resolution includes a success label?"
|
|
346
428
|
* - "How likely am I to get any hits or crits across all attacks?"
|
|
429
|
+
*
|
|
430
|
+
* Note: this must NOT be computed by summing `combined` bin probabilities. A
|
|
431
|
+
* single combined damage total is reachable by many outcome combinations and
|
|
432
|
+
* a bin can hold several labels at once, so summing `bin.p` over bins that
|
|
433
|
+
* contain a label over-counts. The correct marginal is the Poisson-binomial
|
|
434
|
+
* complement over the per-attack probabilities, i.e. {@link probAtLeastOne}.
|
|
347
435
|
*/
|
|
348
436
|
probabilityOf(labels: OutcomeType | OutcomeType[]): number;
|
|
349
437
|
/**
|
|
@@ -525,6 +613,16 @@ declare class DiceQuery {
|
|
|
525
613
|
* Snapshot of the distribution in the exact shape the UI consumes.
|
|
526
614
|
* - outcome probabilities are "at least one" (and equal to "all" for a single PMF)
|
|
527
615
|
* - damageRange is conditional on the outcome occurring
|
|
616
|
+
*
|
|
617
|
+
* The outcome probabilities use the correct Poisson-binomial marginals
|
|
618
|
+
* (`atLeastOneProbability` = P(≥1 attack has it), `allProbability` = P(all do)),
|
|
619
|
+
* so they are always valid probabilities in [0,1].
|
|
620
|
+
*
|
|
621
|
+
* KNOWN LIMITATION (multi-attack): `damageRange.avg` is still aggregated from
|
|
622
|
+
* the combined PMF's `count`, which the convolution accumulates as an EXPECTED
|
|
623
|
+
* COUNT, so for N≥2 attacks it is the size-biased mean E[dmg·#label]/E[#label]
|
|
624
|
+
* rather than a clean conditional expectation. It is correct for a single
|
|
625
|
+
* attack.
|
|
528
626
|
*/
|
|
529
627
|
snapshot(order?: readonly OutcomeType[]): Snapshot;
|
|
530
628
|
/**
|
|
@@ -629,7 +727,7 @@ declare class DiceQuery {
|
|
|
629
727
|
*
|
|
630
728
|
* Returns tuple: [pFirstNonSubset, pFirstSubset, pAnySuccess, pNone]
|
|
631
729
|
*/
|
|
632
|
-
firstSuccessSplit(successOutcome:
|
|
730
|
+
firstSuccessSplit(successOutcome: OutcomeType | OutcomeType[], subsetOutcome: OutcomeType | OutcomeType[], eps?: number): readonly [pSuccess: number, pSubset: number, pAny: number, pNone: number];
|
|
633
731
|
}
|
|
634
732
|
type OutcomeSnapshot = {
|
|
635
733
|
atLeastOneProbability: number;
|
|
@@ -669,10 +767,21 @@ declare class PMF {
|
|
|
669
767
|
private _mean?;
|
|
670
768
|
private _variance?;
|
|
671
769
|
private _stdev?;
|
|
770
|
+
private _fingerprint?;
|
|
672
771
|
constructor(map?: Map<number, Bin>, epsilon?: number, normalized?: boolean, identifier?: string, _preservedProvenance?: boolean);
|
|
673
772
|
static empty(epsilon?: number, identifier?: string): PMF;
|
|
674
773
|
static zero(epsilon?: number): PMF;
|
|
675
774
|
static delta(value: number, epsilon?: number): PMF;
|
|
775
|
+
/**
|
|
776
|
+
* Point mass at damage 0 tagged with the canonical `missNone` outcome.
|
|
777
|
+
*
|
|
778
|
+
* Differs from {@link PMF.zero}, which labels its zero bin `miss` — the
|
|
779
|
+
* builder's attack-resolution vocabulary. This uses the `missNone`
|
|
780
|
+
* {@link OutcomeType} that the attribution charts and outcome stats key on,
|
|
781
|
+
* so it is the correct "clean miss / no damage" delta for provenance-aware
|
|
782
|
+
* mixtures feeding those consumers.
|
|
783
|
+
*/
|
|
784
|
+
static missNone(epsilon?: number): PMF;
|
|
676
785
|
static emptyMass(): PMF;
|
|
677
786
|
[Symbol.iterator](): IterableIterator<[number, Bin]>;
|
|
678
787
|
static clearCache(): void;
|
|
@@ -726,7 +835,7 @@ declare class PMF {
|
|
|
726
835
|
* @param fallback PMF to apply when this PMF is *not* selected.
|
|
727
836
|
* @returns A new PMF representing the weighted mixture of this PMF and the fallback.
|
|
728
837
|
*/
|
|
729
|
-
gate(p: number,
|
|
838
|
+
gate(p: number, fallback: PMF): PMF;
|
|
730
839
|
/**
|
|
731
840
|
* PMF.exclusive()
|
|
732
841
|
*
|
|
@@ -773,6 +882,13 @@ declare class PMF {
|
|
|
773
882
|
*
|
|
774
883
|
* @returns New PMF with attr field populated in each bin
|
|
775
884
|
*/
|
|
885
|
+
/**
|
|
886
|
+
* Returns true if this PMF already carries damage attribution metadata.
|
|
887
|
+
*
|
|
888
|
+
* Only the first positive-damage bin is inspected (parser-generated PMFs
|
|
889
|
+
* populate `attr` uniformly), so this is O(1) in practice.
|
|
890
|
+
*/
|
|
891
|
+
hasAttribution(): boolean;
|
|
776
892
|
withAttribution(): PMF;
|
|
777
893
|
/**
|
|
778
894
|
* General-purpose N-way mixture.
|
|
@@ -827,6 +943,10 @@ declare class PMF {
|
|
|
827
943
|
* Returns the standard deviation of the damage distribution.
|
|
828
944
|
*/
|
|
829
945
|
stdev(): number;
|
|
946
|
+
/** Deep-copies a Bin, cloning its count and (optional) attr maps. */
|
|
947
|
+
private static cloneBin;
|
|
948
|
+
/** Returns a new Bin with p, count, and attr all multiplied by `factor`. */
|
|
949
|
+
private static scaleBin;
|
|
830
950
|
private static mergeInto;
|
|
831
951
|
add(other: PMF): PMF;
|
|
832
952
|
/**
|
|
@@ -837,10 +957,38 @@ declare class PMF {
|
|
|
837
957
|
* Example: `pmf.addScaled(critBranch, 0.05)` → PMF including 5% crit outcomes
|
|
838
958
|
*/
|
|
839
959
|
addScaled(branch: PMF, probability: number): PMF;
|
|
960
|
+
/**
|
|
961
|
+
* Redistributes probability mass to model an effect that only occurs with
|
|
962
|
+
* probability `frequency` — a conditional attack, an on-hit rider, or a
|
|
963
|
+
* sub-one AoE target fraction.
|
|
964
|
+
*
|
|
965
|
+
* Every hit outcome (damage > 0) is scaled by `frequency` — probability mass,
|
|
966
|
+
* per-label `count`, AND per-label `attr` — and the freed mass is moved into
|
|
967
|
+
* the miss bin at damage 0, tagged with the canonical `missNone` outcome.
|
|
968
|
+
* Total probability mass is preserved.
|
|
969
|
+
*
|
|
970
|
+
* Unlike a bare {@link scaleMass} or {@link mapDamage}, this keeps damage
|
|
971
|
+
* attribution (`attr`) intact, so a frequency-scaled PMF still renders
|
|
972
|
+
* correctly in the damage-attribution charts.
|
|
973
|
+
*
|
|
974
|
+
* `frequency >= 1` (or non-finite) returns this PMF unchanged; `frequency <= 0`
|
|
975
|
+
* collapses all mass into the miss bin. The miss outcome is assumed to be
|
|
976
|
+
* encoded at damage value 0.
|
|
977
|
+
*
|
|
978
|
+
* @param frequency Probability in [0, 1] that the effect occurs.
|
|
979
|
+
*/
|
|
980
|
+
applyHitFrequency(frequency: number): PMF;
|
|
840
981
|
scaleMass(factor: number): PMF;
|
|
841
982
|
mapDamage(damageTransformFunction: (damageValue: number) => number): PMF;
|
|
842
983
|
scaleDamage(factor: number, rounding?: "floor" | "round" | "ceil"): PMF;
|
|
843
984
|
private getPMFCombineCacheKey;
|
|
985
|
+
/**
|
|
986
|
+
* A small content fingerprint (mass + bin count + face sum) so convolution
|
|
987
|
+
* cache keys change if the underlying numbers do. Memoized because a PMF is
|
|
988
|
+
* immutable once constructed — this avoids re-summing every key on each
|
|
989
|
+
* convolve() call (including cache hits).
|
|
990
|
+
*/
|
|
991
|
+
fingerprint(): string;
|
|
844
992
|
convolve(other: PMF, eps?: number, raw?: boolean): PMF;
|
|
845
993
|
combineRaw(other: PMF, eps?: number): PMF;
|
|
846
994
|
private static reduceConvolveLeft;
|
|
@@ -855,7 +1003,20 @@ declare class PMF {
|
|
|
855
1003
|
* - Order-independent cache keys work better with consistent build patterns
|
|
856
1004
|
*/
|
|
857
1005
|
static convolveMany(pmfList: PMF[], eps?: number): PMF;
|
|
858
|
-
|
|
1006
|
+
/**
|
|
1007
|
+
* Returns a plain, JSON-serializable representation of this PMF.
|
|
1008
|
+
*
|
|
1009
|
+
* Follows the standard `toJSON` contract, so `JSON.stringify(pmf)` produces
|
|
1010
|
+
* the expected output (no double-encoding). Use {@link PMF.fromJSON} to
|
|
1011
|
+
* reconstruct, or {@link PMF.toJSONString} if you need the string directly.
|
|
1012
|
+
*/
|
|
1013
|
+
toJSON(): {
|
|
1014
|
+
bins: Array<[number, Bin]>;
|
|
1015
|
+
normalized: boolean;
|
|
1016
|
+
identifier: string;
|
|
1017
|
+
};
|
|
1018
|
+
/** Serializes this PMF to a JSON string (equivalent to `JSON.stringify(pmf)`). */
|
|
1019
|
+
toJSONString(): string;
|
|
859
1020
|
static fromJSON(jsonData: {
|
|
860
1021
|
bins: Array<[number, Bin]>;
|
|
861
1022
|
normalized?: boolean;
|
|
@@ -868,9 +1029,27 @@ declare class PMF {
|
|
|
868
1029
|
* Returns a new, non-normalized PMF.
|
|
869
1030
|
*/
|
|
870
1031
|
prune(epsRel: number, minBins?: number): PMF;
|
|
871
|
-
/** NEW - REVIEW IF THESE ARE USEFUL OR DUPLCIATIVE? */
|
|
872
1032
|
/** Probability mass at exactly x. */
|
|
873
1033
|
pAt(x: number): number;
|
|
1034
|
+
/**
|
|
1035
|
+
* P(any damage) — the mass on all non-zero outcomes, i.e. `1 - P(0)`.
|
|
1036
|
+
* Assumes a miss is encoded as the damage-0 bin (the convention used across
|
|
1037
|
+
* attack/save PMFs). The dual of {@link missProbability}.
|
|
1038
|
+
*/
|
|
1039
|
+
hitProbability(): number;
|
|
1040
|
+
/** P(no damage) — the mass at damage 0. The dual of {@link hitProbability}. */
|
|
1041
|
+
missProbability(): number;
|
|
1042
|
+
/**
|
|
1043
|
+
* Coarsen the distribution into at most `maxBuckets` contiguous, equal-width
|
|
1044
|
+
* damage buckets, aggregating probability mass (and `count`/`attr`
|
|
1045
|
+
* provenance) into each bucket's start value. Returns this PMF unchanged when
|
|
1046
|
+
* its integer support already fits within `maxBuckets`.
|
|
1047
|
+
*
|
|
1048
|
+
* This is a lossy display/downsampling transform (bucket start replaces the
|
|
1049
|
+
* exact damage value) — use it for charting wide distributions, not for DPR
|
|
1050
|
+
* math.
|
|
1051
|
+
*/
|
|
1052
|
+
rebin(maxBuckets: number): PMF;
|
|
874
1053
|
/** Dense integer support from min..max (inclusive).
|
|
875
1054
|
* Useful for showing empty bars in charts.
|
|
876
1055
|
*/
|
|
@@ -895,6 +1074,21 @@ declare class PMF {
|
|
|
895
1074
|
} | null;
|
|
896
1075
|
/** Check if outcome exists in this PMF. */
|
|
897
1076
|
hasOutcome(outcome: string): boolean;
|
|
1077
|
+
/**
|
|
1078
|
+
* Split each damage value's probability mass across outcome labels, returning
|
|
1079
|
+
* per-label maps of `damage value → probability mass attributable to that
|
|
1080
|
+
* label`. Summing over labels at a given value recovers that value's `p`.
|
|
1081
|
+
*
|
|
1082
|
+
* Damage-bearing bins are split by `attr` weight (the share of damage each
|
|
1083
|
+
* outcome contributed); the clean-miss bin at 0 is split by `count` weight
|
|
1084
|
+
* (there is no damage to attribute). Attribution is computed on demand via
|
|
1085
|
+
* {@link withAttribution} when absent, so builder-generated PMFs work too.
|
|
1086
|
+
*
|
|
1087
|
+
* This is the provenance core of the stacked damage-attribution chart — the
|
|
1088
|
+
* caller only maps these series into its rendering format (colors, binning,
|
|
1089
|
+
* axis labels).
|
|
1090
|
+
*/
|
|
1091
|
+
attributionByValue(): Map<string, Map<number, number>>;
|
|
898
1092
|
tailProbGE(t: number): number;
|
|
899
1093
|
tailProbGT(t: number): number;
|
|
900
1094
|
/**
|
|
@@ -932,4 +1126,4 @@ declare class PMF {
|
|
|
932
1126
|
query(): DiceQuery;
|
|
933
1127
|
}
|
|
934
1128
|
|
|
935
|
-
export { type Bin as B, type CritConfig as C, type DamageDistribution as D, EPS as E, LRUCache as L, type OutcomeLabelMap as O, PMF as P, type Rounding as R, type Snapshot as S, type OutcomeType as a,
|
|
1129
|
+
export { ALL_OUTCOME_TYPES as A, type Bin as B, type CritConfig as C, type DamageDistribution as D, EPS as E, LRUCache as L, MISS_NONE_OUTCOME as M, type OutcomeLabelMap as O, PMF as P, type Rounding as R, type Snapshot as S, type OutcomeType as a, type RollType as b, critProbability as c, OUTCOME_DISPLAY_ORDER as d, onCritOnly as e, onHitOnly as f, onMissOnly as g, onMissDamageOnly as h, onSaveHalfOnly as i, onSaveFailOnly as j, onPotentCantripOnly as k, DiceQuery as l, type OutcomeSnapshot as m, onAnyHit as o, pmfCache as p, sortOutcomes as s };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yipe/dice",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "A high-performance dice probability engine for D&D 5e DPR calculations. Powers dprcalc.com.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dnd",
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
"./dist/builder/dc.js"
|
|
63
63
|
],
|
|
64
64
|
"scripts": {
|
|
65
|
+
"format": "eslint . --fix",
|
|
65
66
|
"lint": "eslint .",
|
|
66
67
|
"typecheck": "tsc -p config/tsconfig.build.json --noEmit",
|
|
67
68
|
"build": "tsup --config config/tsup.config.ts",
|
|
@@ -79,17 +80,14 @@
|
|
|
79
80
|
"node": ">=18.17"
|
|
80
81
|
},
|
|
81
82
|
"devDependencies": {
|
|
82
|
-
"@types/node": "^
|
|
83
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
84
|
-
"@typescript-eslint/parser": "^8.
|
|
85
|
-
"@vitest/coverage-v8": "^
|
|
86
|
-
"eslint": "^
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"tsx": "^4.20.5",
|
|
92
|
-
"typescript": "^5.9.2",
|
|
93
|
-
"vitest": "^3.2.4"
|
|
83
|
+
"@types/node": "^26.0.1",
|
|
84
|
+
"@typescript-eslint/eslint-plugin": "^8.62.0",
|
|
85
|
+
"@typescript-eslint/parser": "^8.62.0",
|
|
86
|
+
"@vitest/coverage-v8": "^4.1.9",
|
|
87
|
+
"eslint": "^10.6.0",
|
|
88
|
+
"tsup": "^8.5.1",
|
|
89
|
+
"tsx": "^4.22.4",
|
|
90
|
+
"typescript": "^6.0.3",
|
|
91
|
+
"vitest": "^4.1.9"
|
|
94
92
|
}
|
|
95
|
-
}
|
|
93
|
+
}
|