@yipe/dice 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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. */
@@ -572,7 +587,7 @@ declare class DiceQuery {
572
587
  * const bonusAttack = parse("(d20 + 3 AC 15) * (1d6 + 1)");
573
588
  * const bothAttacks = mainAttack.convolve(bonusAttack);
574
589
  */
575
- convolve(other: DiceQuery, eps?: number): DiceQuery;
590
+ convolve(other: DiceQuery): DiceQuery;
576
591
  /**
577
592
  * First-success split over an ordered list of DISTINCT single-swing PMFs.
578
593
  * Each PMF may have different success/subset probabilities (from labels).
@@ -604,6 +619,7 @@ 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
625
  *
@@ -635,7 +651,7 @@ declare class PMF {
635
651
  constructor(map?: Map<number, Bin>, epsilon?: number, normalized?: boolean, identifier?: string, _preservedProvidence?: boolean);
636
652
  static empty(epsilon?: number, identifier?: string): PMF;
637
653
  static zero(epsilon?: number): PMF;
638
- static emptyMass(epsilon?: number): PMF;
654
+ static emptyMass(): PMF;
639
655
  [Symbol.iterator](): IterableIterator<[number, Bin]>;
640
656
  static clearCache(): void;
641
657
  /**
@@ -730,6 +746,7 @@ declare class PMF {
730
746
  static mixN(weights: [number, PMF][]): PMF;
731
747
  private setPreservedProvidence;
732
748
  preservedProvidence(): boolean;
749
+ private getPowerCacheKey;
733
750
  /**
734
751
  * Efficiently computes this PMF convolved with itself `n` times.
735
752
  * Uses exponentiation by squaring to reduce total convolutions.
@@ -741,7 +758,7 @@ declare class PMF {
741
758
  * If you want to query any atLeast probabilities, you should use the DiceQuery class instead without power().
742
759
  */
743
760
  power(n: number, eps?: number): PMF;
744
- replicate(n: number, eps?: number): PMF[];
761
+ replicate(n: number): PMF[];
745
762
  mass(): number;
746
763
  outcomeMass(outcome: string): number;
747
764
  faceTotal(): number;
@@ -864,7 +881,6 @@ declare class PMF {
864
881
  };
865
882
  query(): DiceQuery;
866
883
  }
867
- declare function getPowerCacheKey(base: PMF, n: number, eps: number): string;
868
884
 
869
885
  /**
870
886
  * @internal
@@ -925,23 +941,6 @@ declare class Dice {
925
941
  }
926
942
  type _DiceInternal = never;
927
943
 
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>;
943
- }
944
-
945
944
  /** Enable or disable the internal parse cache. */
946
945
  declare function setCachingEnabled(enabled: boolean): void;
947
946
  /** Returns whether the internal parse cache is currently enabled. */
@@ -955,4 +954,4 @@ declare function clearParserCache(): void;
955
954
  */
956
955
  declare function parse(expression: string, n?: number): PMF;
957
956
 
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 };
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 };
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. */
@@ -572,7 +587,7 @@ declare class DiceQuery {
572
587
  * const bonusAttack = parse("(d20 + 3 AC 15) * (1d6 + 1)");
573
588
  * const bothAttacks = mainAttack.convolve(bonusAttack);
574
589
  */
575
- convolve(other: DiceQuery, eps?: number): DiceQuery;
590
+ convolve(other: DiceQuery): DiceQuery;
576
591
  /**
577
592
  * First-success split over an ordered list of DISTINCT single-swing PMFs.
578
593
  * Each PMF may have different success/subset probabilities (from labels).
@@ -604,6 +619,7 @@ 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
625
  *
@@ -635,7 +651,7 @@ declare class PMF {
635
651
  constructor(map?: Map<number, Bin>, epsilon?: number, normalized?: boolean, identifier?: string, _preservedProvidence?: boolean);
636
652
  static empty(epsilon?: number, identifier?: string): PMF;
637
653
  static zero(epsilon?: number): PMF;
638
- static emptyMass(epsilon?: number): PMF;
654
+ static emptyMass(): PMF;
639
655
  [Symbol.iterator](): IterableIterator<[number, Bin]>;
640
656
  static clearCache(): void;
641
657
  /**
@@ -730,6 +746,7 @@ declare class PMF {
730
746
  static mixN(weights: [number, PMF][]): PMF;
731
747
  private setPreservedProvidence;
732
748
  preservedProvidence(): boolean;
749
+ private getPowerCacheKey;
733
750
  /**
734
751
  * Efficiently computes this PMF convolved with itself `n` times.
735
752
  * Uses exponentiation by squaring to reduce total convolutions.
@@ -741,7 +758,7 @@ declare class PMF {
741
758
  * If you want to query any atLeast probabilities, you should use the DiceQuery class instead without power().
742
759
  */
743
760
  power(n: number, eps?: number): PMF;
744
- replicate(n: number, eps?: number): PMF[];
761
+ replicate(n: number): PMF[];
745
762
  mass(): number;
746
763
  outcomeMass(outcome: string): number;
747
764
  faceTotal(): number;
@@ -864,7 +881,6 @@ declare class PMF {
864
881
  };
865
882
  query(): DiceQuery;
866
883
  }
