// Deterministic balanced pilot selection for the CAD BIM pipeline. // Keeps the city-core and southern/river masks represented, with both asset and exact-outline massing. import { readFileSync, writeFileSync } from 'node:fs' const source = JSON.parse(readFileSync('tools/city-massing/city/cad-bim/seated-plan.json', 'utf8')) const targets = new Map([[66, 1800], [65, 700], [130, 300], [126, 200]]) const hash = (id) => { let value = 2166136261 for (const ch of id) value = ((value ^ ch.charCodeAt(0)) * 16777619) >>> 0 return value } const selected = [] const details = {} for (const [maskId, target] of targets) { const group = source.buildings.filter((b) => Number(b.maskId) === maskId) const ordered = [...group].sort((a, b) => hash(a.id) - hash(b.id)) const take = ordered.slice(0, Math.min(target, ordered.length)) selected.push(...take) details[maskId] = { available: group.length, selected: take.length } } const out = { ...source, buildings: selected, pilot: { name: 'urban-mask-cad-bim-pilot-3000', selection: details, note: 'Bounded first CIM pass; full 48k seated buildings remain a later batched export.', }, } writeFileSync('tools/city-massing/city/cad-bim/seated-pilot.json', JSON.stringify(out, null, 2)) console.log(JSON.stringify({ selected: selected.length, byMask: details, byKind: Object.fromEntries([...new Set(selected.map((b) => b.kind))].map((k) => [k, selected.filter((b) => b.kind === k).length])) }))