{
  "schemaVersion": 1,
  "slug": "basketball-free-throw-pct-calculator",
  "category": "sports",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "8bb2a12a4915a7b9a8e2342fbefcef125eca3dcaf0755b94198063d1235f8752",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/basketball-free-throw-pct-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": "P = m ÷ a × 100; i* = min { i : (m+i) ÷ (a+i) × 100 ≥ T }",
    "vars": [
      [
        "m",
        "Free throws made"
      ],
      [
        "a",
        "Attempted"
      ],
      [
        "P",
        "Percentage"
      ],
      [
        "T",
        "Target percentage"
      ],
      [
        "i*",
        "Consecutive makes needed"
      ]
    ],
    "note": "i* is searched iteratively from 1 to 500; if the target cannot be reached within 500 makes, it returns −1."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "if (![made,attempted,targetPct,gamesPlayed].every(Number.isFinite) || ![made,attempted,targetPct,gamesPlayed].every(Number.isInteger) || attempted < 1 || made < 0 || made > attempted || targetPct < 0 || targetPct > 100 || gamesPlayed < 1) return {percentage:null,misses:null,perGame:null,makesNeeded:null,__error:'inputError'};const percentage=made/attempted*100;let needed=0;while((made+needed)/(attempted+needed)*100<targetPct&&needed<500)needed++;if((made+needed)/(attempted+needed)*100<targetPct)needed=-1;return{percentage,misses:attempted-made,perGame:attempted/gamesPlayed,makesNeeded:needed};",
    "inputs": [
      {
        "name": "made",
        "type": "number",
        "default": 82,
        "min": 0,
        "max": 5000,
        "step": 1,
        "slider": true
      },
      {
        "name": "attempted",
        "type": "number",
        "default": 100,
        "min": 0,
        "max": 5000,
        "step": 1,
        "slider": true
      },
      {
        "name": "targetPct",
        "type": "number",
        "default": 85,
        "min": 0,
        "max": 100,
        "step": 1,
        "slider": true
      },
      {
        "name": "gamesPlayed",
        "type": "number",
        "default": 25,
        "min": 1,
        "max": 200,
        "step": 1,
        "slider": true
      }
    ],
    "outputs": [
      {
        "name": "percentage",
        "precision": 1,
        "unit": "%"
      },
      {
        "name": "misses",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "perGame",
        "precision": 1,
        "unit": ""
      },
      {
        "name": "makesNeeded",
        "precision": 0,
        "unit": ""
      }
    ],
    "interpret": null
  }
}