867
- declare function getPowerCacheKey(base: PMF, n: number, eps: number): string;
868
884
 
869
885
  /**
870
886
  * @internal
@@ -925,23 +941,6 @@ declare class Dice {
925
941
  }
926
942
  type _DiceInternal = never;
927
943
 
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>;
943
- }
944
-
945
944
  /** Enable or disable the internal parse cache. */
946
945
  declare function setCachingEnabled(enabled: boolean): void;
947
946
  /** Returns whether the internal parse cache is currently enabled. */
@@ -955,4 +954,4 @@ declare function clearParserCache(): void;
955
954
  */
956
955
  declare function parse(expression: string, n?: number): PMF;
957
956
 
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 };
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 };
package/dist/index.js CHANGED
@@ -1,8 +1,12 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+
1
5
  // src/lru-cache.ts
2
6
  var LRUCache = class {
3
7
  constructor(maxSize = 1e3) {
4
8
  this.maxSize = maxSize;
5
- this.cache = /* @__PURE__ */ new Map();
9
+ __publicField(this, "cache", /* @__PURE__ */ new Map());
6
10
  }
7
11
  get(key) {
8
12
  const value = this.cache.get(key);
@@ -41,12 +45,13 @@ var LRUCache = class {
41
45
  };
42
46
 
43
47
  // src/types.ts
44
- var COMPUTATIONAL_EPS = 1e-40;
45
- var TEST_EPS = 1e-10;
48
+ var EPS = 1e-12;
46
49
 
47
50
  // src/query.ts
48
51
  var _DiceQuery = class _DiceQuery {
49
52
  constructor(singles, combined) {
53
+ __publicField(this, "singles");
54
+ __publicField(this, "combined");
50
55
  this.singles = Array.isArray(singles) ? singles : [singles];
51
56
  const c = combined ?? PMF.convolveMany(this.singles);
52
57
  this.combined = Math.abs(c.mass() - 1) <= 1e-12 ? c : c.normalize();
@@ -993,7 +998,7 @@ var _DiceQuery = class _DiceQuery {
993
998
  outcomeTotals(outcomes = this.outcomeKeys()) {
994
999
  const totals = /* @__PURE__ */ new Map();
995
1000
  outcomes.forEach((o) => totals.set(o, 0));
996
- for (const [x, row] of this.combined.map) {
1001
+ for (const [, row] of this.combined.map) {
997
1002
  for (const o of outcomes) {
998
1003
  const p = row.count[o] || 0;
999
1004
  totals.set(o, (totals.get(o) || 0) + p);
@@ -1208,7 +1213,7 @@ var _DiceQuery = class _DiceQuery {
1208
1213
  * const bonusAttack = parse("(d20 + 3 AC 15) * (1d6 + 1)");
1209
1214
  * const bothAttacks = mainAttack.convolve(bonusAttack);
1210
1215
  */
1211
- convolve(other, eps) {
1216
+ convolve(other) {
1212
1217
  const singles = [...this.singles, ...other.singles];
1213
1218
  return new _DiceQuery(singles);
1214
1219
  }
@@ -1221,7 +1226,7 @@ var _DiceQuery = class _DiceQuery {
1221
1226
  *
1222
1227
  * Returns tuple: [pFirstNonSubset, pFirstSubset, pAnySuccess, pNone]
1223
1228
  */
1224
- firstSuccessSplit(successOutcome, subsetOutcome, eps = COMPUTATIONAL_EPS) {
1229
+ firstSuccessSplit(successOutcome, subsetOutcome, eps = EPS) {
1225
1230
  const pmfs = this.singles;
1226
1231
  if (!pmfs.length) {
1227
1232
  throw new Error("firstSuccessSplitFromPMFs: pmfs must be non-empty");
@@ -1264,33 +1269,40 @@ var _DiceQuery = class _DiceQuery {
1264
1269
  return [a, b, any, none];
1265
1270
  }
1266
1271
  };
1267
- _DiceQuery.DEFAULT_OUTCOMES = [
1272
+ __publicField(_DiceQuery, "DEFAULT_OUTCOMES", [
1268
1273
  "hit",
1269
1274
  "crit",
1270
1275
  "missNone"
1271
- ];
1276
+ ]);
1272
1277
  var DiceQuery = _DiceQuery;
1273
- var EPSILON = COMPUTATIONAL_EPS;
1274
1278
  var pmfCache = new LRUCache(1e3);
1275
1279
  var _PMF = class _PMF {
1276
- constructor(map = /* @__PURE__ */ new Map(), epsilon = EPSILON, normalized = false, identifier = `anon#${_PMF.__anonIdCounter++}`, _preservedProvidence = true) {
1280
+ constructor(map = /* @__PURE__ */ new Map(), epsilon = EPS, normalized = false, identifier = `anon#${_PMF.__anonIdCounter++}`, _preservedProvidence = true) {
1277
1281
  this.map = map;
1278
1282
  this.epsilon = epsilon;
1279
1283
  this.normalized = normalized;
1280
1284
  this.identifier = identifier;
1281
1285
  this._preservedProvidence = _preservedProvidence;
1282
- }
1283
- static empty(epsilon = EPSILON, identifier = "empty") {
1286
+ // Cached computed values
1287
+ __publicField(this, "_support");
1288
+ __publicField(this, "_min");
1289
+ __publicField(this, "_max");
1290
+ __publicField(this, "_totalMass");
1291
+ __publicField(this, "_mean");
1292
+ __publicField(this, "_variance");
1293
+ __publicField(this, "_stdev");
1294
+ }
1295
+ static empty(epsilon = EPS, identifier = "empty") {
1284
1296
  return new _PMF(/* @__PURE__ */ new Map(), epsilon, false, identifier);
1285
1297
  }
1286
1298
  // This has a single bin at value 0, mass of 1
1287
- static zero(epsilon = EPSILON) {
1299
+ static zero(epsilon = EPS) {
1288
1300
  const m = /* @__PURE__ */ new Map();
1289
1301
  m.set(0, { p: 1, count: { miss: 1 }, attr: {} });
1290
1302
  return new _PMF(m, epsilon, false, "zero");
1291
1303
  }
1292
1304
  // This creates a single bin at value 0, but with weight 0.
1293
- static emptyMass(epsilon = EPSILON) {
1305
+ static emptyMass() {
1294
1306
  return _PMF.zero().scaleMass(0);
1295
1307
  }
1296
1308
  // Makes PMF iterable over [damage, bin] pairs.
@@ -1456,6 +1468,12 @@ var _PMF = class _PMF {
1456
1468
  preservedProvidence() {
1457
1469
  return this._preservedProvidence;
1458
1470
  }
1471
+ getPowerCacheKey(n, eps) {
1472
+ const id = this.identifier;
1473
+ let key = `${id}`;
1474
+ for (let i = 1; i < n; i++) key += `+${id}`;
1475
+ return `${key}@${eps}`;
1476
+ }
1459
1477
  /**
1460
1478
  * Efficiently computes this PMF convolved with itself `n` times.
1461
1479
  * Uses exponentiation by squaring to reduce total convolutions.
@@ -1472,7 +1490,7 @@ var _PMF = class _PMF {
1472
1490
  }
1473
1491
  if (n === 1) return this;
1474
1492
  const epsilon = eps ?? this.epsilon;
1475
- const key = getPowerCacheKey(this, n, epsilon);
1493
+ const key = this.getPowerCacheKey(n, epsilon);
1476
1494
  {
1477
1495
  const cached = pmfCache?.get(key);
1478
1496
  if (cached) return cached;
@@ -1498,7 +1516,7 @@ var _PMF = class _PMF {
1498
1516
  /*
1499
1517
  * Helper for chaining multiple identical attacks
1500
1518
  */
1501
- replicate(n, eps = this.epsilon) {
1519
+ replicate(n) {
1502
1520
  if (!Number.isInteger(n) || n <= 0) {
1503
1521
  throw new Error("combineN(n): n must be a positive integer");
1504
1522
  }
@@ -1871,7 +1889,7 @@ var _PMF = class _PMF {
1871
1889
  * - Similar PMF lists share common prefixes (A+B, (A+B)+C, etc.)
1872
1890
  * - Order-independent cache keys work better with consistent build patterns
1873
1891
  */
1874
- static convolveMany(pmfList, eps = EPSILON) {
1892
+ static convolveMany(pmfList, eps = EPS) {
1875
1893
  if (pmfList.length === 0) return _PMF.empty(eps);
1876
1894
  if (pmfList.length === 1) return pmfList[0];
1877
1895
  return _PMF.reduceConvolveLeft(pmfList, eps);
@@ -1886,7 +1904,7 @@ var _PMF = class _PMF {
1886
1904
  static fromJSON(jsonData) {
1887
1905
  return new _PMF(
1888
1906
  new Map(jsonData.bins),
1889
- EPSILON,
1907
+ EPS,
1890
1908
  !!jsonData.normalized,
1891
1909
  jsonData.identifier || "fromJSON"
1892
1910
  );
@@ -2096,22 +2114,17 @@ var _PMF = class _PMF {
2096
2114
  }
2097
2115
  };
2098
2116
  // Unique ID generator for anonymous PMFs to avoid cache key collisions
2099
- _PMF.__anonIdCounter = 1;
2117
+ __publicField(_PMF, "__anonIdCounter", 1);
2100
2118
  var PMF = _PMF;
2101
- function getPowerCacheKey(base, n, eps) {
2102
- const id = base.identifier;
2103
- let key = `${id}`;
2104
- for (let i = 1; i < n; i++) key += `+${id}`;
2105
- return `${key}@${eps}`;
2106
- }
2107
2119
 
2108
2120
  // src/dice.ts
2109
2121
  var Dice = class _Dice {
2110
2122
  constructor(x = 0) {
2111
- this.faces = {};
2112
- this.privateData = {};
2113
- this.outcomeData = {};
2114
- this.hasHitDistributionCalculated = false;
2123
+ __publicField(this, "faces", {});
2124
+ __publicField(this, "privateData", {});
2125
+ __publicField(this, "outcomeData", {});
2126
+ __publicField(this, "hasHitDistributionCalculated", false);
2127
+ __publicField(this, "identifier");
2115
2128
  if (x <= 0) return;
2116
2129
  for (let i = 1; i <= x; i++) {
2117
2130
  this.faces[i] = 1;
@@ -2418,7 +2431,7 @@ var Dice = class _Dice {
2418
2431
  * Convert dice to PMF using OutcomeType labels directly from damage distribution.
2419
2432
  * This is much cleaner than the original complex distribution conversion.
2420
2433
  */
2421
- toPMF(numEpsilon = COMPUTATIONAL_EPS) {
2434
+ toPMF(numEpsilon = EPS) {
2422
2435
  const total = this.total();
2423
2436
  if (total === 0) return PMF.empty(numEpsilon);
2424
2437
  this.ensureHitDistribution();
@@ -2780,20 +2793,12 @@ function parseArgumentInternal(s, n) {
2780
2793
  case "k":
2781
2794
  assertToken(s, "k");
2782
2795
  return parseKeep(s, n);
2783
- case "0":
2784
- case "1":
2785
- case "2":
2786
- case "3":
2787
- case "4":
2788
- case "5":
2789
- case "6":
2790
- case "7":
2791
- case "8":
2792
- case "9":
2793
2796
  case "n":
2794
2797
  return parseNumber(s, n);
2798
+ default:
2799
+ if (isDigit(c)) return parseNumber(s, n);
2800
+ return;
2795
2801
  }
2796
- return;
2797
2802
  }
2798
2803
  function parseBinaryArgument(arg, arr, n) {
2799
2804
  if (arr.length >= 4 && arr[0] === "h" && peek(arr, "half")) {
@@ -2939,6 +2944,6 @@ function parseOperation(s) {
2939
2944
  return;
2940
2945
  }
2941
2946
 
2942
- export { COMPUTATIONAL_EPS, Dice, DiceQuery, LRUCache, PMF, TEST_EPS, clearParserCache, getCachingEnabled, getPowerCacheKey, parse, setCachingEnabled };
2947
+ export { Dice, DiceQuery, EPS, LRUCache, PMF, clearParserCache, getCachingEnabled, parse, pmfCache, setCachingEnabled };
2943
2948
  //# sourceMappingURL=index.js.map
2944
2949
  //# sourceMappingURL=index.js.map