Counting Faces with Spiral Dice

By Kaylee Roland. Published .

Somewhere around August of last year, I became interested in Fantasy Flight’s Genesys TTRPG system. I would spend many days theorizing campaigns I would certainly never play. Eventually, I decided I wanted to order myself a set of Genesys dice and came face-to-face with the biggest complaint about Genesys: The dice are really, really hard to get.

Fast-forward to December. I had just missed the first print run of the Genesys dice in years, and looked around for other options. I became quite intrigued in Jon Kohlingen’s spiral dice, pitched, among other things, as inspired by Genesys. Jon has done some great work preparing the Spiral Dice Hackers’ Guide, which outlines many of the probabilities built into the dice. However, I’m an absolute fiend for data, and there’s a good bit that’s out-of-scope for the Hacker’s Guide.

Today, we’re going to answer some questions about spiral dice. By the end of this, we should know:

  • How much impact does adding or removing dice have?
  • How good are automatic hits, spares, or spirals?
  • How useful is converting dice into automatic hits, spares, or spirals?
  • How often do I get to use an ability…
    • …that requires 1, 2, 3, or 4 spares or spirals?
    • …if it can only be used on success or failure?

Hopefully, this will serve as a comprehensive reference to basically any statistic you’re interested in with the spiral dice.

Let’s get started!

The System

First, we’ll establish the rules of the system we’re using. Fundamentally, this is just the dice part of the Sapio System, but it bears reiterating. The fundamental rules are as follows:

  1. A pool consists of 0–7 dice. Sapio limits dice pools to 6, but my order includes 7 dice, so we might as well consider them. We’ll also ignore the 0 case; I trust you can handle that math on your own.
  2. Hits are counted and compared to a Target Number (TN). If we meet or exceed the TN, our roll is a success, otherwise it is a failure.
  3. Spares and spirals are canceled and the remaining are counted. The net result provides a benefit (in the case of spares) or a drawback (in the case of spirals). In general, you cannot have both spirals and spares for a roll.
  4. In combat, extra hits are spent to upgrade a weapon’s damage. We’ll use the same tiered steps, where 1 hit upgrades minor to moderate, 2 upgrades moderate to severe, and 3 upgrades severe to lethal.

Getting the Raw Data

Alright, we’ve got a system. Now we’ve got to get our numbers. There’s a pretty easy-to-implement algorithm I like that gives the odds of every outcome on a set of dice, so we’ll go with that:

pub fn calculate_outcomes(
    number_of_dice: u16,
    die_table: &HashMap<Outcome, Rational>,
) -> HashMap<Outcome, Rational> {
    let mut outcomes = HashMap::new();
    // We start with an outcome of nothing with 100% probability.
    outcomes.insert(Outcome::ZERO, Rational::from(1));
    for _ in 0..number_of_dice {
        // In each iteration, we build on the previous outcomes...
        let previous_outcomes = outcomes;
        outcomes = HashMap::new();
        for (cum_outcome, cum_chance) in &previous_outcomes {
            for (die_outcome, die_chance) in die_table {
                // ...by adding in the new die's contribution...
                let outcome = cum_outcome + die_outcome;
                // ...scaled by the chance we see that outcome.
                let chance = cum_chance * die_chance;
                // Finally, we combine common outcomes to a single probability.
                if let Some(current) = outcomes.get(&outcome) {
                    outcomes.insert(outcome, chance + current);
                } else {
                    outcomes.insert(outcome, chance);
                }
            }
        }
    }
    outcomes
}

The source code is available on GitLab, if you’d like to tinker around. There’s a small command-line tool for generating all values in a range, if you just want the data. It does get significantly slower for higher values, so I’d advise starting low.

# Generates the outcome odds for 100-200 dice, inclusive.
cargo run -- --min 100 --max 200

From here, all you need to do is import the CSV files into your favorite spreadsheet editor, preferably with “Evaluate formulas” enabled. I’d recommend creating a pivot table on the data to make it a bit nicer to parse. SpiralDice.ods provides exactly these pivot tables---though with somewhat reduced precision.

Hitting that Target Number

Okay, first goal: we want to succeed our check. Sapio generally recommends GMs use Target Numbers from 0 to 6; we’ll once again ignore 0 and include 7.

TN 1TN 2TN 3TN 4TN 5TN 6TN 7
1 die50.00%16.67%-----
2 dice75.00%41.67%13.89%2.78%---
3 dice87.50%62.50%33.33%12.96%3.24%0.46%-
4 dice93.75%77.08%52.08%28.01%11.50%3.47%0.69%
5 dice96.88%86.46%67.36%44.21%23.77%10.24%3.42%
6 dice98.44%92.19%78.65%58.97%37.85%20.41%9.08%
7 dice99.22%95.57%86.46%71.06%51.69%32.65%17.65%

This data is perhaps less immediately useful than some we’ll look at later—Sapio’s own reference is certainly just as useful, if not more so. We’ll circle back to these when we start talking about those conditionally-usable abilities, since these will be necessary to determine how often we get to use an ability overall.

We can now answer some questions:

  • How good is reducing the TN by 1/an automatic hit? Pretty good. In most normal cases it can halve the odds of failure. In the most extreme case, it can increase your odds of success by 25 times.
  • How good is adding a die? While we don’t see as many significant jumps, adding a die is still quite good, especially when we’re more concerned with reliability and secondary abilities than pushing our limits. Of course, the most important use is changing certain TN 3+ checks from impossible to possible.
  • If I can decrease the TN by 1 at the cost of a die, should I? If your goal is succeeding the check, almost always, yes. There are a few cases where it’s even worth sacrificing two dice, but that’s a bit of an oddity. Frankly, the swings are so minimal that it’s not really worth having this as an ability, unless we’re going so far as to decrease the TN by 2.
  • Are abilities that clamp TN good? Similarly to reducing TN, yeah, these are pretty good, at least if you’re creative enough to find uses for them.

