@yipe/dice 0.1.1 → 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
@@ -1,9 +1,24 @@
1
+ /**
2
+ * Simple LRU cache implementation
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
+
1
18
  /** Mapping from outcome label to probability mass or damage attribution. */
2
19
  type OutcomeLabelMap = Partial<Record<string, number>>;
3
20
  /** Computational epsilon for pruning negligible probabilities. */
4
- declare const COMPUTATIONAL_EPS = 1e-40;
5
- /** Test tolerance for floating-point precision errors. */
6
- declare const TEST_EPS = 1e-10;
21
+ declare const EPS = 1e-12;
7
22
  /** A probability bin for a specific damage value. */
8
23
  interface Bin {
9
24
  /** Total probability mass at this damage value. */
@@ -17,6 +32,7 @@ interface Bin {
17
32
  type DamageDistribution = Record<number, number>;
18
33
  /** Canonical outcome labels supported by the query helpers. */
19
34
  type OutcomeType = "crit" | "hit" | "missNone" | "missDamage" | "saveHalf" | "saveFail" | "pc";
35
+ type Rounding = "none" | "floor" | "round" | "ceil";
20
36
 
21
37
  /**
22
38
  * Query interface for analyzing dice roll probability distributions.
@@ -31,7 +47,7 @@ type OutcomeType = "crit" | "hit" | "missNone" | "missDamage" | "saveHalf" | "sa
31
47
  declare class DiceQuery {
32
48
  readonly singles: PMF[];
33
49
  readonly combined: PMF;
34
- constructor(singles: PMF | PMF[], combined?: PMF);
50
+ constructor(singles: PMF | PMF[], combined?: PMF, eps?: number);
35
51
  private static readonly DEFAULT_OUTCOMES;
36
52
  /**
37
53
  * Returns the expected damage across all possible outcomes.
@@ -191,7 +207,6 @@ declare class DiceQuery {
191
207
  * - "How much damage comes from miss effects (like save-for-half spells)?"
192
208
  */
193
209
  expectedDamageFrom(labels: OutcomeType | OutcomeType[]): number;
194
- private _expectedDamageFromSingle;
195
210
  /**
196
211
  * Returns damage statistics for scenarios where AT LEAST ONE attack results in
197
212
  * the specified outcome(s).
@@ -604,26 +619,16 @@ type Snapshot = {
604
619
  outcomes: Map<OutcomeType, OutcomeSnapshot>;
605
620
  };
606
621
 
622
+ declare const pmfCache: LRUCache<string, PMF>;
607
623
  /**
608
624
  * Probability Mass Function for discrete damage distributions.
609
- *
610
- * Represents the probability distribution of dice roll outcomes with support for:
611
- * - Damage values and their probabilities
612
- * - Outcome type tracking (hit, miss, crit, etc)
613
- * - Damage attribution by outcome type
614
- *
615
- * Core operations:
616
- * - convolve(): Convolve two PMFs to represent multiple dice/attacks
617
- * - addScaled(): Add a scaled PMF branch (for conditional outcomes)
618
- * - mapDamage(): Transform damage values (for modifiers, resistances)
619
- * - normalize(): Ensure probabilities sum to 1.0
620
625
  */
621
626
  declare class PMF {
622
627
  readonly map: Map<number, Bin>;
623
628
  readonly epsilon: number;
624
629
  readonly normalized: boolean;
625
630
  readonly identifier: string;
626
- private _preservedProvidence;
631
+ private _preservedProvenance;
627
632
  private static __anonIdCounter;
628
633
  private _support?;
629
634
  private _min?;
@@ -632,9 +637,10 @@ declare class PMF {
632
637
  private _mean?;
633
638
  private _variance?;
634
639
  private _stdev?;
635
- 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);
636
641
  static empty(epsilon?: number, identifier?: string): PMF;
637
642
  static zero(epsilon?: number): PMF;
643
+ static delta(value: number, epsilon?: number): PMF;
638
644
  static emptyMass(): PMF;
639
645
  [Symbol.iterator](): IterableIterator<[number, Bin]>;
640
646
  static clearCache(): void;
@@ -727,9 +733,10 @@ declare class PMF {
727
733
  * [pCrit, critPMF],
728
734
  * ]);
729
735
  */
730
- static mixN(weights: [number, PMF][]): PMF;
731
- private setPreservedProvidence;
732
- preservedProvidence(): boolean;
736
+ static mixN(weights: [number, PMF][], eps?: number): PMF;
737
+ private setPreservedProvenance;
738
+ preservedProvenance(): boolean;
739
+ private getPowerCacheKey;
733
740
  /**
734
741
  * Efficiently computes this PMF convolved with itself `n` times.
735
742
  * Uses exponentiation by squaring to reduce total convolutions.
@@ -837,6 +844,8 @@ declare class PMF {
837
844
  } | null;
838
845
  /** Check if outcome exists in this PMF. */
839
846
  hasOutcome(outcome: string): boolean;
847
+ tailProbGE(t: number): number;
848
+ tailProbGT(t: number): number;
840
849
  /**
841
850
  * Returns a new PMF containing only bins where the specified outcome has non-zero probability.
842
851
  * This creates a marginal distribution for the given outcome type, with probabilities
@@ -862,84 +871,50 @@ declare class PMF {
862
871
  pNone: number;
863
872
  pAny: number;
864
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;
865
881
  query(): DiceQuery;
866
882
  }
867
- declare function getPowerCacheKey(base: PMF, n: number, eps: number): string;
868
883
 
869
- /**
870
- * @internal
871
- */
872
- declare class Dice {
873
- private readonly faces;
874
- privateData: Record<string, any>;
875
- private outcomeData;
876
- private hasHitDistributionCalculated;
877
- identifier?: string;
878
- constructor(x?: number);
879
- getOutcomeDistribution(key: OutcomeType): DamageDistribution | undefined;
880
- getFullOutcomeDistribution(): Record<OutcomeType, DamageDistribution | undefined>;
881
- setOutcomeDistribution(key: OutcomeType, data: DamageDistribution | undefined): void;
882
- hasOutcomeData(key: OutcomeType): boolean;
883
- getOutcomeCount(key: OutcomeType, face: number): number;
884
- getAverage(key: OutcomeType): number;
885
- calculateHitDistribution(): DamageDistribution;
886
- private ensureHitDistribution;
887
- private binaryOp;
888
- private removeFaces;
889
- getFaceEntries(): [number, number][];
890
- getFaceMap(): DamageDistribution;
891
- get(face: number): number;
892
- keys(): number[];
893
- values(): number[];
894
- total(): number;
895
- setFace(key: number, value: number): void;
896
- static scalar(value: number): Dice;
897
- maxFace(): number;
898
- minFace(): number;
899
- increment(face: number, count: number): void;
900
- normalize(scalar: number): Dice;
901
- add(other: Dice | number): Dice;
902
- subtract(other: Dice | number): Dice;
903
- conditionalApply(other: Dice | number): Dice;
904
- multiply(other: Dice | number): Dice;
905
- addNonZero(other: Dice | number): Dice;
906
- eq(other: Dice | number): Dice;
907
- max(other: Dice | number): Dice;
908
- min(other: Dice | number): Dice;
909
- advantage(): Dice;
910
- ge(other: Dice | number): Dice;
911
- divide(other: Dice | number): Dice;
912
- divideRoundUp(other: Dice | number): Dice;
913
- divideRoundDown(other: Dice | number): Dice;
914
- and(other: Dice | number): Dice;
915
- private checkTarget;
916
- dc(other: Dice | number): Dice;
917
- ac(other: Dice | number): Dice;
918
- deleteFace(face: number): Dice;
919
- reroll(toReroll: Dice | number): Dice;
920
- combine(other: Dice | number): Dice;
921
- combineInPlace(other: Dice): void;
922
- percent(): DamageDistribution;
923
- average(): number;
924
- toPMF(numEpsilon?: number): PMF;
925
- }
926
- type _DiceInternal = never;
927
-
928
- /**
929
- * Simple LRU cache implementation
930
- */
931
- declare class LRUCache<K, V> {
932
- private readonly maxSize;
933
- private cache;
934
- constructor(maxSize?: number);
935
- get(key: K): V | undefined;
936
- delete(key: K): void;
937
- set(key: K, value: V): this;
938
- clear(): void;
939
- get size(): number;
940
- has(key: K): boolean;
941
- keys(): IterableIterator<K>;
942
- values(): IterableIterator<V>;
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;
943
918
  }
944
919
 
945
920
  /** Enable or disable the internal parse cache. */
@@ -955,4 +930,4 @@ declare function clearParserCache(): void;
955
930
  */
956
931
  declare function parse(expression: string, n?: number): PMF;
957
932
 
958
- export { type Bin, COMPUTATIONAL_EPS, type DamageDistribution, Dice, DiceQuery, LRUCache, type OutcomeLabelMap, type OutcomeSnapshot, type OutcomeType, PMF, type Snapshot, TEST_EPS, type _DiceInternal, clearParserCache, getCachingEnabled, getPowerCacheKey, parse, 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
@@ -1,9 +1,24 @@
1
+ /**
2
+ * Simple LRU cache implementation
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
+
1
18
  /** Mapping from outcome label to probability mass or damage attribution. */
2
19
  type OutcomeLabelMap = Partial<Record<string, number>>;
3
20
  /** Computational epsilon for pruning negligible probabilities. */
4
- declare const COMPUTATIONAL_EPS = 1e-40;
5
- /** Test tolerance for floating-point precision errors. */
6
- declare const TEST_EPS = 1e-10;
21
+ declare const EPS = 1e-12;
7
22
  /** A probability bin for a specific damage value. */
8
23
  interface Bin {
9
24
  /** Total probability mass at this damage value. */
@@ -17,6 +32,7 @@ interface Bin {
17
32
  type DamageDistribution = Record<number, number>;
18
33
  /** Canonical outcome labels supported by the query helpers. */
19
34
  type OutcomeType = "crit" | "hit" | "missNone" | "missDamage" | "saveHalf" | "saveFail" | "pc";
35
+ type Rounding = "none" | "floor" | "round" | "ceil";
20
36
 
21
37
  /**
22
38
  * Query interface for analyzing dice roll probability distributions.
@@ -31,7 +47,7 @@ type OutcomeType = "crit" | "hit" | "missNone" | "missDamage" | "saveHalf" | "sa
31
47
  declare class DiceQuery {
32
48
  readonly singles: PMF[];
33
49
  readonly combined: PMF;
34
- constructor(singles: PMF | PMF[], combined?: PMF);
50
+ constructor(singles: PMF | PMF[], combined?: PMF, eps?: number);
35
51
  private static readonly DEFAULT_OUTCOMES;
36
52
  /**
37
53
  * Returns the expected damage across all possible outcomes.
@@ -191,7 +207,6 @@ declare class DiceQuery {
191
207
  * - "How much damage comes from miss effects (like save-for-half spells)?"
192
208
  */
193
209
  expectedDamageFrom(labels: OutcomeType | OutcomeType[]): number;
194
- private _expectedDamageFromSingle;
195
210
  /**
196
211
  * Returns damage statistics for scenarios where AT LEAST ONE attack results in
197
212
  * the specified outcome(s).
@@ -604,26 +619,16 @@ type Snapshot = {
604
619
  outcomes: Map<OutcomeType, OutcomeSnapshot>;
605
620
  };
606
621
 
622
+ declare const pmfCache: LRUCache<string, PMF>;
607
623
  /**
608
624
  * Probability Mass Function for discrete damage distributions.
609
- *
610
- * Represents the probability distribution of dice roll outcomes with support for:
611
- * - Damage values and their probabilities
612
- * - Outcome type tracking (hit, miss, crit, etc)
613
- * - Damage attribution by outcome type
614
- *
615
- * Core operations:
616
- * - convolve(): Convolve two PMFs to represent multiple dice/attacks
617
- * - addScaled(): Add a scaled PMF branch (for conditional outcomes)
618
- * - mapDamage(): Transform damage values (for modifiers, resistances)
619
- * - normalize(): Ensure probabilities sum to 1.0
620
625
  */
621
626
  declare class PMF {
622
627
  readonly map: Map<number, Bin>;
623
628
  readonly epsilon: number;
624
629
  readonly normalized: boolean;
625
630
  readonly identifier: string;
626
- private _preservedProvidence;
631
+ private _preservedProvenance;
627
632
  private static __anonIdCounter;
628
633
  private _support?;
629
634
  private _min?;
@@ -632,9 +637,10 @@ declare class PMF {
632
637
  private _mean?;
633
638
  private _variance?;
634
639
  private _stdev?;
635
- 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);
636
641
  static empty(epsilon?: number, identifier?: string): PMF;
637
642
  static zero(epsilon?: number): PMF;
643
+ static delta(value: number, epsilon?: number): PMF;
638
644
  static emptyMass(): PMF;
639
645
  [Symbol.iterator](): IterableIterator<[number, Bin]>;
640
646
  static clearCache(): void;
@@ -727,9 +733,10 @@ declare class PMF {
727
733
  * [pCrit, critPMF],
728
734
  * ]);
729
735
  */
730
- static mixN(weights: [number, PMF][]): PMF;
731
- private setPreservedProvidence;
732
- preservedProvidence(): boolean;
736
+ static mixN(weights: [number, PMF][], eps?: number): PMF;
737
+ private setPreservedProvenance;
738
+ preservedProvenance(): boolean;
739
+ private getPowerCacheKey;
733
740
  /**
734
741
  * Efficiently computes this PMF convolved with itself `n` times.
735
742
  * Uses exponentiation by squaring to reduce total convolutions.
@@ -837,6 +844,8 @@ declare class PMF {
837
844
  } | null;
838
845
  /** Check if outcome exists in this PMF. */
839
846
  hasOutcome(outcome: string): boolean;
847
+ tailProbGE(t: number): number;
848
+ tailProbGT(t: number): number;
840
849
  /**
841
850
  * Returns a new PMF containing only bins where the specified outcome has non-zero probability.
842
851
  * This creates a marginal distribution for the given outcome type, with probabilities
@@ -862,84 +871,50 @@ declare class PMF {
862
871
  pNone: number;
863
872
  pAny: number;
864
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;
865
881
  query(): DiceQuery;
866
882
  }
867
- declare function getPowerCacheKey(base: PMF, n: number, eps: number): string;
868
883
 
869
- /**
870
- * @internal
871
- */
872
- declare class Dice {
873
- private readonly faces;
874
- privateData: Record<string, any>;
875
- private outcomeData;
876
- private hasHitDistributionCalculated;
877
- identifier?: string;
878
- constructor(x?: number);
879
- getOutcomeDistribution(key: OutcomeType): DamageDistribution | undefined;
880
- getFullOutcomeDistribution(): Record<OutcomeType, DamageDistribution | undefined>;
881
- setOutcomeDistribution(key: OutcomeType, data: DamageDistribution | undefined): void;
882
- hasOutcomeData(key: OutcomeType): boolean;
883
- getOutcomeCount(key: OutcomeType, face: number): number;
884
- getAverage(key: OutcomeType): number;
885
- calculateHitDistribution(): DamageDistribution;
886
- private ensureHitDistribution;
887
- private binaryOp;
888
- private removeFaces;
889
- getFaceEntries(): [number, number][];
890
- getFaceMap(): DamageDistribution;
891
- get(face: number): number;
892
- keys(): number[];
893
- values(): number[];
894
- total(): number;
895
- setFace(key: number, value: number): void;
896
- static scalar(value: number): Dice;
897
- maxFace(): number;
898
- minFace(): number;
899
- increment(face: number, count: number): void;
900
- normalize(scalar: number): Dice;
901
- add(other: Dice | number): Dice;
902
- subtract(other: Dice | number): Dice;
903
- conditionalApply(other: Dice | number): Dice;
904
- multiply(other: Dice | number): Dice;
905
- addNonZero(other: Dice | number): Dice;
906
- eq(other: Dice | number): Dice;
907
- max(other: Dice | number): Dice;
908
- min(other: Dice | number): Dice;
909
- advantage(): Dice;
910
- ge(other: Dice | number): Dice;
911
- divide(other: Dice | number): Dice;
912
- divideRoundUp(other: Dice | number): Dice;
913
- divideRoundDown(other: Dice | number): Dice;
914
- and(other: Dice | number): Dice;
915
- private checkTarget;
916
- dc(other: Dice | number): Dice;
917
- ac(other: Dice | number): Dice;
918
- deleteFace(face: number): Dice;
919
- reroll(toReroll: Dice | number): Dice;
920
- combine(other: Dice | number): Dice;
921
- combineInPlace(other: Dice): void;
922
- percent(): DamageDistribution;
923
- average(): number;
924
- toPMF(numEpsilon?: number): PMF;
925
- }
926
- type _DiceInternal = never;
927
-
928
- /**
929
- * Simple LRU cache implementation
930
- */
931
- declare class LRUCache<K, V> {
932
- private readonly maxSize;
933
- private cache;
934
- constructor(maxSize?: number);
935
- get(key: K): V | undefined;
936
- delete(key: K): void;
937
- set(key: K, value: V): this;
938
- clear(): void;
939
- get size(): number;
940
- has(key: K): boolean;
941
- keys(): IterableIterator<K>;
942
- values(): IterableIterator<V>;
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;
943
918
  }
944
919
 
945
920
  /** Enable or disable the internal parse cache. */
@@ -955,4 +930,4 @@ declare function clearParserCache(): void;
955
930
  */
956
931
  declare function parse(expression: string, n?: number): PMF;
957
932
 
958
- export { type Bin, COMPUTATIONAL_EPS, type DamageDistribution, Dice, DiceQuery, LRUCache, type OutcomeLabelMap, type OutcomeSnapshot, type OutcomeType, PMF, type Snapshot, TEST_EPS, type _DiceInternal, clearParserCache, getCachingEnabled, getPowerCacheKey, parse, 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 };