87 lines
3.8 KiB
JavaScript
87 lines
3.8 KiB
JavaScript
import { Worker } from "node:worker_threads";
|
|
import { performance } from "node:perf_hooks";
|
|
import { generateMap } from "../src/mapPipeline.js";
|
|
import { createWorldMap } from "../src/worldMap.js";
|
|
|
|
function assert(condition, message) {
|
|
if (!condition) throw new Error(message);
|
|
console.log(`OK: ${message}`);
|
|
}
|
|
|
|
const initial = generateMap(114514);
|
|
const baseline = createWorldMap(initial);
|
|
const rect = { x0: 90, y0: 55, x1: 165, y1: 120 };
|
|
const baseSeed = 88001;
|
|
const candidatePlan = [0, 1, 2].map((variant, index) => ({
|
|
candidateId: `r10-exact:${variant}`,
|
|
candidateOrdinal: index + 1,
|
|
variant,
|
|
seed: (baseSeed + Math.imul(variant, 2654435761)) >>> 0,
|
|
}));
|
|
|
|
async function runSearch(draftSelection) {
|
|
return await new Promise((resolve, reject) => {
|
|
const worker = new Worker(new URL("./browser-worker-node-shim.mjs", import.meta.url), { type: "module" });
|
|
const startedAt = performance.now();
|
|
worker.on("message", async (message) => {
|
|
if (message?.type === "progress") return;
|
|
await worker.terminate();
|
|
resolve({ message, elapsedMs: Math.round(performance.now() - startedAt) });
|
|
});
|
|
worker.on("error", reject);
|
|
worker.postMessage({
|
|
id: draftSelection ? 1001 : 1002,
|
|
world: structuredClone(baseline),
|
|
rect,
|
|
options: {
|
|
patchMode: "regeneration",
|
|
terrainType: "auto",
|
|
variant: 0,
|
|
seed: baseSeed,
|
|
maxQualityRetries: 0,
|
|
qualityTerrainAttempts: 1,
|
|
acceptBestAvailableQuality: false,
|
|
includeSeamVisualization: false,
|
|
},
|
|
search: {
|
|
searchId: draftSelection ? "r10-exact-fast" : "r10-exact-exhaustive",
|
|
operationId: "r10-exact-production",
|
|
committedRevision: 1,
|
|
workerEpoch: 1,
|
|
executionAttempt: 1,
|
|
totalCandidateCount: candidatePlan.length,
|
|
selectBestCandidate: true,
|
|
draftSelection,
|
|
resolvedPatchMode: "regeneration",
|
|
candidatePlan,
|
|
},
|
|
});
|
|
});
|
|
}
|
|
|
|
const fast = await runSearch(true);
|
|
const exhaustive = await runSearch(false);
|
|
assert(fast.message?.result?.ok === true && exhaustive.message?.result?.ok === true,
|
|
"both optimized and exhaustive searches produce publishable production candidates");
|
|
assert(fast.message.result.actualVariant === exhaustive.message.result.actualVariant,
|
|
"terrain-scout Branch-and-Bound selects the same variant as exhaustive full-production search");
|
|
assert(Math.abs(Number(fast.message.result.selectionScore) - Number(exhaustive.message.result.selectionScore)) <= 1e-12,
|
|
"optimized search returns the exact same final production quality score as exhaustive search");
|
|
assert(fast.message.result.draftSelection?.reusedWinningDraft === false
|
|
&& fast.message.result.draftSelection?.fullProductionFromTerrainOnly === true,
|
|
"optimized search never publishes or reuses simplified human/transport draft output");
|
|
assert(fast.message.result.draftSelection?.parallelDraftGeneration === true
|
|
&& fast.message.result.draftSelection?.parallelDraftLaneCount === 2,
|
|
"two resident terrain-scout lanes are active in the real Worker path");
|
|
assert(fast.message.result.draftSelection?.fullCandidateCount <= candidatePlan.length
|
|
&& Number.isFinite(fast.message.result.draftSelection?.branchBoundPrunedCount)
|
|
&& fast.message.result.draftSelection?.ranking?.every((row) => Number.isFinite(row.qualityUpperBound)),
|
|
"admissible bounds never evaluate more full candidates than exhaustive search and retain explicit upper-bound audit data");
|
|
console.log(JSON.stringify({
|
|
optimizedMs: fast.elapsedMs,
|
|
exhaustiveMs: exhaustive.elapsedMs,
|
|
optimizedFullCandidates: fast.message.result.draftSelection?.fullCandidateCount,
|
|
prunedCandidates: fast.message.result.draftSelection?.branchBoundPrunedCount,
|
|
variant: fast.message.result.actualVariant,
|
|
score: fast.message.result.selectionScore,
|
|
}, null, 2));
|