npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@swrpg-online/monte-carlo

v2.3.4

Published

A library for performing Monte Carlo simulations with the Star Wars RPG narrative dice system by Fantasy Flight Games

Downloads

39

Readme

@swrpg-online/monte-carlo

npm version build codecov semantic-release: angular

A utility library for Star Wars RPG by Fantasy Flight Games and Edge Studio. Provides statistical analysis for the narrative dice system.

Installation

npm install @swrpg-online/monte-carlo

Features

Monte Carlo Simulation

The MonteCarlo class provides statistical analysis of dice pools through simulation. It helps to understand the probabilities and distributions of different outcomes.

import { MonteCarlo, DicePool } from "@swrpg-online/monte-carlo";

// Create a dice pool
const pool: DicePool = {
  abilityDice: 2, // 2 green (Ability) dice
  proficiencyDice: 1, // 1 yellow (Proficiency) die
};

// Create a Monte Carlo simulation with 10000 iterations (default)
// Optional: disable automatic simulation with runSimulate=false
const simulation = new MonteCarlo(pool, 10000, false);
const results = simulation.simulate();

console.log("Success Probability:", results.successProbability);
console.log("Average Successes:", results.averages.successes);
console.log(
  "Standard Deviation of Successes:",
  results.standardDeviations.successes,
);

Dice Pool Modifiers (New in v2.2.0)

The Monte Carlo library now supports dice pool modifiers including automatic symbols, dice upgrades, and downgrades. These features integrate with @swrpg-online/dice v1.4.0+.

Automatic Symbols

Add automatic successes, failures, advantages, threats, triumphs, or despairs to your dice pools:

import { MonteCarlo, SimulationConfig } from "@swrpg-online/monte-carlo";

const config: SimulationConfig = {
  dicePool: {
    abilityDice: 2,
    difficultyDice: 2,
  },
  iterations: 10000,
  modifiers: {
    automaticSuccesses: 1, // Add 1 automatic success
    automaticAdvantages: 2, // Add 2 automatic advantages
  },
};

const simulation = new MonteCarlo(config);
const results = simulation.simulate();

// Results include modifier analysis
console.log(
  "Automatic Contributions:",
  results.modifierAnalysis?.automaticSymbolContribution,
);
console.log(
  "Rolled Contributions:",
  results.modifierAnalysis?.rolledSymbolContribution,
);

Dice Upgrades and Downgrades

Upgrade ability dice to proficiency dice, or downgrade challenge dice to difficulty dice:

const config: SimulationConfig = {
  dicePool: {
    abilityDice: 3,
    difficultyDice: 2,
  },
  modifiers: {
    upgradeAbility: 2, // Upgrade 2 ability dice to proficiency
    upgradeDifficulty: 1, // Upgrade 1 difficulty die to challenge
  },
};

Player vs Opposition Modifiers

Apply different modifiers to player and opposition rolls:

const config: SimulationConfig = {
  dicePool: {
    abilityDice: 2,
    proficiencyDice: 1,
    difficultyDice: 2,
  },
  playerModifiers: {
    automaticSuccesses: 1,
    upgradeAbility: 1,
  },
  oppositionModifiers: {
    automaticThreats: 1,
    upgradeDifficulty: 1,
  },
};

Modifier Analysis

When using modifiers, the results include additional analysis:

interface ModifierAnalysis {
  automaticSymbolContribution: {
    successes: number;
    failures: number;
    advantages: number;
    threats: number;
    triumphs: number;
    despairs: number;
  };
  rolledSymbolContribution: {
    // Same structure, showing dice-rolled symbols
  };
  upgradeImpact: {
    abilityUpgrades: number;
    difficultyUpgrades: number;
    proficiencyDowngrades: number;
    challengeDowngrades: number;
  };
}

Results Include

  • Averages: Mean values for success, advantage, triumph, failure, threat, and despair
  • Medians: Median values for all symbols
  • Standard Deviations: Standard deviation for all symbols
  • Probabilities:
    • Success probability (net successes > 0)
    • Critical success probability (at least one triumph)
    • Critical failure probability (at least one despair)
    • Net positive probability (both net successes and net advantages > 0)
  • Distribution Analysis:
    • Skewness (distribution asymmetry)
    • Kurtosis (distribution "tailedness")
    • Outliers (values > 2 standard deviations from mean)
    • Modes (most common values)
    • Percentiles (25th, 50th, 75th, 90th)

