@yipe/dice 0.2.16 → 0.2.19
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 +256 -35
- package/dist/builder/index.cjs +947 -12
- package/dist/builder/index.cjs.map +1 -1
- package/dist/builder/index.d.cts +23 -2
- package/dist/builder/index.d.ts +23 -2
- package/dist/builder/index.js +947 -13
- package/dist/builder/index.js.map +1 -1
- package/dist/index.cjs +70 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +70 -2
- package/dist/index.js.map +1 -1
- package/dist/{pmf-CYaEbY7m.d.cts → pmf-BC1poIqF.d.cts} +31 -0
- package/dist/{pmf-CYaEbY7m.d.ts → pmf-BC1poIqF.d.ts} +31 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,7 +36,9 @@ console.log("DPR:", attack.mean());
|
|
|
36
36
|
- **Composable API**: Build dice expressions, run queries, and analyze results in just a few lines.
|
|
37
37
|
- **TypeScript First**: Full type safety and developer experience.
|
|
38
38
|
|
|
39
|
-
## 🚀
|
|
39
|
+
## 🚀 Quick Start
|
|
40
|
+
|
|
41
|
+
### Installation
|
|
40
42
|
|
|
41
43
|
```bash
|
|
42
44
|
# Install with npm or yarn
|
|
@@ -45,6 +47,236 @@ npm install @yipe/dice
|
|
|
45
47
|
yarn add @yipe/dice
|
|
46
48
|
```
|
|
47
49
|
|
|
50
|
+
### Basic Usage
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { parse, DiceQuery } from "@yipe/dice";
|
|
54
|
+
|
|
55
|
+
const query = d20.plus(8).ac(16).onHit(d4.plus(4)).toQuery();
|
|
56
|
+
|
|
57
|
+
console.log("Hit chance:", query.probAtLeastOne(["hit", "crit"]));
|
|
58
|
+
console.log("Crit chance:", query.probAtLeastOne(["crit"]));
|
|
59
|
+
console.log("DPR:", query.mean());
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Output:**
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
Hit chance: 0.65
|
|
66
|
+
Crit chance: 0.05
|
|
67
|
+
DPR: 4.35
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 🛠 Development Setup
|
|
71
|
+
|
|
72
|
+
### Prerequisites
|
|
73
|
+
|
|
74
|
+
- **Node.js**: >= 18.17
|
|
75
|
+
- **Yarn**: 4.9.4 (specified in `packageManager`)
|
|
76
|
+
|
|
77
|
+
### Initial Setup
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Clone the repository
|
|
81
|
+
git clone https://github.com/yipe/dice.git
|
|
82
|
+
cd dice
|
|
83
|
+
|
|
84
|
+
# Install dependencies
|
|
85
|
+
yarn install
|
|
86
|
+
|
|
87
|
+
# Build the project
|
|
88
|
+
yarn build
|
|
89
|
+
|
|
90
|
+
# Run tests
|
|
91
|
+
yarn test
|
|
92
|
+
|
|
93
|
+
# Run examples
|
|
94
|
+
yarn example
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Available Scripts
|
|
98
|
+
|
|
99
|
+
| Command | Purpose |
|
|
100
|
+
|---------|---------|
|
|
101
|
+
| `yarn build` | Compile TypeScript to JavaScript (outputs to `dist/`) |
|
|
102
|
+
| `yarn test` | Run test suite once |
|
|
103
|
+
| `yarn test:watch` | Run tests in watch mode |
|
|
104
|
+
| `yarn typecheck` | Type-check without emitting files |
|
|
105
|
+
| `yarn lint` | Run ESLint |
|
|
106
|
+
| `yarn example` | Run example scripts |
|
|
107
|
+
|
|
108
|
+
### Project Structure
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
src/
|
|
112
|
+
├── builder/ # Fluent API for building dice expressions
|
|
113
|
+
│ ├── factory.ts # Factory functions (d20, d6, roll, etc.)
|
|
114
|
+
│ ├── roll.ts # RollBuilder - core builder class
|
|
115
|
+
│ ├── ac.ts # ACBuilder - attack roll builder
|
|
116
|
+
│ ├── attack.ts # AttackBuilder - attack with damage
|
|
117
|
+
│ ├── save.ts # SaveBuilder - saving throw builder
|
|
118
|
+
│ ├── dc.ts # DCBuilder - difficulty check builder
|
|
119
|
+
│ ├── ast.ts # AST generation and PMF conversion
|
|
120
|
+
│ └── nodes.ts # AST node type definitions
|
|
121
|
+
├── parser/ # String-based dice expression parser
|
|
122
|
+
│ ├── parser.ts # Main parser implementation
|
|
123
|
+
│ └── dice.ts # Dice class (legacy parser representation)
|
|
124
|
+
├── pmf/ # Probability Mass Function core
|
|
125
|
+
│ ├── pmf.ts # PMF class - core data structure
|
|
126
|
+
│ ├── query.ts # DiceQuery - analysis interface
|
|
127
|
+
│ └── mixture.ts # Mixture operations
|
|
128
|
+
└── common/ # Shared utilities
|
|
129
|
+
├── types.ts # Type definitions
|
|
130
|
+
└── lru-cache.ts # LRU cache implementation
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## 🏗 Architecture Overview
|
|
134
|
+
|
|
135
|
+
The library provides two parallel entry points for creating dice expressions:
|
|
136
|
+
|
|
137
|
+
### Entry Point 1: String Parser
|
|
138
|
+
|
|
139
|
+
Parses text expressions like `"(d20 + 8 AC 16) * (1d8 + 4) crit (2d8 + 4)"`:
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
String Expression
|
|
143
|
+
│
|
|
144
|
+
├─ parse() ──────────────┐
|
|
145
|
+
│ │
|
|
146
|
+
│ ▼
|
|
147
|
+
│ parseExpression()
|
|
148
|
+
│ │
|
|
149
|
+
│ ├─ parseArgument() ──► Dice objects
|
|
150
|
+
│ │
|
|
151
|
+
│ └─ parseOperation() ──► Dice operations
|
|
152
|
+
│ │
|
|
153
|
+
│ ▼
|
|
154
|
+
│ Dice.toPMF() ──► PMF
|
|
155
|
+
│ │
|
|
156
|
+
└────────────────────────┘
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Entry Point 2: Fluent Builder API
|
|
160
|
+
|
|
161
|
+
Type-safe builder pattern:
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
RollBuilder (d20, d6, roll(), etc.)
|
|
165
|
+
│
|
|
166
|
+
├─ .plus() ──► RollBuilder
|
|
167
|
+
├─ .ac() ────► ACBuilder
|
|
168
|
+
│ │
|
|
169
|
+
│ └─ .onHit() ──► AttackBuilder
|
|
170
|
+
│ │
|
|
171
|
+
│ ├─ .toQuery() ──► DiceQuery
|
|
172
|
+
│ └─ .pmf ─────────► PMF
|
|
173
|
+
│
|
|
174
|
+
└─ .toPMF() ──► PMF
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Core Class Flow
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
181
|
+
│ User Input Layer │
|
|
182
|
+
├─────────────────────────────────────────────────────────────┤
|
|
183
|
+
│ String Parser │ Fluent Builder │
|
|
184
|
+
│ parse("...") │ d20.plus(8).ac(16) │
|
|
185
|
+
└────────────┬────────────┴────────────┬──────────────────────┘
|
|
186
|
+
│ │
|
|
187
|
+
▼ ▼
|
|
188
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
189
|
+
│ Builder Layer │
|
|
190
|
+
├─────────────────────────────────────────────────────────────┤
|
|
191
|
+
│ RollBuilder ──► ACBuilder ──► AttackBuilder │
|
|
192
|
+
│ │ │ │ │
|
|
193
|
+
│ │ │ │ │
|
|
194
|
+
│ └──────────────┼──────────────┘ │
|
|
195
|
+
│ │ │
|
|
196
|
+
│ ▼ │
|
|
197
|
+
│ astFromRollConfigs() │
|
|
198
|
+
│ │ │
|
|
199
|
+
│ ▼ │
|
|
200
|
+
│ ExpressionNode (AST) │
|
|
201
|
+
└──────────────────────┬──────────────────────────────────────┘
|
|
202
|
+
│
|
|
203
|
+
▼
|
|
204
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
205
|
+
│ PMF Generation │
|
|
206
|
+
├─────────────────────────────────────────────────────────────┤
|
|
207
|
+
│ pmfFromRollBuilder() │
|
|
208
|
+
│ │ │
|
|
209
|
+
│ ├─ d20RollPMF() ──► PMF (for d20 rolls) │
|
|
210
|
+
│ ├─ diePMF() ──────► PMF (for regular dice) │
|
|
211
|
+
│ └─ combinePMFs() ─► PMF (convolve multiple PMFs) │
|
|
212
|
+
└──────────────────────┬──────────────────────────────────────┘
|
|
213
|
+
│
|
|
214
|
+
▼
|
|
215
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
216
|
+
│ Query & Analysis │
|
|
217
|
+
├─────────────────────────────────────────────────────────────┤
|
|
218
|
+
│ DiceQuery │
|
|
219
|
+
│ │ │
|
|
220
|
+
│ ├─ .mean() ────────────► Expected damage │
|
|
221
|
+
│ ├─ .variance() ────────► Damage variance │
|
|
222
|
+
│ ├─ .probAtLeastOne() ──► Hit/crit probabilities │
|
|
223
|
+
│ ├─ .toChartSeries() ────► Chart data │
|
|
224
|
+
│ └─ .combined ───────────► Final PMF │
|
|
225
|
+
└─────────────────────────────────────────────────────────────┘
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### PMF Data Structure
|
|
229
|
+
|
|
230
|
+
The `PMF` class is the core mathematical representation:
|
|
231
|
+
|
|
232
|
+
```
|
|
233
|
+
PMF
|
|
234
|
+
├── map: Map<number, Bin>
|
|
235
|
+
│ └── Bin
|
|
236
|
+
│ ├── p: number (probability)
|
|
237
|
+
│ ├── count: {...} (outcome counts: hit, crit, miss)
|
|
238
|
+
│ └── attr: {...} (damage attribution)
|
|
239
|
+
├── epsilon: number (probability threshold)
|
|
240
|
+
├── normalized: boolean (whether PMF sums to 1.0)
|
|
241
|
+
└── identifier: string (cache key / debug name)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Main Flow Example
|
|
245
|
+
|
|
246
|
+
Here's how a simple attack flows through the system:
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
1. User creates: d20.plus(5).ac(15).onHit(d6.plus(2))
|
|
250
|
+
|
|
251
|
+
2. Builder chain:
|
|
252
|
+
RollBuilder(d20)
|
|
253
|
+
→ plus(5) → RollBuilder(d20 + 5)
|
|
254
|
+
→ ac(15) → ACBuilder(d20 + 5 AC 15)
|
|
255
|
+
→ onHit(...) → AttackBuilder
|
|
256
|
+
|
|
257
|
+
3. AST generation:
|
|
258
|
+
RollConfig[] → ExpressionNode
|
|
259
|
+
- DieNode (d20)
|
|
260
|
+
- ConstantNode (+5)
|
|
261
|
+
- D20RollNode (AC check)
|
|
262
|
+
- ConditionalNode (on hit)
|
|
263
|
+
|
|
264
|
+
4. PMF generation:
|
|
265
|
+
AST → PMF operations
|
|
266
|
+
- d20RollPMF(rollType, rerollOne) → PMF
|
|
267
|
+
- Conditional application → PMF.branch()
|
|
268
|
+
- Damage PMF → PMF
|
|
269
|
+
- Combine → PMF (final result)
|
|
270
|
+
|
|
271
|
+
5. Query creation:
|
|
272
|
+
AttackBuilder.toQuery() → DiceQuery
|
|
273
|
+
- singles: [PMF]
|
|
274
|
+
- combined: PMF (convolved)
|
|
275
|
+
|
|
276
|
+
6. Analysis:
|
|
277
|
+
DiceQuery.mean() → 3.20 DPR
|
|
278
|
+
```
|
|
279
|
+
|
|
48
280
|
## 📦 Core Concepts
|
|
49
281
|
|
|
50
282
|
| Concept | Description |
|
|
@@ -52,11 +284,12 @@ yarn add @yipe/dice
|
|
|
52
284
|
| **PMF** | Probability Mass Function. The core mathematical representation of outcomes. |
|
|
53
285
|
| **Query** | Runs calculations and scenarios over one or more PMFs. |
|
|
54
286
|
| **Parser** | Parses text-based dice expressions like `(d20 + 8 AC 16) * (1d4 + 4)`. |
|
|
55
|
-
| **
|
|
287
|
+
| **Builder**| Fluent TypeScript API for building dice expressions. |
|
|
288
|
+
| **AST** | Abstract Syntax Tree representing dice operations. |
|
|
56
289
|
|
|
57
|
-
## 🧙
|
|
290
|
+
## 🧙 Usage Examples
|
|
58
291
|
|
|
59
|
-
|
|
292
|
+
### Basic Attack
|
|
60
293
|
|
|
61
294
|
```ts
|
|
62
295
|
import { parse, DiceQuery } from "@yipe/dice";
|
|
@@ -68,20 +301,23 @@ console.log("Crit chance:", query.probAtLeastOne(["crit"]));
|
|
|
68
301
|
console.log("DPR:", query.mean());
|
|
69
302
|
```
|
|
70
303
|
|
|
71
|
-
|
|
304
|
+
### String Parser
|
|
72
305
|
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
306
|
+
```ts
|
|
307
|
+
import { parse } from "@yipe/dice";
|
|
308
|
+
|
|
309
|
+
const pmf = parse("(d20 + 8 AC 16) * (1d8 + 4) crit (2d8 + 4)");
|
|
310
|
+
const query = new DiceQuery(pmf);
|
|
311
|
+
|
|
312
|
+
console.log("DPR:", query.mean());
|
|
77
313
|
```
|
|
78
314
|
|
|
79
|
-
|
|
315
|
+
### Sneak Attack (Conditional Damage)
|
|
80
316
|
|
|
81
317
|
Conditional damage ("once-per-turn damage riders") like Sneak Attack can be modeled easily:
|
|
82
318
|
|
|
83
319
|
```ts
|
|
84
|
-
import { DiceQuery } from "@yipe/dice";
|
|
320
|
+
import { DiceQuery, PMF, roll } from "@yipe/dice";
|
|
85
321
|
|
|
86
322
|
function sneakAttack() {
|
|
87
323
|
const attackPMF = d20.plus(8).ac(16).onHit(d4.plus(4)).pmf;
|
|
@@ -99,15 +335,13 @@ function sneakAttack() {
|
|
|
99
335
|
console.log("DPR with once-per-turn sneak attack: ", sneakAttack().mean());
|
|
100
336
|
```
|
|
101
337
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
You can generate full statistical distributions for visualization or reporting.
|
|
338
|
+
### Statistics and Charts
|
|
105
339
|
|
|
106
340
|
```ts
|
|
107
341
|
import { parse, DiceQuery } from "@yipe/dice";
|
|
108
342
|
|
|
109
|
-
const
|
|
110
|
-
console.table(
|
|
343
|
+
const query = parse("(d20 + 8 AC 16) * (1d4 + 4) crit (2d4 + 4)").toQuery();
|
|
344
|
+
console.table(query.toChartSeries());
|
|
111
345
|
```
|
|
112
346
|
|
|
113
347
|
**Output:**
|
|
@@ -128,17 +362,9 @@ console.table(query2.toChartSeries());
|
|
|
128
362
|
└─────────┴────┴──────────┘
|
|
129
363
|
```
|
|
130
364
|
|
|
131
|
-
## 🗂 Project Structure
|
|
132
|
-
|
|
133
|
-
| File | Purpose |
|
|
134
|
-
| ----------- | ------------------------------------- |
|
|
135
|
-
| `src/` | Core Dice class and logic |
|
|
136
|
-
| `examples/` | Example scripts showing library usage |
|
|
137
|
-
| `tests/` | Comprehensive library tests |
|
|
138
|
-
|
|
139
365
|
## 🧪 Running Examples
|
|
140
366
|
|
|
141
|
-
This repository includes example scripts
|
|
367
|
+
This repository includes example scripts:
|
|
142
368
|
|
|
143
369
|
```bash
|
|
144
370
|
yarn example basic
|
|
@@ -147,7 +373,7 @@ yarn example sneakattack
|
|
|
147
373
|
yarn example misc
|
|
148
374
|
```
|
|
149
375
|
|
|
150
|
-
Here is the basic example:
|
|
376
|
+
Here is the basic example output:
|
|
151
377
|
|
|
152
378
|
```
|
|
153
379
|
% yarn example basic
|
|
@@ -217,10 +443,9 @@ Here is the basic example:
|
|
|
217
443
|
│ 13 │ 0.278% │ 0.278% │ 0.000% │ 0.000% │
|
|
218
444
|
│ 14 │ 0.139% │ 0.139% │ 0.000% │ 0.000% │
|
|
219
445
|
└────────┴─────────┴────────┴────────┴─────────┘
|
|
220
|
-
|
|
221
446
|
```
|
|
222
447
|
|
|
223
|
-
|
|
448
|
+
This enables rich statistics like "how much damage comes from crits vs hits".
|
|
224
449
|
|
|
225
450
|
## 🧱 Roadmap
|
|
226
451
|
|
|
@@ -247,13 +472,13 @@ cd dice
|
|
|
247
472
|
yarn install
|
|
248
473
|
```
|
|
249
474
|
|
|
250
|
-
Run tests
|
|
475
|
+
Run tests:
|
|
251
476
|
|
|
252
477
|
```bash
|
|
253
478
|
yarn test
|
|
254
479
|
```
|
|
255
480
|
|
|
256
|
-
Run examples
|
|
481
|
+
Run examples:
|
|
257
482
|
|
|
258
483
|
```bash
|
|
259
484
|
yarn example
|
|
@@ -273,8 +498,4 @@ Wizards of the Coast, Dungeons & Dragons, and their logos are trademarks of Wiza
|
|
|
273
498
|
|
|
274
499
|
Portions of this code are inspired by [dice.clockworkmod.com](https://github.com/koush/dice.clockworkmod.com) by Koushik Dutta (2013), licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0).
|
|
275
500
|
|
|
276
|
-
Initial [TypeScript port](https://github.com/loginName1/dice-calculator-ts) expertly created by [loginName1](https://github.com/loginName1).
|
|
277
|
-
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
```
|
|
501
|
+
Initial [TypeScript port](https://github.com/loginName1/dice-calculator-ts) expertly created by [loginName1](https://github.com/loginName1).
|