map/archive/generated-history/VALIDATE_FINAL_LARGE_COVERAGE.mjs
2026-08-08 17:41:30 +09:00

97 lines
4 KiB
JavaScript

import assert from 'node:assert/strict';
import { Worker } from 'node:worker_threads';
import { generateMap } from './mapGenerator.js';
import { createWorldMap } from './worldMap.js';
import { collectTransferableBuffers } from './transferUtils.js';
const BASE_SEED = 24681357;
const PATCH_SEED = 0x4a35b921;
const WIDTH = 600;
const HEIGHT = 400;
function footprintContains(fp, x, y) {
if (!fp || x < fp.x0 || y < fp.y0 || x >= fp.x1 || y >= fp.y1) return false;
const row = fp.rowRuns?.[y - fp.y0];
if (!Array.isArray(row)) return false;
for (let i = 0; i + 1 < row.length; i += 2) if (x >= row[i] && x < row[i + 1]) return true;
return false;
}
function recordContains(record, x, y) {
if (record?.generatedFootprint) return footprintContains(record.generatedFootprint, x, y);
const r = record?.coreRect || record;
return !!r && x >= r.x0 && y >= r.y0 && x < r.x1 && y < r.y1;
}
function generatedAt(world, x, y) {
return (world.generatedRects || []).some(record => recordContains(record, x, y));
}
function centeredRect(world, width, height) {
// Use a deliberately off-center but fully valid selection so this exercises
// a different outer seam than the existing centered stability test.
const x0 = Math.max(0, world.width - width);
const y0 = Math.max(0, world.height - height);
return { x0, y0, x1: x0 + width, y1: y0 + height };
}
function workerAdapter(url) {
const code = `import { parentPort } from 'node:worker_threads';\n`
+ `globalThis.self = { onmessage: null, postMessage(message, transfer) { parentPort.postMessage(message, transfer); } };\n`
+ `await import(${JSON.stringify(url.href)});\n`
+ `parentPort.on('message', data => self.onmessage?.({ data }));\n`;
return new Worker(new URL(`data:text/javascript,${encodeURIComponent(code)}`), { type: 'module', execArgv: [] });
}
const initial = generateMap(BASE_SEED, { terrainType: 'auto', onProgress() {} });
const baseWorld = createWorldMap(initial);
const rect = centeredRect(baseWorld, WIDTH, HEIGHT);
const needed = [];
for (let y = rect.y0; y < rect.y1; y++) {
for (let x = rect.x0; x < rect.x1; x++) {
if (!generatedAt(baseWorld, x, y)) needed.push([x, y]);
}
}
assert.ok(needed.length > 0, 'test selection must contain ungenerated cells');
const preview = structuredClone(baseWorld);
const transfer = Array.from(collectTransferableBuffers(preview));
const worker = workerAdapter(new URL('./mapPatchWorker.js', import.meta.url));
const startedAt = Date.now();
const message = await new Promise((resolve, reject) => {
const timer = setTimeout(() => reject(new Error('600x400 worker timeout')), 120000);
worker.on('message', message => {
if (message?.type === 'progress') return;
clearTimeout(timer);
resolve(message);
});
worker.on('error', error => { clearTimeout(timer); reject(error); });
worker.postMessage({
id: 1,
world: preview,
rect,
options: {
patchMode: 'expansion', terrainType: 'auto', seed: PATCH_SEED, variant: 1,
maxQualityRetries: 0, qualityTerrainAttempts: 1, acceptBestAvailableQuality: true,
},
}, transfer);
});
assert.equal(message?.ok, true, message?.error || 'worker outer failure');
assert.equal(message?.result?.ok, true, message?.result?.reason || message?.result?.code || 'patch failure');
assert.equal(message?.result?.seamDiagnostics?.hardPass, true, 'seam hard gate failed');
const returnedWorld = message.world;
let missing = 0;
for (const [x, y] of needed) if (!generatedAt(returnedWorld, x, y)) missing++;
assert.equal(missing, 0, `missing ${missing} previously-ungenerated selected cells`);
const out = {
ok: true,
size: `${WIDTH}x${HEIGHT}`,
selectedCells: WIDTH * HEIGHT,
previouslyUngeneratedSelectedCells: needed.length,
missingPreviouslyUngeneratedCells: missing,
tileCount: message.result?.tileCount || 1,
seam: message.result?.seamDiagnostics?.status || null,
hardPass: message.result?.seamDiagnostics?.hardPass ?? null,
ms: Date.now() - startedAt,
};
console.log(JSON.stringify(out, null, 2));
await worker.terminate();
process.exit(0);