Year Zero Probabilities Redux

Posted: 2019-12-19
Last Modified: 2023-03-18
Word Count: 924
Tags: lua-code rpg year-zero-system

Table of Contents

2023-03-18: Added Table of Contents and Titles.

In Which I Consider The Number Of Successes

In most versions of the Year Zero System, if players roll more than one 6, they can spend them for added benefits. (Mutant Year Zero and the Alien RPG calls them “stunts”; Forbidden Lands has no special name and only certain skills benefit.)

So how likely are you to roll more than one 6? Not very. The average number of successes is N/6, where N is the number of dice.

Below is a table created by a Lua program at the end of this post.

Dice Success No Stunts 1 2 3 4 5 6 7 > 7
1d 16.67% 16.67%
2d 30.56% 27.78% 2.78%
3d 42.13% 34.72% 6.94% 0.46%
4d 51.77% 38.58% 11.57% 1.54% 0.08%
5d 59.81% 40.19% 16.08% 3.22% 0.32% 0.01%
6d 66.51% 40.19% 20.09% 5.36% 0.80% 0.06% <0.01%
7d 72.09% 39.07% 23.44% 7.81% 1.56% 0.19% 0.01% <0.01%
8d 76.74% 37.21% 26.05% 10.42% 2.60% 0.42% 0.04% <0.01% <0.01% <0.01%
9d 80.62% 34.89% 27.91% 13.02% 3.91% 0.78% 0.10% <0.01% <0.01% <0.01%
10d 83.85% 32.30% 29.07% 15.50% 5.43% 1.30% 0.22% 0.02% <0.01% <0.01%
11d 86.54% 29.61% 29.61% 17.77% 7.11% 1.99% 0.40% 0.06% <0.01% <0.01%
12d 88.78% 26.92% 29.61% 19.74% 8.88% 2.84% 0.66% 0.11% 0.01% 0.02%
13d 90.65% 24.30% 29.16% 21.38% 10.69% 3.85% 1.03% 0.21% 0.03% 0.03%
14d 92.21% 21.81% 28.35% 22.68% 12.47% 4.99% 1.50% 0.34% 0.06% 0.07%
15d 93.51% 19.47% 27.26% 23.63% 14.18% 6.24% 2.08% 0.53% 0.11% 0.13%
16d 94.59% 17.31% 25.96% 24.23% 15.75% 7.56% 2.77% 0.79% 0.18% 0.21%
17d 95.49% 15.32% 24.52% 24.52% 17.16% 8.93% 3.57% 1.12% 0.28% 0.35%
18d 96.24% 13.52% 22.99% 24.52% 18.39% 10.30% 4.46% 1.53% 0.42% 0.53%
19d 96.87% 11.89% 21.41% 24.26% 19.41% 11.65% 5.44% 2.02% 0.61% 0.79%
20d 97.39% 10.43% 19.82% 23.79% 20.22% 12.94% 6.47% 2.59% 0.84% 1.13%
NOTE: On Dec. 31, 2019, I added rows to the table and a section about the probabilities of pushed rolls.

In Which I Consider Pushed Rolls

The table above doesn’t include the chances of success for a Pushed Roll in Mutant Year Zero or Forbidden Lands, because that would make the table (and the math) much more complicated. (The mix of Base Dice, Skill Dice, and Gear Dice is also a factor.)

To calculate pushed rolls in Coriolis, Tales from the Loop, Things from the Flood, and Vaesen, where a roll of 1 on a die has no effect, use the row that’s double the size of the pool. e.g. a pushed pool of 6d has a total1 probability of 12d.

In Alien, if Stress is less than 3, take the number of Base Dice and Stress Dice, double it, and add 1 for the new point of Stress. Once Stress reaches 4 or more, the chance of a Panic Action superseding the player’s intended action starts affecting the probabilities.

BTW, I’ve worked out a success table for the Alien RPG as a function of the number of Base Dice and Stress Dice, because of course I would. However, I’m not entirely sure it’s correct. (I actually tried calculating it two different ways, and the numbers of each are close, but not exact, which makes me suspicious.) When I’m more confident about the calculations I’ll print them for the amusement of whatever masochist reads this blog, if any. And my own, of course.

In Which I Show Yet More Code

#!/usr/bin/env lua

-- Chances of success on a single die
local SUCCESS = 1/6

local function factorial(n)
    if n <= 1 then
        return 1
    end
    return n * factorial(n-1)
end

local function choose(n, k)
    if n < 1 or k < 0 or k > n then
        return 0
    end
    return factorial(n) / (factorial(k) * factorial(n-k))
end

local function binomial(n, k, p)
    return choose (n, k) * (p)^k * (1-p)^(n-k)
end

-- chance of rolling at least exactly `k` successes on `n` dice
local function success_equal(n, k)
    return binomial(n, k, SUCCESS)
end

local function success_greater(n, k)
    local result = 0
    for i = k+1, n do
        result = result + success_equal(n, i)
    end
    return result
end

local function success(n)
    return (1 - (1 - SUCCESS)^n)
end

local function format_percent(p)
    if p <= 0 then
        return string.rep(' ', 8)
    elseif p < 0.0001 then
        return ' <0.01% '
    end
    return string.format(" %5.2f%% ", p * 100)
end

local function print_table(maxdice, maxstunts)
    local md = (maxdice or 10)
    local ms = (maxstunts or ((md-1) // 2))
    local rowbuf

    -- print header
    local gtcol = ms < md
    local cols
    if gtcol then
        cols = ms + 3
    else
        cols = ms + 2
    end

    rowbuf = { "Dice ", " Success ", " No Stunts ", " 1  " }
    for n = 2, ms do
        table.insert(rowbuf, string.format(" %-6d ", n))
    end
    if gtcol then
        table.insert(rowbuf, string.format(" > %-4d ", ms))
    end
    table.insert(rowbuf, "")
    print(table.concat(rowbuf, '|'))

    rowbuf = { ":---:" }
    for n = 1, cols do
        table.insert(rowbuf, "-------:")
    end
    table.insert(rowbuf, "")
    print(table.concat(rowbuf, '|'))

    -- print each row

    for n = 1, md do
        rowbuf = { string.format(" %2dd ", n) }

        -- success totals

        table.insert(rowbuf, format_percent(success(n)))

        -- 0 - `ms` stunts
        for k = 0, ms do
            table.insert(rowbuf, format_percent(success_equal(n, k+1)))
        end

        -- > `ms` stunts
        if gtcol then
            table.insert(rowbuf, format_percent(success_greater(n, ms)))
        end

        table.insert(rowbuf, "")
        print(table.concat(rowbuf, '|'))
    end
end

print_table(20, 7)

  1. I.e. including the probabilities of the original roll and the reroll. If the original roll failed, the reroll has the same probability as the original; if the original roll succeeded, the column for N indicates the probability of scoring N + 1 additional stunts. ↩︎