{
  "schemaVersion": 1,
  "slug": "board-game-score-tracker-calculator",
  "category": "fun",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "b35067f5270a50ab3b8e5adb9a66f348b4fd07258108d8867cee5ade36851a97",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/board-game-score-tracker-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": "winner = argmax s_i (↑) | argmin s_i (↓); avg = (Σ s_i)/n; spread = max s_i − min s_i",
    "vars": [
      [
        "s_i",
        "Player i score"
      ],
      [
        "n",
        "Players with a score"
      ],
      [
        "avg",
        "Mean score"
      ],
      [
        "spread",
        "Gap between highest and lowest"
      ],
      [
        "↑/↓",
        "↑ highest score wins; ↓ lowest score wins"
      ],
      [
        "winner",
        "Winning player"
      ]
    ],
    "note": "Scores and player names are comma-separated lists; the ranking is produced by sorting (highest or lowest wins); total = Σ s_i."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "const raw=String(scores).split(',').map(x=>x.trim()),names=String(players).split(',').map(x=>x.trim());if(!raw.length||raw.some(x=>! /^[+-]?(?:\\d+\\.?\\d*|\\.\\d+)$/.test(x)||!Number.isFinite(Number(x)))||names.length!==raw.length)return{winner:null,winningScore:null,ranking:null,average:null,total:null,spread:null,playersCount:null,__error:'inputError'};const nums=raw.map(Number),idx=nums.map((v,i)=>({v,i})).sort((a,b)=>higherWins==='low'?a.v-b.v:b.v-a.v),winner=idx.filter(o=>o.v===idx[0].v).map(o=>names[o.i]||'Player '+(o.i+1)).join(', '),ranking=idx.map((o,r)=>(r+1)+'. '+(names[o.i]||'Player '+(o.i+1))+' ('+o.v+')').join('; '),total=nums.reduce((a,b)=>a+b,0);return{winner,winningScore:idx[0].v,ranking,average:total/nums.length,total,spread:Math.abs(idx[0].v-idx[idx.length-1].v),playersCount:nums.length};",
    "inputs": [
      {
        "name": "scores",
        "type": "text",
        "default": "42, 37, 51, 29",
        "step": 1
      },
      {
        "name": "players",
        "type": "text",
        "default": "Alex, Sam, Riley, Jordan",
        "step": 1
      },
      {
        "name": "higherWins",
        "type": "select",
        "default": "high",
        "options": [
          {
            "value": "high"
          },
          {
            "value": "low"
          }
        ]
      }
    ],
    "outputs": [
      {
        "name": "winner",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "winningScore",
        "precision": 2,
        "unit": ""
      },
      {
        "name": "ranking",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "average",
        "precision": 2,
        "unit": ""
      },
      {
        "name": "total",
        "precision": 2,
        "unit": ""
      },
      {
        "name": "spread",
        "precision": 2,
        "unit": ""
      },
      {
        "name": "playersCount",
        "precision": 0,
        "unit": ""
      }
    ],
    "interpret": null
  }
}
