{
  "schemaVersion": 1,
  "slug": "dice-notation-calculator",
  "category": "gaming",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "952a8904ccf44bd797aa296bdfe4ada03b4cf9b5e545338760541ce8a229bf18",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/dice-notation-calculator.json",
    "src/engine.js"
  ],
  "runtimeSource": "/sources/engine.txt",
  "runtimeHash": "5c888d8898afbdee36267bb9977829e1e2ac568f6677c8ee87469c139864645c",
  "scope": "The compute function records implemented equations, constants, lookup tables and custom rules. Inputs record defaults and allowed values; outputs record precision and units. Defaults are examples, not recommendations. General background references are not evidence for this specific algorithm.",
  "publishedFormula": {
    "formula": "r_i = int(u_i × s) + 1 → T = m + Σ r_i (i = 1..n)",
    "vars": [
      [
        "n",
        "dice count"
      ],
      [
        "s",
        "sides per die"
      ],
      [
        "m",
        "flat modifier"
      ],
      [
        "r_i",
        "result of die i"
      ],
      [
        "u_i",
        "seeded random value, 0–1"
      ]
    ],
    "note": "Notation n d s with optional +m or −m; n is clamped to 1–500 and s to 2–1000. The u_i stream is generated from the seed and the loop stops after n rolls; total ranges from n+m to n×s+m."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "if(!Number.isInteger(seed)||seed<0||seed>1000000)return{__error:'inputError'};const m=String(notation).toLowerCase().replace(/\\s+/g,'').match(/^(\\d*)d(\\d+)([+-]\\d+)?$/);if(!m)return{diceCount:null,sides:null,modifier:null,rolls:null,total:null,minimum:null,maximum:null,__error:'inputError'};const n=Number(m[1]||1),sd=Number(m[2]),mod=m[3]?Number(m[3]):0;if(!Number.isSafeInteger(n)||n<1||n>500||!Number.isSafeInteger(sd)||sd<2||sd>1000||!Number.isSafeInteger(mod)||Math.abs(mod)>1000000)return{diceCount:null,sides:null,modifier:null,rolls:null,total:null,minimum:null,maximum:null,__error:'inputError'};const rng=s=>{let a=Math.floor(s)>>>0;return()=>{a=(a+0x6D2B79F5)>>>0;let t=a;t=Math.imul(t^(t>>>15),t|1);t^=t+Math.imul(t^(t>>>7),t|61);return((t^(t>>>14))>>>0)/4294967296;};};const r=rng(seed),list=[];let sum=0;for(let i=0;i<n;i++){const v=Math.floor(r()*sd)+1;list.push(v);sum+=v;}return{diceCount:n,sides:sd,modifier:mod,rolls:list.join(', '),total:sum+mod,minimum:n+mod,maximum:n*sd+mod};",
    "inputs": [
      {
        "name": "notation",
        "type": "text",
        "default": "4d6+2",
        "step": 1,
        "preserveEmpty": true
      },
      {
        "name": "seed",
        "type": "number",
        "default": 4,
        "min": 0,
        "max": 1000000,
        "step": 1,
        "requiredValue": true,
        "advanced": true
      }
    ],
    "outputs": [
      {
        "name": "total",
        "precision": 0,
        "unit": "",
        "trimTrailingZeros": true
      },
      {
        "name": "rolls",
        "precision": 0,
        "unit": "",
        "type": "text",
        "display": "tokens",
        "separator": ","
      },
      {
        "name": "diceCount",
        "precision": 0,
        "unit": "",
        "trimTrailingZeros": true
      },
      {
        "name": "sides",
        "precision": 0,
        "unit": "",
        "trimTrailingZeros": true
      },
      {
        "name": "modifier",
        "precision": 0,
        "unit": "",
        "trimTrailingZeros": true
      },
      {
        "name": "minimum",
        "precision": 0,
        "unit": "",
        "trimTrailingZeros": true
      },
      {
        "name": "maximum",
        "precision": 0,
        "unit": "",
        "trimTrailingZeros": true
      }
    ],
    "interpret": null
  }
}
