dice-rng
v1.0.3
Published
   [ using the Xorshift128+ algorithm. Perfect for simulations, games, and applications requiring high-quality randomness without cryptographic requirements.
🚀 Installation
npm install dice-rng💻 Basic Usage
// ES6 Modules
import diceRng from 'dice-rng';
// CommonJS (if using require)
// const diceRng = require('dice-rng');
// Create generator with random seed
const rng = new diceRng();
// Generate random numbers
console.log(rng.nextRange(1, 6)); // Dice roll: 1-6🔧 API Reference
new diceRng([seed])
Creates a new generator instance:
seed(optional):undefined: Use cryptographically secure random seed (recommended). If result is state [0n, 0n], state1 is automatically set to 1n.BigInt: Single seed. Converted to state using formula:state0 = seedstate1 = seed ^ 0x6a09e667f3bcc909n
If result is [0n, 0n], state1 is set to 1n.[state0, state1]: Full state as BigInt array (must have exactly 2 elements).
⚠️ Cannot be [0n, 0n] - will throw Error.
// Initialization examples
const rng1 = new diceRng(); // Random seed
const rng2 = new diceRng(123456789n); // Fixed seed (note the 'n' for BigInt!)
const rng3 = new diceRng([0x123n, 0xABCn]); // Full stateGenerator Methods
.next() → BigInt
Generates a 64-bit random number as BigInt
const bigIntValue = rng.next();
console.log(bigIntValue); // 18643850231453088000n.nextInt() → Number
Generates a 32-bit integer (0 to 4294967295)
const intValue = rng.nextInt();
console.log(intValue); // 3158275367.nextDouble() → Number
Generates a double-precision float [0, 1) with 53-bit precision (JavaScript's maximum precision)
const floatValue = rng.nextDouble();
console.log(floatValue); // 0.3578451201923456.nextRange(min, max) → Number
Generates an integer within range [min, max] (inclusive).
⚠️ Throws error if:
minormaxis not an integermin >= max
const diceRoll = rng.nextRange(1, 6); // Dice roll: 1-6
const lotteryNumber = rng.nextRange(1, 60); // Lottery number: 1-60.currentState() → [BigInt, BigInt]
Returns current internal state for debugging
const state = rng.currentState();
console.log(state); // [123456789n, 987654321n]📖 Usage Examples
Dice Simulation
function rollDice(rng) {
return rng.nextRange(1, 6);
}
const rng = new diceRng();
console.log('Dice roll result:', rollDice(rng));Card Deck Shuffling
function shuffleDeck(rng) {
const suits = ['♠', '♥', '♦', '♣'];
const values = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
const deck = [];
for (const suit of suits) {
for (const value of values) {
deck.push(`${value}${suit}`);
}
}
// Fisher-Yates shuffle
for (let i = deck.length - 1; i > 0; i--) {
const j = rng.nextRange(0, i); // [0, i] inclusive
[deck[i], deck[j]] = [deck[j], deck[i]];
}
return deck;
}
const rng = new diceRng();
const deck = shuffleDeck(rng);
console.log('Top card:', deck[0]);Procedural World Generation
function generateTerrain(seed) {
const rng = new diceRng(seed);
const size = 5;
let world = "";
for (let y = 0; y < size; y++) {
for (let x = 0; x < size; x++) {
const tile = rng.nextRange(1, 4);
world +=
tile === 1
? "🌲" // Forest
: tile === 2
? "⛰️" // Mountaint
: tile === 3
? "🌊" // River
: "🟫"; // Land
}
world += "\n";
}
return world;
}
const worldSeed = 1234n;
console.log(generateTerrain());
// Output example:
// 🌲⛰️🌊🟫🌲
// 🟫🌲⛰️🌊🟫
// 🌊🟫🌲⛰️🌊
// ⛰️🌊🟫🌲⛰️
// 🌲⛰️🌊🟫🌲
// Use fixed seed for reproducible world
const worldSeed = 2023n; // Note the 'n' for BigInt!
const world = generateWorld(worldSeed, 10, 10);Dice gambling simulation
class GradualLuckSimulator {
constructor() {
this.rng = new Xorshift128Plus();
this.rollCount = 0;
}
roll() {
this.rollCount++;
// Luck graph decreases linearly
const luckFactor = Math.max(0, 1 - (this.rollCount - 1) / 30);
// Adjust probability based on luck factor
const rand = this.rng.nextDouble();
if (rand < 0.2 + 0.6 * luckFactor) {
// High number (4-6)
return this.rng.nextRange(4, 6);
} else {
// Low number (1-3)
return this.rng.nextRange(1, 3);
}
}
}
// Run simulation with visualization
function runGradualSimulation() {
const simulator = new GradualLuckSimulator();
const results = [];
console.log("===== [ GRADUAL SIMULATION: LUCKY → UNLUCKY ] =====");
for (let i = 1; i <= 30; i++) {
const roll = simulator.roll();
results.push(roll);
const status = roll >= 4 ? "LUCKY 🎇" : "UNLUCKY 💩";
const progress =
"▰".repeat(Math.ceil(i / 2)) + "▱".repeat(15 - Math.ceil(i / 2));
console.log(
`[${progress}] Roll ${i
.toString()
.padStart(2, " ")}: ${roll} - ${status}`
);
}
// Calculate luck percentage per 10 rolls
console.log("\n===== [ LUCK TREND ] =====");
for (let segment = 0; segment < 3; segment++) {
const segmentResults = results.slice(segment * 10, (segment + 1) * 10);
const luckyCount = segmentResults.filter(r => r >= 4).length;
const progressBar = "⬛".repeat(luckyCount) + "⬜".repeat(10 - luckyCount);
console.log(
`Rolls ${segment * 10 + 1}-${
(segment + 1) * 10
}: ${progressBar} ${luckyCount}/10 (${luckyCount * 10}%)`
);
}
}
runGradualSimulation();❗ Error Handling
This module throws errors in the following cases:
- Initialization:
- Seed array doesn't have exactly 2 elements
- Resulting state is [0n, 0n]
- Invalid seed type
- nextRange():
minormaxis not an integermin >= max
- Internal Operations:
- nextDouble() produces value outside [0, 1) (extremely rare)
⚠️ Important Notes
Not for Cryptography
This module is not suitable for security applications or cryptographyReproducibility
Same seed will produce exactly the same sequence of numbersHigh Performance
Capable of generating ~65 million numbers/second on modern CPUsCompatibility
Requires Node.js v14.0+ (ES6 modules and BigInt support).
⚠️ Must use BigInt for seeds:123n(correct) vs123(incorrect)Double Precision
nextDouble()uses 53-bit precision (not 64-bit) due to JavaScript limitationsModule System
Code uses ES6 modules (import/export). Ensurepackage.jsonhas"type": "module"or use.mjsextension
📊 Comparison with Math.random()
Both dice-rng and Math.random() use the same Xorshift128+ algorithm under the hood (in V8 engine), but there are key differences in implementation and features:
| Feature | dice-rng | Math.random() | |--------------------|-----------------------|-----------------------| | Algorithm | Xorshift128+ | Xorshift128+ (V8) | | Seed Control | ✅ Full control | ❌ Auto-seeded | | Reproducibility| ✅ Deterministic | ❌ Non-deterministic | | State Access | ✅ Can inspect/save | ❌ Hidden internal | | Precision | 53-bit | 53-bit | | Period | 2128-1 | 2128-1 | | Performance | Very Fast | Very Fast | | Portability | ✅ Cross-platform | ⚠️ Engine-dependent |
🔧 package.json Configuration
To use ES6 modules, ensure your package.json has:
{
"name": "dice-rng",
"type": "module",
"engines": {
"node": ">=14.0.0"
}
}🎯 Performance Benchmarks
// Quick performance test
const rng = new diceRng();
const start = performance.now();
for (let i = 0; i < 1000000; i++) {
rng.nextDouble();
}
const elapsed = performance.now() - start;
console.log(`Generated 1M numbers in ${elapsed.toFixed(2)}ms`);🔬 Algorithm Details
Xorshift128+ is a variant of the Xorshift family of PRNGs:
- Period: 2^128 - 1
- State Size: 128 bits (2 × 64-bit values)
- Operations: XOR, left shift, right shift
- Quality: Passes most statistical tests
- Speed: Excellent performance on modern CPUs
Why Use dice-rng Instead of Math.random()?
Since both use the same algorithm, the main advantages of dice-rng are:
- 🎯 Reproducibility: Perfect for testing, debugging, and deterministic simulations
- 🔧 Control: You can save/restore generator state
- 🎮 Gaming: Essential for save/load functionality in games
- 🧪 Scientific: Reproducible experiments and research
- 🔄 Portability: Same results across different JavaScript engines
📜 License
MIT License. Free to use for personal and commercial projects.
Made with ❤️ for developers who need reliable randomness
