{
  "schemaVersion": 1,
  "slug": "lottery-odds-calculator",
  "category": "gaming",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "3ed86ff308fc09a10dc245029b41333e8d2e794fd9a583b245f4cf491b447e15",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/lottery-odds-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": "C(n,k) = n! ÷ (k!(n−k)!); p = 1 ÷ C(n,k); p_all = min(tickets,C(n,k)) ÷ C(n,k)",
    "vars": [
      [
        "n",
        "pool size"
      ],
      [
        "k",
        "numbers selected"
      ],
      [
        "C(n,k)",
        "possible combinations"
      ],
      [
        "tickets",
        "tickets purchased"
      ],
      [
        "p",
        "probability per ticket"
      ],
      [
        "p_all",
        "probability across distinct combinations"
      ]
    ],
    "note": "Ticket probability assumes a simple draw with no order and distinct combinations. Multiple-ticket probability counts at most C(n,k) unique combinations; ticket spend still uses all tickets. Jackpot-only model; no prizes, taxes or expected value."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "const n=poolSize,k=pickCount;if(!Number.isInteger(n)||n<5||n>200||!Number.isInteger(k)||k<1||k>20||k>n||!Number.isInteger(tickets)||tickets<1||!Number.isFinite(ticketPrice)||ticketPrice<0)return{combinations:null,ticketsCounted:null,probability:null,probabilityAllTickets:null,ticketSpend:null,__error:'inputError'};let C=1n;for(let i=1;i<=k;i++)C=C*BigInt(n-k+i)/BigInt(i);const cNum=Number(C),used=Number(C<BigInt(tickets)?C:BigInt(tickets)),p=1/cNum;return{combinations:cNum,ticketsCounted:used,probability:p*100,probabilityAllTickets:used/cNum*100,ticketSpend:tickets*ticketPrice};",
    "inputs": [
      {
        "name": "poolSize",
        "type": "number",
        "default": 49,
        "min": 5,
        "max": 200,
        "step": 1,
        "slider": true
      },
      {
        "name": "pickCount",
        "type": "number",
        "default": 6,
        "min": 1,
        "max": 20,
        "step": 1,
        "slider": true
      },
      {
        "name": "tickets",
        "type": "number",
        "default": 1,
        "min": 1,
        "max": 10000000,
        "step": 1
      },
      {
        "name": "ticketPrice",
        "type": "number",
        "default": 2,
        "min": 0,
        "max": 1000,
        "step": 0.01
      }
    ],
    "outputs": [
      {
        "name": "combinations",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "ticketsCounted",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "probability",
        "precision": 10,
        "unit": "%"
      },
      {
        "name": "probabilityAllTickets",
        "precision": 8,
        "unit": "%"
      },
      {
        "name": "ticketSpend",
        "precision": 2,
        "unit": "$"
      }
    ],
    "interpret": null
  }
}