Development

# Install dependencies
npm install

# Run tests
npm test

# Build the package
npm run build

Use Cases

Basic Combat Check

import { DicePool } from "@swrpg-online/dice";
import { MonteCarlo } from "@swrpg-online/monte-carlo";

// Combat check with 2 green (Ability) and 1 yellow (Proficiency)
const combatPool: DicePool = {
  abilityDice: 2,
  proficiencyDice: 2,
  difficultyDice: 2,
  challengeDice: 1,
};

const combatSim = new MonteCarlo(combatPool);
const combatResults = combatSim.simulate();

console.log("Combat Check Results:", JSON.stringify(combatResults, null, 2));
{
  "averages": {
    "successes": 1.4205,
    "advantages": 2.5969,
    "triumphs": 0.1717,
    "failures": 0.3253,
    "threats": 2.1799,
    "despair": 0.0827,
    "lightSide": 0.0,
    "darkSide": 0.0
  },
  "medians": {
    "successs": 1,
    "advantages": 3,
    "triumphs": 0,
    "failures": 0,
    "threats": 2,
    "despair": 0,
    "lightSide": 0,
    "darkSide": 0
  },
  "standardDeviations": {
    "successes": 1.4573536804770009,
    "advantages": 1.4342978735255518,
    "triumphs": 0.396256369033995,
    "failures": 0.7638585667516965,
    "threats": 1.1950464384281536,
    "despair": 0.2754282302161655,
    "lightSide": 0.0,
    "darkSide": 0.0
  },
  "successProbability": 0.6273,
  "criticalSuccessProbability": 0.1643,
  "criticalFailureProbability": 0.0827,
  "netPositiveProbability": 0.219,
  "histogram": {
    "netSuccesses": { /* distribution data */ },
    "netAdvantages": { /* distribution data */ },
    "triumphs": { /* distribution data */ },
    "despairs": { /* distribution data */ },
    "lightSide": { /* distribution data */ },
    "darkSide": { /* distribution data */ }
  },
  "analysis": {
    "netSuccesses": {
      "skewness": 0.12,
      "kurtosis": -0.20,
      "outliers": [-2, 4],
      "modes": [1],
      "percentiles": {
        "25": 0,
        "50": 1,
        "75": 2,
        "90": 3
      }
    },
    "netAdvantages": { /* similar structure */ },
    "triumphs": { /* similar structure */ },
    "despairs": { /* similar structure */ },
    "lightSide": { /* similar structure */ },
    "darkSide": { /* similar structure */ }
  }
}

Statistical Analysis Features

The Monte Carlo simulation provides detailed statistical information:

  1. Basic Probabilities

    • Success rate (net positive successes)
    • Triumph and Despair chances
    • Net positive results (both success and advantage)
  2. Detailed Statistics

    • Mean values for all symbols
    • Median values for all symbols
    • Standard deviations
    • Distribution analysis (skewness, kurtosis, outliers)
    • Mode detection
    • Percentile calculations

How to Interpret Results

When analyzing your dice pool using the Monte Carlo simulation, here's how to interpret each result:

Probability Metrics

  • successProbability: Represents the chance of achieving a net success (successes minus failures > 0). For example, a value of 0.65 means you have a 65% chance of succeeding at the task. In SWRPG terms, this is your chance of meeting or exceeding the difficulty of the check.

  • criticalSuccessProbability: The chance of rolling at least one triumph (⊺). In SWRPG, triumphs can trigger powerful narrative effects or special abilities regardless of success/failure. A value of 0.167 means you have about a 1-in-6 chance of scoring a triumph.

  • criticalFailureProbability: The chance of rolling at least one despair (⊝). Similar to triumphs, despairs can trigger significant negative narrative events. A probability of 0.083 indicates about a 1-in-12 chance of a despair occurring.

  • netPositiveProbability: The likelihood of achieving both net successes and net advantages. This is particularly useful for social encounters or situations where both succeeding and gaining advantage are important. A value of 0.432 means you have a 43.2% chance of both succeeding and gaining advantage.

