User guide All lessons Cookbook Function reference Open playground

Open this document in the playground · Download source

Build and defend a complete scoped model

Part H · L32 · Prerequisite: L31 · One modelling idea

Situation, question, and prediction

Graduation brief: model one target’s risk of taking at least 28 damage from a base D&D 2014 Fireball, with Dexterity save bonus +3 against DC 15. A success halves damage, rounded down. No resistance or Evasion. Before reading the solution, write assumptions, choose representations, predict bounds, and construct the report from a blank file.

Build

Sample solution: build the independent damage total and natural save, then classify their pair. Preserve the actual damage total while deciding whether to halve it. >= includes damage exactly equal to the target’s HP. The policy does not multiply unrelated hit and damage marginals; both determine one event inside the callback.

hp = 28
save_bonus = 3
save_dc = 15
full = dice_pool(8, 6).sum()
bands = scale().step("Below HP threshold").step("Damage reaches HP")
def harm(raw_damage, natural_save):
    damage = raw_damage
    if natural_save + save_bonus >= save_dc:
        damage = raw_damage // 2
    if damage >= hp:
        return "Damage reaches HP"
    return "Below HP threshold"
result = joint_classify(full, d(20), bands, harm)
output("One-target Fireball risk", result)
output("At least current HP in damage", result.pmf("Damage reaches HP"))

One-target Fireball risk · Outcomes

outcome%fracX/730
Below HP threshold70.3513/730513
Damage reaches HP29.7217/730217

At least current HP in damage · Prob

outcome%fracX/730
At least current HP in damage29.7217/730217

Run, read, and check

The save succeeds on natural 12–20: 9/20. A successful save deals at most 24, so cannot reach 28 HP. An independent oracle is therefore (11/20) × P(8d6 ≥28). Count eight-d6 totals by repeated convolution or a separate small dynamic count. Overall mean damage is (11/20)×28 + (9/20)×13.75 = 21.5875, but the risk is a separate question.

Change one thing

Set HP to 49: risk is zero. Set HP to 4: every possible damage result reaches it, so risk is one. At HP 28 with save bonus 20 the risk is zero because all ordinary saves succeed; at bonus −20 it becomes P(8d6 ≥28). These are model boundary checks, not special death-save rules.

Try it yourself

Graduation: invent a two-d6 rule where armour subtracts after taking the higher die, then ask about a specified HP threshold. Deliver a standalone literate file, one independent face count, at least two boundary checks, and exclusions. Acceptance criteria: use 36 equally likely pairs, keep the higher before armour, floor at zero, and query inclusively. Example d6+d6, armour 2, HP 4: only a maximum 6 reaches HP, probability 11/36. Do not reuse this Fireball script unchanged.

Rules and model notes

D&D Basic Rules 2014: Fireball, ordinary saves, and rounding down. One target; no shared multi-target event, concentration, resistance, vulnerability, Evasion, or instant-death interpretation. “Damage reaches HP” is not a claim of death.

What you now know / where next

Build and defend a complete scoped model is the reusable idea. Follow the generated previous/next links below, or return to the course index. For a complete self-contained application, see fireball-one-target.

Content ID: L32 · Review status: pilot

Prerequisites: L31