{
  "schemaVersion": 1,
  "slug": "name-picker-calculator",
  "category": "gaming",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "746f7034e78b18c44b455ed8c367d8f698194e75da7ad5cda6361d9585b9a38b",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/name-picker-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": "a_{k+1} = (a_k + 1831565813) mod 4294967296 → u_k; (x_i, x_j) → (x_j, x_i), j = floor(u_k(i+1)), i = n−1,…,1; picked = x₀",
    "vars": [
      [
        "a_k",
        "internal generator state"
      ],
      [
        "x_i",
        "name at position i"
      ],
      [
        "u_k",
        "pseudorandom value 0–1"
      ],
      [
        "j",
        "swap index"
      ],
      [
        "n",
        "number of names"
      ]
    ],
    "note": "Trims comma-separated entries, rejects empty lists and lists over 1,000 names, and applies a seeded Fisher–Yates shuffle. Duplicate names remain separate entries and report their actual original position."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "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 list=String(names).split(',').map(x=>x.trim()).filter(Boolean);if(!list.length||list.length>1000)return{picked:null,position:null,totalNames:list.length,order:null,__error:'inputError'};const r=rng(seed),arr=list.map((name,index)=>({name,index}));for(let i=arr.length-1;i>0;i--){const j=Math.floor(r()*(i+1));[arr[i],arr[j]]=[arr[j],arr[i]];}return{picked:arr[0].name,position:arr[0].index+1,totalNames:list.length,order:firstNames==='yes'?arr.map(x=>x.name).join(' > '):''};",
    "inputs": [
      {
        "name": "names",
        "type": "text",
        "default": "Alex, Sam, Riley, Jordan, Casey",
        "step": 1
      },
      {
        "name": "seed",
        "type": "number",
        "default": 2026,
        "min": 0,
        "max": 1000000,
        "step": 1
      },
      {
        "name": "firstNames",
        "type": "select",
        "default": "no",
        "options": [
          {
            "value": "no"
          },
          {
            "value": "yes"
          }
        ]
      }
    ],
    "outputs": [
      {
        "name": "picked",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "position",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "totalNames",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "order",
        "precision": 0,
        "unit": "",
        "type": "text"
      }
    ],
    "interpret": null
  }
}
