@yipe/dice 0.1.2 → 0.1.3

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/index.d.cts CHANGED
@@ -32,6 +32,7 @@ interface Bin {
32
32
  type DamageDistribution = Record<number, number>;
33
33
  /** Canonical outcome labels supported by the query helpers. */
34
34
  type OutcomeType = "crit" | "hit" | "missNone" | "missDamage" | "saveHalf" | "saveFail" | "pc";
35
+ type Rounding = "none" | "floor" | "round" | "ceil";
35
36
 
36
37
  /**
37
38
  * Query interface for analyzing dice roll probability distributions.
@@ -46,7 +47,7 @@ type OutcomeType = "crit" | "hit" | "missNone" | "missDamage" | "saveHalf" | "sa
46
47
  declare class DiceQuery {
47
48
  readonly singles: PMF[];
48
49
  readonly combined: PMF;
49
- constructor(singles: PMF | PMF[], combined?: PMF);
50
+ constructor(singles: PMF | PMF[], combined?: PMF, eps?: number);
50
51
  private static readonly DEFAULT_OUTCOMES;
51
52
  /**
52
53
  * Returns the expected damage across all possible outcomes.
@@ -206,7 +207,6 @@ declare class DiceQuery {
206
207
  * - "How much damage comes from miss effects (like save-for-half spells)?"
207
208
  */
208
209
  expectedDamageFrom(labels: OutcomeType | OutcomeType[]): number;
209
- private _expectedDamageFromSingle;
210
210
  /**
211
211
  * Returns damage statistics for scenarios where AT LEAST ONE attack results in
212
212
  * the specified outcome(s).
@@ -622,24 +622,13 @@ type Snapshot = {
622
622
  declare const pmfCache: LRUCache<string, PMF>;
623
623
  /**
624
624
  * Probability Mass Function for discrete damage distributions.
625
- *
626
- * Represents the probability distribution of dice roll outcomes with support for:
627
- * - Damage values and their probabilities
628
- * - Outcome type tracking (hit, miss, crit, etc)
629
- * - Damage attribution by outcome type
630
- *
631
- * Core operations:
632
- * - convolve(): Convolve two PMFs to represent multiple dice/attacks
633
- * - addScaled(): Add a scaled PMF branch (for conditional outcomes)
634
- * - mapDamage(): Transform damage values (for modifiers, resistances)
635
- * - normalize(): Ensure probabilities sum to 1.0
636
625
  */
637
626
  declare class PMF {
638
627
  readonly map: Map<number, Bin>;
639
628
  readonly epsilon: number;
640
629
  readonly normalized: boolean;
641
630
  readonly identifier: string;
642
- private _preservedProvidence;
631
+ private _preservedProvenance;
643
632
  private static __anonIdCounter;
644
633
  private _support?;
645
634
  private _min?;
@@ -648,9 +637,10 @@ declare class PMF {
648
637
  private _mean?;
649
638
  private _variance?;
650
639
  private _stdev?;
651
- constructor(map?: Map<number, Bin>, epsilon?: number, normalized?: boolean, identifier?: string, _preservedProvidence?: boolean);
640
+ constructor(map?: Map<number, Bin>, epsilon?: number, normalized?: boolean, identifier?: string, _preservedProvenance?: boolean);
652
641
  static empty(epsilon?: number, identifier?: string): PMF;
653
642
  static zero(epsilon?: number): PMF;
643
+ static delta(value: number, epsilon?: number): PMF;
654
644
  static emptyMass(): PMF;
655
645
  [Symbol.iterator](): IterableIterator<[number, Bin]>;
656
646
  static clearCache(): void;
@@ -743,9 +733,9 @@ declare class PMF {
743
733
  * [pCrit, critPMF],
744
734
  * ]);
745
735
  */
746
- static mixN(weights: [number, PMF][]): PMF;
747
- private setPreservedProvidence;
748
- preservedProvidence(): boolean;
736
+ static mixN(weights: [number, PMF][], eps?: number): PMF;
737
+ private setPreservedProvenance;
738
+ preservedProvenance(): boolean;
749
739
  private getPowerCacheKey;
750
740
  /**
751
741
  * Efficiently computes this PMF convolved with itself `n` times.
@@ -854,6 +844,8 @@ declare class PMF {
854
844
  } | null;
855
845
  /** Check if outcome exists in this PMF. */
856
846
  hasOutcome(outcome: string): boolean;
847
+ tailProbGE(t: number): number;
848
+ tailProbGT(t: number): number;
857
849
  /**
858
850
  * Returns a new PMF containing only bins where the specified outcome has non-zero probability.
859
851
  * This creates a marginal distribution for the given outcome type, with probabilities
@@ -879,67 +871,51 @@ declare class PMF {
879
871
  pNone: number;
880
872
  pAny: number;
881
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;
882
881
  query(): DiceQuery;
883
882
  }
884
883
 
885
- /**
886
- * @internal
887
- */
888
- declare class Dice {
889
- private readonly faces;
890
- privateData: Record<string, any>;
891
- private outcomeData;
892
- private hasHitDistributionCalculated;
893
- identifier?: string;
894
- constructor(x?: number);
895
- getOutcomeDistribution(key: OutcomeType): DamageDistribution | undefined;
896
- getFullOutcomeDistribution(): Record<OutcomeType, DamageDistribution | undefined>;
897
- setOutcomeDistribution(key: OutcomeType, data: DamageDistribution | undefined): void;
898
- hasOutcomeData(key: OutcomeType): boolean;
899
- getOutcomeCount(key: OutcomeType, face: number): number;
900
- getAverage(key: OutcomeType): number;
901
- calculateHitDistribution(): DamageDistribution;
902
- private ensureHitDistribution;
903
- private binaryOp;
904
- private removeFaces;
905
- getFaceEntries(): [number, number][];
906
- getFaceMap(): DamageDistribution;
907
- get(face: number): number;
908
- keys(): number[];
909
- values(): number[];
910
- total(): number;
911
- setFace(key: number, value: number): void;
912
- static scalar(value: number): Dice;
913
- maxFace(): number;
914
- minFace(): number;
915
- increment(face: number, count: number): void;
916
- normalize(scalar: number): Dice;
917
- add(other: Dice | number): Dice;
918
- subtract(other: Dice | number): Dice;
919
- conditionalApply(other: Dice | number): Dice;
920
- multiply(other: Dice | number): Dice;
921
- addNonZero(other: Dice | number): Dice;
922
- eq(other: Dice | number): Dice;
923
- max(other: Dice | number): Dice;
924
- min(other: Dice | number): Dice;
925
- advantage(): Dice;
926
- ge(other: Dice | number): Dice;
927
- divide(other: Dice | number): Dice;
928
- divideRoundUp(other: Dice | number): Dice;
929
- divideRoundDown(other: Dice | number): Dice;
930
- and(other: Dice | number): Dice;
931
- private checkTarget;
932
- dc(other: Dice | number): Dice;
933
- ac(other: Dice | number): Dice;
934
- deleteFace(face: number): Dice;
935
- reroll(toReroll: Dice | number): Dice;
936
- combine(other: Dice | number): Dice;
937
- combineInPlace(other: Dice): void;
938
- percent(): DamageDistribution;
939
- average(): number;
940
- toPMF(numEpsilon?: number): PMF;
884
+ /** A labeled mixture builder that preserves provenance in Bin.count. */
885
+ declare class Mixture<L extends string = string> {
886
+ private readonly totals;
887
+ private readonly labelMass;
888
+ private readonly eps;
889
+ constructor(eps?: number);
890
+ /** Remove all accumulated state. */
891
+ clear(): this;
892
+ /** Number of distinct outcome values currently accumulated. */
893
+ size(): number;
894
+ /** Whether a label was ever added. */
895
+ hasLabel(label: L): boolean;
896
+ /**
897
+ * Add a labeled component with a mixture weight.
898
+ * Weight can be any positive finite number. Very small contributions are pruned by eps.
899
+ */
900
+ add(label: L, pmf: PMF, weight?: number): this;
901
+ buildPMF(eps?: number): PMF;
902
+ /**
903
+ * Produce normalized *per-label* PMFs (labels independent).
904
+ * These are unlabeled PMFs built from the raw mass of that label alone.
905
+ */
906
+ byOutcome(): Record<L, PMF>;
907
+ /**
908
+ * Mixture weights per label, normalized to sum to 1 over labels that appeared.
909
+ * Uses raw mass before per-outcome normalization.
910
+ */
911
+ weights(): Record<L, number>;
912
+ toJSON(): {
913
+ totals: Array<[number, number]>;
914
+ labels: Array<[number, Record<L, number>]>;
915
+ eps: number;
916
+ };
917
+ static mix<L extends string = string>(items: Array<[label: L, pmf: PMF, weight: number]>, eps?: number): PMF;
941
918
  }
942
- type _DiceInternal = never;
943
919
 
944
920
  /** Enable or disable the internal parse cache. */
945
921
  declare function setCachingEnabled(enabled: boolean): void;
@@ -954,4 +930,4 @@ declare function clearParserCache(): void;
954
930
  */
955
931
  declare function parse(expression: string, n?: number): PMF;
956
932
 
957
- export { type Bin, type DamageDistribution, Dice, DiceQuery, EPS, LRUCache, type OutcomeLabelMap, type OutcomeSnapshot, type OutcomeType, PMF, type Snapshot, type _DiceInternal, clearParserCache, getCachingEnabled, parse, pmfCache, setCachingEnabled };
933
+ export { type Bin, type DamageDistribution, DiceQuery, EPS, LRUCache, Mixture, type OutcomeLabelMap, type OutcomeSnapshot, type OutcomeType, PMF, type Rounding, type Snapshot, clearParserCache, getCachingEnabled, parse, pmfCache, setCachingEnabled };
package/dist/index.d.ts CHANGED
@@ -32,6 +32,7 @@ interface Bin {
32
32
  type DamageDistribution = Record<number, number>;
33
33
  /** Canonical outcome labels supported by the query helpers. */
34
34
  type OutcomeType = "crit" | "hit" | "missNone" | "missDamage" | "saveHalf" | "saveFail" | "pc";
35
+ type Rounding = "none" | "floor" | "round" | "ceil";
35
36
 
36
37
  /**
37
38
  * Query interface for analyzing dice roll probability distributions.
@@ -46,7 +47,7 @@ type OutcomeType = "crit" | "hit" | "missNone" | "missDamage" | "saveHalf" | "sa
46
47
  declare class DiceQuery {
47
48
  readonly singles: PMF[];
48
49
  readonly combined: PMF;
49
- constructor(singles: PMF | PMF[], combined?: PMF);
50
+ constructor(singles: PMF | PMF[], combined?: PMF, eps?: number);
50
51
  private static readonly DEFAULT_OUTCOMES;
51
52
  /**
52
53
  * Returns the expected damage across all possible outcomes.
@@ -206,7 +207,6 @@ declare class DiceQuery {
206
207
  * - "How much damage comes from miss effects (like save-for-half spells)?"
207
208
  */
208
209
  expectedDamageFrom(labels: OutcomeType | OutcomeType[]): number;
209
- private _expectedDamageFromSingle;
210
210
  /**
211
211
  * Returns damage statistics for scenarios where AT LEAST ONE attack results in
212
212
  * the specified outcome(s).
@@ -622,24 +622,13 @@ type Snapshot = {
622
622
  declare const pmfCache: LRUCache<string, PMF>;
623
623
  /**
624
624
  * Probability Mass Function for discrete damage distributions.
625
- *
626
- * Represents the probability distribution of dice roll outcomes with support for:
627
- * - Damage values and their probabilities
628
- * - Outcome type tracking (hit, miss, crit, etc)
629
- * - Damage attribution by outcome type
630
- *
631
- * Core operations:
632
- * - convolve(): Convolve two PMFs to represent multiple dice/attacks
633
- * - addScaled(): Add a scaled PMF branch (for conditional outcomes)
634
- * - mapDamage(): Transform damage values (for modifiers, resistances)
635
- * - normalize(): Ensure probabilities sum to 1.0
636
625
  */
637
626
  declare class PMF {
638
627
  readonly map: Map<number, Bin>;
639
628
  readonly epsilon: number;
640
629
  readonly normalized: boolean;
641
630
  readonly identifier: string;
642
- private _preservedProvidence;
631
+ private _preservedProvenance;
643
632
  private static __anonIdCounter;
644
633
  private _support?;
645
634
  private _min?;
@@ -648,9 +637,10 @@ declare class PMF {
648
637
  private _mean?;
649
638
  private _variance?;
650
639
  private _stdev?;
651
- constructor(map?: Map<number, Bin>, epsilon?: number, normalized?: boolean, identifier?: string, _preservedProvidence?: boolean);
640
+ constructor(map?: Map<number, Bin>, epsilon?: number, normalized?: boolean, identifier?: string, _preservedProvenance?: boolean);
652
641
  static empty(epsilon?: number, identifier?: string): PMF;
653
642
  static zero(epsilon?: number): PMF;
643
+ static delta(value: number, epsilon?: number): PMF;
654
644
  static emptyMass(): PMF;
655
645
  [Symbol.iterator](): IterableIterator<[number, Bin]>;
656
646
  static clearCache(): void;
@@ -743,9 +733,9 @@ declare class PMF {
743
733
  * [pCrit, critPMF],
744
734
  * ]);
745
735
  */
746
- static mixN(weights: [number, PMF][]): PMF;
747
- private setPreservedProvidence;
748
- preservedProvidence(): boolean;
736
+ static mixN(weights: [number, PMF][], eps?: number): PMF;
737
+ private setPreservedProvenance;
738
+ preservedProvenance(): boolean;
749
739
  private getPowerCacheKey;
750
740
  /**
751
741
  * Efficiently computes this PMF convolved with itself `n` times.
@@ -854,6 +844,8 @@ declare class PMF {
854
844
  } | null;
855
845
  /** Check if outcome exists in this PMF. */
856
846
  hasOutcome(outcome: string): boolean;
847
+ tailProbGE(t: number): number;
848
+ tailProbGT(t: number): number;
857
849
  /**
858
850
  * Returns a new PMF containing only bins where the specified outcome has non-zero probability.
859
851
  * This creates a marginal distribution for the given outcome type, with probabilities
@@ -879,67 +871,51 @@ declare class PMF {
879
871
  pNone: number;
880
872
  pAny: number;
881
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;
882
881
  query(): DiceQuery;
883
882
  }
884
883
 
885
- /**
886
- * @internal
887
- */
888
- declare class Dice {
889
- private readonly faces;
890
- privateData: Record<string, any>;
891
- private outcomeData;
892
- private hasHitDistributionCalculated;
893
- identifier?: string;
894
- constructor(x?: number);
895
- getOutcomeDistribution(key: OutcomeType): DamageDistribution | undefined;
896
- getFullOutcomeDistribution(): Record<OutcomeType, DamageDistribution | undefined>;
897
- setOutcomeDistribution(key: OutcomeType, data: DamageDistribution | undefined): void;
898
- hasOutcomeData(key: OutcomeType): boolean;
899
- getOutcomeCount(key: OutcomeType, face: number): number;
900
- getAverage(key: OutcomeType): number;
901
- calculateHitDistribution(): DamageDistribution;
902
- private ensureHitDistribution;
903
- private binaryOp;
904
- private removeFaces;
905
- getFaceEntries(): [number, number][];
906
- getFaceMap(): DamageDistribution;
907
- get(face: number): number;
908
- keys(): number[];
909
- values(): number[];
910
- total(): number;
911
- setFace(key: number, value: number): void;
912
- static scalar(value: number): Dice;
913
- maxFace(): number;
914
- minFace(): number;
915
- increment(face: number, count: number): void;
916
- normalize(scalar: number): Dice;
917
- add(other: Dice | number): Dice;
918
- subtract(other: Dice | number): Dice;
919
- conditionalApply(other: Dice | number): Dice;
920
- multiply(other: Dice | number): Dice;
921
- addNonZero(other: Dice | number): Dice;
922
- eq(other: Dice | number): Dice;
923
- max(other: Dice | number): Dice;
924
- min(other: Dice | number): Dice;
925
- advantage(): Dice;
926
- ge(other: Dice | number): Dice;
927
- divide(other: Dice | number): Dice;
928
- divideRoundUp(other: Dice | number): Dice;
929
- divideRoundDown(other: Dice | number): Dice;
930
- and(other: Dice | number): Dice;
931
- private checkTarget;
932
- dc(other: Dice | number): Dice;
933
- ac(other: Dice | number): Dice;
934
- deleteFace(face: number): Dice;
935
- reroll(toReroll: Dice | number): Dice;
936
- combine(other: Dice | number): Dice;
937
- combineInPlace(other: Dice): void;
938
- percent(): DamageDistribution;
939
- average(): number;
940
- toPMF(numEpsilon?: number): PMF;
884
+ /** A labeled mixture builder that preserves provenance in Bin.count. */
885
+ declare class Mixture<L extends string = string> {
886
+ private readonly totals;
887
+ private readonly labelMass;
888
+ private readonly eps;
889
+ constructor(eps?: number);
890
+ /** Remove all accumulated state. */
891
+ clear(): this;
892
+ /** Number of distinct outcome values currently accumulated. */
893
+ size(): number;
894
+ /** Whether a label was ever added. */
895
+ hasLabel(label: L): boolean;
896
+ /**
897
+ * Add a labeled component with a mixture weight.
898
+ * Weight can be any positive finite number. Very small contributions are pruned by eps.
899
+ */
900
+ add(label: L, pmf: PMF, weight?: number): this;
901
+ buildPMF(eps?: number): PMF;
902
+ /**
903
+ * Produce normalized *per-label* PMFs (labels independent).
904
+ * These are unlabeled PMFs built from the raw mass of that label alone.
905
+ */
906
+ byOutcome(): Record<L, PMF>;
907
+ /**
908
+ * Mixture weights per label, normalized to sum to 1 over labels that appeared.
909
+ * Uses raw mass before per-outcome normalization.
910
+ */
911
+ weights(): Record<L, number>;
912
+ toJSON(): {
913
+ totals: Array<[number, number]>;
914
+ labels: Array<[number, Record<L, number>]>;
915
+ eps: number;
916
+ };
917
+ static mix<L extends string = string>(items: Array<[label: L, pmf: PMF, weight: number]>, eps?: number): PMF;
941
918
  }
942
- type _DiceInternal = never;
943
919
 
944
920
  /** Enable or disable the internal parse cache. */
945
921
  declare function setCachingEnabled(enabled: boolean): void;
@@ -954,4 +930,4 @@ declare function clearParserCache(): void;
954
930
  */
955
931
  declare function parse(expression: string, n?: number): PMF;
956
932
 
957
- export { type Bin, type DamageDistribution, Dice, DiceQuery, EPS, LRUCache, type OutcomeLabelMap, type OutcomeSnapshot, type OutcomeType, PMF, type Snapshot, type _DiceInternal, clearParserCache, getCachingEnabled, parse, pmfCache, setCachingEnabled };
933
+ export { type Bin, type DamageDistribution, DiceQuery, EPS, LRUCache, Mixture, type OutcomeLabelMap, type OutcomeSnapshot, type OutcomeType, PMF, type Rounding, type Snapshot, clearParserCache, getCachingEnabled, parse, pmfCache, setCachingEnabled };