@yipe/dice 0.1.0 → 0.1.1

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 CHANGED
@@ -1,15 +1,23 @@
1
- <!-- [![npm version](https://img.shields.io/npm/v/@dpr/dice.svg)](https://www.npmjs.com/package/@dpr/dice)
2
- [![Build Status](https://github.com/yipe/dpr/actions/workflows/ci.yml/badge.svg)](https://github.com/yipe/dpr/actions)
3
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) -->
1
+ [![npm version](https://img.shields.io/npm/v/@yipe/dice.svg)](https://www.npmjs.com/package/@yipe/dice)
2
+ [![License: MIT](https://img.shields.io/badge/License-MIT-007ec6.svg)](LICENSE)
3
+ ![TypeScript](https://img.shields.io/badge/TypeScript-Ready-3178c6?logo=typescript)
4
+ ![Size](https://img.shields.io/bundlephobia/minzip/@yipe/dice?logo=npm&logoColor=fff&label=Size)
5
+ ![Dice](https://dprcalc.com/api/roll)
4
6
 
5
- # 🎲 @dpr/dice
7
+ ![Last Commit](https://img.shields.io/github/last-commit/yipe/dice?logo=github)
8
+ ![Dependencies](https://img.shields.io/librariesio/release/npm/@yipe/dice?logo=npm)
9
+ [![GitHub issues](https://img.shields.io/github/issues/yipe/dice.svg?logo=github)](https://github.com/yipe/dice/issues)
10
+ [![Build Status](https://github.com/yipe/dice/actions/workflows/ci.yml/badge.svg)](https://github.com/yipe/dice/actions)
11
+ [![Tests](https://img.shields.io/badge/tests-passing-4c1.svg?logo=vitest&logoColor=white)](https://github.com/yipe/dice/actions/workflows/ci.yml)
12
+
13
+ # 🎲 @yipe/dice
6
14
 
7
15
  A TypeScript library for **D&D 5e damage-per-round (DPR) calculations**, designed for players, Dungeon Masters, and developers who want to analyze combat mathematically.
8
16
 
9
17
  This library powers [dprcalc.com](https://dprcalc.com) and provides a precise, composable way to model dice rolls, attacks, and outcomes with probability mass functions (PMFs) — not just averages. This allows for rich charting and statistics with full outcome attribution.
10
18
 
11
19
  ```ts
12
- import { parse } from "@dpr/dice";
20
+ import { parse } from "@yipe/dice";
13
21
 
14
22
  const attack = parse("(d20 + 8 AC 16) * (1d8 + 4) crit (2d8 + 4)");
15
23
  console.log("DPR:", attack.mean());
@@ -29,9 +37,9 @@ console.log("DPR:", attack.mean());
29
37
 
30
38
  ```bash
31
39
  # Install with npm or yarn
32
- npm install @dpr/dice
40
+ npm install @yipe/dice
33
41
  # or
34
- yarn add @dpr/dice
42
+ yarn add @yipe/dice
35
43
  ```
36
44
 
37
45
  ## 📦 Core Concepts
@@ -48,7 +56,7 @@ yarn add @dpr/dice
48
56
  Here's a simple example of calculating damage for a basic attack:
49
57
 
50
58
  ```ts
51
- import { parse, DiceQuery } from "@dpr/dice";
59
+ import { parse, DiceQuery } from "@yipe/dice";
52
60
 
53
61
  const query = parse("(d20 + 8 AC 16) * (1d4 + 4) crit (2d4 + 4)").toQuery();
54
62
 
@@ -70,7 +78,7 @@ DPR: 4.35
70
78
  Conditional damage ("once-per-turn damage riders") like Sneak Attack can be modeled easily:
71
79
 
72
80
  ```ts
73
- import { parse, DiceQuery } from "@dpr/dice";
81
+ import { parse, DiceQuery } from "@yipe/dice";
74
82
 
75
83
  function damageRiderExample() {
76
84
  const attack = parse("(d20 + 8 AC 16) * (1d4 + 4) crit (2d4 + 4)");
@@ -107,7 +115,7 @@ function damageRiderExample() {
107
115
  You can generate full statistical distributions for visualization or reporting.
108
116
 
109
117
  ```ts
110
- import { parse, DiceQuery } from "@dpr/dice";
118
+ import { parse, DiceQuery } from "@yipe/dice";
111
119
 
112
120
  const query2 = parse("(d20 + 8 AC 16) * (1d4 + 4) crit (2d4 + 4)").toQuery();
113
121
  console.table(query2.toChartSeries());
@@ -227,7 +235,6 @@ Here is the basic example:
227
235
 
228
236
  ## 🧱 Roadmap
229
237
 
230
- - [ ] **Publish** to npm as `@dpr/dice`
231
238
  - [ ] Create a **web playground** with live examples
232
239
  - [ ] Consider creating higher-level APIs: `Turn`, `Attack`, `DamageRider`
233
240
  - [ ] Simplify and improve PMF and Query interface ergonomics
package/dist/index.cjs CHANGED
@@ -1,10 +1,14 @@
1
1
  'use strict';
2
2
 
3
+ var __defProp = Object.defineProperty;
4
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
6
+
3
7
  // src/lru-cache.ts
4
8
  var LRUCache = class {
5
9
  constructor(maxSize = 1e3) {
6
10
  this.maxSize = maxSize;
7
- this.cache = /* @__PURE__ */ new Map();
11
+ __publicField(this, "cache", /* @__PURE__ */ new Map());
8
12
  }
9
13
  get(key) {
10
14
  const value = this.cache.get(key);
@@ -49,6 +53,8 @@ var TEST_EPS = 1e-10;
49
53
  // src/query.ts
50
54
  var _DiceQuery = class _DiceQuery {
51
55
  constructor(singles, combined) {
56
+ __publicField(this, "singles");
57
+ __publicField(this, "combined");
52
58
  this.singles = Array.isArray(singles) ? singles : [singles];
53
59
  const c = combined ?? PMF.convolveMany(this.singles);
54
60
  this.combined = Math.abs(c.mass() - 1) <= 1e-12 ? c : c.normalize();
@@ -995,7 +1001,7 @@ var _DiceQuery = class _DiceQuery {
995
1001
  outcomeTotals(outcomes = this.outcomeKeys()) {
996
1002
  const totals = /* @__PURE__ */ new Map();
997
1003
  outcomes.forEach((o) => totals.set(o, 0));
998
- for (const [x, row] of this.combined.map) {
1004
+ for (const [, row] of this.combined.map) {
999
1005
  for (const o of outcomes) {
1000
1006
  const p = row.count[o] || 0;
1001
1007
  totals.set(o, (totals.get(o) || 0) + p);
@@ -1210,7 +1216,7 @@ var _DiceQuery = class _DiceQuery {
1210
1216
  * const bonusAttack = parse("(d20 + 3 AC 15) * (1d6 + 1)");
1211
1217
  * const bothAttacks = mainAttack.convolve(bonusAttack);
1212
1218
  */
1213
- convolve(other, eps) {
1219
+ convolve(other) {
1214
1220
  const singles = [...this.singles, ...other.singles];
1215
1221
  return new _DiceQuery(singles);
1216
1222
  }
@@ -1266,11 +1272,11 @@ var _DiceQuery = class _DiceQuery {
1266
1272
  return [a, b, any, none];
1267
1273
  }
1268
1274
  };
1269
- _DiceQuery.DEFAULT_OUTCOMES = [
1275
+ __publicField(_DiceQuery, "DEFAULT_OUTCOMES", [
1270
1276
  "hit",
1271
1277
  "crit",
1272
1278
  "missNone"
1273
- ];
1279
+ ]);
1274
1280
  var DiceQuery = _DiceQuery;
1275
1281
  var EPSILON = COMPUTATIONAL_EPS;
1276
1282
  var pmfCache = new LRUCache(1e3);
@@ -1281,6 +1287,14 @@ var _PMF = class _PMF {
1281
1287
  this.normalized = normalized;
1282
1288
  this.identifier = identifier;
1283
1289
  this._preservedProvidence = _preservedProvidence;
1290
+ // Cached computed values
1291
+ __publicField(this, "_support");
1292
+ __publicField(this, "_min");
1293
+ __publicField(this, "_max");
1294
+ __publicField(this, "_totalMass");
1295
+ __publicField(this, "_mean");
1296
+ __publicField(this, "_variance");
1297
+ __publicField(this, "_stdev");
1284
1298
  }
1285
1299
  static empty(epsilon = EPSILON, identifier = "empty") {
1286
1300
  return new _PMF(/* @__PURE__ */ new Map(), epsilon, false, identifier);
@@ -1292,7 +1306,7 @@ var _PMF = class _PMF {
1292
1306
  return new _PMF(m, epsilon, false, "zero");
1293
1307
  }
1294
1308
  // This creates a single bin at value 0, but with weight 0.
1295
- static emptyMass(epsilon = EPSILON) {
1309
+ static emptyMass() {
1296
1310
  return _PMF.zero().scaleMass(0);
1297
1311
  }
1298
1312
  // Makes PMF iterable over [damage, bin] pairs.
@@ -1500,7 +1514,7 @@ var _PMF = class _PMF {
1500
1514
  /*
1501
1515
  * Helper for chaining multiple identical attacks
1502
1516
  */
1503
- replicate(n, eps = this.epsilon) {
1517
+ replicate(n) {
1504
1518
  if (!Number.isInteger(n) || n <= 0) {
1505
1519
  throw new Error("combineN(n): n must be a positive integer");
1506
1520
  }
@@ -2098,7 +2112,7 @@ var _PMF = class _PMF {
2098
2112
  }
2099
2113
  };
2100
2114
  // Unique ID generator for anonymous PMFs to avoid cache key collisions
2101
- _PMF.__anonIdCounter = 1;
2115
+ __publicField(_PMF, "__anonIdCounter", 1);
2102
2116
  var PMF = _PMF;
2103
2117
  function getPowerCacheKey(base, n, eps) {
2104
2118
  const id = base.identifier;
@@ -2110,10 +2124,11 @@ function getPowerCacheKey(base, n, eps) {
2110
2124
  // src/dice.ts
2111
2125
  var Dice = class _Dice {
2112
2126
  constructor(x = 0) {
2113
- this.faces = {};
2114
- this.privateData = {};
2115
- this.outcomeData = {};
2116
- this.hasHitDistributionCalculated = false;
2127
+ __publicField(this, "faces", {});
2128
+ __publicField(this, "privateData", {});
2129
+ __publicField(this, "outcomeData", {});
2130
+ __publicField(this, "hasHitDistributionCalculated", false);
2131
+ __publicField(this, "identifier");
2117
2132
  if (x <= 0) return;
2118
2133
  for (let i = 1; i <= x; i++) {
2119
2134
  this.faces[i] = 1;
@@ -2782,20 +2797,12 @@ function parseArgumentInternal(s, n) {
2782
2797
  case "k":
2783
2798
  assertToken(s, "k");
2784
2799
  return parseKeep(s, n);
2785
- case "0":
2786
- case "1":
2787
- case "2":
2788
- case "3":
2789
- case "4":
2790
- case "5":
2791
- case "6":
2792
- case "7":
2793
- case "8":
2794
- case "9":
2795
2800
  case "n":
2796
2801
  return parseNumber(s, n);
2802
+ default:
2803
+ if (isDigit(c)) return parseNumber(s, n);
2804
+ return;
2797
2805
  }
2798
- return;
2799
2806
  }
2800
2807
  function parseBinaryArgument(arg, arr, n) {
2801
2808
  if (arr.length >= 4 && arr[0] === "h" && peek(arr, "half")) {