2 releases
Uses new Rust 2024
| 0.1.1 | Feb 3, 2026 |
|---|---|
| 0.1.0 | Feb 3, 2026 |
#703 in Parser implementations
67KB
1K
SLoC
dice-parser
A parser and roller for standard RPG dice notation in Rust.
This crate provides a simple way to parse and evaluate dice expressions commonly used in tabletop role-playing games. It supports basic arithmetic operations (addition and subtraction) and dice rolling with various modifiers.
Features
- Parse standard dice notation (e.g., "2d6", "1d20+5", "3d8-2")
- Support for keeping n highest or lowest rolls (currently via manual construction only; parsing support planned for a future release)
- Detailed roll results including individual die rolls and modifiers
- Custom RNG support for deterministic testing
- Comprehensive error handling
Installation
Add this to your Cargo.toml:
[dependencies]
dice-parser = "0.1"
Quick Start
Parsing and Rolling
use dice_parser::DiceExpr;
// Parse a dice expression from a string
let expr = DiceExpr::parse("2d6+3").unwrap();
// Roll the dice
let result = expr.roll().unwrap();
println!("Total: {}", result.total);
println!("Rolls: {:?}", result.rolls);
println!("Modifier: {}", result.modifier);
Manual Construction
You can also manually construct dice expressions for more control:
use dice_parser::{DiceExpr, RollSpec, Keep};
// Create a "4d6 keep highest 3" roll (common for D&D ability scores)
let roll_spec = RollSpec::new(4, 6, Some(Keep::Highest(3)));
let expr = DiceExpr::Roll(roll_spec);
let result = expr.roll().unwrap();
println!("Total: {}", result.total);
Complex Expressions
Build complex expressions by combining multiple operations:
use dice_parser::{DiceExpr, RollSpec};
// Create "2d6 + 1d4 - 2"
let d2d6 = DiceExpr::Roll(RollSpec::new(2, 6, None));
let d1d4 = DiceExpr::Roll(RollSpec::new(1, 4, None));
let modifier = DiceExpr::Literal(2);
let sum = DiceExpr::Sum(Box::new(d2d6), Box::new(d1d4));
let expr = DiceExpr::Difference(Box::new(sum), Box::new(modifier));
let result = expr.roll().unwrap();
Using Custom RNG
For deterministic testing or custom randomness:
use dice_parser::DiceExpr;
use rand::{SeedableRng, rngs::StdRng};
let expr = DiceExpr::parse("1d20").unwrap();
// Use a seeded RNG for reproducible results
let rng = StdRng::seed_from_u64(42);
let result = expr.roll_with_rng(rng).unwrap();
Supported Syntax
When parsing from strings, the following syntax is supported:
- Dice rolls:
NdSwhere N is the number of dice and S is the number of sides- Example:
2d6,1d20,3d8 - Note: Both the number of dice, and the number of sides needs to be strictly non-negative.
- Example:
- Literals: Any integer (positive or negative)
- Example:
5,-3,100
- Example:
- Addition:
expr + expr- Example:
2d6 + 3,1d20 + 1d4
- Example:
- Subtraction:
expr - expr- Example:
1d20 - 2,10 - 2d6
- Example:
- Whitespace: Ignored throughout the expression
- Example:
2d6+3and2d6 + 3are equivalent
- Example:
Note: Keep mechanics (Keep::Highest and Keep::Lowest) are currently only available through manual construction. Parsing support for keep syntax (e.g., "2d20kh" for keep highest, "6d6kl3" for keep lowest 3) is planned for a future release.
Examples
D&D 5e Advantage/Disadvantage
use dice_parser::{DiceExpr, RollSpec, Keep};
// Advantage: roll 2d20, keep highest
let advantage = DiceExpr::Roll(RollSpec::new(2, 20, Some(Keep::Highest(1))));
let result = advantage.roll().unwrap();
// Disadvantage: roll 2d20, keep lowest
let disadvantage = DiceExpr::Roll(RollSpec::new(2, 20, Some(Keep::Lowest(1))));
let result = disadvantage.roll().unwrap();
Character Ability Scores (4d6 drop lowest)
use dice_parser::{DiceExpr, RollSpec, Keep};
let ability_roll = DiceExpr::Roll(RollSpec::new(4, 6, Some(Keep::Highest(3))));
// Roll 6 times for all abilities
for i in 0..6 {
let result = ability_roll.roll().unwrap();
println!("Ability {}: {}", i + 1, result.total);
}
Error Handling
use dice_parser::DiceExpr;
// Parse error - invalid syntax
match DiceExpr::parse("2d") {
Ok(expr) => println!("Parsed successfully"),
Err(e) => eprintln!("Parse error: {}", e),
}
// Syntax error - negative dice count
match DiceExpr::parse("-2d6") {
Ok(expr) => println!("Parsed successfully"),
Err(e) => eprintln!("Syntax error: {}", e),
}
API Cheat-sheet
The public API consists of the following main types:
-
DiceExpr: The main enum representing a dice expressionDiceExpr::parse(input): Parse from a stringDiceExpr::roll(): Roll using default RNGDiceExpr::roll_with_rng(rng): Roll using custom RNG- Variants:
Sum,Difference,Roll,Literal
-
RollSpec: Specification for a dice roll- Fields:
count,sides,keep RollSpec::new(count, sides, keep): Create a new specification
- Fields:
-
Keep: Keep modifier for roll specificationsKeep::Highest(n): Keep N highest diceKeep::Lowest(n): Keep N lowest dice
-
ExprResult: Result of evaluating an expression- Fields:
total,rolls,modifier
- Fields:
-
DiceError: Error type for all operations- Variants:
Overflow,InvalidSpec,ParseError,SyntaxError,TrailingInput
- Variants:
License
This library is licensed under GNU-GPL v3.
Contributing
This began as a personal project, but if it was of any use for you and you have suggestions on how to improve it: feel free to reach out on GitHub or submit a pull request!
Dependencies
~370KB