We can also conceptualize our weapon damage a bit. Suppose we’re rolling 3 dice to hit with our low draw weight bow (an example from the handbook that does minor damage) and need a TN of 1 (“average”) to hit. We can then determine:

  • We’ll do at least minor damage 87.5% of the time (TN 1).
  • We’ll do at least moderate damage 62.5% of the time (TN 2).
  • We’ll do at least severe damage 12.96% of the time (TN 4).
  • We’ll never do lethal damage (TN 7).

Thus, we’re just increasing our TN if we want to do a specific amount of damage. We can also determine that we’ll do exactly moderate damage ~50% of the time by subtracting those adjacent ranges—I’ll leave that math to you.

Given this method of computing damage odds by adjusting the TN, we’re actually going to need the rest of the possible values:

TN 8TN 9TN 10TN 11TN 12TN 13TN 14
<4 dice-------
4 dice0.08%------
5 dice0.85%0.14%0.01%----
6 dice3.27%0.92%0.20%0.03%>0.00%*--
7 dice8.06%3.07%0.95%0.23%0.04%0.01%>0.00%**

*About 1 in 50,000. **A little under 1 in 250,000.

So an impossible check with a minor damage weapon and 7 dice will become lethal once every 2,500 or so tries. I’m not sure these values will ever be useful, but at least we have them. Feel free to email me if any of your players ever roll 14 hits on 7 dice naturally.

Scoring those Spares and Spirals

Feeling fresh? Feeling good? Hope you’re ready for more numbers—I know I am. Next, up, we’re interested in those spares and spirals. We’re going to consider the case where we have some ability we want to activate by spending spares or spirals from a roll, or perhaps want to consider how powerful a “3 spiral penalty” should be.

Here’s our numbers:

Spirals1+2+3+4+5+6+7
1 die41.67%-----
2 dice38.19%17.36%----
3 dice41.09%20.25%7.23%----
4 dice42.03%23.99%10.25%3.01%---
5 dice42.81%26.32%13.31%5.02%1.26%--
6 dice43.40%28.16%15.66%7.12%2.41%0.52%-
7 dice43.87%29.63%17.63%8.95%3.70%1.13%0.22%
Spares1+2+3+4+5+6+7+
1 die33.33%8.33%-----
2 dice34.72%15.28%4.86%0.69%---
3 dice37.38%19.68%8.22%2.66%0.58%0.06%-
4 dice38.92%22.60%11.20%4.60%1.52%0.38%0.6%
5 dice39.97%24.88%13.61%6.47%2.62%0.88%0.24%
6 dice40.80%26.65%15.65%8.18%3.77%1.52%0.52%
7 dice41.44%28.10%17.38%9.75%4.92%2.22%0.89%
Spares8+9+10+11+12+13+14
<4 dice-------
4 dice>0.00%------
5 dice0.05%0.01%>0.00%----
6 dice0.15%0.03%0.01%>0.00%>0.00%--
7 dice0.31%0.09%0.02%>0.00%>0.00%>0.00%>0.00%

As we’d expect, spares and spirals are about evenly matched, with spares having a bit less reliability in exchange for a significantly higher ceiling.

We’re still missing some of the picture. By design, you are more likely to roll spirals with hits, and spares with misses. For our next bit, let’s focus in on how many spirals and spares we can expect assuming that we succeed and assuming that we fail. This is going to be a lot of tables.

Okay, so what can we do with this? Let’s suppose we’re making a hard check (TN 3), but we’re decently skilled, taking 4 dice. Then we know:

  • If we succeed, we’ll probably (half the time) do so with a negative side effect, and have a ‘critical success’ (positive outcome with a positive side effect) around a quarter of the time.
  • If we fail, we’ll probably (half the time) still get some positive benefit, but around a third of the time we’ll get a ‘critical failure’ (negative outcome with a negative side effect).

Factoring in that we hit the target number around half the time, we then figure out the chance of every situation:

TN 3 with 4 DiceNet SparesNet ZeroNet Spirals
Success14.55%10.42%27.11%
Failure24.37%8.64%14.91%

Computing Metrics

There’s a couple metrics that can help conceptualize these tables a bit more.

First up, you can calculate the median by looking for the point where the chance goes from “more than half” to “less than half”. Your median is somewhere between these two values. With the median, we can say, “Half the time, we’ll get more than the median, and half the time, we’ll get less than the median.”

Second, the mode can be calculated by determining the exact chance of each outcome, and finding the largest. This exact chance is just computed by subtracting off the chance of getting more than a specific value from the chance of getting at least a specific value. The mode will tell us, “What specific result are we most likely to get?”

Finally, the average is a bit less useful, only needed for determining the total number of hits/spares/spirals accumulated over so-many die rolls. In the world of TTRPGs, this is only useful for checks such as “In 6 rolls, you need to score at least 14 hits.” For this, you’ll want to find the exact chance of each outcome again, and then compute a weighted arithmetic mean by scaling each outcome by its likelihood and summing those scaled outcomes.

Closing Thoughts

So, what now? What should we do with all this power? Well, I certainly wouldn’t recommend optimizing Sapio to hell and back, but perhaps this can be a helpful resource to “get a feel” for how the dice are likely to behave.

If you’re somehow still hungry for more stats, the raw data is once again available on GitLab. If you’re making your own dice-based system, the code should be pretty easy to adapt to your rules or dice. Feel free to reach out to me with any comments or questions, of course!