{
  "schemaVersion": 1,
  "slug": "seating-arrangement-calculator",
  "category": "party",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "01e8b3e85c586f3b738d17061d08e6425c275cefc19b9946514b3b256f4cbe64",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/seating-arrangement-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": "n = min(s, round(G÷T)); A = n!; seats = T×s; left = T×s − G",
    "vars": [
      [
        "G",
        "Number of guests"
      ],
      [
        "T",
        "Number of tables"
      ],
      [
        "s",
        "Seats per table"
      ],
      [
        "n",
        "Seated people per table"
      ],
      [
        "A",
        "Arrangements for one table"
      ],
      [
        "seats",
        "Total seats available"
      ],
      [
        "left",
        "Seats left over"
      ]
    ],
    "note": "Spare seats = max(0, tables×seatsPerTable − guests); unseated guests = max(0, guests − capacity). Seating orders show factorial of the ceiling of average guests per table, capped at capacity; this is a largest-table illustration, not the number of whole-event assignments."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "const per=guests/tables;const seats=tables*seatsPerTable;const fact=n=>{let r=1;for(let i=2;i<=n;i++){r*=i;if(r>1e15)return'over 1 quadrillion';}return String(Math.round(r));};const n1=Math.min(seatsPerTable,Math.ceil(per));return{perTableAverage:per,seatsAvailable:seats,seatsLeft:Math.max(0,seats-guests),unseatedGuests:Math.max(0,guests-seats),arrangementsPerTable:fact(n1)};",
    "inputs": [
      {
        "name": "guests",
        "type": "number",
        "default": 80,
        "min": 1,
        "max": 2000,
        "step": 1,
        "slider": true
      },
      {
        "name": "tables",
        "type": "number",
        "default": 8,
        "min": 1,
        "max": 200,
        "step": 1,
        "slider": true
      },
      {
        "name": "seatsPerTable",
        "type": "number",
        "default": 10,
        "min": 2,
        "max": 24,
        "step": 1,
        "slider": true
      }
    ],
    "outputs": [
      {
        "name": "perTableAverage",
        "precision": 1,
        "unit": ""
      },
      {
        "name": "seatsAvailable",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "seatsLeft",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "unseatedGuests",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "arrangementsPerTable",
        "precision": 0,
        "unit": "",
        "type": "text"
      }
    ],
    "interpret": null
  }
}