Statistical Measures

  • averages: The expected number of each symbol you'll get on average:

    • A successes average of 1.5 means you typically get 1-2 successes
    • An advantages average of 0.8 means you usually get about 1 advantage
    • Triumphs/Despair averages are typically low (e.g., 0.083 = 1 triumph per 12 rolls)
    • Light/Dark side averages are typically 0 unless using Force dice
  • medians: The middle value when all results are sorted. Useful for understanding the "typical" roll:

    • If different from the average, indicates skewed results
    • More resistant to extreme rolls than averages
    • Helps understand what a "normal" roll looks like
  • standardDeviations: Measures how much variation exists from the average:

    • Lower values (e.g., 0.5) indicate consistent results
    • Higher values (e.g., 1.5) indicate more volatile/swingy rolls
    • About 68% of rolls fall within ±1 standard deviation of the average
    • About 95% of rolls fall within ±2 standard deviations

Histogram Data

The histogram field provides a detailed frequency distribution for key outcomes:

"histogram": {
  "netSuccesses": { // Distribution of (Successes - Failures)
    "0": 37445,     // 37445 rolls resulted in 0 net Successes
    "1": 26516,     // 26516 rolls resulted in 1 net Success
    "2": 8298,      //  8298 rolls resulted in 2 net Successes
    "-1": 20853,    // 20853 rolls resulted in -1 net Success (1 net Failure)
    "-2": 6888       //  6888 rolls resulted in -2 net Successes (2 net Failures)
  },
  "netAdvantages": { // Distribution of (Advantages - Threats)
    "0": 39009,     // 39009 rolls resulted in 0 net Advantages
    "1": 22149,     // 22149 rolls resulted in 1 net Advantage
    "2": 8463,      //  8463 rolls resulted in 2 net Advantages
    "-1": 22030,    // 22030 rolls resulted in -1 net Advantage (1 net Threat)
    "-2": 8349       //  8349 rolls resulted in -2 net Advantages (2 net Threats)
  },
  "triumphs": {      // Distribution of Triumph counts
    "0": 83570,     // 83570 rolls had 0 Triumphs
    "1": 15430,     // 15430 rolls had 1 Triumph
    "2": 1000       //  1000 rolls had 2 Triumphs
  },
  "despairs": {      // Distribution of Despair counts (similar structure) },
  "lightSide": {     // Distribution of Light Side point counts (Force Dice) },
  "darkSide": {      // Distribution of Dark Side point counts (Force Dice) }
}
  • Keys: Represent the specific outcome value (e.g., the net number of successes/advantages, or the count of triumphs/despairs).
    • For netSuccesses, negative keys indicate net Failures (e.g., -1 means 1 net Failure).
    • For netAdvantages, negative keys indicate net Threats (e.g., -2 means 2 net Threats).
  • Values: Represent the number of simulation iterations (rolls) that resulted in that specific outcome.

This data allows for a detailed view of the likelihood of every possible outcome, going beyond the summary statistics. It's the basis for calculating the analysis metrics like skewness, kurtosis, and percentiles.

Distribution Analysis

  • skewness: Measures distribution asymmetry:

    • Positive: More extreme positive results than negative
    • Negative: More extreme negative results than positive
    • Near 0: Roughly symmetric distribution
  • kurtosis: Measures distribution "tailedness":

    • Positive: More extreme results than a normal distribution
    • Negative: Fewer extreme results than a normal distribution
    • Near 0: Similar to a normal distribution
  • outliers: Values more than 2 standard deviations from the mean:

    • Useful for identifying unusual or extreme results
    • Helps understand the range of possible outcomes
    • Important for risk assessment
  • modes: Most common values in the distribution:

    • Single mode: One clear "most common" result
    • Multiple modes: Several equally common results
    • Helps identify typical outcomes
  • percentiles: Value thresholds for different percentiles:

    • 25th: "Worst quarter" threshold
    • 50th: Median result
    • 75th: "Best quarter" threshold
    • 90th: "Exceptional" threshold

For example, if you have:

{
  averages: { successes: 2.0, advantages: 1.5 },
  standardDeviations: { successes: 1.2, advantages: 1.1 },
  analysis: {
    netSuccesses: {
      skewness: 0.12,
      kurtosis: -0.20,
      outliers: [-2, 4],
      modes: [1],
      percentiles: {
        "25": 0,
        "50": 1,
        "75": 2,
        "90": 3
      }
    }
  }
}

This means:

  • You typically get 2 successes, but about 68% of rolls will give you 0.8 to 3.2 successes
  • You usually get 1-2 advantages, with 68% of rolls giving you 0.4 to 2.6 advantages
  • The distribution is slightly right-skewed (0.12) and has lighter tails than normal (-0.20)
  • Unusual results include -2 and 4 successes
  • The most common result is 1 success
  • 25% of rolls give 0 or fewer successes
  • 50% of rolls give 1 or fewer successes
  • 75% of rolls give 2 or fewer successes
  • 90% of rolls give 3 or fewer successes

Performance Considerations

  • Default 10,000 iterations provide a good balance of accuracy and speed

  • Increase iterations for more precise probability calculations:

    const preciseSim = new MonteCarlo(pool, 100000);
  • Memory-efficient implementation:

    • Uses running statistics to avoid storing all roll results
    • Sparse histogram storage for distribution analysis
    • Cached calculations for frequently accessed statistics
    • Direct array access for histogram updates
    • Optimized for large datasets and long-running simulations
    • Selector-based caching for improved performance
  • Performance optimizations:

    • Single-pass calculations for all statistics
    • Efficient histogram-based calculations
    • Running statistics for improved accuracy
    • Minimized memory allocations
    • Optimized for large iteration counts
    • Prefixed cache keys for better organization
    • Selector-based caching for reuse

Available Statistics

The simulate() method returns a MonteCarloResult with the following information:

interface MonteCarloResult {
  // Mean values for each symbol (calculated using running statistics)
  averages: {
    successes: number;
    advantages: number;
    triumphs: number;
    failures: number;
    threats: number;
    despair: number;
    lightSide: number;
    darkSide: number;
  };

  // Median values for each symbol (calculated from histogram)
  medians: {
    successes: number;
    advantages: number;
    triumphs: number;
    failures: number;
    threats: number;
    despair: number;
    lightSide: number;
    darkSide: number;
  };

  // Standard deviations for each symbol (calculated using running statistics)
  standardDeviations: {
    successes: number;
    advantages: number;
    triumphs: number;
    failures: number;
    threats: number;
    despair: number;
    lightSide: number;
    darkSide: number;
  };

  // Probability of net successes > 0 (calculated during simulation)
  successProbability: number;

  // Probability of at least one triumph (calculated during simulation)
  criticalSuccessProbability: number;

  // Probability of at least one despair (calculated during simulation)
  criticalFailureProbability: number;

  // Probability of both net successes and net advantages > 0 (calculated during simulation)
  netPositiveProbability: number;

  // Histogram data for distribution analysis (sparse storage)
  histogram: HistogramData;

  // Detailed analysis of distributions (calculated from histogram)
  analysis: {
    netSuccesses: DistributionAnalysis;
    netAdvantages: DistributionAnalysis;
    triumphs: DistributionAnalysis;
    despairs: DistributionAnalysis;
    lightSide: DistributionAnalysis;
    darkSide: DistributionAnalysis;
  };
}

Error Handling

The MonteCarlo class includes built-in validation:

  • Validates that the dice pool contains at least one die
  • Ensures all die counts are non-negative integers
  • Validates iteration count (minimum 100, maximum 1,000,000)
  • Handles unknown selector types in statistical calculations
  • Manages cache misses with valid selectors
  • Handles empty histograms and incomplete data
try {
  const simulation = new MonteCarlo(pool);
  const results = simulation.simulate();
} catch (error) {
  if (error instanceof MonteCarloError) {
    console.error("Simulation error:", error.message);
  }
}

License

MIT