# Blades in the Dark — action-result categories

**R18 · Intermediate · Scoped procedure: base action-result bands**

## Question and scope

For a supplied number of dice, how often is an action roll bad, partial, clean,
or critical? Take the highest d6 unless two or more sixes produce a critical.
At zero dice, roll two and take the lower, with no critical.

**Zero dice is not desperate position.** Position sets consequences; effect
sets what is accomplished. Neither is computed here. An action critical
increases effect, not a separate universal damage bonus. This component does
not assemble the pool, spend stress, resist consequences, or apply special abilities.

## Inputs

| Input | Default | Supported range |
|---|---:|---|
| `dice` | 2 | Integer 0–20; negative game pools should be supplied as zero |

This uses probability decomposition instead of enumerating every face tuple.
The [tutorial callback](../tutorial/23-shared-pool-rule.html) is useful for learning
shared-face rules, but its interactive limit is five dice. Seven dice took
roughly 13 seconds in a debug-WASM test; the engine's tuple guard is not a speed guarantee.

## Model

Bad means no die reaches 4. Partial means no six, minus the bad cases. Clean
means exactly one six; critical means at least two. These are mutually exclusive
and exhaustive categories, so this particular table **does** sum to one.
`pool.count(6)` constructs the count distribution efficiently without a custom
callback. The zero-dice branch uses the lower of two d6 explicitly.

```dice
dice = 2
if type(dice) != "int" or dice < 0 or dice > 20:
    fail("Use an integer dice count 0–20")
if dice == 0:
    lowest = keep_lowest(2, 6, 1)
    bad = lowest.cdf(3)
    partial = lowest.cdf(5) - bad
    clean = lowest.pmf(6)
    critical = 0.0
else:
    pool = dice_pool(dice, 6)
    sixes = pool.count(6)
    bad = pool.p_none([4, 5, 6])
    partial = pool.p_none(6) - bad
    clean = sixes.pmf(1)
    critical = sixes.p_ge(2)
rows = [("Bad", bad), ("Partial", partial), ("Clean", clean), ("Critical", critical)]
output("Blades action categories", prob_table(rows))
```

## Reading and independent checks

At two dice, the rows are 9/36, 16/36, 10/36, and 1/36. At zero dice they are
27/36, 8/36, 1/36, and zero. At one die, bad is 1/2 and partial is 1/3:
partial is not the most common band. At four dice, clean plus critical is
1 − (5/6)^4 = 671/1296, over half.

For positive n, an independent oracle is:
- bad = (1/2)^n;
- partial = (5/6)^n − (1/2)^n;
- clean = n × (1/6) × (5/6)^(n−1);
- critical = 1 − (5/6)^n − clean.

Tests compare this decomposition against a separate face count for small pools
and these formulas through the documented upper bound.

## Adaptations and limits

Change `dice` without changing the resolution rule. Do not treat a probability
of a clean result as a probability of a particular fictional consequence: that
also depends on position and the situation. Do not multiply these rows together;
they are exclusive categories from the same roll.

## Rules and related lessons

[Blades core system](https://bladesinthedark.com/core-system) and
[action roll](https://bladesinthedark.com/action-roll), source checked 2026-09-15.
Independent human rules/novice review remains pending. Read
[L15](../tutorial/15-counting-successes.html) for counts and
[L23](../tutorial/23-shared-pool-rule.html) for the equivalent callback approach.
