@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/README.md +0 -2
- package/dist/index.cjs +232 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -76
- package/dist/index.d.ts +52 -76
- package/dist/index.js +232 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -49,15 +49,15 @@ var EPS = 1e-12;
|
|
|
49
49
|
|
|
50
50
|
// src/query.ts
|
|
51
51
|
var _DiceQuery = class _DiceQuery {
|
|
52
|
-
constructor(singles, combined) {
|
|
52
|
+
constructor(singles, combined, eps = EPS) {
|
|
53
53
|
__publicField(this, "singles");
|
|
54
54
|
__publicField(this, "combined");
|
|
55
55
|
this.singles = Array.isArray(singles) ? singles : [singles];
|
|
56
|
-
const c = combined ?? PMF.convolveMany(this.singles);
|
|
57
|
-
this.combined = Math.abs(c.mass() - 1) <= 1e-12 ? c : c.normalize();
|
|
58
56
|
if (this.singles.some((s) => s === void 0)) {
|
|
59
57
|
throw new Error("DiceQuery contains undefined singles");
|
|
60
58
|
}
|
|
59
|
+
const c = combined ?? PMF.convolveMany(this.singles);
|
|
60
|
+
this.combined = Math.abs(c.mass() - 1) <= eps ? c : c.normalize();
|
|
61
61
|
}
|
|
62
62
|
/**
|
|
63
63
|
* Returns the expected damage across all possible outcomes.
|
|
@@ -355,23 +355,16 @@ var _DiceQuery = class _DiceQuery {
|
|
|
355
355
|
* - "How much damage comes from miss effects (like save-for-half spells)?"
|
|
356
356
|
*/
|
|
357
357
|
expectedDamageFrom(labels) {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
358
|
+
const wanted = Array.isArray(labels) ? labels : [labels];
|
|
359
|
+
let total = 0;
|
|
360
|
+
for (const single of this.singles) {
|
|
361
|
+
for (const [dmg, bin] of single) {
|
|
362
|
+
let p = 0;
|
|
363
|
+
for (const label of wanted) p += bin.count[label] ?? 0;
|
|
364
|
+
total += dmg * p;
|
|
365
365
|
}
|
|
366
366
|
}
|
|
367
|
-
return
|
|
368
|
-
}
|
|
369
|
-
_expectedDamageFromSingle(label) {
|
|
370
|
-
let totalExpectedDamage = 0;
|
|
371
|
-
for (const [, probabilityBin] of this.combined) {
|
|
372
|
-
totalExpectedDamage += probabilityBin.attr?.[label] || 0;
|
|
373
|
-
}
|
|
374
|
-
return totalExpectedDamage;
|
|
367
|
+
return total;
|
|
375
368
|
}
|
|
376
369
|
/**
|
|
377
370
|
* Returns damage statistics for scenarios where AT LEAST ONE attack results in
|
|
@@ -594,7 +587,7 @@ var _DiceQuery = class _DiceQuery {
|
|
|
594
587
|
* query.toStackedChartData(['hit', 'crit'])
|
|
595
588
|
* // → {labels: [0, 6, 12, ...], datasets: [{label: 'hit', data: [0, 0.03, ...]}, ...]}
|
|
596
589
|
*/
|
|
597
|
-
toStackedChartData(labels = [], epsilon =
|
|
590
|
+
toStackedChartData(labels = [], epsilon = EPS) {
|
|
598
591
|
const damageValues = this.combined.support();
|
|
599
592
|
damageValues.map((dmg) => {
|
|
600
593
|
const bin = this.combined.map.get(dmg);
|
|
@@ -1277,12 +1270,12 @@ __publicField(_DiceQuery, "DEFAULT_OUTCOMES", [
|
|
|
1277
1270
|
var DiceQuery = _DiceQuery;
|
|
1278
1271
|
var pmfCache = new LRUCache(1e3);
|
|
1279
1272
|
var _PMF = class _PMF {
|
|
1280
|
-
constructor(map = /* @__PURE__ */ new Map(), epsilon = EPS, normalized = false, identifier = `anon#${_PMF.__anonIdCounter++}`,
|
|
1273
|
+
constructor(map = /* @__PURE__ */ new Map(), epsilon = EPS, normalized = false, identifier = `anon#${_PMF.__anonIdCounter++}`, _preservedProvenance = true) {
|
|
1281
1274
|
this.map = map;
|
|
1282
1275
|
this.epsilon = epsilon;
|
|
1283
1276
|
this.normalized = normalized;
|
|
1284
1277
|
this.identifier = identifier;
|
|
1285
|
-
this.
|
|
1278
|
+
this._preservedProvenance = _preservedProvenance;
|
|
1286
1279
|
// Cached computed values
|
|
1287
1280
|
__publicField(this, "_support");
|
|
1288
1281
|
__publicField(this, "_min");
|
|
@@ -1301,6 +1294,9 @@ var _PMF = class _PMF {
|
|
|
1301
1294
|
m.set(0, { p: 1, count: { miss: 1 }, attr: {} });
|
|
1302
1295
|
return new _PMF(m, epsilon, false, "zero");
|
|
1303
1296
|
}
|
|
1297
|
+
static delta(value, epsilon = EPS) {
|
|
1298
|
+
return _PMF.fromMap(/* @__PURE__ */ new Map([[value, 1]]), epsilon);
|
|
1299
|
+
}
|
|
1304
1300
|
// This creates a single bin at value 0, but with weight 0.
|
|
1305
1301
|
static emptyMass() {
|
|
1306
1302
|
return _PMF.zero().scaleMass(0);
|
|
@@ -1403,7 +1399,7 @@ var _PMF = class _PMF {
|
|
|
1403
1399
|
* @param eps Optional tolerance for floating point rounding
|
|
1404
1400
|
* @returns A single PMF representing the exclusive mixture of all options.
|
|
1405
1401
|
*/
|
|
1406
|
-
static exclusive(options, eps =
|
|
1402
|
+
static exclusive(options, eps = EPS) {
|
|
1407
1403
|
const items = options.map(
|
|
1408
1404
|
(o) => Array.isArray(o) ? { pmf: o[0], weight: o[1] } : o
|
|
1409
1405
|
);
|
|
@@ -1433,8 +1429,7 @@ var _PMF = class _PMF {
|
|
|
1433
1429
|
* [pCrit, critPMF],
|
|
1434
1430
|
* ]);
|
|
1435
1431
|
*/
|
|
1436
|
-
static mixN(weights) {
|
|
1437
|
-
const eps = 1e-12;
|
|
1432
|
+
static mixN(weights, eps = EPS) {
|
|
1438
1433
|
const filtered = weights.filter(([w]) => w > eps);
|
|
1439
1434
|
if (filtered.length === 0) {
|
|
1440
1435
|
return _PMF.emptyMass();
|
|
@@ -1456,17 +1451,17 @@ var _PMF = class _PMF {
|
|
|
1456
1451
|
// This is a convenience method for when we use power
|
|
1457
1452
|
// TODO: It can be smarter in the future, and we can also add it to query
|
|
1458
1453
|
// That way statistics operations on invalid PMFs can throw an error
|
|
1459
|
-
// TODO… how can we detect if manually merging two queries' combined PMFs, as that loses
|
|
1460
|
-
|
|
1461
|
-
if (!this.
|
|
1454
|
+
// TODO… how can we detect if manually merging two queries' combined PMFs, as that loses provenance?
|
|
1455
|
+
setPreservedProvenance(preserved) {
|
|
1456
|
+
if (!this._preservedProvenance && preserved) {
|
|
1462
1457
|
throw new Error(
|
|
1463
|
-
"Preserved
|
|
1458
|
+
"Preserved provenance is already set to false, cannot fix that"
|
|
1464
1459
|
);
|
|
1465
1460
|
}
|
|
1466
|
-
this.
|
|
1461
|
+
this._preservedProvenance = preserved;
|
|
1467
1462
|
}
|
|
1468
|
-
|
|
1469
|
-
return this.
|
|
1463
|
+
preservedProvenance() {
|
|
1464
|
+
return this._preservedProvenance;
|
|
1470
1465
|
}
|
|
1471
1466
|
getPowerCacheKey(n, eps) {
|
|
1472
1467
|
const id = this.identifier;
|
|
@@ -1507,7 +1502,7 @@ var _PMF = class _PMF {
|
|
|
1507
1502
|
base = base.convolve(base, epsilon);
|
|
1508
1503
|
}
|
|
1509
1504
|
}
|
|
1510
|
-
result.
|
|
1505
|
+
result.setPreservedProvenance(false);
|
|
1511
1506
|
{
|
|
1512
1507
|
pmfCache?.set(key, result);
|
|
1513
1508
|
}
|
|
@@ -1536,7 +1531,7 @@ var _PMF = class _PMF {
|
|
|
1536
1531
|
outcomeMass(outcome) {
|
|
1537
1532
|
let totalProbabilityMass = 0;
|
|
1538
1533
|
for (const { p, count } of this.map.values()) {
|
|
1539
|
-
totalProbabilityMass += p * count[outcome];
|
|
1534
|
+
totalProbabilityMass += p * (count[outcome] ?? 0);
|
|
1540
1535
|
}
|
|
1541
1536
|
return totalProbabilityMass;
|
|
1542
1537
|
}
|
|
@@ -1799,7 +1794,7 @@ var _PMF = class _PMF {
|
|
|
1799
1794
|
}
|
|
1800
1795
|
convolve(other, eps, raw = false) {
|
|
1801
1796
|
const epsilon = eps ?? this.epsilon;
|
|
1802
|
-
const norm = (x) => raw ? x : Math.abs(x.mass() - 1) <=
|
|
1797
|
+
const norm = (x) => raw ? x : Math.abs(x.mass() - 1) <= epsilon ? x : x.normalize();
|
|
1803
1798
|
const A0 = norm(this);
|
|
1804
1799
|
const B0 = norm(other);
|
|
1805
1800
|
const [A, B] = A0.identifier <= B0.identifier ? [A0, B0] : [B0, A0];
|
|
@@ -1834,14 +1829,13 @@ var _PMF = class _PMF {
|
|
|
1834
1829
|
epsilon,
|
|
1835
1830
|
!raw,
|
|
1836
1831
|
`${A.identifier}${raw ? "*" : "+"}${B.identifier}`
|
|
1837
|
-
// ← canonical order
|
|
1838
1832
|
);
|
|
1839
1833
|
const mExp = (raw ? A.mass() : 1) * (raw ? B.mass() : 1);
|
|
1840
1834
|
const mGot = result.mass();
|
|
1841
|
-
if (mExp !== 0 && Math.abs(mGot - mExp) >
|
|
1835
|
+
if (mExp !== 0 && Math.abs(mGot - mExp) > epsilon) {
|
|
1842
1836
|
result = result.scaleMass(mExp / mGot);
|
|
1843
1837
|
}
|
|
1844
|
-
if (!raw && Math.abs(result.mass() - 1) >
|
|
1838
|
+
if (!raw && Math.abs(result.mass() - 1) > epsilon)
|
|
1845
1839
|
result = result.normalize();
|
|
1846
1840
|
pmfCache?.set(cacheKey, result);
|
|
1847
1841
|
return result;
|
|
@@ -2050,6 +2044,21 @@ var _PMF = class _PMF {
|
|
|
2050
2044
|
}
|
|
2051
2045
|
return false;
|
|
2052
2046
|
}
|
|
2047
|
+
tailProbGE(t) {
|
|
2048
|
+
let s = 0;
|
|
2049
|
+
for (const [x, rec] of this) {
|
|
2050
|
+
const p = typeof rec === "number" ? rec : rec.p;
|
|
2051
|
+
if (p > 0 && x >= t) s += p;
|
|
2052
|
+
}
|
|
2053
|
+
return s;
|
|
2054
|
+
}
|
|
2055
|
+
tailProbGT(t) {
|
|
2056
|
+
let s = 0;
|
|
2057
|
+
for (const [x, rec] of this) {
|
|
2058
|
+
if (x > t) s += rec.p;
|
|
2059
|
+
}
|
|
2060
|
+
return s;
|
|
2061
|
+
}
|
|
2053
2062
|
/**
|
|
2054
2063
|
* Returns a new PMF containing only bins where the specified outcome has non-zero probability.
|
|
2055
2064
|
* This creates a marginal distribution for the given outcome type, with probabilities
|
|
@@ -2109,6 +2118,66 @@ var _PMF = class _PMF {
|
|
|
2109
2118
|
const pNone = 1 - pSpecificSuccess - pGeneralSuccess;
|
|
2110
2119
|
return { pSpecificSuccess, pGeneralSuccess, pNone, pAny };
|
|
2111
2120
|
}
|
|
2121
|
+
mapValues(f, eps = EPS, opts) {
|
|
2122
|
+
const rounding = opts?.rounding ?? "none";
|
|
2123
|
+
const preserveCounts = opts?.preserveCounts ?? true;
|
|
2124
|
+
const round = (x) => rounding === "floor" ? Math.floor(x) : rounding === "ceil" ? Math.ceil(x) : rounding === "round" ? Math.round(x) : x;
|
|
2125
|
+
const probs = /* @__PURE__ */ new Map();
|
|
2126
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2127
|
+
for (const [v, rec] of this) {
|
|
2128
|
+
if (Math.abs(rec.p) < eps) continue;
|
|
2129
|
+
const u = round(f(v));
|
|
2130
|
+
probs.set(u, (probs.get(u) ?? 0) + rec.p);
|
|
2131
|
+
if (preserveCounts) {
|
|
2132
|
+
const rec2 = this.map.get(v);
|
|
2133
|
+
const src = typeof rec2 === "number" ? void 0 : rec2?.count;
|
|
2134
|
+
if (src) {
|
|
2135
|
+
const dest = counts.get(u) ?? {};
|
|
2136
|
+
for (const k in src) {
|
|
2137
|
+
dest[k] = (dest[k] ?? 0) + src[k];
|
|
2138
|
+
}
|
|
2139
|
+
counts.set(u, dest);
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
const internal = /* @__PURE__ */ new Map();
|
|
2144
|
+
for (const [u, p] of probs) {
|
|
2145
|
+
internal.set(u, { p, count: counts.get(u) ?? {} });
|
|
2146
|
+
}
|
|
2147
|
+
return _PMF.fromMap(
|
|
2148
|
+
new Map(Array.from(internal, ([u, b]) => [u, b.p])),
|
|
2149
|
+
eps
|
|
2150
|
+
);
|
|
2151
|
+
}
|
|
2152
|
+
static fromMap(m, eps = EPS, { requireIntegerValues = true } = {}) {
|
|
2153
|
+
const filtered = [];
|
|
2154
|
+
for (const [v, p] of m) {
|
|
2155
|
+
if (!Number.isFinite(v) || !Number.isFinite(p)) continue;
|
|
2156
|
+
if (p <= 0 || Math.abs(p) < eps) continue;
|
|
2157
|
+
if (requireIntegerValues && !Number.isInteger(v)) {
|
|
2158
|
+
throw new Error(`fromMap: non-integer outcome ${v}`);
|
|
2159
|
+
}
|
|
2160
|
+
filtered.push([v, p]);
|
|
2161
|
+
}
|
|
2162
|
+
if (filtered.length === 0) {
|
|
2163
|
+
throw new Error("fromMap: empty or invalid input map");
|
|
2164
|
+
}
|
|
2165
|
+
let sum = 0;
|
|
2166
|
+
let c = 0;
|
|
2167
|
+
for (const [, p] of filtered) {
|
|
2168
|
+
const y = p - c;
|
|
2169
|
+
const t = sum + y;
|
|
2170
|
+
c = t - sum - y;
|
|
2171
|
+
sum = t;
|
|
2172
|
+
}
|
|
2173
|
+
if (sum <= 0) throw new Error("pmfFromMap: probabilities sum to 0");
|
|
2174
|
+
filtered.sort((a, b) => a[0] - b[0]);
|
|
2175
|
+
const internal = /* @__PURE__ */ new Map();
|
|
2176
|
+
for (const [v, p] of filtered) {
|
|
2177
|
+
internal.set(v, { p: p / sum, count: {} });
|
|
2178
|
+
}
|
|
2179
|
+
return new _PMF(internal, eps);
|
|
2180
|
+
}
|
|
2112
2181
|
query() {
|
|
2113
2182
|
return new DiceQuery(this);
|
|
2114
2183
|
}
|
|
@@ -2117,6 +2186,127 @@ var _PMF = class _PMF {
|
|
|
2117
2186
|
__publicField(_PMF, "__anonIdCounter", 1);
|
|
2118
2187
|
var PMF = _PMF;
|
|
2119
2188
|
|
|
2189
|
+
// src/mixture.ts
|
|
2190
|
+
var Mixture = class _Mixture {
|
|
2191
|
+
constructor(eps = EPS) {
|
|
2192
|
+
__publicField(this, "totals", /* @__PURE__ */ new Map());
|
|
2193
|
+
// raw mass per outcome (pre-normalization)
|
|
2194
|
+
__publicField(this, "labelMass", /* @__PURE__ */ new Map());
|
|
2195
|
+
// raw mass per outcome per label
|
|
2196
|
+
__publicField(this, "eps");
|
|
2197
|
+
this.eps = Number.isFinite(eps) ? eps : EPS;
|
|
2198
|
+
}
|
|
2199
|
+
/** Remove all accumulated state. */
|
|
2200
|
+
clear() {
|
|
2201
|
+
this.totals.clear();
|
|
2202
|
+
this.labelMass.clear();
|
|
2203
|
+
return this;
|
|
2204
|
+
}
|
|
2205
|
+
/** Number of distinct outcome values currently accumulated. */
|
|
2206
|
+
size() {
|
|
2207
|
+
return this.totals.size;
|
|
2208
|
+
}
|
|
2209
|
+
/** Whether a label was ever added. */
|
|
2210
|
+
hasLabel(label) {
|
|
2211
|
+
for (const bag of this.labelMass.values()) if (bag[label]) return true;
|
|
2212
|
+
return false;
|
|
2213
|
+
}
|
|
2214
|
+
/**
|
|
2215
|
+
* Add a labeled component with a mixture weight.
|
|
2216
|
+
* Weight can be any positive finite number. Very small contributions are pruned by eps.
|
|
2217
|
+
*/
|
|
2218
|
+
add(label, pmf, weight = 1) {
|
|
2219
|
+
if (!Number.isFinite(weight) || weight <= 0) return this;
|
|
2220
|
+
for (const [v, binOrNumber] of pmf) {
|
|
2221
|
+
const isNumber = typeof binOrNumber === "number";
|
|
2222
|
+
const p = isNumber ? binOrNumber : binOrNumber?.p ?? 0;
|
|
2223
|
+
if (p <= 0) continue;
|
|
2224
|
+
const add = weight * p;
|
|
2225
|
+
if (!Number.isFinite(add) || Math.abs(add) < this.eps) continue;
|
|
2226
|
+
this.totals.set(v, (this.totals.get(v) ?? 0) + add);
|
|
2227
|
+
const bag = this.labelMass.get(v) ?? {};
|
|
2228
|
+
bag[label] = (bag[label] ?? 0) + add;
|
|
2229
|
+
this.labelMass.set(v, bag);
|
|
2230
|
+
}
|
|
2231
|
+
return this;
|
|
2232
|
+
}
|
|
2233
|
+
buildPMF(eps = EPS) {
|
|
2234
|
+
let grand = 0;
|
|
2235
|
+
let c = 0;
|
|
2236
|
+
for (const m of this.totals.values()) {
|
|
2237
|
+
const y = m - c;
|
|
2238
|
+
const t = grand + y;
|
|
2239
|
+
c = t - grand - y;
|
|
2240
|
+
grand = t;
|
|
2241
|
+
}
|
|
2242
|
+
if (!(grand > 0)) throw new Error("LabeledMixture: zero total mass");
|
|
2243
|
+
const internal = /* @__PURE__ */ new Map();
|
|
2244
|
+
for (const [v, m] of this.totals) {
|
|
2245
|
+
if (m <= 0 || Math.abs(m) < this.eps) continue;
|
|
2246
|
+
const count = this.labelMass.get(v) ?? {};
|
|
2247
|
+
internal.set(v, { p: m / grand, count });
|
|
2248
|
+
}
|
|
2249
|
+
return new PMF(internal, eps);
|
|
2250
|
+
}
|
|
2251
|
+
/**
|
|
2252
|
+
* Produce normalized *per-label* PMFs (labels independent).
|
|
2253
|
+
* These are unlabeled PMFs built from the raw mass of that label alone.
|
|
2254
|
+
*/
|
|
2255
|
+
byOutcome() {
|
|
2256
|
+
const labels = /* @__PURE__ */ new Set();
|
|
2257
|
+
for (const bag of this.labelMass.values()) {
|
|
2258
|
+
for (const k of Object.keys(bag)) labels.add(k);
|
|
2259
|
+
}
|
|
2260
|
+
const out = {};
|
|
2261
|
+
for (const label of labels) {
|
|
2262
|
+
const m = /* @__PURE__ */ new Map();
|
|
2263
|
+
for (const [v, bag] of this.labelMass) {
|
|
2264
|
+
const w = bag[label];
|
|
2265
|
+
if (w && Math.abs(w) >= this.eps) m.set(v, w);
|
|
2266
|
+
}
|
|
2267
|
+
if (m.size > 0) out[label] = PMF.fromMap(m, this.eps);
|
|
2268
|
+
}
|
|
2269
|
+
return out;
|
|
2270
|
+
}
|
|
2271
|
+
/**
|
|
2272
|
+
* Mixture weights per label, normalized to sum to 1 over labels that appeared.
|
|
2273
|
+
* Uses raw mass before per-outcome normalization.
|
|
2274
|
+
*/
|
|
2275
|
+
weights() {
|
|
2276
|
+
const res = {};
|
|
2277
|
+
for (const [, bag] of this.labelMass) {
|
|
2278
|
+
for (const [lab, w] of Object.entries(bag)) {
|
|
2279
|
+
if (!Number.isFinite(w) || w <= 0) continue;
|
|
2280
|
+
res[lab] = (res[lab] ?? 0) + w;
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
let total = 0;
|
|
2284
|
+
let c = 0;
|
|
2285
|
+
for (const v of Object.values(res)) {
|
|
2286
|
+
const y = v - c;
|
|
2287
|
+
const t = total + y;
|
|
2288
|
+
c = t - total - y;
|
|
2289
|
+
total = t;
|
|
2290
|
+
}
|
|
2291
|
+
if (total > 0) {
|
|
2292
|
+
for (const k in res) res[k] = res[k] / total;
|
|
2293
|
+
}
|
|
2294
|
+
return res;
|
|
2295
|
+
}
|
|
2296
|
+
toJSON() {
|
|
2297
|
+
return {
|
|
2298
|
+
totals: Array.from(this.totals.entries()).sort((a, b) => a[0] - b[0]),
|
|
2299
|
+
labels: Array.from(this.labelMass.entries()).sort((a, b) => a[0] - b[0]),
|
|
2300
|
+
eps: this.eps
|
|
2301
|
+
};
|
|
2302
|
+
}
|
|
2303
|
+
static mix(items, eps = EPS) {
|
|
2304
|
+
const mix = new _Mixture(eps);
|
|
2305
|
+
for (const [lab, pmf, w] of items) mix.add(lab, pmf, w);
|
|
2306
|
+
return mix.buildPMF();
|
|
2307
|
+
}
|
|
2308
|
+
};
|
|
2309
|
+
|
|
2120
2310
|
// src/dice.ts
|
|
2121
2311
|
var Dice = class _Dice {
|
|
2122
2312
|
constructor(x = 0) {
|
|
@@ -2610,7 +2800,7 @@ function parseExpression(arr, n) {
|
|
|
2610
2800
|
}
|
|
2611
2801
|
critNorm = crit.total();
|
|
2612
2802
|
crit = op.call(crit, parseBinaryArgument(arg, arr, n));
|
|
2613
|
-
critNorm = critNorm ? crit.total() / critNorm : 1;
|
|
2803
|
+
critNorm = crit && critNorm ? crit.total() / critNorm : 1;
|
|
2614
2804
|
}
|
|
2615
2805
|
let save;
|
|
2616
2806
|
let saveNorm = 1;
|
|
@@ -2625,7 +2815,7 @@ function parseExpression(arr, n) {
|
|
|
2625
2815
|
saveNorm = save.total();
|
|
2626
2816
|
finalResult = finalResult.deleteFace(min);
|
|
2627
2817
|
save = op.call(save, parseBinaryArgument(arg, arr, n));
|
|
2628
|
-
saveNorm = saveNorm ? save.total() / saveNorm : 1;
|
|
2818
|
+
saveNorm = save && saveNorm ? save.total() / saveNorm : 1;
|
|
2629
2819
|
}
|
|
2630
2820
|
let pc;
|
|
2631
2821
|
let pcNorm = 1;
|
|
@@ -2638,7 +2828,7 @@ function parseExpression(arr, n) {
|
|
|
2638
2828
|
const missBefore = pc.total();
|
|
2639
2829
|
finalResult = finalResult.deleteFace(min);
|
|
2640
2830
|
pc = op.call(pc, parseBinaryArgument(arg, arr, n)).divideRoundDown(2);
|
|
2641
|
-
const missAfter = pc.total();
|
|
2831
|
+
const missAfter = pc ? pc.total() : 0;
|
|
2642
2832
|
pcNorm = missBefore ? missAfter / missBefore : 1;
|
|
2643
2833
|
}
|
|
2644
2834
|
let miss;
|
|
@@ -2654,7 +2844,7 @@ function parseExpression(arr, n) {
|
|
|
2654
2844
|
missNorm = miss.total();
|
|
2655
2845
|
finalResult = finalResult.deleteFace(min);
|
|
2656
2846
|
miss = op.call(miss, parseBinaryArgument(arg, arr, n));
|
|
2657
|
-
missNorm = missNorm ? miss.total() / missNorm : 1;
|
|
2847
|
+
missNorm = miss && missNorm ? miss.total() / missNorm : 1;
|
|
2658
2848
|
}
|
|
2659
2849
|
let norm = finalResult.total();
|
|
2660
2850
|
finalResult = op.call(finalResult, arg);
|
|
@@ -2944,6 +3134,6 @@ function parseOperation(s) {
|
|
|
2944
3134
|
return;
|
|
2945
3135
|
}
|
|
2946
3136
|
|
|
2947
|
-
export {
|
|
3137
|
+
export { DiceQuery, EPS, LRUCache, Mixture, PMF, clearParserCache, getCachingEnabled, parse, pmfCache, setCachingEnabled };
|
|
2948
3138
|
//# sourceMappingURL=index.js.map
|
|
2949
3139
|
//# sourceMappingURL=index.js.map
|