{
  "schemaVersion": 1,
  "slug": "lucky-number-generator-calculator",
  "category": "fun",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "47bb0f1d52f418d71035046dcd9c629a6cc32a3d54e7937faa30921ce61d0bf7",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/lucky-number-generator-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": "v₁, …, v_count: vⱼ = lo + floor(uⱼ × (hi − lo + 1)), uⱼ ∈ [0,1); U = 1 ⇒ vⱼ ≠ vᵢ ∀ i < j",
    "vars": [
      [
        "seed",
        "PRNG seed"
      ],
      [
        "lo",
        "lowest value"
      ],
      [
        "hi",
        "highest value"
      ],
      [
        "u",
        "pseudo-random value in [0,1)"
      ],
      [
        "v",
        "generated integer"
      ],
      [
        "count",
        "how many numbers"
      ],
      [
        "U",
        "unique-mode flag (1 = no repeats, 0 = repeats allowed)"
      ]
    ],
    "note": "Seeded Mulberry32-style pseudorandom generator. Unique mode requires range size ≥ requested count; otherwise input is rejected. Deterministic for a given seed; not a cryptographic RNG."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "const lo=Math.min(lowest,highest),hi=Math.max(lowest,highest),size=hi-lo+1;if(unique==='yes'&&size<count)return{numbers:null,sorted:null,sum:null,average: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),out=[],seen=new Set();let guard=0;while(out.length<count&&guard<count*300+2000){guard++;const v=lo+Math.floor(r()*size);if(unique==='yes'){if(seen.has(v))continue;seen.add(v);}out.push(v);}if(out.length!==count)return{numbers:null,sorted:null,sum:null,average:null,__error:'inputError'};const sum=out.reduce((a,b)=>a+b,0),sorted=out.slice().sort((a,b)=>a-b);return{numbers:out.join(', '),sorted:sorted.join(', '),sum,average:sum/out.length};",
    "inputs": [
      {
        "name": "count",
        "type": "number",
        "default": 6,
        "min": 1,
        "max": 100,
        "step": 1,
        "slider": true
      },
      {
        "name": "lowest",
        "type": "number",
        "default": 1,
        "min": -10000,
        "max": 1000000,
        "step": 1
      },
      {
        "name": "highest",
        "type": "number",
        "default": 49,
        "min": -10000,
        "max": 1000000,
        "step": 1
      },
      {
        "name": "unique",
        "type": "select",
        "default": "yes",
        "options": [
          {
            "value": "yes"
          },
          {
            "value": "no"
          }
        ]
      },
      {
        "name": "seed",
        "type": "number",
        "default": 88,
        "min": 0,
        "max": 1000000,
        "step": 1
      }
    ],
    "outputs": [
      {
        "name": "numbers",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "sorted",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "sum",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "average",
        "precision": 2,
        "unit": ""
      }
    ],
    "interpret": null
  }
}
