70 lines
4.7 KiB
JavaScript
70 lines
4.7 KiB
JavaScript
|
|
import assert from 'node:assert/strict';
|
||
|
|
import { generateMap } from './mapGenerator.js';
|
||
|
|
import { createWorldMap } from './worldMap.js';
|
||
|
|
import { generatePatch } from './mapPatch.js';
|
||
|
|
import { MAP_W, MAP_H, worldIndexOf } from './mapUtils.js';
|
||
|
|
|
||
|
|
const baseSeeds = (process.env.BASE_SEEDS || '24681357,13579246').split(',').map(Number).filter(Number.isFinite);
|
||
|
|
const requestedDirections = new Set((process.env.DIRECTIONS || 'right,left,down,up').split(',').map(s => s.trim()));
|
||
|
|
const results = [];
|
||
|
|
const quiet = process.env.QUIET === '1';
|
||
|
|
|
||
|
|
function probeAxis(world, direction, baseOriginX, baseOriginY) {
|
||
|
|
const edgeX = baseOriginX + MAP_W - 1;
|
||
|
|
const edgeY = baseOriginY + MAP_H - 1;
|
||
|
|
if (direction === 'right') return { horizontal: false, fixed: edgeX, start: baseOriginY + Math.floor(MAP_H*.22), end: baseOriginY + Math.floor(MAP_H*.78), oldOffset: 0, newOffset: 1 };
|
||
|
|
if (direction === 'left') return { horizontal: false, fixed: baseOriginX, start: baseOriginY + Math.floor(MAP_H*.22), end: baseOriginY + Math.floor(MAP_H*.78), oldOffset: 0, newOffset: -1 };
|
||
|
|
if (direction === 'down') return { horizontal: true, fixed: edgeY, start: baseOriginX + Math.floor(MAP_W*.22), end: baseOriginX + Math.floor(MAP_W*.78), oldOffset: 0, newOffset: 1 };
|
||
|
|
return { horizontal: true, fixed: baseOriginY, start: baseOriginX + Math.floor(MAP_W*.22), end: baseOriginX + Math.floor(MAP_W*.78), oldOffset: 0, newOffset: -1 };
|
||
|
|
}
|
||
|
|
|
||
|
|
function makeRect(direction, ox, oy) {
|
||
|
|
const edgeX = ox + MAP_W - 1, edgeY = oy + MAP_H - 1;
|
||
|
|
const x0 = ox + Math.floor(MAP_W*.22), x1 = ox + Math.floor(MAP_W*.78);
|
||
|
|
const y0 = oy + Math.floor(MAP_H*.22), y1 = oy + Math.floor(MAP_H*.78);
|
||
|
|
if (direction === 'right') return { x0: edgeX - 33, y0, x1: edgeX + 93, y1 };
|
||
|
|
if (direction === 'left') return { x0: ox - 93, y0, x1: ox + 33, y1 };
|
||
|
|
if (direction === 'down') return { x0, y0: edgeY - 33, x1, y1: edgeY + 93 };
|
||
|
|
return { x0, y0: oy - 93, x1, y1: oy + 33 };
|
||
|
|
}
|
||
|
|
|
||
|
|
function measureFrontier(world, probe) {
|
||
|
|
let pairs = 0, maxJump = 0, sum = 0;
|
||
|
|
for (let t = probe.start; t < probe.end; t++) {
|
||
|
|
let ax, ay, bx, by;
|
||
|
|
if (!probe.horizontal) {
|
||
|
|
ax = probe.fixed + probe.oldOffset; ay = t;
|
||
|
|
bx = probe.fixed + probe.newOffset; by = t;
|
||
|
|
} else {
|
||
|
|
ax = t; ay = probe.fixed + probe.oldOffset;
|
||
|
|
bx = t; by = probe.fixed + probe.newOffset;
|
||
|
|
}
|
||
|
|
const a = worldIndexOf(world,ax,ay), b = worldIndexOf(world,bx,by);
|
||
|
|
if (a < 0 || b < 0 || world.fields.sea[a] || world.fields.sea[b]) continue;
|
||
|
|
const jump = Math.abs(world.fields.elevation[a] - world.fields.elevation[b]);
|
||
|
|
pairs++; sum += jump; maxJump = Math.max(maxJump,jump);
|
||
|
|
}
|
||
|
|
return { pairs, maxJump, meanJump: pairs ? sum/pairs : 0 };
|
||
|
|
}
|
||
|
|
|
||
|
|
for (const baseSeed of baseSeeds) {
|
||
|
|
const initial = generateMap(baseSeed, { terrainType:'auto', onProgress(){} });
|
||
|
|
for (const direction of ['right','left','down','up']) {
|
||
|
|
if (!requestedDirections.has(direction)) continue;
|
||
|
|
const world = createWorldMap(structuredClone(initial));
|
||
|
|
const ox = world.originX, oy = world.originY;
|
||
|
|
const rect = makeRect(direction,ox,oy);
|
||
|
|
const patchSeed = (0x13579bdf ^ baseSeed ^ ({right:0x11,left:0x22,down:0x33,up:0x44}[direction])) >>> 0;
|
||
|
|
const result = generatePatch(world,rect,{patchMode:'expansion',terrainType:'auto',seed:patchSeed,variant:1,maxQualityRetries:0,qualityTerrainAttempts:1,acceptBestAvailableQuality:true});
|
||
|
|
assert.equal(result.ok,true,`${baseSeed}/${direction}: ${result.reason || result.code}`);
|
||
|
|
const probe = measureFrontier(world,probeAxis(world,direction,ox,oy));
|
||
|
|
assert.ok(probe.pairs >= 12,`${baseSeed}/${direction}: insufficient land frontier pairs (${probe.pairs})`);
|
||
|
|
assert.ok(probe.maxJump <= 0.075,`${baseSeed}/${direction}: frontier max jump ${probe.maxJump}`);
|
||
|
|
assert.equal(result.seamDiagnostics?.hardPass,true,`${baseSeed}/${direction}: seam gate ${JSON.stringify(result.seamDiagnostics?.gateReasons || [])}`);
|
||
|
|
assert.ok((result.seamDiagnostics?.maxEstablishedFrontierElevationJump || 0) <= 0.075,`${baseSeed}/${direction}: diagnostic frontier jump ${result.seamDiagnostics?.maxEstablishedFrontierElevationJump}`);
|
||
|
|
const row={baseSeed,direction,patchSeed,pairs:probe.pairs,maxJump:+probe.maxJump.toFixed(4),meanJump:+probe.meanJump.toFixed(4),diagnosticMax:+(result.seamDiagnostics?.maxEstablishedFrontierElevationJump||0).toFixed(4),seamStatus:result.seamDiagnostics?.status,seamReasons:result.seamDiagnostics?.gateReasons||[],adjusted:result.humanGeography?.establishedFrontierElevationCellsAdjusted||0,gradientAdjusted:result.humanGeography?.establishedFrontierGradientCellsAdjusted||0};
|
||
|
|
results.push(row);
|
||
|
|
if (!quiet) console.log(JSON.stringify(row));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
console.log(JSON.stringify({ok:true,cases:results.length,maxObserved:Math.max(...results.map(r=>r.maxJump)),results},null,2));
|