A Swift package for representing and rolling dice using standard tabletop RPG notation.
SwiftDice is built for developers implementing tabletop RPG mechanics who need more than a random number generator. Dice expressions are first-class Swift values that are composable with operators, parseable from notation strings, and serializable to JSON, so your game data layer and your dice logic speak the same language.
-
Operator-based expression building — write
4 * .d6,2 * .d8 + 4, or(4 * .d6).dropping(.lowest)directly in Swift without formatting strings -
Full notation parser — round-trips between Swift values and standard dice notation strings;
DiceParseraccepts everything fromd6to4d6-L+d4 -
Drop and keep mechanics —
dropping(.lowest),keeping(3, .highest),keeping(.highest)for ability rolls, advantage, and disadvantage -
Exploding and reroll modifiers — per-die explosion chains and one-time reroll thresholds, combinable on a single die
-
Fudge/FATE dice — built-in
dFsupport with the same operator and parser integration as standard dice -
Pool mechanics —
rollAll()returns per-die results before summing, enabling success-counting and per-die threshold logic -
JSON round-trip — encode any
Rollableas its notation string and decode it back -
AnyRollable— a concrete,Equatable/Hashable/Codablevalue type wrapping anyRollable, so a struct gets dice-valuedCodablefor free:struct Treasure: Codable { let goldPerGoblin: AnyRollable // decodes from `8` or `"2d6"` alike }
Add the package to your Package.swift:
dependencies: [
.package(url: "https://github.com/mrlegowatch/SwiftDice.git", from: "0.1.0"),
],
targets: [
.target(name: "YourTarget", dependencies: ["SwiftDice"]),
]import SwiftDice
// Roll ability scores: 4d6, keep 3 highest
let abilityRoll = (4 * .d6).keeping(3, .highest)
let result = abilityRoll.roll()
print(result.result) // e.g. 14
print(result.description) // e.g. "((3 + 6 + 4 + 5) - 3)"
// Attack with advantage: 2d20, keep highest
let attack = (2 * .d20).keeping(.highest)
// Weapon damage: 2d8+4
let damage = 2 * .d8 + 4
// Parse from a notation string
if let gold = try? DiceParser().parse("5d4x10") {
print(gold.roll().result) // e.g. 80
}For full API documentation — dice types, notation reference, drop/keep mechanics, exploding dice, JSON encoding, and error handling — build the documentation in Xcode via Product → Build Documentation.
The dice implementation was originally developed as part of RolePlayingCore. Its early evolution is described in three posts on medium.com: