2026-08-08 17:41:30 +09:00
import { generateMap , MAP _W , MAP _H , indexOf } from "../src/mapPipeline.js" ;
2026-08-10 13:59:33 +09:00
import { createWorldMap } from "../src/worldMap.js" ;
import { PATCH _MIN _HEIGHT , generatePatch } from "../src/mapPatch.js" ;
import { applyCommittedMirrorDelta , buildCommittedMirrorDelta , runPatchCandidateSearch } from "../src/mapPatchWorker.js" ;
2026-05-21 02:55:58 +09:00
import {
2026-05-26 00:45:01 +09:00
CUSTOM _NAME _LIST ,
2026-05-21 02:55:58 +09:00
NAME _KANJI _POOLS ,
NAME _PROBABILITIES ,
NAME _TEMPLATES ,
NAME _TEMPLATE _WEIGHTS ,
2026-05-21 13:20:19 +09:00
generateEntityName ,
2026-05-26 00:45:01 +09:00
validateGeneratedName ,
2026-08-08 17:41:30 +09:00
} from "../src/names.js" ;
2026-05-20 13:50:56 +09:00
2026-05-29 22:00:42 +09:00
const IS _BROWSER = typeof document !== "undefined" ;
const result = IS _BROWSER ? document . getElementById ( "result" ) : { className : "" , textContent : "" } ;
2026-05-20 13:50:56 +09:00
const logLines = [ ] ;
let failed = 0 ;
2026-08-08 17:41:30 +09:00
const TEST _SUITE = ( ( ) => {
if ( IS _BROWSER ) return new URLSearchParams ( location . search ) . get ( "suite" ) || "core" ;
const arg = process . argv . find ( ( value ) => value . startsWith ( "--suite=" ) ) ;
return arg ? arg . slice ( "--suite=" . length ) : "core" ;
} ) ( ) ;
2026-08-11 21:51:07 +09:00
const STATIC _TEST _SUITES = new Set ( [ "all" , "core" , "terrain" , "terrain-name" , "admin" , "patch" , "patch-large" , "determinism" ] ) ;
if ( ! STATIC _TEST _SUITES . has ( TEST _SUITE ) && ! /^determinism-(?:0|[1-9]\d*)$/ . test ( TEST _SUITE ) ) {
throw new Error ( ` Unknown test suite: ${ TEST _SUITE } ` ) ;
}
2026-08-08 17:41:30 +09:00
const TEST _STARTED _AT = typeof performance !== "undefined" && performance . now ? performance . now ( ) : Date . now ( ) ;
const DETERMINISM _SEED = ( ( ) => {
if ( IS _BROWSER ) return Number ( new URLSearchParams ( location . search ) . get ( "seed" ) ) || 114514 ;
const arg = process . argv . find ( ( value ) => value . startsWith ( "--seed=" ) ) ;
return arg ? Number ( arg . slice ( "--seed=" . length ) ) : 114514 ;
} ) ( ) ;
let fullMapGenerations = 0 ;
function suiteEnabled ( name ) {
return TEST _SUITE === "all" || TEST _SUITE === name ;
}
function generateTestMap ( seed ) {
fullMapGenerations ++ ;
return generateMap ( seed ) ;
}
2026-05-29 22:00:42 +09:00
async function readLocalText ( path ) {
if ( IS _BROWSER ) return fetch ( path ) . then ( ( response ) => response . text ( ) ) ;
const { readFile } = await import ( "node:fs/promises" ) ;
return readFile ( new URL ( path , import . meta . url ) , "utf8" ) ;
}
2026-08-11 21:51:07 +09:00
let namesSource = "" ;
let mapGeneratorSource = "" ;
let mapOutputSource = "" ;
let mapTerrainSource = "" ;
let rendererSource = "" ;
let appSource = "" ;
let mapPipelineSource = "" ;
let mapAdminStageSource = "" ;
let mapPatchSource = "" ;
let mapPatchWorkerSource = "" ;
let committedWorldDeltaSource = "" ;
let worldMapSource = "" ;
let municipalSource = "" ;
if ( suiteEnabled ( "core" ) ) {
[ namesSource , mapOutputSource , mapTerrainSource , rendererSource , appSource , mapPipelineSource , mapAdminStageSource , mapPatchSource , mapPatchWorkerSource , committedWorldDeltaSource , worldMapSource , municipalSource ] = await Promise . all ( [
readLocalText ( "../src/names.js" ) ,
readLocalText ( "../src/mapOutput.js" ) ,
readLocalText ( "../src/mapTerrain.js" ) ,
readLocalText ( "../src/renderer.js" ) ,
readLocalText ( "../src/app.js" ) ,
readLocalText ( "../src/mapPipeline.js" ) ,
readLocalText ( "../src/mapAdminStage.js" ) ,
readLocalText ( "../src/mapPatch.js" ) ,
readLocalText ( "../src/mapPatchWorker.js" ) ,
readLocalText ( "../src/committedWorldDelta.js" ) ,
readLocalText ( "../src/worldMap.js" ) ,
readLocalText ( "../src/mapMunicipalCoherence.js" ) ,
] ) ;
mapGeneratorSource = mapPipelineSource ;
}
2026-08-10 13:59:33 +09:00
const derivePatchSeedStart = appSource . indexOf ( "function derivePatchSeed" ) ;
const derivePatchSeedEnd = derivePatchSeedStart >= 0 ? appSource . indexOf ( "\n}" , derivePatchSeedStart ) : - 1 ;
const derivePatchSeedSource = derivePatchSeedStart >= 0 && derivePatchSeedEnd > derivePatchSeedStart
? appSource . slice ( derivePatchSeedStart , derivePatchSeedEnd + 2 )
: "" ;
2026-05-21 02:55:58 +09:00
2026-05-20 13:50:56 +09:00
function assert ( condition , message ) {
if ( condition ) logLines . push ( ` OK: ${ message } ` ) ;
else {
failed += 1 ;
logLines . push ( ` NG: ${ message } ` ) ;
}
}
2026-08-10 13:59:33 +09:00
function arraysEqual ( a , b ) {
if ( ! a || ! b || a . length !== b . length ) return false ;
for ( let index = 0 ; index < a . length ; index ++ ) {
if ( a [ index ] !== b [ index ] && ! ( Number . isNaN ( a [ index ] ) && Number . isNaN ( b [ index ] ) ) ) return false ;
}
return true ;
}
2026-05-21 03:13:39 +09:00
function terrainBoundaryTargetForMetrics ( map , i ) {
const lu = map . landuse [ i ] ;
const urbanPenalty = Math . min ( 1 , ( lu === 3 ? 1.45 : lu === 2 ? 1.12 : lu === 4 ? 0.95 : lu === 7 ? 0.90 : lu === 8 ? 0.64 : lu === 5 || lu === 6 ? 0.48 : 0 ) + map . populationDensity [ i ] * 1.35 ) ;
const majorRiver = Math . min ( 1 , Math . max ( map . river [ i ] - 0.32 , 0 ) * 1.9 + Math . max ( map . flowAccum [ i ] - 0.38 , 0 ) * 0.75 ) ;
const minorStream = Math . min ( 1 , map . river [ i ] * 0.34 + map . flowAccum [ i ] * 0.18 ) ;
const ridgeDivide = Math . min ( 1 , map . ridgeField [ i ] * 1.55 + Math . max ( 0 , map . elevation [ i ] - 0.54 ) * map . ridgeField [ i ] * 0.95 ) ;
const slopeBreak = Math . min ( 1 , map . slope [ i ] * 0.58 + Math . max ( 0 , map . slope [ i ] - 0.32 ) * 0.68 ) ;
const highGround = Math . max ( 0 , map . elevation [ i ] - 0.56 ) * 0.22 ;
const valleyFloorPenalty = map . valleyField [ i ] * ( majorRiver > 0.34 ? - 0.10 : - 0.62 ) ;
return Math . max ( 0 , Math . min ( 1 , ridgeDivide + majorRiver * 0.88 + minorStream * 0.22 + slopeBreak + highGround + valleyFloorPenalty - urbanPenalty * 0.72 ) ) ;
}
2026-08-08 17:41:30 +09:00
function humanRegionMaskForMetrics ( map ) {
if ( map . humanRegionMask ? . length === MAP _W * MAP _H ) return map . humanRegionMask ;
const mask = new Uint8Array ( MAP _W * MAP _H ) ;
for ( let i = 0 ; i < mask . length ; i ++ ) mask [ i ] = ! map . sea [ i ] && ( map . prefectureRegionId ? . [ i ] ? ? - 1 ) >= 0 ? 1 : 0 ;
return mask ;
}
function deterministicTransportDebug ( debug ) {
if ( ! debug ) return debug ;
const copy = typeof structuredClone === "function" ? structuredClone ( debug ) : JSON . parse ( JSON . stringify ( debug ) ) ;
delete copy . featureTimings ;
if ( copy . layers ) delete copy . layers . featureTimings ;
return copy ;
}
2026-05-21 03:13:39 +09:00
function adminBoundaryMetrics ( map ) {
2026-08-08 17:41:30 +09:00
const humanMask = humanRegionMaskForMetrics ( map ) ;
2026-05-21 03:13:39 +09:00
let borderEdges = 0 ;
let targetSum = 0 ;
let denseUrbanEdges = 0 ;
let rightAngleRuns = 0 ;
let voronoiLikeEdges = 0 ;
let lowScoreFlatEdges = 0 ;
for ( let y = 1 ; y < MAP _H - 1 ; y ++ ) {
for ( let x = 1 ; x < MAP _W - 1 ; x ++ ) {
const i = indexOf ( x , y ) ;
2026-08-08 17:41:30 +09:00
if ( ! humanMask [ i ] || map . sea [ i ] || map . adminId [ i ] < 0 ) continue ;
2026-05-21 03:13:39 +09:00
for ( const [ dx , dy ] of [ [ 1 , 0 ] , [ 0 , 1 ] ] ) {
const ni = indexOf ( x + dx , y + dy ) ;
2026-08-08 17:41:30 +09:00
if ( ! humanMask [ ni ] || map . sea [ ni ] || map . adminId [ ni ] < 0 || map . adminId [ ni ] === map . adminId [ i ] ) continue ;
2026-05-21 03:13:39 +09:00
borderEdges ++ ;
const edgeTarget = ( terrainBoundaryTargetForMetrics ( map , i ) + terrainBoundaryTargetForMetrics ( map , ni ) ) * 0.5 ;
targetSum += edgeTarget ;
const urban = Math . max ( map . populationDensity [ i ] , map . populationDensity [ ni ] ) > 0.58 || [ 2 , 3 , 4 , 7 , 8 ] . includes ( map . landuse [ i ] ) || [ 2 , 3 , 4 , 7 , 8 ] . includes ( map . landuse [ ni ] ) ;
if ( urban ) denseUrbanEdges ++ ;
const ca = map . adminCenters [ map . adminId [ i ] ] ;
const cb = map . adminCenters [ map . adminId [ ni ] ] ;
if ( ca && cb ) {
const mx = x + dx * 0.5 ;
const my = y + dy * 0.5 ;
const dA = Math . hypot ( mx - ca . x , my - ca . y ) ;
const dB = Math . hypot ( mx - cb . x , my - cb . y ) ;
if ( Math . abs ( dA - dB ) < 4.2 && edgeTarget < 0.40 ) voronoiLikeEdges ++ ;
}
if ( edgeTarget < 0.16 && Math . max ( map . slope [ i ] , map . slope [ ni ] ) < 0.24 && Math . max ( map . ridgeField [ i ] , map . ridgeField [ ni ] ) < 0.28 && Math . max ( map . river [ i ] , map . river [ ni ] ) < 0.26 ) {
lowScoreFlatEdges ++ ;
}
const sideA = indexOf ( x + ( dy ? 1 : 0 ) , y + ( dx ? 1 : 0 ) ) ;
const sideB = indexOf ( x - ( dy ? 1 : 0 ) , y - ( dx ? 1 : 0 ) ) ;
2026-08-08 17:41:30 +09:00
if ( humanMask [ sideA ] && humanMask [ sideB ] && ! map . sea [ sideA ] && ! map . sea [ sideB ] ) {
2026-05-21 03:13:39 +09:00
const turnA = map . adminId [ sideA ] !== map . adminId [ i ] && map . adminId [ sideA ] !== map . adminId [ ni ] ;
const turnB = map . adminId [ sideB ] !== map . adminId [ i ] && map . adminId [ sideB ] !== map . adminId [ ni ] ;
if ( ( turnA || turnB ) && terrainBoundaryTargetForMetrics ( map , i ) < 0.46 ) rightAngleRuns ++ ;
}
}
}
}
2026-08-08 17:41:30 +09:00
const ids = new Set ( [ ... map . adminId ] . filter ( ( id , i ) => id >= 0 && humanMask [ i ] && ! map . sea [ i ] ) ) ;
2026-05-21 03:13:39 +09:00
const areaById = new Map ( ) ;
for ( let i = 0 ; i < map . adminId . length ; i ++ ) {
2026-08-08 17:41:30 +09:00
if ( humanMask [ i ] && ! map . sea [ i ] && map . adminId [ i ] >= 0 ) areaById . set ( map . adminId [ i ] , ( areaById . get ( map . adminId [ i ] ) || 0 ) + 1 ) ;
2026-05-21 03:13:39 +09:00
}
const areas = [ ... areaById . values ( ) ] . sort ( ( a , b ) => a - b ) ;
const medianArea = areas . length ? areas [ Math . floor ( areas . length / 2 ) ] : 1 ;
const maxArea = areas . length ? areas [ areas . length - 1 ] : 1 ;
let disconnectedMunicipalities = 0 ;
let maxComponents = 0 ;
2026-08-08 17:41:30 +09:00
let maxLandmassComponents = 0 ;
const landmassId = new Int32Array ( MAP _W * MAP _H ) ;
landmassId . fill ( - 1 ) ;
let landmass = 0 ;
for ( let i = 0 ; i < landmassId . length ; i ++ ) {
if ( ! humanMask [ i ] || map . sea [ i ] || landmassId [ i ] >= 0 ) continue ;
const queue = [ i ] ;
landmassId [ i ] = landmass ;
for ( let q = 0 ; q < queue . length ; q ++ ) {
const cur = queue [ q ] ;
const x = cur % MAP _W , y = Math . floor ( cur / MAP _W ) ;
for ( const [ dx , dy ] of [ [ 1 , 0 ] , [ - 1 , 0 ] , [ 0 , 1 ] , [ 0 , - 1 ] ] ) {
const nx = x + dx , ny = y + dy ;
if ( nx < 0 || ny < 0 || nx >= MAP _W || ny >= MAP _H ) continue ;
const ni = indexOf ( nx , ny ) ;
if ( ! humanMask [ ni ] || map . sea [ ni ] || landmassId [ ni ] >= 0 ) continue ;
landmassId [ ni ] = landmass ;
queue . push ( ni ) ;
}
}
landmass ++ ;
}
2026-05-21 03:13:39 +09:00
const seen = new Uint8Array ( MAP _W * MAP _H ) ;
for ( const id of ids ) {
let comps = 0 ;
2026-08-08 17:41:30 +09:00
const componentsByLandmass = new Map ( ) ;
2026-05-21 03:13:39 +09:00
seen . fill ( 0 ) ;
for ( let i = 0 ; i < map . adminId . length ; i ++ ) {
2026-08-08 17:41:30 +09:00
if ( seen [ i ] || map . adminId [ i ] !== id || ! humanMask [ i ] || map . sea [ i ] ) continue ;
2026-05-21 03:13:39 +09:00
comps ++ ;
2026-08-08 17:41:30 +09:00
const mass = landmassId [ i ] ;
componentsByLandmass . set ( mass , ( componentsByLandmass . get ( mass ) || 0 ) + 1 ) ;
2026-05-21 03:13:39 +09:00
const queue = [ i ] ;
seen [ i ] = 1 ;
for ( let q = 0 ; q < queue . length ; q ++ ) {
const cur = queue [ q ] ;
const x = cur % MAP _W ;
const y = Math . floor ( cur / MAP _W ) ;
for ( const [ dx , dy ] of [ [ 1 , 0 ] , [ - 1 , 0 ] , [ 0 , 1 ] , [ 0 , - 1 ] ] ) {
const nx = x + dx ;
const ny = y + dy ;
if ( nx < 0 || ny < 0 || nx >= MAP _W || ny >= MAP _H ) continue ;
const ni = indexOf ( nx , ny ) ;
2026-08-08 17:41:30 +09:00
if ( seen [ ni ] || map . adminId [ ni ] !== id || ! humanMask [ ni ] || map . sea [ ni ] ) continue ;
2026-05-21 03:13:39 +09:00
seen [ ni ] = 1 ;
queue . push ( ni ) ;
}
}
}
if ( comps > 1 ) disconnectedMunicipalities ++ ;
maxComponents = Math . max ( maxComponents , comps ) ;
2026-08-08 17:41:30 +09:00
maxLandmassComponents = Math . max ( maxLandmassComponents , ... componentsByLandmass . values ( ) , 0 ) ;
2026-05-21 03:13:39 +09:00
}
const centerValidCount = map . adminCenters . filter ( ( center ) => {
const i = indexOf ( center . x , center . y ) ;
2026-08-08 17:41:30 +09:00
const id = center . adminId ? ? center . municipalityId ? ? center . adminNumericId ;
return humanMask [ i ] && ! map . sea [ i ] && Number . isFinite ( id ) && map . adminId [ i ] === id ;
2026-05-21 03:13:39 +09:00
} ) . length ;
return {
borderEdges ,
avgTarget : borderEdges ? targetSum / borderEdges : 0 ,
denseUrbanRate : borderEdges ? denseUrbanEdges / borderEdges : 0 ,
rightAngleRate : borderEdges ? rightAngleRuns / borderEdges : 0 ,
voronoiLikeRate : borderEdges ? voronoiLikeEdges / borderEdges : 0 ,
lowScoreFlatRate : borderEdges ? lowScoreFlatEdges / borderEdges : 0 ,
areaDiversity : maxArea / Math . max ( 1 , medianArea ) ,
municipalityCount : ids . size ,
disconnectedMunicipalities ,
maxComponents ,
2026-08-08 17:41:30 +09:00
maxLandmassComponents ,
2026-05-21 03:13:39 +09:00
centerValidRatio : map . adminCenters . length ? centerValidCount / map . adminCenters . length : 1 ,
} ;
}
function majorCityCoreIntegrity ( map ) {
const majorCities = map . modernCities . filter ( ( city ) => ( city . population || 0 ) >= 180000 ) ;
if ( majorCities . length === 0 ) return 1 ;
let sum = 0 ;
let checked = 0 ;
for ( const city of majorCities ) {
const counts = new Map ( ) ;
const r = Math . ceil ( Math . max ( 3 , city . coreRadius || 4 ) ) ;
for ( let dy = - r ; dy <= r ; dy ++ ) {
for ( let dx = - r ; dx <= r ; dx ++ ) {
const x = city . x + dx ;
const y = city . y + dy ;
if ( x < 0 || y < 0 || x >= MAP _W || y >= MAP _H || Math . hypot ( dx , dy ) > r ) continue ;
const i = indexOf ( x , y ) ;
if ( ! map . prefectureMask [ i ] || map . sea [ i ] ) continue ;
if ( map . landuse [ i ] !== 3 && map . populationDensity [ i ] < 0.38 ) continue ;
const id = map . adminId [ i ] ;
if ( id >= 0 ) counts . set ( id , ( counts . get ( id ) || 0 ) + 1 ) ;
}
}
const total = [ ... counts . values ( ) ] . reduce ( ( a , b ) => a + b , 0 ) ;
if ( total === 0 ) continue ;
sum += Math . max ( ... counts . values ( ) ) / total ;
checked ++ ;
}
return checked ? sum / checked : 1 ;
}
2026-05-21 13:20:19 +09:00
function satelliteMunicipalityMetrics ( map ) {
const areaById = new Map ( ) ;
for ( let i = 0 ; i < map . adminId . length ; i ++ ) {
if ( map . prefectureMask [ i ] && ! map . sea [ i ] && map . adminId [ i ] >= 0 ) areaById . set ( map . adminId [ i ] , ( areaById . get ( map . adminId [ i ] ) || 0 ) + 1 ) ;
}
const rows = ( map . satelliteCities || [ ] )
. filter ( ( sat ) => map . prefectureMask [ indexOf ( sat . x , sat . y ) ] && ! map . sea [ indexOf ( sat . x , sat . y ) ] )
. map ( ( sat ) => {
const admin = map . adminId [ indexOf ( sat . x , sat . y ) ] ;
return { sat , admin , area : areaById . get ( admin ) || 0 } ;
} ) ;
const independent = rows . filter ( ( row ) => row . sat . municipalityClass === "independentSatelliteMunicipality" ) ;
const small = independent . filter ( ( row ) => row . area < 80 ) ;
const largeTooSmall = rows . filter ( ( row ) => ( row . sat . population || 0 ) >= 60000 && row . sat . municipalityClass === "independentSatelliteMunicipality" && row . area < 120 ) ;
const average = independent . length ? independent . reduce ( ( sum , row ) => sum + row . area , 0 ) / independent . length : 0 ;
return { rows , independent , small , largeTooSmall , average } ;
}
function regionalComponentMetrics ( map ) {
const ids = new Set ( [ ... map . prefectureRegionId ] . filter ( ( id , i ) => id >= 0 && ! map . sea [ i ] ) ) ;
2026-08-08 17:41:30 +09:00
const landmassId = new Int32Array ( MAP _W * MAP _H ) ;
landmassId . fill ( - 1 ) ;
let landmass = 0 ;
for ( let i = 0 ; i < landmassId . length ; i ++ ) {
if ( map . sea [ i ] || landmassId [ i ] >= 0 ) continue ;
const queue = [ i ] ;
landmassId [ i ] = landmass ;
for ( let q = 0 ; q < queue . length ; q ++ ) {
const cur = queue [ q ] ;
const x = cur % MAP _W , y = Math . floor ( cur / MAP _W ) ;
for ( const [ dx , dy ] of [ [ 1 , 0 ] , [ - 1 , 0 ] , [ 0 , 1 ] , [ 0 , - 1 ] ] ) {
const nx = x + dx , ny = y + dy ;
if ( nx < 0 || ny < 0 || nx >= MAP _W || ny >= MAP _H ) continue ;
const ni = indexOf ( nx , ny ) ;
if ( map . sea [ ni ] || landmassId [ ni ] >= 0 ) continue ;
landmassId [ ni ] = landmass ;
queue . push ( ni ) ;
}
}
landmass ++ ;
}
2026-05-21 13:20:19 +09:00
const seen = new Uint8Array ( MAP _W * MAP _H ) ;
let maxComponents = 0 ;
2026-08-08 17:41:30 +09:00
let maxLandmassComponents = 0 ;
2026-05-26 15:32:27 +09:00
const areas = [ ] ;
2026-05-21 13:20:19 +09:00
for ( const id of ids ) {
seen . fill ( 0 ) ;
let comps = 0 ;
2026-05-26 15:32:27 +09:00
let area = 0 ;
2026-08-08 17:41:30 +09:00
const componentsByLandmass = new Map ( ) ;
2026-05-21 13:20:19 +09:00
for ( let i = 0 ; i < map . prefectureRegionId . length ; i ++ ) {
2026-05-26 15:32:27 +09:00
if ( ! map . sea [ i ] && map . prefectureRegionId [ i ] === id ) area ++ ;
2026-05-21 13:20:19 +09:00
if ( seen [ i ] || map . sea [ i ] || map . prefectureRegionId [ i ] !== id ) continue ;
comps ++ ;
2026-08-08 17:41:30 +09:00
const mass = landmassId [ i ] ;
componentsByLandmass . set ( mass , ( componentsByLandmass . get ( mass ) || 0 ) + 1 ) ;
2026-05-21 13:20:19 +09:00
const queue = [ i ] ;
seen [ i ] = 1 ;
for ( let q = 0 ; q < queue . length ; q ++ ) {
const cur = queue [ q ] ;
const x = cur % MAP _W ;
const y = Math . floor ( cur / MAP _W ) ;
for ( const [ dx , dy ] of [ [ 1 , 0 ] , [ - 1 , 0 ] , [ 0 , 1 ] , [ 0 , - 1 ] ] ) {
const nx = x + dx ;
const ny = y + dy ;
if ( nx < 0 || ny < 0 || nx >= MAP _W || ny >= MAP _H ) continue ;
const ni = indexOf ( nx , ny ) ;
if ( seen [ ni ] || map . sea [ ni ] || map . prefectureRegionId [ ni ] !== id ) continue ;
seen [ ni ] = 1 ;
queue . push ( ni ) ;
}
}
}
maxComponents = Math . max ( maxComponents , comps ) ;
2026-08-08 17:41:30 +09:00
maxLandmassComponents = Math . max ( maxLandmassComponents , ... componentsByLandmass . values ( ) , 0 ) ;
2026-05-26 15:32:27 +09:00
areas . push ( area ) ;
2026-05-21 13:20:19 +09:00
}
2026-05-26 15:32:27 +09:00
areas . sort ( ( a , b ) => a - b ) ;
const medianArea = areas . length ? areas [ Math . floor ( areas . length / 2 ) ] : 0 ;
const minArea = areas . length ? areas [ 0 ] : 0 ;
const tinyCount = areas . filter ( ( area ) => area < 520 ) . length ;
2026-08-08 17:41:30 +09:00
return { regionCount : ids . size , maxComponents , maxLandmassComponents , minArea , medianArea , tinyCount , areas } ;
2026-05-26 15:32:27 +09:00
}
function regionalBorderMetrics ( map ) {
let invalidSame = 0 ;
let expected = 0 ;
const ids = map . prefectureRegionId ;
for ( let y = 0 ; y < MAP _H ; y ++ ) {
for ( let x = 0 ; x < MAP _W ; x ++ ) {
const i = indexOf ( x , y ) ;
if ( map . sea [ i ] || ids [ i ] < 0 ) continue ;
if ( x + 1 < MAP _W ) {
const ni = indexOf ( x + 1 , y ) ;
if ( ! map . sea [ ni ] && ids [ ni ] >= 0 && ids [ ni ] !== ids [ i ] ) expected ++ ;
}
if ( y + 1 < MAP _H ) {
const ni = indexOf ( x , y + 1 ) ;
if ( ! map . sea [ ni ] && ids [ ni ] >= 0 && ids [ ni ] !== ids [ i ] ) expected ++ ;
}
}
}
for ( const segment of map . regionalPrefectureBorders || [ ] ) {
const [ [ x1 , y1 ] , [ x2 , y2 ] ] = segment ;
let a = - 1 , b = - 1 ;
if ( x1 === x2 ) {
const x = x1 ;
const y = Math . min ( y1 , y2 ) ;
if ( x > 0 && x < MAP _W && y >= 0 && y < MAP _H ) {
a = ids [ indexOf ( x - 1 , y ) ] ;
b = ids [ indexOf ( x , y ) ] ;
}
} else if ( y1 === y2 ) {
const x = Math . min ( x1 , x2 ) ;
const y = y1 ;
if ( y > 0 && y < MAP _H && x >= 0 && x < MAP _W ) {
a = ids [ indexOf ( x , y - 1 ) ] ;
b = ids [ indexOf ( x , y ) ] ;
}
}
if ( a < 0 || b < 0 || a === b ) invalidSame ++ ;
}
return { invalidSame , expected , actual : ( map . regionalPrefectureBorders || [ ] ) . length } ;
}
2026-08-08 17:41:30 +09:00
function municipalBorderVectorMetrics ( map ) {
let invalid = 0 ;
let expected = 0 ;
const admin = map . adminId ;
const pref = map . prefectureRegionId ;
for ( let y = 0 ; y < MAP _H ; y ++ ) {
for ( let x = 0 ; x < MAP _W ; x ++ ) {
const i = indexOf ( x , y ) ;
if ( map . sea [ i ] || admin [ i ] < 0 || pref [ i ] < 0 ) continue ;
if ( x + 1 < MAP _W ) {
const j = indexOf ( x + 1 , y ) ;
if ( ! map . sea [ j ] && admin [ j ] >= 0 && pref [ j ] === pref [ i ] && admin [ j ] !== admin [ i ] ) expected ++ ;
}
if ( y + 1 < MAP _H ) {
const j = indexOf ( x , y + 1 ) ;
if ( ! map . sea [ j ] && admin [ j ] >= 0 && pref [ j ] === pref [ i ] && admin [ j ] !== admin [ i ] ) expected ++ ;
}
}
}
for ( const segment of map . adminBorders || [ ] ) {
const [ [ x1 , y1 ] , [ x2 , y2 ] ] = segment ;
let ai = - 1 ;
let bi = - 1 ;
if ( x1 === x2 ) {
const x = x1 ;
const y = Math . min ( y1 , y2 ) ;
if ( x > 0 && x < MAP _W && y >= 0 && y < MAP _H ) {
ai = indexOf ( x - 1 , y ) ;
bi = indexOf ( x , y ) ;
}
} else if ( y1 === y2 ) {
const x = Math . min ( x1 , x2 ) ;
const y = y1 ;
if ( y > 0 && y < MAP _H && x >= 0 && x < MAP _W ) {
ai = indexOf ( x , y - 1 ) ;
bi = indexOf ( x , y ) ;
}
}
if ( ai < 0 || bi < 0 || map . sea [ ai ] || map . sea [ bi ] || admin [ ai ] < 0 || admin [ bi ] < 0 || admin [ ai ] === admin [ bi ] || pref [ ai ] < 0 || pref [ ai ] !== pref [ bi ] ) invalid ++ ;
}
return { invalid , expected , actual : ( map . adminBorders || [ ] ) . length } ;
}
2026-05-26 15:32:27 +09:00
function borderHierarchyViolations ( map ) {
let prefectureCutsMunicipality = 0 ;
let municipalityCutsCompartment = 0 ;
const compId = map . naturalCompartmentId ;
for ( let y = 0 ; y < MAP _H ; y ++ ) {
for ( let x = 0 ; x < MAP _W ; x ++ ) {
const i = indexOf ( x , y ) ;
if ( map . sea [ i ] ) continue ;
for ( const [ nx , ny ] of [ [ x + 1 , y ] , [ x , y + 1 ] ] ) {
if ( nx >= MAP _W || ny >= MAP _H ) continue ;
const ni = indexOf ( nx , ny ) ;
if ( map . sea [ ni ] ) continue ;
if ( map . prefectureRegionId [ i ] !== map . prefectureRegionId [ ni ] && map . adminId [ i ] === map . adminId [ ni ] ) prefectureCutsMunicipality ++ ;
if ( map . adminId [ i ] !== map . adminId [ ni ] && compId && compId [ i ] === compId [ ni ] ) municipalityCutsCompartment ++ ;
}
}
}
return { prefectureCutsMunicipality , municipalityCutsCompartment } ;
}
function longStraightLowBarrierSegments ( map , segments , minRun = 18 ) {
const runs = new Map ( ) ;
for ( const seg of segments || [ ] ) {
const [ [ x1 , y1 ] , [ x2 , y2 ] ] = seg ;
const vertical = x1 === x2 ;
const key = vertical ? ` v: ${ x1 } ` : ` h: ${ y1 } ` ;
const pos = vertical ? Math . min ( y1 , y2 ) : Math . min ( x1 , x2 ) ;
if ( ! runs . has ( key ) ) runs . set ( key , [ ] ) ;
runs . get ( key ) . push ( { pos , seg } ) ;
}
let bad = 0 ;
for ( const rows of runs . values ( ) ) {
rows . sort ( ( a , b ) => a . pos - b . pos ) ;
let start = 0 ;
for ( let k = 1 ; k <= rows . length ; k ++ ) {
if ( k < rows . length && rows [ k ] . pos <= rows [ k - 1 ] . pos + 1.01 ) continue ;
const run = rows . slice ( start , k ) ;
if ( run . length >= minRun ) {
const natural = run . reduce ( ( sum , row ) => {
const [ [ x1 , y1 ] , [ x2 , y2 ] ] = row . seg ;
const sx = Math . min ( Math . max ( 0 , Math . floor ( ( x1 + x2 ) / 2 ) ) , MAP _W - 1 ) ;
const sy = Math . min ( Math . max ( 0 , Math . floor ( ( y1 + y2 ) / 2 ) ) , MAP _H - 1 ) ;
return sum + ( map . naturalBarrierScore ? . [ indexOf ( sx , sy ) ] || 0 ) ;
} , 0 ) / run . length ;
if ( natural < 0.18 ) bad ++ ;
}
start = k ;
}
}
return bad ;
}
function regionalEnclaveCount ( map ) {
const ids = map . prefectureRegionId ;
const regionIds = [ ... new Set ( [ ... ids ] . filter ( ( id , i ) => id >= 0 && ! map . sea [ i ] ) ) ] ;
let enclaves = 0 ;
for ( const id of regionIds ) {
const seen = new Uint8Array ( MAP _W * MAP _H ) ;
for ( let i = 0 ; i < ids . length ; i ++ ) {
if ( seen [ i ] || map . sea [ i ] || ids [ i ] !== id ) continue ;
const queue = [ i ] ;
const cells = [ ] ;
let touchesOutside = false ;
const neighbors = new Set ( ) ;
seen [ i ] = 1 ;
for ( let q = 0 ; q < queue . length ; q ++ ) {
const cur = queue [ q ] ;
cells . push ( cur ) ;
const x = cur % MAP _W ;
const y = Math . floor ( cur / MAP _W ) ;
if ( x === 0 || y === 0 || x === MAP _W - 1 || y === MAP _H - 1 ) touchesOutside = true ;
for ( const [ dx , dy ] of [ [ 1 , 0 ] , [ - 1 , 0 ] , [ 0 , 1 ] , [ 0 , - 1 ] ] ) {
const nx = x + dx ;
const ny = y + dy ;
if ( nx < 0 || ny < 0 || nx >= MAP _W || ny >= MAP _H ) continue ;
const ni = indexOf ( nx , ny ) ;
if ( map . sea [ ni ] ) {
touchesOutside = true ;
continue ;
}
if ( ids [ ni ] !== id && ids [ ni ] >= 0 ) neighbors . add ( ids [ ni ] ) ;
if ( seen [ ni ] || ids [ ni ] !== id ) continue ;
seen [ ni ] = 1 ;
queue . push ( ni ) ;
}
}
if ( cells . length && ! touchesOutside && neighbors . size === 1 ) enclaves ++ ;
}
}
return enclaves ;
}
function cityMunicipalityAreaMetrics ( map ) {
const areaById = new Map ( ) ;
for ( let i = 0 ; i < map . adminId . length ; i ++ ) {
const id = map . adminId [ i ] ;
if ( id >= 0 && ! map . sea [ i ] ) areaById . set ( id , ( areaById . get ( id ) || 0 ) + 1 ) ;
}
const rows = ( map . modernCities || [ ] )
. filter ( ( city ) => ( city . population || 0 ) >= 95000 && city . insidePrefecture && ! map . sea [ indexOf ( city . x , city . y ) ] )
. map ( ( city ) => {
const admin = map . adminId [ indexOf ( city . x , city . y ) ] ;
const minArea = Math . min ( ( city . population || 0 ) >= 450000 ? 780 : 520 , Math . max ( 130 , 95 + Math . sqrt ( city . population || 0 ) * 0.72 + ( city . urbanFootprintCells || 0 ) * 0.42 ) ) ;
return { city , admin , area : areaById . get ( admin ) || 0 , minArea } ;
} ) ;
return { rows , tooSmall : rows . filter ( ( row ) => row . area + 1e-6 < row . minArea * 0.82 ) } ;
}
function prefectureNameForTest ( map , i ) {
const id = map . prefectureRegionId ? . [ i ] ? ? - 1 ;
return ( map . prefectureRegions || [ ] ) . find ( ( region ) => region . id === id ) ? . name || "" ;
2026-05-21 13:20:19 +09:00
}
2026-05-21 22:03:14 +09:00
function meanField ( map , fieldName , predicate ) {
let sum = 0 ;
let count = 0 ;
const field = map [ fieldName ] ;
for ( let i = 0 ; i < field . length ; i ++ ) {
if ( ! predicate ( i ) ) continue ;
sum += field [ i ] ;
count ++ ;
}
return count ? sum / count : 0 ;
}
function ridgeSinuosityMetric ( map ) {
const centers = [ ] ;
for ( let y = 1 ; y < MAP _H - 1 ; y ++ ) {
let sum = 0 ;
let weight = 0 ;
for ( let x = 1 ; x < MAP _W - 1 ; x ++ ) {
const i = indexOf ( x , y ) ;
if ( map . sea [ i ] ) continue ;
const r = Math . max ( 0 , map . ridgeField [ i ] - 0.36 ) ;
sum += x * r ;
weight += r ;
}
if ( weight > 1.2 ) centers . push ( sum / weight ) ;
}
if ( centers . length < 8 ) return 0 ;
let turn = 0 ;
let total = 0 ;
for ( let i = 2 ; i < centers . length ; i ++ ) {
const a = centers [ i - 1 ] - centers [ i - 2 ] ;
const b = centers [ i ] - centers [ i - 1 ] ;
turn += Math . abs ( b - a ) ;
total += Math . abs ( b ) + Math . abs ( a ) + 0.01 ;
}
return turn / total ;
}
function terrainCoreMetrics ( map ) {
const land = [ ... map . elevation ] . map ( ( _ , i ) => i ) . filter ( ( i ) => ! map . sea [ i ] ) ;
const mountainCells = land . filter ( ( i ) => map . elevation [ i ] > 0.58 || map . ridgeField [ i ] > 0.42 ) . length ;
const lowlandCells = land . filter ( ( i ) => map . plain [ i ] > 0.38 || map . depositionalLowland ? . [ i ] > 0.24 ) . length ;
const ridgeValues = land . map ( ( i ) => map . ridgeField [ i ] ) ;
const ridgeMean = ridgeValues . reduce ( ( sum , value ) => sum + value , 0 ) / Math . max ( 1 , ridgeValues . length ) ;
const ridgeVariance = ridgeValues . reduce ( ( sum , value ) => sum + ( value - ridgeMean ) * * 2 , 0 ) / Math . max ( 1 , ridgeValues . length ) ;
const depositionTargetMean = meanField ( map , "depositionField" , ( i ) => ! map . sea [ i ] && ( map . coastalLowland [ i ] > 0.18 || map . basinField [ i ] > 0.22 || map . river [ i ] > 0.18 || map . flowAccum [ i ] > 0.24 ) ) ;
const depositionOtherMean = meanField ( map , "depositionField" , ( i ) => ! map . sea [ i ] && map . coastalLowland [ i ] < 0.08 && map . basinField [ i ] < 0.12 && map . river [ i ] < 0.06 && map . flowAccum [ i ] < 0.12 && map . ridgeField [ i ] < 0.28 ) ;
const riverValleyMean = meanField ( map , "valleyField" , ( i ) => ! map . sea [ i ] && map . river [ i ] > 0.20 ) ;
const nonRiverValleyMean = meanField ( map , "valleyField" , ( i ) => ! map . sea [ i ] && map . river [ i ] <= 0.02 ) ;
return {
landCount : land . length ,
mountainRatio : mountainCells / Math . max ( 1 , land . length ) ,
lowlandRatio : lowlandCells / Math . max ( 1 , land . length ) ,
ridgeVariance ,
ridgeSinuosity : ridgeSinuosityMetric ( map ) ,
depositionTargetMean ,
depositionOtherMean ,
riverValleyMean ,
nonRiverValleyMean ,
depositionSum : [ ... map . depositionField ] . reduce ( ( sum , value ) => sum + value , 0 ) ,
alluvialMax : Math . max ( ... ( map . alluvialFanField || [ 0 ] ) ) ,
deltaMax : Math . max ( ... ( map . deltaField || [ 0 ] ) ) ,
} ;
}
2026-05-22 02:11:18 +09:00
function requiredTransportNodes ( map ) {
const nodes = [ ] ;
const seen = new Set ( ) ;
function add ( p , reason ) {
if ( ! p ) return ;
const key = ` ${ p . x } , ${ p . y } ` ;
if ( seen . has ( key ) ) return ;
seen . add ( key ) ;
nodes . push ( { ... p , requiredTransportReason : reason } ) ;
}
add ( map . prefecturalCapital , "capital" ) ;
for ( const gate of map . externalGateways || [ ] ) add ( gate , "externalGateway" ) ;
for ( const city of map . modernCities || [ ] ) if ( ( city . population || 0 ) >= 120000 || city . isPrefecturalCapital ) add ( city , "majorCity" ) ;
for ( const port of map . ports || [ ] ) if ( port . portClass === "major" ) add ( port , "majorPort" ) ;
return nodes ;
}
function transportConnectivityMetrics ( map ) {
const paths = [
... map . railways ,
... map . branchRailways ,
... map . externalRailways ,
... map . nationalRoads ,
... ( map . ringRoads || [ ] ) ,
... map . expressways ,
... map . externalRoads ,
... map . externalExpressways ,
] ;
const pathCells = new Set ( ) ;
for ( const path of paths ) for ( const [ x , y ] of path ) pathCells . add ( ` ${ x } , ${ y } ` ) ;
const nodes = requiredTransportNodes ( map ) ;
function nearestCell ( node ) {
let best = null ;
let bestD = Infinity ;
for ( const key of pathCells ) {
const [ x , y ] = key . split ( "," ) . map ( Number ) ;
const d = Math . hypot ( node . x - x , node . y - y ) ;
if ( d < bestD ) {
bestD = d ;
best = key ;
}
}
return { key : best , distance : bestD } ;
}
const seen = new Set ( ) ;
const components = [ ] ;
for ( const key of pathCells ) {
if ( seen . has ( key ) ) continue ;
const queue = [ key ] ;
const component = new Set ( [ key ] ) ;
seen . add ( key ) ;
for ( let q = 0 ; q < queue . length ; q ++ ) {
const [ x , y ] = queue [ q ] . split ( "," ) . map ( Number ) ;
for ( const [ dx , dy ] of [ [ 1 , 0 ] , [ - 1 , 0 ] , [ 0 , 1 ] , [ 0 , - 1 ] , [ 1 , 1 ] , [ - 1 , 1 ] , [ 1 , - 1 ] , [ - 1 , - 1 ] ] ) {
const nk = ` ${ x + dx } , ${ y + dy } ` ;
if ( ! pathCells . has ( nk ) || seen . has ( nk ) ) continue ;
seen . add ( nk ) ;
component . add ( nk ) ;
queue . push ( nk ) ;
}
}
components . push ( component ) ;
}
const mapped = nodes . map ( ( node ) => ( {
node ,
nearest : nearestCell ( node ) ,
components : components
. map ( ( component , componentIndex ) => ( {
componentIndex ,
near : [ ... component ] . some ( ( key ) => {
const [ x , y ] = key . split ( "," ) . map ( Number ) ;
return Math . hypot ( node . x - x , node . y - y ) <= 7 ;
} ) ,
} ) )
. filter ( ( item ) => item . near )
. map ( ( item ) => item . componentIndex ) ,
} ) ) ;
const reachable = mapped . filter ( ( item ) => item . components . length > 0 ) ;
let largestRequiredComponent = 0 ;
for ( let componentIndex = 0 ; componentIndex < components . length ; componentIndex ++ ) {
largestRequiredComponent = Math . max ( largestRequiredComponent , reachable . filter ( ( item ) => item . components . includes ( componentIndex ) ) . length ) ;
}
return {
requiredCount : nodes . length ,
reachableCount : reachable . length ,
largestRequiredComponent ,
isolatedExternalGateways : mapped . filter ( ( item ) => item . node . requiredTransportReason === "externalGateway" && item . components . length === 0 ) . length ,
isolatedMajorCities : mapped . filter ( ( item ) => item . node . requiredTransportReason === "majorCity" && item . components . length === 0 ) . length ,
} ;
}
2026-05-20 13:50:56 +09:00
try {
const size = MAP _W * MAP _H ;
2026-08-10 13:59:33 +09:00
let terrainSeedSummaries = [ ] ;
2026-08-08 17:41:30 +09:00
if ( suiteEnabled ( "core" ) ) {
const map = generateTestMap ( 12345 ) ;
2026-05-20 13:50:56 +09:00
const urbanCellCount = [ ... map . landuse ] . filter ( ( value ) => value >= 2 && value <= 8 ) . length ;
const cityPopulations = map . modernCities . map ( ( city ) => city . population || 0 ) ;
const maxPopulation = Math . max ( ... cityPopulations ) ;
const minPopulation = Math . min ( ... cityPopulations ) ;
const landElevations = [ ... map . elevation ] . filter ( ( _ , i ) => ! map . sea [ i ] ) ;
const meanElevation = landElevations . reduce ( ( sum , value ) => sum + value , 0 ) / landElevations . length ;
const elevationStdDev = Math . sqrt ( landElevations . reduce ( ( sum , value ) => sum + ( value - meanElevation ) * * 2 , 0 ) / landElevations . length ) ;
const modernPaths = [
... map . railways ,
... map . branchRailways ,
... map . externalRailways ,
... ( map . ringRailways || [ ] ) ,
... map . nationalRoads ,
... ( map . ringRoads || [ ] ) ,
... map . expressways ,
... ( map . ringExpressways || [ ] ) ,
... map . externalRoads ,
... map . externalExpressways ,
] ;
const endpointDegree = new Map ( ) ;
for ( const path of modernPaths ) {
if ( path . length < 2 ) continue ;
for ( const point of [ path [ 0 ] , path [ path . length - 1 ] ] ) {
const key = point . join ( "," ) ;
endpointDegree . set ( key , ( endpointDegree . get ( key ) || 0 ) + 1 ) ;
}
}
const maxModernEndpointDegree = Math . max ( 0 , ... endpointDegree . values ( ) ) ;
let maxCoastalElevationStep = 0 ;
for ( let y = 1 ; y < MAP _H - 1 ; y ++ ) {
for ( let x = 1 ; x < MAP _W - 1 ; x ++ ) {
const i = indexOf ( x , y ) ;
if ( map . sea [ i ] ) continue ;
for ( const [ dx , dy ] of [ [ 1 , 0 ] , [ - 1 , 0 ] , [ 0 , 1 ] , [ 0 , - 1 ] ] ) {
const ni = indexOf ( x + dx , y + dy ) ;
if ( map . sea [ ni ] ) maxCoastalElevationStep = Math . max ( maxCoastalElevationStep , Math . abs ( map . elevation [ i ] - map . elevation [ ni ] ) ) ;
}
}
}
let railExpressHighMountainCells = 0 ;
for ( const path of [ ... map . railways , ... map . branchRailways , ... ( map . ringRailways || [ ] ) , ... map . externalRailways , ... map . expressways , ... ( map . ringExpressways || [ ] ) , ... map . externalExpressways ] ) {
for ( const [ x , y ] of path ) {
const i = indexOf ( x , y ) ;
if ( map . elevation [ i ] > 0.82 ) railExpressHighMountainCells += 1 ;
}
}
2026-05-20 15:02:37 +09:00
let trunkHighElevationCells = 0 ;
for ( const path of modernPaths ) {
for ( const [ x , y ] of path ) {
if ( map . elevation [ indexOf ( x , y ) ] > 0.72 ) trunkHighElevationCells += 1 ;
}
}
const flatPlainCells = [ ... map . plain ] . filter ( ( value , i ) => ! map . sea [ i ] && value > 0.72 && map . slope [ i ] < 0.12 ) . length ;
const largeMountainCities = map . modernCities . filter ( ( city ) => {
const i = indexOf ( city . x , city . y ) ;
return ( city . population || 0 ) >= 250000 && ( map . elevation [ i ] > 0.66 || map . plain [ i ] < 0.18 || map . slope [ i ] > 0.88 ) ;
} ) ;
const capitalInside = map . prefecturalCapital && map . prefectureMask [ indexOf ( map . prefecturalCapital . x , map . prefecturalCapital . y ) ] ;
2026-05-20 17:15:09 +09:00
const allNameable = map . entitiesForNames || [ ] ;
const uniqueNames = new Set ( allNameable . map ( ( item ) => item . name ) ) ;
const duplicateNameRatio = allNameable . length ? 1 - uniqueNames . size / allNameable . length : 0 ;
2026-05-21 02:55:58 +09:00
const activePoolChars = new Set ( Object . values ( NAME _KANJI _POOLS ) . flat ( ) . flatMap ( ( part ) => Array . from ( String ( part ) ) ) ) ;
const namedEntityCount = [
... map . villages ,
... map . ports ,
... map . crossings ,
... map . passes ,
... map . markets ,
... map . castles ,
... map . castleTowns ,
... map . modernCities ,
... map . stations ,
... map . industrialZones ,
... map . interchanges ,
... map . logisticsParks ,
... map . satelliteCities ,
... map . newTowns ,
... map . castleRuins ,
... map . externalGateways ,
... map . adminCenters ,
] . filter ( ( item ) => item ? . id && item ? . name ) . length ;
2026-05-20 17:15:09 +09:00
const villageClusterMean = map . villages . length
? map . villages . reduce ( ( sum , p ) => sum + ( map . settlementCluster ? . [ indexOf ( p . x , p . y ) ] || 0 ) , 0 ) / map . villages . length
: 0 ;
const meaningfulTransportNodes = [
... map . modernCities ,
... map . ports ,
... map . markets ,
... map . externalGateways ,
... map . interchanges ,
... map . industrialZones ,
... map . logisticsParks ,
] ;
const endpointPaths = [
... map . railways ,
... map . branchRailways ,
... map . externalRailways ,
... map . nationalRoads ,
... map . expressways ,
... map . externalRoads ,
... map . externalExpressways ,
... ( map . icAccessRoads || [ ] ) ,
] ;
const endpointDistances = endpointPaths . flatMap ( ( path ) => path . length >= 2 ? [ path [ 0 ] , path [ path . length - 1 ] ] : [ ] )
. map ( ( [ x , y ] ) => Math . min ( ... meaningfulTransportNodes . map ( ( p ) => Math . hypot ( p . x - x , p . y - y ) ) ) ) ;
const saneEndpointRatio = endpointDistances . length
? endpointDistances . filter ( ( d ) => d <= 10 ) . length / endpointDistances . length
: 1 ;
const adminMetrics = adminBoundaryMetrics ( map ) ;
const cityCoreIntegrity = majorCityCoreIntegrity ( map ) ;
2026-05-21 13:20:19 +09:00
const satelliteMetrics = satelliteMunicipalityMetrics ( map ) ;
const regionalMetrics = regionalComponentMetrics ( map ) ;
2026-05-21 22:03:14 +09:00
const terrainMetrics = terrainCoreMetrics ( map ) ;
2026-05-20 13:50:56 +09:00
2026-05-21 02:55:58 +09:00
assert ( NAME _KANJI _POOLS && Array . isArray ( NAME _KANJI _POOLS . modifiers ) , "NAME_KANJI_POOLS exists" ) ;
assert ( NAME _TEMPLATES && NAME _TEMPLATES . modifierTerrain ? . slots ? . length === 2 , "NAME_TEMPLATES exists" ) ;
assert ( NAME _TEMPLATE _WEIGHTS && NAME _TEMPLATE _WEIGHTS . generic ? . modifierTerrain > 0 , "NAME_TEMPLATE_WEIGHTS exists" ) ;
assert ( NAME _PROBABILITIES && NAME _PROBABILITIES . contextCategoryWeights ? . generic , "NAME_PROBABILITIES exists" ) ;
const removedContextModule = "placeName" + "Context.js" ;
2026-08-11 21:51:07 +09:00
assert ( ! namesSource . includes ( removedContextModule ) && ! mapGeneratorSource . includes ( removedContextModule ) , "removed name-context import is absent from production modules" ) ;
2026-05-21 02:55:58 +09:00
assert ( Object . keys ( NAME _KANJI _POOLS ) . every ( ( key ) => Array . isArray ( NAME _KANJI _POOLS [ key ] ) ) , "name category pools are centralized arrays" ) ;
2026-05-21 13:20:19 +09:00
assert ( Object . values ( NAME _KANJI _POOLS ) . every ( ( pool ) => pool . every ( ( part ) => typeof part === "string" && ! part . includes ( "\uFFFD" ) ) ) , "configured name category pools contain valid strings" ) ;
2026-05-21 02:55:58 +09:00
const removedContextSuffixConst = "CONTEXT" + "_SUFFIXES" ;
const removedContextSuffixKey = "context" + "Suffixes" ;
assert ( ! namesSource . includes ( removedContextSuffixConst ) && ! namesSource . includes ( removedContextSuffixKey ) , "hidden context suffix arrays are absent" ) ;
assert ( ! /export\s+const\s+NAME_PROBABILITIES[\s\S]*export\s+const\s+NAME_PROBABILITIES/ . test ( namesSource ) , "NAME_PROBABILITIES has one source" ) ;
2026-05-29 15:49:09 +09:00
assert ( mapPatchSource . includes ( "splitWorldPathByPatch" ) && mapPatchSource . includes ( "patchAffected" ) , "patch path merging is alpha-aware for lasso selections" ) ;
assert ( ! mapPatchSource . includes ( "patchAlpha(x, y, rects, 0)" ) , "patch admin repair uses the active patch seed" ) ;
assert ( mapPatchSource . includes ( "refreshPatchInfluenceFields" ) && mapPatchSource . includes ( "roadCellsPainted" ) , "patch generation refreshes derived transport influence fields after path merges" ) ;
2026-08-11 21:51:07 +09:00
assert ( mapPatchSource . includes ( "createTransportPathSpatialIndex" ) && mapPatchSource . includes ( "TRANSPORT_SPATIAL_BUCKET_SIZE" ) , "patch transport queries use a bucketed spatial index instead of repeatedly scanning every path" ) ;
assert ( mapPatchSource . includes ( "pathfindScratch" ) && mapPatchSource . includes ( "Float32Array" ) && mapPatchSource . includes ( "buildHierarchicalPathCorridor" ) , "patch connector pathfinding reuses typed scratch storage and has a coarse-to-fine hierarchy" ) ;
assert ( mapPatchSource . includes ( "TransportUnionFind" ) && mapPatchSource . includes ( "GraphIncrementalUnions" ) && mapPatchSource . includes ( "GraphFullRebuilds" ) , "transport graph repair tracks connector merges incrementally and reserves full rebuilds for audit" ) ;
assert ( mapPatchSource . includes ( "getRadialInfluenceKernel" ) && mapPatchSource . includes ( "paintInfluenceDisk" ) , "regional influence refresh reuses exact radial kernels instead of recalculating distance powers per painted cell" ) ;
assert ( mapPatchSource . includes ( "regionalUrbanScratch" ) && mapPatchSource . includes ( "population.subarray" ) , "regional urban recalculation reuses compact scratch buffers and row copies" ) ;
assert ( mapPatchSource . includes ( "ensurePatchSelectionDistanceCache" ) && mapPatchSource . includes ( "_selectionDistanceCache" ) && mapPatchSource . includes ( "selectionDistanceCacheReused" ) , "lasso regional transport and urban recalculation share one lazy selection-distance raster" ) ;
assert ( mapPatchWorkerSource . includes ( "admissible-terrain-scout-branch-and-bound-two-lane-v2" ) && mapPatchWorkerSource . includes ( "draftCandidateUpperBound" ) && mapPatchWorkerSource . includes ( "branchBoundPrunedCount" ) && mapPatchWorkerSource . includes ( "precomputeRawTerrainScoutBatch" ) && mapPatchWorkerSource . includes ( "fullProductionFromTerrainOnly" ) && ! mapPatchWorkerSource . includes ( "draftNearTieFullGap" ) , "candidate ranking uses admissible Branch-and-Bound with resident two-lane terrain scouts; simplified human/transport drafts are never reused for publication" ) ;
assert ( worldMapSource . includes ( "INITIAL_QUALITY_TRANSPORT_CLASSES" ) && worldMapSource . includes ( "initial-production-quality-v2" ) && mapPatchSource . includes ( "transportHierarchyPass" ) , "initial quality oracle records national, expressway, and rail-trunk production density and enforces hierarchy-aware final quality" ) ;
assert ( mapPatchSource . includes ( "finalizeRegionalTrunkTransport" ) && mapPatchSource . includes ( "patchRegionalTrunkFinalizer" ) && mapPatchSource . includes ( "productionTransportParity" ) , "full additional-generation finalists restore production trunk transport and fill missing national, expressway, and trunk-rail demand" ) ;
assert ( mapPatchSource . includes ( "connectorLayerForEndpoints" ) && mapPatchSource . includes ( "transportHierarchyAtPoint" ) , "transport seam repair preserves expressway, national-road, and trunk-rail hierarchy instead of demoting every connector" ) ;
assert ( appSource . includes ( "PATCH_SEARCH_BATCH_SIZE = 3" ) && appSource . includes ( "PATCH_SEARCH_DEFAULT_LIMIT = 12" ) && appSource . includes ( "contentBatchExhausted" ) && appSource . includes ( "allCandidatePlan" ) , "quality-rejected candidates advance automatically in three-candidate batches up to twelve without publishing drafts" ) ;
assert ( ! appSource . includes ( "BEST AVAILABLE" ) && appSource . includes ( "acceptBestAvailableQuality: false" ) , "top-level preview publication has no best-available quality bypass" ) ;
2026-05-29 15:49:09 +09:00
assert ( mapPatchSource . includes ( "normalizeGeneratedPointIds" ) , "patch generation normalizes generated point admin and prefecture ids" ) ;
2026-08-10 13:59:33 +09:00
assert ( mapPatchSource . includes ( "generateUnifiedWorldNativePatchCandidate" ) && mapPatchSource . includes ( "generateMap(seed" ) && mapPatchSource . includes ( "unified-world-native-patch" ) , "patch modes execute the complete production generation pipeline" ) ;
2026-08-08 17:41:30 +09:00
assert ( ! mapPatchSource . includes ( "generateVariablePatchCandidate" ) && ! mapPatchSource . includes ( "PATCH_VARIABLE_CANDIDATE_ENABLED" ) , "retired variable rectangle candidate implementation is removed" ) ;
assert ( mapPatchSource . includes ( "resolvePatchMode" ) && mapPatchSource . includes ( "PATCH_MODE_EXPANSION" ) && mapPatchSource . includes ( "PATCH_MODE_REGENERATION" ) , "patch generation separates expansion and regeneration modes" ) ;
assert ( mapPatchSource . includes ( "resolveWorldSeaLevel" ) && mapPatchSource . includes ( "buildTerrainBoundaryContract" ) && mapPatchSource . includes ( "applyTerrainBoundaryContract" ) , "patch terrain uses a shared world sea level and an explicit boundary contract" ) ;
2026-08-10 13:59:33 +09:00
assert ( mapPatchSource . includes ( "candidateOriginX" ) && mapPatchSource . includes ( "world?.originX" ) && mapPatchSource . includes ( "canonicalWorldGrid" ) , "patch candidates use padding-invariant world coordinates and canonical tile windows" ) ;
assert ( appSource . includes ( "activePatchOperation" ) && appSource . includes ( "selectionRevision" ) && appSource . includes ( "isPatchOperationCurrent" ) , "patch preview publication is guarded by immutable operation and selection generations" ) ;
assert ( appSource . includes ( "fullGenerationBusy" ) && appSource . includes ( "state.patchBusy || state.fullGenerationBusy" ) && appSource . includes ( "cancelPatchGeneration" ) , "full and patch generation share one explicit busy/cancellation domain" ) ;
assert ( derivePatchSeedSource . includes ( "function derivePatchSeed(world, terrainType, variant" ) && ! derivePatchSeedSource . includes ( "rect.x" ) && ! derivePatchSeedSource . includes ( "rect.y" ) , "UI patch seed is independent of selection bounds and backing-world padding" ) ;
assert ( ! appSource . includes ( "qualityWorkerRetries: 1" ) && ! appSource . includes ( "attemptVariant = (attemptVariant + 3)" ) , "UI does not run the obsolete hidden whole-patch retry wrapper" ) ;
assert ( mapPatchSource . includes ( "generateTiledRegenerationPatch" ) && mapPatchSource . includes ( "patch-candidate-coverage-incomplete" ) , "large Regeneration is tiled and rejects uncovered active cells instead of silently skipping them" ) ;
2026-08-11 21:51:07 +09:00
assert ( mapPatchSource . includes ( "initial-quality-oracle-admin-transport-coherence-v4" ) && mapPatchSource . includes ( "const requestedAttempts = 1" ) , "each search candidate runs exactly one explicit complete production variant" ) ;
2026-08-10 13:59:33 +09:00
assert ( mapPatchWorkerSource . includes ( "runPatchCandidateSearch" ) && mapPatchWorkerSource . includes ( "candidatePlan" ) && mapPatchWorkerSource . includes ( "patch-search-exhausted" ) , "worker owns a bounded multi-candidate search controller" ) ;
assert ( mapPatchWorkerSource . includes ( "persistentCommittedMirror" ) && appSource . includes ( "reuseCommittedMirror" ) && appSource . includes ( "committedRevision" ) , "warm Alternative searches reuse a revision-checked committed Worker mirror" ) ;
assert ( mapPatchWorkerSource . includes ( "patch-apply-ack" ) && appSource . includes ( "acknowledgePatchApply" ) , "Apply advances the persistent mirror through a revision-checked transactional ACK" ) ;
assert ( appSource . includes ( "stagePreviewRenderBundle" ) && appSource . includes ( "publishPreviewRenderBundle" ) , "preview rendering is staged offscreen before atomic state and canvas publication" ) ;
assert ( mapPatchSource . includes ( "auditRepairAndReauditPatchSeam" ) && mapPatchSource . includes ( "PATCH_SEAM_INVARIANT_REASONS" ) , "seam repair is audit-driven and keeps invariant failures outside the repair path" ) ;
assert ( mapPatchSource . includes ( "large-regeneration-final-quality" ) && mapPatchSource . includes ( "whole-selection-post-merge" ) , "tiled Regeneration applies one authoritative whole-selection quality audit" ) ;
assert ( mapPatchSource . includes ( "minFinalAdminCenters" ) && mapPatchSource . includes ( "transportRequired" )
&& mapPatchSource . includes ( "roadPaths > 0" ) , "final quality rejects Regeneration candidates that lose required administration or transport" ) ;
assert ( mapPatchWorkerSource . includes ( "computePreviewDelta" ) && appSource . includes ( "previewPatchDelta(baseWorld, job.world" ) ,
"preview raster and feature change auditing remains available for both immutable-reference and transactional-delta paths" ) ;
assert ( appSource . includes ( "buildPatchCandidatePlan" ) && appSource . includes ( "consumedCandidateIds" ) && appSource . includes ( "nextVariant" ) , "UI continues Alternative batches without repeating content-rejected candidates" ) ;
const controllerBase = { fields : { marker : new Uint8Array ( [ 1 ] ) } } ;
const controllerCalls = [ ] ;
const controllerProgress = [ ] ;
const controllerResult = runPatchCandidateSearch ( {
id : 1 ,
world : controllerBase ,
rect : { x0 : 0 , y0 : 0 , x1 : 1 , y1 : 1 } ,
options : { } ,
search : {
searchId : "controller-regression" ,
workerEpoch : 1 ,
committedRevision : 1 ,
candidatePlan : [ { variant : 5 , seed : 105 } , { variant : 6 , seed : 106 } , { variant : 7 , seed : 107 } ] ,
} ,
} , {
cloneWorld : ( value ) => structuredClone ( value ) ,
onProgress : ( message ) => controllerProgress . push ( message . progress ) ,
generateCandidate : ( candidateWorld , rect , options ) => {
controllerCalls . push ( { variant : options . variant , baseline : candidateWorld . fields . marker [ 0 ] } ) ;
candidateWorld . fields . marker [ 0 ] = options . variant ;
if ( options . variant === 5 ) return { ok : false , code : "patch-quality-gate-failed" , reason : "forced content rejection" } ;
return { ok : true , variant : options . variant , seed : options . seed , seamDiagnostics : { hardPass : true } } ;
} ,
} ) ;
assert ( controllerResult . result ? . ok === true && controllerResult . result ? . actualVariant === 6 , "content rejection automatically advances to the next complete candidate" ) ;
assert ( controllerCalls . length === 2 && controllerCalls . every ( ( call ) => call . baseline === 1 ) && controllerBase . fields . marker [ 0 ] === 1 , "each candidate starts from an isolated immutable committed baseline" ) ;
assert ( controllerResult . result ? . searchAttempts ? . map ( ( attempt ) => attempt . status ) . join ( "," ) === "rejected,success" , "candidate search preserves an ordered rejection and success audit trail" ) ;
assert ( controllerProgress . length > 0 && controllerProgress . every ( ( event ) => Number . isFinite ( event . eventSeq ) && event . phase && event . workUnitId ) , "worker progress carries ordered operation, phase, and work-unit identity" ) ;
assert ( controllerProgress . filter ( ( event ) => event . boundedWork ) . every ( ( event ) => event . completed >= 0 && event . completed <= event . total ) , "bounded worker progress never exceeds its declared finite work total" ) ;
const invalidProgressResult = runPatchCandidateSearch ( {
id : 4 ,
world : controllerBase ,
rect : { x0 : 0 , y0 : 0 , x1 : 1 , y1 : 1 } ,
options : { } ,
search : { searchId : "controller-progress-invariant" , candidatePlan : [ { variant : 12 , seed : 112 } ] } ,
} , {
cloneWorld : ( value ) => structuredClone ( value ) ,
generateCandidate : ( candidateWorld , rect , options ) => {
options . onProgress ( { status : "step" , key : "invalid-bounds" , completed : 2 , total : 1 } ) ;
return { ok : true , seamDiagnostics : { hardPass : true } } ;
} ,
} ) ;
assert ( invalidProgressResult . ok === false && invalidProgressResult . code === "worker-progress-invariant" , "invalid or runaway bounded progress stops the worker search as an invariant failure" ) ;
const invariantCalls = [ ] ;
const invariantResult = runPatchCandidateSearch ( {
id : 2 ,
world : controllerBase ,
rect : { x0 : 0 , y0 : 0 , x1 : 1 , y1 : 1 } ,
options : { } ,
search : {
searchId : "controller-invariant" ,
workerEpoch : 1 ,
committedRevision : 1 ,
candidatePlan : [ { variant : 8 , seed : 108 } , { variant : 9 , seed : 109 } ] ,
} ,
} , {
cloneWorld : ( value ) => structuredClone ( value ) ,
generateCandidate : ( candidateWorld , rect , options ) => {
invariantCalls . push ( options . variant ) ;
return {
ok : false ,
code : "patch-seam-gate-failed" ,
reason : "forced write escape" ,
seamDiagnostics : { hardPass : false , gateReasons : [ "generated-footprint-write-escape" ] } ,
} ;
} ,
} ) ;
assert ( invariantResult . result ? . searchStatus === "invariant-breach" && invariantCalls . length === 1 , "write invariant failures stop the search without consuming another variant" ) ;
const cloneFailure = runPatchCandidateSearch ( {
id : 3 ,
world : controllerBase ,
rect : { x0 : 0 , y0 : 0 , x1 : 1 , y1 : 1 } ,
options : { } ,
search : { searchId : "controller-clone" , candidatePlan : [ { variant : 10 , seed : 110 } , { variant : 11 , seed : 111 } ] } ,
} , {
cloneWorld : ( ) => { throw new Error ( "forced clone failure" ) ; } ,
generateCandidate : ( ) => { throw new Error ( "candidate must not start after clone failure" ) ; } ,
} ) ;
assert ( cloneFailure . result ? . searchStatus === "infrastructure-error" && cloneFailure . result ? . nextVariant === 10 , "candidate clone failure preserves the current variant for infrastructure retry" ) ;
const deltaBase = {
width : 4 , height : 2 ,
fields : { elevation : new Float32Array ( [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ) , adminId : new Int32Array ( 8 ) } ,
generatedMask : new Uint8Array ( 8 ) , sourceMap : { villages : [ { x : 1 , y : 1 } ] } , patchGenerationSerial : 1 ,
} ;
const deltaTarget = structuredClone ( deltaBase ) ;
deltaTarget . fields . elevation [ 2 ] = 20 ;
deltaTarget . fields . adminId [ 7 ] = 9 ;
deltaTarget . generatedMask [ 6 ] = 1 ;
deltaTarget . sourceMap . villages . push ( { x : 2 , y : 2 } ) ;
deltaTarget . patchGenerationSerial = 2 ;
const committedDelta = buildCommittedMirrorDelta ( deltaBase , deltaTarget ) ;
const deltaApplied = applyCommittedMirrorDelta ( structuredClone ( deltaBase ) , committedDelta ) ;
assert (
arraysEqual ( deltaApplied . fields . elevation , deltaTarget . fields . elevation )
&& arraysEqual ( deltaApplied . fields . adminId , deltaTarget . fields . adminId )
&& arraysEqual ( deltaApplied . generatedMask , deltaTarget . generatedMask )
&& JSON . stringify ( deltaApplied . sourceMap ) === JSON . stringify ( deltaTarget . sourceMap )
&& deltaApplied . patchGenerationSerial === 2 ,
"transactional Apply delta reproduces the accepted world fields, mask, metadata, and serial"
) ;
assert ( mapPatchWorkerSource . includes ( "sourceMapDelta" ) && mapPatchWorkerSource . includes ( "metaDelta" )
&& ! mapPatchWorkerSource . includes ( "sourceMap: structuredClone(nextWorld.sourceMap" ) , "Apply ACK retains only changed source/world metadata instead of duplicating the complete map metadata" ) ;
assert ( mapPatchWorkerSource . includes ( "buildExactArraySplice" )
&& mapPatchWorkerSource . includes ( "arraySplices" )
&& mapPatchWorkerSource . includes ( "isDensePlainArray" )
&& committedWorldDeltaSource . includes ( "applyCommittedWorldDelta" ) ,
"changed dense feature/path/history layers use exact splice deltas instead of transferring the complete layer" ) ;
assert ( appSource . includes ( "consumeMetadata: true" )
&& mapPatchWorkerSource . includes ( "pending.delta, { consumeMetadata: true }" ) ,
"main preview publication and Worker Apply ACK consume their isolated metadata delta without cloning it a second time" ) ;
assert ( mapPatchWorkerSource . includes ( "buildMainThreadTransferDelta" )
&& ! mapPatchWorkerSource . includes ( "const mainThreadDelta = structuredClone(delta)" )
&& mapPatchWorkerSource . includes ( "{ fields: payload.worldDelta.fields, generatedMask: payload.worldDelta.generatedMask }" ) ,
"Worker main-transfer preparation copies detachable raster rows without cloning or detaching retained metadata" ) ;
assert ( mapPatchWorkerSource . includes ( "const exactDeltas = { sourceMapDelta: rawSourceMapDelta, metaDelta: rawMetaDelta }" )
&& ! mapPatchWorkerSource . includes ( "structuredClone({ sourceMapDelta: rawSourceMapDelta, metaDelta: rawMetaDelta })" ) ,
"transaction delta owns completed candidate metadata directly instead of cloning the graph before rollback" ) ;
assert ( mapPatchWorkerSource . includes ( "transactional: true" ) && mapPatchWorkerSource . includes ( "buildCommittedMirrorDeltaFromTransaction" )
&& appSource . includes ( "materializeCommittedWorldDeltaCooperative(world, event.data.worldDelta" ) , "production previews mutate the Worker mirror transactionally and materialize only the accepted delta on the main thread" ) ;
assert ( appSource . includes ( "materializeCommittedWorldDelta" )
&& ! appSource . includes ( "previewWorld = structuredClone(world)" ) ,
"main preview creation uses copy-on-write changed fields instead of cloning every committed raster and metadata layer" ) ;
assert ( appSource . includes ( "Accepted preview hash mismatch" ) && appSource . includes ( "hashCommittedWorldAsync" )
&& mapPatchWorkerSource . includes ( "acceptedWorldHash" ) ,
"main-thread preview publication cooperatively rejects any transaction delta that does not reproduce the Worker-completed world hash" ) ;
assert ( mapPatchWorkerSource . includes ( "changeTracker.mask" ) && mapPatchWorkerSource . includes ( "successDelta?.previewDelta" ) ,
"transaction delta construction also produces preview statistics so the main thread does not repeat the field comparison" ) ;
assert ( mapPatchWorkerSource . includes ( "const scanLocalRect = localEntry && rect" )
&& mapPatchWorkerSource . includes ( "const scanStart = scanLocalRect" ) ,
"transaction delta compares local fields only inside their captured mutation rectangle" ) ;
assert ( mapPatchWorkerSource . includes ( "const transferRoot = payload.worldDelta" )
&& mapPatchWorkerSource . includes ( "{ fields: payload.worldDelta.fields, generatedMask: payload.worldDelta.generatedMask }" )
&& mapPatchWorkerSource . includes ( ": (payload.world || null)" ) ,
"result transfer discovery scans only the transferable raster delta/full-world root instead of the complete diagnostic graph" ) ;
assert ( ! worldMapSource . includes ( "invalidatedRects" ) && ! mapPatchSource . includes ( "addInvalidatedRect" )
&& ! worldMapSource . includes ( "humanPatchHistory" ) && ! mapPatchSource . includes ( "humanPatchHistory" ) ,
"unused invalidation and patch-history arrays are absent from world state, transactions, padding shifts, and Worker payloads" ) ;
assert ( mapPatchSource . includes ( "PATCH_MUTABLE_SOURCE_KEYS" )
&& mapPatchSource . includes ( "PATCH_MUTABLE_SOURCE_KEYS.has(key)" )
&& mapPatchSource . includes ( "out[key] = PATCH_MUTABLE_SOURCE_KEYS.has(key)" ) ,
"transaction snapshots recursively clone only patch-mutable sourceMap roots and share read-only production metadata" ) ;
assert ( mapPatchWorkerSource . includes ( "isolateSourceMap: true" )
&& mapPatchSource . includes ( "sourceMapIsolated: isolateSourceMap" )
&& mapPatchSource . includes ( "world.sourceMap = snapshot.sourceMapRef || {}" ) ,
"Worker candidates mutate an isolated sourceMap and rollback by reference without a second metadata clone" ) ;
assert ( mapPatchSource . includes ( "generatedRects: lightweight ? null : (world.generatedRects || [])" )
&& mapPatchSource . includes ( "lastPatchResult: lightweight ? null : (world.lastPatchResult ?? null)" )
&& ! mapPatchSource . includes ( "cloneTransactionValue(world.generatedRects || [])" )
&& ! mapPatchSource . includes ( "cloneTransactionValue(world.lastPatchResult ?? null)" ) ,
"transaction rollback retains immutable history and prior diagnostics by reference instead of cloning their debug graphs" ) ;
assert ( mapPatchSource . includes ( "baselineSourceMap" ) && mapPatchSource . includes ( "snapshotPoint = baselineSourceMap" )
&& mapPatchSource . includes ( "capturePrefectureIdentitySnapshot(sourceMap, strictMetadataSnapshot)" ) ,
"strict Regeneration metadata reuses the immutable transaction baseline across outside-point and identity snapshots" ) ;
assert ( mapPatchSource . includes ( "rects.patchMode === PATCH_MODE_EXPANSION" )
&& mapPatchSource . includes ( "protectedIndexLookup?.fill(-1)" ) ,
"Regeneration strict snapshots do not allocate the Expansion-only random lookup table" ) ;
assert ( mapPatchSource . includes ( "_strictBaselineTransactionSnapshot: transaction" )
&& mapPatchSource . includes ( "transactionSnapshot?.fields?.has(name)" ) ,
"large internal tiles reuse the outer transaction's field before-images instead of cloning strict fields per tile" ) ;
assert ( mapPatchSource . includes ( "PATCH_TRANSACTION_READ_ONLY_FIELDS" )
&& mapPatchSource . includes ( "PATCH_TRANSACTION_READ_ONLY_FIELDS.has(name)" ) ,
"transaction and strict snapshots omit the read-only flowTo field instead of copying unused rollback values" ) ;
assert ( appSource . includes ( "resolvedPatchMode: operation.resolvedPatchMode" )
&& mapPatchWorkerSource . includes ( "copyGeneratedMask:" )
&& mapPatchWorkerSource . includes ( "resolvedPatchMode || \"\").toLowerCase() !== \"regeneration\"" )
&& mapPatchSource . includes ( "generatedMaskRef" ) ,
"Regeneration transactions retain generatedMask by reference while Expansion keeps an exact writable before-image" ) ;
assert ( mapPatchSource . includes ( "synchronizePatchMunicipalityField" ) && mapPatchSource . includes ( "municipalityWriteRects: aggregateSourceRects" ) ,
"Regeneration administrative coherence avoids a whole-world municipality write followed by whole-world strict restoration" ) ;
assert ( mapPatchSource . includes ( "municipalityWriteRects: rects," )
&& ! mapPatchSource . includes ( "snapshot.globalFields.set(\"municipalityId\"" )
&& ! mapPatchSource . includes ( "new municipality.constructor(municipality)" )
&& ! mapPatchSource . includes ( "globalFields:" ) ,
"Expansion and Regeneration scope municipality writes to patch alpha and omit the full-world rollback copy" ) ;
assert ( mapPatchSource . includes ( "bestFallbackCellByPrefecture" ) && mapPatchSource . includes ( "previous || score > previous.score" ) ,
"prefecture capital fallback collects best cells in one world pass instead of rescanning the world per missing prefecture" ) ;
assert ( mapPatchSource . includes ( "_tileCoreWidth: MAP_W" ) && mapPatchSource . includes ( "_tileCoreHeight: MAP_H" )
&& appSource . includes ( "buildLargeExpansionTiles(rect, world, regeneration ? {" )
&& appSource . includes ( "_tileCoreWidth: MAP_W" ) && appSource . includes ( "_tileCoreHeight: MAP_H" ) ,
"large Regeneration plans full-size production cores and the UI derives the same tile count from the production tiler" ) ;
assert ( ! mapPatchWorkerSource . includes ( "stableLayerText" ) && ! appSource . includes ( "stableLayerText" ) , "preview feature comparison does not allocate full JSON strings" ) ;
assert ( rendererSource . includes ( "MAX_BASE_CACHE_IMAGES = 1" ) && rendererSource . includes ( "MAX_OVERLAY_CACHE_IMAGES = 1" )
&& ! appSource . includes ( "snapshotVisibleCanvas" ) , "preview raster caches and publication rollback do not retain obsolete full canvases" ) ;
assert ( worldMapSource . includes ( "initialQualityReference" ) && mapPatchSource . includes ( "world?.initialQualityReference" ) , "quality reference is fixed at initial generation instead of growing with patch history" ) ;
assert ( worldMapSource . includes ( "generatedMask" ) && mapPatchSource . includes ( "addGeneratedFootprintToMask" ) , "generated coverage uses a world-sized mask rather than scanning all patch history per cell" ) ;
assert ( appSource . includes ( "featureLayersChanged" ) && appSource . includes ( "transportReachRect" ) && appSource . includes ( "fieldNames" ) , "preview identical diagnostics cover all raster fields and feature/path layers in the affected range" ) ;
assert ( mapPatchSource . includes ( "_deferInternalSeamDiagnostics" ) && mapPatchSource . includes ( "_coverageDistanceBaseline" ) , "large tiles reuse coverage distances and defer internal seam diagnostics to the whole selection" ) ;
assert ( worldMapSource . includes ( "MAX_WORLD_WIDTH" ) && worldMapSource . includes ( "MAX_WORLD_HEIGHT" ) , "backing-world padding has an explicit upper bound" ) ;
2026-08-08 17:41:30 +09:00
assert ( worldMapSource . includes ( "seaLevel: Number.isFinite(initialMap?.seaLevel)" ) , "world map persists the initial sea level as a world invariant" ) ;
assert ( mapPatchSource . includes ( "capturePatchSeamSnapshot" ) && mapPatchSource . includes ( "analyzePatchSeam" ) && mapPatchSource . includes ( "roadPortalsBroken" ) && mapPatchSource . includes ( "duplicateBoundaryPairs" ) , "patch generation records coast, transport, and boundary seam diagnostics" ) ;
assert ( appSource . includes ( "advancedSeamDiagnostics" ) && appSource . includes ( "showSeamDiagnostics" ) && appSource . includes ( "seamDiagnosticRows" ) , "seam diagnostics are exposed in the UI and map overlay controls" ) ;
2026-08-11 21:51:07 +09:00
assert ( appSource . includes ( "state.world.sourceMap.patchSeamDiagnostics.enabled = false" )
&& appSource . includes ( "state.showSeamDiagnostics = false" )
&& appSource . includes ( "showSeamDiagnosticsInput.checked = false" ) ,
"applying an additional-generation preview disables and unchecks the seam diagnostic overlay so red dotted diagnostics cannot become stuck" ) ;
2026-05-29 15:49:09 +09:00
assert ( mapPatchSource . includes ( "patchTimings" ) && appSource . includes ( "result.patchTimings" ) , "patch generation returns and renders timing rows" ) ;
2026-08-08 17:41:30 +09:00
assert ( ! mapPatchSource . includes ( "patchCandidateCacheKey" ) && ! mapPatchSource . includes ( "patchCandidateCache" ) , "unused patch candidate cache is removed" ) ;
2026-05-29 15:49:09 +09:00
assert ( mapPatchSource . includes ( "getPatchAlphaCache" ) && mapPatchSource . includes ( "getPatchSourceIndexCache" ) , "patch generation caches alpha and source-index grids for merge work" ) ;
2026-08-08 17:41:30 +09:00
assert ( mapPatchSource . includes ( "attemptsRemaining = options.maxAttempts" ) && mapPatchSource . includes ( "connectorAttempts" ) , "patch connector pathfinding uses bounded attempts" ) ;
2026-08-11 21:51:07 +09:00
assert ( mapPatchSource . includes ( "minorRoads: 42" ) && mapPatchSource . includes ( "nationalRoads: 94" )
&& mapPatchSource . includes ( "expressways: 164" ) && mapPatchSource . includes ( "railways: 188" )
&& mapPatchSource . includes ( "PATCH_URBAN_RECALC_REACH = 112" )
&& mapPatchSource . includes ( "regionalRecalculationProbability" ) ,
"regional recomputation uses narrow local-road, wider national-road, and widest expressway/rail collars with distance-decaying selection probability" ) ;
2026-05-29 15:49:09 +09:00
assert ( worldMapSource . includes ( "shiftSelectionShape" ) && worldMapSource . includes ( "selectionShape = shiftSelectionShape" ) , "world expansion shifts stored lasso patch polygons" ) ;
assert ( municipalSource . includes ( "reconcileMunicipalMetadata" ) && mapOutputSource . includes ( "reconcileMunicipalMetadata" ) && mapPatchSource . includes ( "reconcileMunicipalMetadata" ) , "municipal metadata is reconciled in output and patch repair" ) ;
assert ( appSource . includes ( "mappedPref === id" ) && ! appSource . includes ( "return nearestNamedAdminCenter(map, cellIndex, maxDistance, null)" ) , "tooltip municipal fallback requires exact coherent ids" ) ;
2026-08-08 17:41:30 +09:00
assert ( mapPatchSource . includes ( "expansionSelectionMask" ) && mapPatchSource . includes ( "coverageDistanceAt" ) && mapPatchSource . includes ( "patchBand" ) , "expansion lasso alpha uses a two-sided generated/new overlap while regeneration remains strict" ) ;
2026-05-29 15:49:09 +09:00
assert ( mapPatchSource . includes ( "repairDiscreteSeamOwnership" ) && mapPatchSource . includes ( "chooseSeamOwnerValue" ) , "patch admin and prefecture seams use ownership repair" ) ;
assert ( mapPatchSource . includes ( "featherTerrainSeam" ) && mapPatchSource . includes ( "terrainFeatherCells" ) , "patch terrain transition bands are feather-smoothed" ) ;
assert ( mapPatchSource . includes ( "strongOnly" ) && mapPatchSource . includes ( "patchAlpha(x, y, rects, seed)" ) , "patch water topology avoids weak low-alpha seam flips" ) ;
assert ( ! municipalSource . includes ( "Municipality ${id + 1}" ) && ! municipalSource . includes ( "Prefecture ${id + 1}" ) && municipalSource . includes ( "自治${id + 1}" ) && municipalSource . includes ( "県域${id + 1}" ) , "fallback municipal and prefecture metadata avoids generic English labels" ) ;
2026-05-21 02:55:58 +09:00
2026-05-20 13:50:56 +09:00
assert ( map . elevation . length === size , "elevation length matches map size" ) ;
assert ( map . sea . length === size , "sea length matches map size" ) ;
2026-05-21 22:03:14 +09:00
assert ( map . ocean . length === size && map . lake . length === size , "ocean and lake masks match map size" ) ;
2026-05-20 13:50:56 +09:00
assert ( map . river . length === size , "river length matches map size" ) ;
assert ( map . landuse . length === size , "land-use length matches map size" ) ;
assert ( map . adminId . length === size , "municipal id length matches map size" ) ;
assert ( map . prefectureMask . length === size , "prefecture mask length matches map size" ) ;
assert ( map . populationDensity . length === size , "population density length matches map size" ) ;
assert ( map . ridgeField . length === size && map . valleyField . length === size && map . flowAccum . length === size , "causal terrain fields match map size" ) ;
assert ( map . erosionField . length === size && map . depositionField . length === size , "erosion and deposition fields match map size" ) ;
2026-05-21 22:03:14 +09:00
assert ( map . arcSpineField . length === size && map . branchRidgeField . length === size , "spine and branch ridge fields match map size" ) ;
assert ( map . depositionalLowland . length === size && map . alluvialFanField . length === size && map . deltaField . length === size , "depositional debug fields match map size" ) ;
assert ( map . naturalBarrierScore . length === size , "natural barrier score field matches map size" ) ;
assert ( map . terrainTemplate && Number . isFinite ( map . terrainTemplate . deposition ) && Number . isFinite ( map . terrainTemplate . erosion ) , "terrain template parameters are exposed" ) ;
2026-05-22 02:11:18 +09:00
assert ( map . terrainDebug && Number . isFinite ( map . terrainDebug . primarySpineStrength ) , "terrain debug metrics exist" ) ;
assert ( map . terrainDebug . primarySpineStrength > 0.08 , "primary mountain spine has visible strength" ) ;
assert ( map . terrainDebug . largeInlandLakeCount <= 1 , "large inland lakes are rare" ) ;
assert ( map . terrainDebug . smallIslandCount <= 24 , "small island/coast speckles stay limited" ) ;
assert ( map . terrainDebug . depositionLowlandArea > 0 , "depositional lowland area is tracked" ) ;
2026-05-21 22:03:14 +09:00
assert ( [ "east-west" , "north-south" , "diagonal" ] . includes ( map . terrainTemplate . coastAxis ) && map . terrainTemplate . coastSides ? . length === 2 , "paired coast template parameters are exposed" ) ;
2026-05-20 17:15:09 +09:00
assert ( map . settlementCluster . length === size , "settlement cluster field matches map size" ) ;
2026-05-20 13:50:56 +09:00
assert ( map . prefectureRegionId . length === size && Array . isArray ( map . regionalPrefectureBorders ) , "neighbor prefecture regions exist" ) ;
2026-05-26 15:32:27 +09:00
assert ( map . prefectureRegionId . length === size , "final prefecture id field matches map size" ) ;
assert ( map . naturalCompartmentId ? . length === size && Array . isArray ( map . naturalCompartments ) , "shared natural compartments are exposed" ) ;
assert ( map . adminDebug ? . naturalCompartmentCount > 0 && map . adminDebug ? . finalMunicipalityCount > 0 , "natural compartments are generated before municipalities" ) ;
assert ( map . regionalDebug ? . prefecturesGeneratedAfterMunicipalities === true && map . regionalDebug ? . prefectureSource === "municipality-boundary-union" , "prefectures are generated from final municipalities" ) ;
2026-08-11 21:51:07 +09:00
assert ( regionalMetrics . regionCount >= 2 && regionalMetrics . maxLandmassComponents === 1 , "larger non-sea prefecture regions remain connected after repair" ) ;
2026-05-26 15:32:27 +09:00
assert ( regionalEnclaveCount ( map ) === 0 , "final prefecture regions contain no one-region enclosed enclaves" ) ;
const regionalBorders = regionalBorderMetrics ( map ) ;
const hierarchyViolations = borderHierarchyViolations ( map ) ;
assert ( hierarchyViolations . prefectureCutsMunicipality === 0 , "no prefecture border cuts through a municipality" ) ;
assert ( hierarchyViolations . municipalityCutsCompartment === 0 , "no municipality border cuts through a natural compartment" ) ;
assert ( regionalBorders . invalidSame === 0 && regionalBorders . actual === regionalBorders . expected , "rendered prefecture borders separate different final prefecture ids only" ) ;
assert ( map . regionalDebug . finalRegionalPrefectureBorderCount === map . regionalPrefectureBorders . length , "regional prefecture borders are final output borders" ) ;
assert ( ! mapTerrainSource . includes ( "generateRegionalPrefectures" ) && ! mapPipelineSource . includes ( "prefectureRegionId, sea" ) && mapAdminStageSource . includes ( "generatePrefecturesFromMunicipalities" ) , "administrative order is natural compartments to municipalities to prefectures" ) ;
assert ( ! [ mapTerrainSource , mapPipelineSource , mapAdminStageSource , mapOutputSource , rendererSource , appSource ] . some ( ( source ) => / displayRegionId | adminPrefectureRegionId / . test ( source ) ) , "prefecture pipeline does not use display/admin-prefecture id aliases" ) ;
assert ( ! ( "maritimePrefectureBorders" in map ) , "maritime prefecture borders are not emitted" ) ;
assert ( ! mapOutputSource . includes ( "maritimePrefectureBorders" ) && ! rendererSource . includes ( "maritimePrefectureBorders" ) , "maritime prefecture borders are not generated or rendered" ) ;
assert ( rendererSource . includes ( "drawPrefectureRegionFill" ) && rendererSource . includes ( "map.prefectureRegionId" ) , "prefecture fill renderer uses final prefecture id source" ) ;
assert ( regionalMetrics . tinyCount <= Math . max ( 1 , Math . floor ( regionalMetrics . regionCount * 0.12 ) ) && regionalMetrics . medianArea >= 1200 && regionalMetrics . minArea >= 520 , "regional prefectures avoid excessive tiny slivers" ) ;
assert ( Array . isArray ( map . prefectureRegions ) && map . prefectureRegions . length === regionalMetrics . regionCount , "prefecture region metadata exists for every region" ) ;
assert ( map . prefectureRegions . every ( ( region ) => region . name && Number . isFinite ( region . x ) && Number . isFinite ( region . y ) && region . area > 0 && map . prefectureRegionId [ indexOf ( region . x , region . y ) ] === region . id ) , "every prefecture region has a name and valid label point" ) ;
2026-08-11 21:51:07 +09:00
assert ( map . regionalDebug . finalRegionalMaxAreaShare < 0.85 , "larger prefectures retain more than one meaningful regional jurisdiction" ) ;
assert ( map . regionalDebug . finalRegionalMinMunicipalityCount >= 10 , "each generated prefecture contains at least ten municipalities" ) ;
2026-05-26 15:32:27 +09:00
assert ( longStraightLowBarrierSegments ( map , map . regionalPrefectureBorders , 22 ) === 0 , "prefecture borders avoid long straight low-barrier cuts" ) ;
assert ( longStraightLowBarrierSegments ( map , map . adminBorders , 20 ) === 0 , "municipality borders avoid long straight low-barrier cuts" ) ;
2026-05-20 13:50:56 +09:00
assert ( Array . isArray ( map . tributaryRivers ) && Array . isArray ( map . smallStreams ) , "river hierarchy arrays exist" ) ;
assert ( Array . isArray ( map . icAccessRoads ) , "IC access road array exists" ) ;
assert ( Array . isArray ( map . satelliteCities ) , "satelliteCities is an array" ) ;
assert ( Array . isArray ( map . ringRoads ) && Array . isArray ( map . ringExpressways ) && Array . isArray ( map . ringRailways ) , "ring transport arrays exist" ) ;
assert ( Array . isArray ( map . mainRivers ) , "mainRivers is an array" ) ;
assert ( Array . isArray ( map . minorRoads ) , "minorRoads is an array" ) ;
assert ( Array . isArray ( map . externalGateways ) , "externalGateways is an array" ) ;
let prefectureComponents = 0 ;
const seenPrefecture = new Uint8Array ( size ) ;
for ( let i = 0 ; i < size ; i ++ ) {
if ( ! map . prefectureMask [ i ] || seenPrefecture [ i ] ) continue ;
prefectureComponents ++ ;
const queue = [ i ] ;
seenPrefecture [ i ] = 1 ;
for ( let q = 0 ; q < queue . length ; q ++ ) {
const cur = queue [ q ] ;
const x = cur % MAP _W ;
const y = Math . floor ( cur / MAP _W ) ;
for ( let dy = - 1 ; dy <= 1 ; dy ++ ) {
for ( let dx = - 1 ; dx <= 1 ; dx ++ ) {
if ( dx === 0 && dy === 0 ) continue ;
const nx = x + dx ;
const ny = y + dy ;
if ( nx < 0 || ny < 0 || nx >= MAP _W || ny >= MAP _H ) continue ;
const ni = ny * MAP _W + nx ;
if ( ! map . prefectureMask [ ni ] || seenPrefecture [ ni ] ) continue ;
seenPrefecture [ ni ] = 1 ;
queue . push ( ni ) ;
}
}
}
}
assert ( prefectureComponents === 1 , "prefecture area is a single connected component" ) ;
assert ( map . prefectureBorder . length > 0 , "prefecture border exists" ) ;
2026-05-21 22:03:14 +09:00
assert ( [ ... map . ocean ] . some ( ( value ) => value === 1 ) , "edge-connected ocean mask exists" ) ;
assert ( [ ... map . lake ] . every ( ( value , i ) => ! value || ( map . sea [ i ] && ! map . ocean [ i ] ) ) , "lake mask only marks isolated non-ocean water" ) ;
assert ( [ ... map . sea ] . every ( ( value , i ) => ! value || map . ocean [ i ] || map . lake [ i ] ) , "water cells are classified as ocean or lake" ) ;
2026-05-20 13:50:56 +09:00
assert ( map . adminBorders . length > 0 , "municipal borders exist" ) ;
2026-08-08 17:41:30 +09:00
const municipalVectors = municipalBorderVectorMetrics ( map ) ;
assert ( municipalVectors . invalid === 0 , "municipal border vectors never duplicate prefecture borders" ) ;
assert ( municipalVectors . actual === municipalVectors . expected , "municipal border vectors exactly match final same-prefecture admin ID changes" ) ;
2026-05-20 13:50:56 +09:00
assert ( map . mainRivers . length > 0 , "at least one major river exists" ) ;
assert ( map . tributaryRivers . length > 0 , "tributary river network exists" ) ;
assert ( map . smallStreams . length > 0 , "small stream network exists" ) ;
2026-05-21 22:03:14 +09:00
assert ( terrainMetrics . mountainRatio > 0.10 && terrainMetrics . mountainRatio < 0.72 , "mountain and ridge area is meaningful but not total" ) ;
assert ( terrainMetrics . lowlandRatio > 0.08 && terrainMetrics . lowlandRatio < 0.72 , "lowlands exist without dominating every map" ) ;
assert ( terrainMetrics . ridgeVariance > 0.004 , "ridge field has nontrivial spatial variance" ) ;
assert ( terrainMetrics . ridgeSinuosity > 0.015 , "ridge centerlines are not perfectly straight bands" ) ;
assert ( terrainMetrics . depositionSum > 0.2 , "deposition field has nonzero values" ) ;
assert ( terrainMetrics . depositionTargetMean >= terrainMetrics . depositionOtherMean * 0.85 , "deposition favors rivers, basins, and coastal lowlands" ) ;
assert ( terrainMetrics . riverValleyMean > terrainMetrics . nonRiverValleyMean * 1.08 , "river cells overlap valley fields more than random non-river cells" ) ;
assert ( terrainMetrics . alluvialMax > 0 || terrainMetrics . deltaMax > 0 , "alluvial fan or delta fields are active" ) ;
2026-05-20 13:50:56 +09:00
assert ( map . ports . some ( ( p ) => p . portClass === "major" ) , "at least one major port is classified" ) ;
assert ( map . ports . every ( ( p ) => [ "major" , "regional" , "fishing" , "lake" ] . includes ( p . portClass ) ) , "ports have explicit classes" ) ;
assert ( map . externalGateways . length > 0 , "external gateways exist" ) ;
assert ( map . minorRoads . length > 0 , "minor roads exist" ) ;
2026-05-22 02:11:18 +09:00
assert ( map . adminCenters . length >= 18 , "municipality center count is sufficiently large" ) ;
2026-05-29 15:49:09 +09:00
const activeMunicipalityIds = new Set ( [ ... map . adminId ] . filter ( ( id , i ) => id >= 0 && ! map . sea [ i ] ) ) ;
const centerIds = new Set ( map . adminCenters . map ( ( center ) => center . adminId ? ? center . municipalityId ? ? center . adminNumericId ) . filter ( ( id ) => Number . isFinite ( id ) ) ) ;
assert ( activeMunicipalityIds . size === map . adminCenters . length && [ ... activeMunicipalityIds ] . every ( ( id ) => centerIds . has ( id ) ) , "every active municipality has exactly one municipal center" ) ;
assert ( map . adminCenters . every ( ( center ) => activeMunicipalityIds . has ( center . adminId ? ? center . municipalityId ? ? center . adminNumericId ) ) , "municipal centers do not point to inactive municipalities" ) ;
assert ( [ ... activeMunicipalityIds ] . every ( ( id ) => map . municipalityToPrefectureId ? . [ id ] >= 0 ) , "every active municipality maps to a prefecture" ) ;
const activePrefectureIds = new Set ( [ ... map . prefectureRegionId ] . filter ( ( id , i ) => id >= 0 && ! map . sea [ i ] ) ) ;
const prefMetadataIds = new Set ( ( map . prefectureRegions || [ ] ) . map ( ( region ) => region . id ) ) ;
assert ( [ ... activePrefectureIds ] . every ( ( id ) => prefMetadataIds . has ( id ) ) , "every active prefecture id has metadata" ) ;
2026-05-20 17:15:09 +09:00
assert ( adminMetrics . municipalityCount >= 10 , "terrain snapping preserves a reasonable municipality count" ) ;
assert ( adminMetrics . centerValidRatio >= 0.95 , "municipality centers remain on valid assigned land cells" ) ;
2026-08-08 17:41:30 +09:00
assert ( adminMetrics . maxLandmassComponents <= 4 , "municipal topology repair prevents excessive disconnected fragments" ) ;
2026-05-20 17:15:09 +09:00
assert ( adminMetrics . disconnectedMunicipalities <= Math . max ( 2 , Math . ceil ( adminMetrics . municipalityCount * 0.20 ) ) , "most municipalities remain connected after terrain snapping" ) ;
assert ( adminMetrics . avgTarget > 0.18 , "admin borders align with terrain target features often enough" ) ;
2026-05-21 13:20:19 +09:00
assert ( map . adminDebug && map . adminDebug . compartmentCount > 0 , "natural compartment debug is available" ) ;
assert ( map . adminDebug . averageCompartmentArea > 0 , "natural compartments have positive average area" ) ;
2026-08-08 17:41:30 +09:00
assert ( Number . isFinite ( map . adminDebug . changedAfterLandscapePartition ) && Number . isFinite ( map . adminDebug . changedAfterUrbanLock ) , "municipal changed-cell diagnostics exist" ) ;
assert ( map . adminDebug . changedAfterCompartmentAssignment > 0 || map . adminDebug . changedAfterLandscapePartition > 0 || map . adminDebug . changedAfterUrbanLock > 0 , "municipal compartment or hierarchy passes change admin cells" ) ;
assert ( map . adminDebug . changedAfterFinalExclaveRemoval + map . adminDebug . changedAfterFinalMerge < Math . max ( 2800 , ( map . adminDebug . changedAfterLandscapePartition + map . adminDebug . changedAfterUrbanLock ) * 1.35 ) , "final municipal repair does not erase most terrain and urban changes" ) ;
2026-05-21 13:20:19 +09:00
assert ( map . adminDebug . finalBorderNaturalBarrierAverage >= 0 , "natural barrier score is tracked along final borders" ) ;
assert ( map . adminDebug . voronoiLikeRateAfter <= Math . max ( 0.72 , map . adminDebug . voronoiLikeRateBefore + 0.20 ) , "natural compartment pass does not increase weak bisectors excessively" ) ;
assert ( Number . isFinite ( map . adminDebug . satelliteMunicipalitiesCreated ) && Number . isFinite ( map . adminDebug . averageSatelliteMunicipalityArea ) , "satellite municipality debug is available" ) ;
assert ( satelliteMetrics . independent . length < 3 || satelliteMetrics . small . length / satelliteMetrics . independent . length <= 0.35 , "tiny independent satellite municipalities are not the dominant pattern" ) ;
assert ( satelliteMetrics . largeTooSmall . length === 0 , "large independent satellites have meaningful municipal area" ) ;
assert ( satelliteMetrics . independent . length < 3 || satelliteMetrics . average >= 140 , "average independent satellite municipality area is meaningful" ) ;
assert ( satelliteMetrics . rows . every ( ( row ) => row . area >= 80 || row . sat . municipalityClass === "smallTownAttachedToRuralMunicipality" || row . sat . municipalityClass === "suburbanDistrictMergedWithParent" || row . sat . municipalityClass === "newTownDistrict" ) , "tiny satellite areas are merged or explicitly classified as attached districts" ) ;
2026-05-20 17:15:09 +09:00
assert ( adminMetrics . denseUrbanRate < 0.42 , "admin borders avoid excessive dense urban crossings" ) ;
assert ( adminMetrics . rightAngleRate < 0.46 , "admin borders avoid excessive unsupported stair-step artifacts" ) ;
assert ( adminMetrics . voronoiLikeRate < 0.58 , "admin borders are not dominated by weak-terrain center bisectors" ) ;
assert ( adminMetrics . lowScoreFlatRate < 0.40 , "admin borders avoid excessive low-score flat-plain cuts" ) ;
assert ( adminMetrics . areaDiversity > 1.45 , "municipality areas retain natural size diversity" ) ;
assert ( cityCoreIntegrity >= 0.62 , "major city cores remain mostly inside one municipality" ) ;
2026-05-20 13:50:56 +09:00
assert ( urbanCellCount > 1000 , "large-city urbanized cells are broad enough" ) ;
const cbdCells = [ ... map . landuse ] . filter ( ( value ) => value === 3 ) . length ;
assert ( cbdCells > 0 , "CBD is represented as land-use cells rather than markers" ) ;
assert ( map . modernCities . every ( ( city ) => Number . isFinite ( city . population ) && city . population > 0 ) , "modern cities have population properties" ) ;
assert ( maxPopulation / Math . max ( 1 , minPopulation ) > 3 , "city populations vary strongly" ) ;
assert ( map . totalPopulation >= cityPopulations . reduce ( ( sum , value ) => sum + value , 0 ) , "total population includes city and satellite populations" ) ;
assert ( Math . max ( ... map . populationDensity ) > 0.9 , "population density is normalized and populated" ) ;
2026-05-26 15:32:27 +09:00
assert ( [ ... map . populationDensity ] . some ( ( value , i ) => value === 0 && ! map . sea [ i ] ) , "valid land cells can retain exactly zero population density" ) ;
2026-05-20 13:50:56 +09:00
assert ( elevationStdDev > 0.18 , "terrain relief has sufficient contrast" ) ;
assert ( maxCoastalElevationStep < 0.12 , "coastline and elevation do not create cliff artifacts" ) ;
assert ( railExpressHighMountainCells === 0 , "railways and expressways avoid huge mountain cells" ) ;
2026-05-20 15:02:37 +09:00
assert ( trunkHighElevationCells === 0 , "trunk roads, railways, and expressways avoid high-elevation cells" ) ;
assert ( flatPlainCells >= 160 , "broad flat plains exist as actual low-slope cells" ) ;
assert ( largeMountainCities . length === 0 , "large cities are not placed on unsuitable mountain sites" ) ;
assert ( capitalInside , "prefectural capital is inside the prefecture" ) ;
2026-05-20 13:50:56 +09:00
assert ( maxModernEndpointDegree <= 10 , "modern transport endpoints are not over-centralized" ) ;
assert ( map . entitiesForNames . every ( ( item ) => item . id && item . name ) , "nameable entities have ids and names" ) ;
2026-05-21 22:03:14 +09:00
assert ( map . adminCenters . every ( ( item ) => item . id && item . name ) , "municipal centers have ids and names" ) ;
assert ( map . entitiesForNames . some ( ( item ) => item . kind === "Municipal Center" ) , "municipal centers are included in label/name candidates" ) ;
2026-05-22 13:57:52 +09:00
assert ( map . adminCenters . every ( ( item ) => item . name && Array . from ( String ( item . name ) ) . length >= 2 ) , "municipal center names are valid labels" ) ;
assert ( map . adminCenters . some ( ( item ) => item . representativeFeatureName ) , "municipal centers keep representative feature metadata when available" ) ;
2026-05-21 22:03:14 +09:00
assert ( map . adminCenters . every ( ( item ) => Array . from ( String ( item . name ) ) . length >= 2 ) , "municipal center names are not one-character labels" ) ;
2026-08-08 17:41:30 +09:00
assert ( map . adminCenters . every ( ( item ) => {
const chars = Array . from ( String ( item . name || "" ) ) ;
const suffix = chars . at ( - 1 ) ;
return chars . length >= 3 && [ "市" , "町" , "村" ] . includes ( suffix ) ;
} ) , "municipal names use a valid multi-character Japanese administrative form" ) ;
2026-05-26 15:32:27 +09:00
const cityMunicipalityMetrics = cityMunicipalityAreaMetrics ( map ) ;
assert ( cityMunicipalityMetrics . tooSmall . length === 0 , "meaningful populated cities keep population-scaled municipality area" ) ;
const hoverCell = map . prefectureRegions . find ( ( region ) => region . area > 0 ) ;
assert ( hoverCell && prefectureNameForTest ( map , indexOf ( hoverCell . x , hoverCell . y ) ) === hoverCell . name && appSource . includes ( "Prefecture:" ) && appSource . includes ( "prefectureNameForCell" ) , "tooltip can resolve prefecture name for a hovered cell" ) ;
assert ( appSource . includes ( "maxLeft" ) && appSource . includes ( "maxTop" ) , "tooltip position is clamped inside map container" ) ;
2026-05-21 22:03:14 +09:00
const adminNameDuplicateRatio = map . adminCenters . length ? 1 - new Set ( map . adminCenters . map ( ( item ) => item . name ) ) . size / map . adminCenters . length : 0 ;
assert ( adminNameDuplicateRatio < 0.22 , "duplicate municipal names stay low" ) ;
assert ( map . adminDebug . naturalCompartmentCount > adminMetrics . municipalityCount , "natural compartments are finer than municipalities" ) ;
2026-08-11 21:51:07 +09:00
assert ( map . adminDebug . targetMunicipalityCount >= 20 && map . adminDebug . targetMunicipalityCount <= 62 && map . adminDebug . actualMunicipalityCount >= 18 , "municipality target and actual counts are dense enough" ) ;
2026-05-21 22:03:14 +09:00
assert ( map . adminDebug . changedAfterCompartmentAssignment > 0 , "municipal compartment assignment is active" ) ;
2026-05-22 13:57:52 +09:00
assert ( map . adminDebug . candidateSeedCount >= map . adminDebug . finalMunicipalityCount , "seed lifecycle tracks candidates beyond final municipalities" ) ;
2026-08-08 17:41:30 +09:00
assert ( map . adminDebug . absorbedSeedCount >= 0 && map . adminDebug . candidateSeedCount >= map . adminDebug . municipalOfficePointCount , "candidate municipality seeds resolve to offices or absorption" ) ;
2026-05-22 13:57:52 +09:00
assert ( map . adminDebug . finalTinyMunicipalityCount <= Math . max ( 3 , Math . ceil ( map . adminDebug . finalMunicipalityCount * 0.16 ) ) , "tiny municipalities remain a small fraction" ) ;
2026-05-21 22:03:14 +09:00
assert ( Array . isArray ( map . adminDebug . compartmentBorders ) && map . adminDebug . compartmentBorders . length > map . adminBorders . length , "natural compartment borders are available for debug rendering" ) ;
2026-05-21 02:55:58 +09:00
assert ( map . entitiesForNames . every ( ( item ) => typeof item . name === "string" ) , "nameable entity names are strings" ) ;
2026-05-20 17:15:09 +09:00
assert ( map . entitiesForNames . every ( ( item ) => ! String ( item . name ) . includes ( "\uFFFD" ) ) , "generated names contain no replacement characters" ) ;
2026-05-21 02:55:58 +09:00
assert ( map . entitiesForNames . every ( ( item ) => Array . from ( String ( item . name ) ) . length >= 2 ) , "one-character generated names are prevented" ) ;
2026-05-26 00:45:01 +09:00
assert ( map . entitiesForNames . every ( ( item ) => validateGeneratedName ( item . name , { allowAsciiDiagnostic : true } ) . valid ) , "generated names pass place-name validation" ) ;
2026-05-21 02:55:58 +09:00
assert ( map . entitiesForNames . every ( ( item ) => String ( item . name ) . length > 0 ) , "empty generated names are prevented" ) ;
2026-05-20 17:15:09 +09:00
assert ( duplicateNameRatio < 0.18 , "generated place-name duplicates stay low" ) ;
2026-05-21 02:55:58 +09:00
assert ( map . nameDebug && Array . isArray ( map . nameDebug . emptyPools ) , "nameDebug reports empty pools" ) ;
2026-05-22 13:57:52 +09:00
assert ( ( map . nameDebug . derivedNameCount || 0 ) === 0 , "derived municipality suffix names are not generated" ) ;
2026-05-22 02:11:18 +09:00
assert ( ( map . nameDebug . maxDerivedPerBase || 0 ) <= 2 , "derived names per base stay small" ) ;
2026-05-21 13:20:19 +09:00
assert ( map . nameDebug . emptyPools . length === Object . values ( NAME _KANJI _POOLS ) . filter ( ( pool ) => pool . length === 0 ) . length , "nameDebug empty pools match configured pools" ) ;
2026-05-21 02:55:58 +09:00
assert ( map . nameDebug . selectedTemplateCounts && typeof map . nameDebug . selectedTemplateCounts === "object" , "nameDebug selectedTemplateCounts exists" ) ;
assert ( map . nameDebug . selectedContextCounts && typeof map . nameDebug . selectedContextCounts === "object" , "nameDebug selectedContextCounts exists" ) ;
assert (
2026-08-08 17:41:30 +09:00
map . nameDebug . outputNamedEntityCount === namedEntityCount && map . nameDebug . totalGeneratedNameSelections >= namedEntityCount ,
"nameDebug distinguishes packaged labels from all generated name selections"
2026-05-21 02:55:58 +09:00
) ;
2026-08-08 17:41:30 +09:00
assert ( activePoolChars . size > 0 , "active name pools expose usable characters" ) ;
2026-05-20 17:15:09 +09:00
assert ( villageClusterMean > 0.16 , "villages prefer clustered valley, basin, coastal, and agricultural cells" ) ;
assert ( saneEndpointRatio >= 0.76 , "transport endpoints stay near meaningful generated nodes" ) ;
2026-08-08 17:41:30 +09:00
const againA = generateTestMap ( 999 ) ;
const againB = generateTestMap ( 999 ) ;
2026-05-20 13:50:56 +09:00
assert ( JSON . stringify ( againA . modernCities ) === JSON . stringify ( againB . modernCities ) , "generation is deterministic for the same seed" ) ;
2026-05-20 17:15:09 +09:00
assert ( JSON . stringify ( againA . entitiesForNames . map ( ( item ) => [ item . id , item . name ] ) ) === JSON . stringify ( againB . entitiesForNames . map ( ( item ) => [ item . id , item . name ] ) ) , "generated names are deterministic for the same seed" ) ;
assert ( JSON . stringify ( againA . adminCenters . map ( ( item ) => [ item . id , item . x , item . y , item . name ] ) ) === JSON . stringify ( againB . adminCenters . map ( ( item ) => [ item . id , item . x , item . y , item . name ] ) ) , "municipal centers are deterministic for the same seed" ) ;
2026-08-11 21:51:07 +09:00
assert ( arraysEqual ( againA . adminId , againB . adminId ) , "municipal adminId snapping is deterministic for the same seed" ) ;
assert ( arraysEqual ( againA . naturalCompartmentId , againB . naturalCompartmentId ) , "natural compartments are deterministic for the same seed" ) ;
assert ( arraysEqual ( againA . prefectureRegionId , againB . prefectureRegionId ) , "regional prefecture ids are deterministic for the same seed" ) ;
assert ( arraysEqual ( againA . municipalityToPrefectureId , againB . municipalityToPrefectureId ) , "municipality-to-prefecture ids are deterministic for the same seed" ) ;
2026-05-26 15:32:27 +09:00
assert ( JSON . stringify ( againA . regionalPrefectureBorders ) === JSON . stringify ( againB . regionalPrefectureBorders ) , "regional prefecture borders are deterministic for the same seed" ) ;
2026-05-21 13:20:19 +09:00
assert ( JSON . stringify ( againA . adminDebug ) === JSON . stringify ( againB . adminDebug ) , "admin debug metrics are deterministic for the same seed" ) ;
assert ( JSON . stringify ( againA . regionalDebug ) === JSON . stringify ( againB . regionalDebug ) , "regional debug metrics are deterministic for the same seed" ) ;
2026-08-08 17:41:30 +09:00
assert ( JSON . stringify ( deterministicTransportDebug ( againA . transportDebug ) ) === JSON . stringify ( deterministicTransportDebug ( againB . transportDebug ) ) , "transport debug metrics are deterministic for the same seed" ) ;
2026-05-22 02:11:18 +09:00
assert ( JSON . stringify ( transportConnectivityMetrics ( againA ) ) === JSON . stringify ( transportConnectivityMetrics ( againB ) ) , "transport connectivity metrics are deterministic for the same seed" ) ;
2026-08-11 21:51:07 +09:00
assert ( arraysEqual ( againA . elevation , againB . elevation ) , "elevation is deterministic for the same seed" ) ;
assert ( arraysEqual ( againA . ridgeField , againB . ridgeField ) , "ridge field is deterministic for the same seed" ) ;
assert ( arraysEqual ( againA . river , againB . river ) , "river field is deterministic for the same seed" ) ;
2026-05-21 22:03:14 +09:00
assert ( JSON . stringify ( terrainCoreMetrics ( againA ) ) === JSON . stringify ( terrainCoreMetrics ( againB ) ) , "terrain debug metrics are deterministic for the same seed" ) ;
2026-05-21 13:20:19 +09:00
2026-08-08 17:41:30 +09:00
}
2026-08-10 13:59:33 +09:00
if ( suiteEnabled ( "terrain-name" ) ) {
const semeMap = generateTestMap ( 8363712 ) ;
const semeAdmin = ( semeMap . adminCenters || [ ] ) . find ( ( center ) => center . canonicalSettlementName ) ;
assert ( ! semeAdmin || String ( semeAdmin . name ) . replace ( /[市町村]$/u , "" ) === String ( semeAdmin . canonicalSettlementName ) . replace ( /[市町村]$/u , "" ) ,
"seed 8363712: municipality label preserves the canonical settlement root" ) ;
}
2026-08-08 17:41:30 +09:00
if ( suiteEnabled ( "terrain" ) ) {
2026-05-21 13:20:19 +09:00
const blockedCapitalName = "\u52A0\u8302" ;
2026-08-10 13:59:33 +09:00
const terrainSeeds = [ 114514 , 12345 , 54321 , 777 , 999 ] ;
const capitalNames = [ ] ;
terrainSeedSummaries = [ ] ;
for ( const seedValue of terrainSeeds ) {
// Evaluate and release each complete map before generating the next seed.
// Retaining five full raster worlds at once made this validation shard
// memory-pressure dependent without increasing its coverage.
const seeded = generateTestMap ( seedValue ) ;
if ( seeded . prefecturalCapital ? . name ) capitalNames . push ( seeded . prefecturalCapital . name ) ;
2026-05-21 22:03:14 +09:00
const metrics = terrainCoreMetrics ( seeded ) ;
2026-08-11 21:51:07 +09:00
terrainSeedSummaries . push ( {
seed : seedValue ,
deposition : seeded . terrainTemplate . deposition ,
lowlandRatio : metrics . lowlandRatio ,
featureCounts : [ seeded . adminCenters . length , seeded . villages . length , seeded . markets . length ] ,
} ) ;
2026-05-21 22:03:14 +09:00
assert ( seeded . mainRivers . length > 0 && seeded . tributaryRivers . length > 0 && seeded . smallStreams . length > 0 , ` seed ${ seedValue } : river hierarchy exists ` ) ;
assert ( metrics . mountainRatio > 0.08 && metrics . lowlandRatio > 0.06 , ` seed ${ seedValue } : mountain and lowland terrain both exist ` ) ;
assert ( metrics . ridgeVariance > 0.003 && metrics . ridgeSinuosity > 0.010 , ` seed ${ seedValue } : ridges have varied jagged structure ` ) ;
assert ( metrics . depositionSum > 0.1 && metrics . depositionTargetMean >= metrics . depositionOtherMean * 0.75 , ` seed ${ seedValue } : deposition is active in plausible lowlands ` ) ;
assert ( metrics . riverValleyMean > metrics . nonRiverValleyMean , ` seed ${ seedValue } : rivers follow valley fields ` ) ;
2026-05-22 02:11:18 +09:00
assert ( seeded . terrainDebug ? . primarySpineStrength > 0.08 , ` seed ${ seedValue } : primary spine is strong enough ` ) ;
assert ( ( seeded . terrainDebug ? . largeInlandLakeCount || 0 ) <= 1 , ` seed ${ seedValue } : large inland lakes are rare ` ) ;
assert ( ( seeded . terrainDebug ? . smallIslandCount || 0 ) <= 24 , ` seed ${ seedValue } : small island speckles are limited ` ) ;
2026-05-21 22:03:14 +09:00
assert ( seeded . villages . length > 0 && seeded . markets . length > 0 && seeded . modernCities . length > 0 , ` seed ${ seedValue } : settlements are generated ` ) ;
assert ( seeded . premodernRoads . length > 0 && seeded . railways . length > 0 , ` seed ${ seedValue } : roads and railways are generated ` ) ;
assert ( seeded . adminId . length === size && seeded . adminBorders . length > 0 && seeded . regionalPrefectureBorders . length > 0 , ` seed ${ seedValue } : admin and regional borders exist ` ) ;
assert ( seeded . adminCenters . every ( ( item ) => item . name && Array . from ( String ( item . name ) ) . length >= 2 ) , ` seed ${ seedValue } : every admin center has a valid name ` ) ;
assert ( seeded . entitiesForNames . some ( ( item ) => item . kind === "Municipal Center" ) , ` seed ${ seedValue } : admin labels are included in label candidates ` ) ;
2026-08-08 17:41:30 +09:00
assert ( seeded . adminCenters . every ( ( item ) => {
const chars = Array . from ( String ( item . name || "" ) ) ;
return chars . length >= 3 && [ "市" , "町" , "村" ] . includes ( chars . at ( - 1 ) ) ;
} ) , ` seed ${ seedValue } : municipality labels use valid administrative suffixes ` ) ;
2026-05-22 13:57:52 +09:00
assert ( ( seeded . nameDebug ? . derivedNameCount || 0 ) === 0 , ` seed ${ seedValue } : derived suffix names stay disabled ` ) ;
const seededAdminMetrics = adminBoundaryMetrics ( seeded ) ;
const debug = seeded . adminDebug || { } ;
assert ( seededAdminMetrics . municipalityCount >= 18 && seededAdminMetrics . municipalityCount <= 50 , ` seed ${ seedValue } : municipality count stays in target range ` ) ;
assert ( debug . naturalCompartmentCount >= debug . actualMunicipalityCount * 2.5 , ` seed ${ seedValue } : natural compartments are substantially finer than municipalities ` ) ;
2026-08-08 17:41:30 +09:00
assert ( debug . naturalCompartmentCount <= debug . actualMunicipalityCount * 11.5 , ` seed ${ seedValue } : natural compartments do not become noisy cells ` ) ;
2026-05-22 13:57:52 +09:00
assert ( debug . averageCompartmentsPerMunicipality >= 2.5 , ` seed ${ seedValue } : municipalities group multiple compartments on average ` ) ;
assert ( debug . singleCompartmentMunicipalityRatio < 0.35 , ` seed ${ seedValue } : one-compartment municipalities are uncommon ` ) ;
assert ( debug . finalMunicipalityCount >= 18 && debug . finalMunicipalityCount <= 50 , ` seed ${ seedValue } : final municipality count remains bounded ` ) ;
assert ( debug . finalTinyMunicipalityCount <= Math . max ( 3 , Math . ceil ( debug . finalMunicipalityCount * 0.16 ) ) , ` seed ${ seedValue } : tiny municipalities stay uncommon ` ) ;
2026-08-08 17:41:30 +09:00
assert ( debug . absorbedSeedCount > 0 || debug . finalMunicipalityCount >= Math . min ( 20 , debug . targetMunicipalityCount ) , ` seed ${ seedValue } : excess candidate seeds are absorbed or the target municipality density is met ` ) ;
2026-05-22 13:57:52 +09:00
const highMountainSeeds = ( seeded . adminCenters || [ ] ) . filter ( ( p ) => {
const i = indexOf ( p . x , p . y ) ;
return seeded . elevation [ i ] > 0.70 || seeded . slope [ i ] > 0.52 || seeded . ridgeField [ i ] > 0.62 ;
} ) . length ;
assert ( highMountainSeeds <= Math . max ( 2 , Math . ceil ( ( seeded . adminCenters || [ ] ) . length * 0.12 ) ) , ` seed ${ seedValue } : high mountain admin seeds are rare ` ) ;
assert ( seededAdminMetrics . avgTarget > 0.13 , ` seed ${ seedValue } : municipal borders beat a loose lowland-random barrier baseline ` ) ;
assert ( seededAdminMetrics . denseUrbanRate < 0.52 , ` seed ${ seedValue } : dense urban boundary crossing rate remains low ` ) ;
assert ( seededAdminMetrics . voronoiLikeRate < 0.66 , ` seed ${ seedValue } : Voronoi-like municipal borders do not dominate ` ) ;
}
2026-08-11 21:51:07 +09:00
const featureCountA = terrainSeedSummaries . find ( ( summary ) => summary . seed === 12345 ) ? . featureCounts ;
const featureCountB = terrainSeedSummaries . find ( ( summary ) => summary . seed === 54321 ) ? . featureCounts ;
assert ( featureCountA ? . some ( ( value , index ) => value !== featureCountB ? . [ index ] ) , "feature counts vary between seeds" ) ;
2026-08-10 13:59:33 +09:00
assert ( new Set ( capitalNames ) . size > 1 , "prefectural capital names vary across seeds" ) ;
assert ( capitalNames . some ( ( name ) => name !== blockedCapitalName ) , "prefectural capital is not always the repeated custom name" ) ;
2026-05-21 22:03:14 +09:00
}
2026-08-08 17:41:30 +09:00
if ( TEST _SUITE === "determinism" || TEST _SUITE . startsWith ( "determinism-" ) ) {
2026-08-11 21:51:07 +09:00
const suffix = TEST _SUITE . startsWith ( "determinism-" ) ? TEST _SUITE . slice ( "determinism-" . length ) : "" ;
const suffixSeed = suffix ? Number ( suffix ) : NaN ;
2026-08-08 17:41:30 +09:00
const seedValue = Number . isFinite ( suffixSeed ) ? suffixSeed : DETERMINISM _SEED ;
const a = generateTestMap ( seedValue ) ;
const b = generateTestMap ( seedValue ) ;
2026-08-11 21:51:07 +09:00
assert ( arraysEqual ( a . adminId , b . adminId ) , ` seed ${ seedValue } : adminId is deterministic ` ) ;
2026-08-08 17:41:30 +09:00
assert ( JSON . stringify ( a . adminDebug ) === JSON . stringify ( b . adminDebug ) , ` seed ${ seedValue } : admin debug metrics are deterministic ` ) ;
}
if ( suiteEnabled ( "terrain" ) ) {
2026-08-10 13:59:33 +09:00
const byDeposition = terrainSeedSummaries . slice ( ) . sort ( ( a , b ) => a . deposition - b . deposition ) ;
2026-05-21 22:03:14 +09:00
assert ( byDeposition [ byDeposition . length - 1 ] . lowlandRatio >= byDeposition [ 0 ] . lowlandRatio * 0.72 , "higher-deposition templates generally preserve or expand lowland area" ) ;
2026-08-08 17:41:30 +09:00
const originalCustomNames = [ ... CUSTOM _NAME _LIST ] ;
CUSTOM _NAME _LIST . length = 0 ;
CUSTOM _NAME _LIST . push ( "青葉" , "若松" ) ;
const listedCustomNames = Array . from ( { length : 80 } , ( _ , n ) => generateEntityName ( 9200 + n , ` list-probe- ${ n } ` , { x : 10 , y : 10 , kind : "Probe" } , { } , new Set ( ) ) ) ;
const listedCustomHits = listedCustomNames . filter ( ( name ) => name === "青葉" || name === "若松" ) . length ;
2026-05-26 00:45:01 +09:00
assert ( NAME _PROBABILITIES . customNameList > 0 && listedCustomHits > 0 && listedCustomHits < listedCustomNames . length , "CUSTOM_NAME_LIST supplies probabilistic selected place names" ) ;
CUSTOM _NAME _LIST . length = 0 ;
2026-08-08 17:41:30 +09:00
CUSTOM _NAME _LIST . push ( ... originalCustomNames ) ;
2026-05-20 17:15:09 +09:00
2026-05-26 00:45:01 +09:00
assert ( ! validateGeneratedName ( "青青" ) . valid && validateGeneratedName ( "青青" ) . reason === "repeatedKanji" , "place names reject repeated kanji" ) ;
2026-05-21 13:20:19 +09:00
2026-08-08 17:41:30 +09:00
}
if ( suiteEnabled ( "admin" ) ) {
2026-05-20 17:15:09 +09:00
for ( const seed of [ 101 , 2026 , 54321 ] ) {
2026-08-08 17:41:30 +09:00
const seeded = generateTestMap ( seed ) ;
2026-05-20 17:15:09 +09:00
const metrics = adminBoundaryMetrics ( seeded ) ;
2026-05-21 13:20:19 +09:00
const seededRegional = regionalComponentMetrics ( seeded ) ;
const seededSatellites = satelliteMunicipalityMetrics ( seeded ) ;
2026-05-20 17:15:09 +09:00
const invalidLandCells = [ ... seeded . adminId ] . filter ( ( id , i ) => seeded . prefectureMask [ i ] && ! seeded . sea [ i ] && id < 0 ) . length ;
2026-05-21 13:20:19 +09:00
const invalidRegionCells = [ ... seeded . prefectureRegionId ] . filter ( ( id , i ) => ! seeded . sea [ i ] && id < 0 ) . length ;
2026-05-20 17:15:09 +09:00
assert ( invalidLandCells === 0 , ` seed ${ seed } : every prefecture land cell has a valid adminId ` ) ;
2026-05-21 13:20:19 +09:00
assert ( invalidRegionCells === 0 , ` seed ${ seed } : every regional land cell has a valid regionId ` ) ;
2026-05-20 17:15:09 +09:00
assert ( seeded . adminBorders . length > 0 , ` seed ${ seed } : municipal borders exist ` ) ;
2026-08-11 21:51:07 +09:00
const seededRegionalBorderMetrics = regionalBorderMetrics ( seeded ) ;
assert ( seededRegionalBorderMetrics . expected === 0 || seeded . regionalPrefectureBorders . length > 0 , ` seed ${ seed } : regional prefecture borders exist whenever land-adjacent prefectures exist ` ) ;
2026-05-26 15:32:27 +09:00
assert ( seeded . regionalDebug ? . prefecturesGeneratedAfterMunicipalities === true , ` seed ${ seed } : prefectures are generated after municipalities ` ) ;
assert ( seeded . regionalDebug ? . prefectureSource === "municipality-boundary-union" , ` seed ${ seed } : prefecture borders are municipality boundary unions ` ) ;
2026-08-08 17:41:30 +09:00
assert ( seededRegional . maxLandmassComponents === 1 , ` seed ${ seed } : every final regional prefecture is connected ` ) ;
2026-05-26 15:32:27 +09:00
assert ( regionalEnclaveCount ( seeded ) === 0 , ` seed ${ seed } : final regional prefectures have no one-region enclosed enclaves ` ) ;
2026-08-11 21:51:07 +09:00
assert ( seededRegionalBorderMetrics . invalidSame === 0 , ` seed ${ seed } : regional borders separate final prefecture ids ` ) ;
2026-08-08 17:41:30 +09:00
const seededMunicipalVectors = municipalBorderVectorMetrics ( seeded ) ;
assert ( seededMunicipalVectors . invalid === 0 && seededMunicipalVectors . actual === seededMunicipalVectors . expected , ` seed ${ seed } : municipal vectors respect final prefecture hierarchy ` ) ;
2026-05-26 15:32:27 +09:00
const seededHierarchy = borderHierarchyViolations ( seeded ) ;
assert ( seededHierarchy . prefectureCutsMunicipality === 0 , ` seed ${ seed } : prefecture borders do not cut municipalities ` ) ;
assert ( seededHierarchy . municipalityCutsCompartment === 0 , ` seed ${ seed } : municipal borders do not cut natural compartments ` ) ;
2026-05-21 13:20:19 +09:00
assert ( seeded . adminDebug && seeded . adminDebug . compartmentCount > 0 , ` seed ${ seed } : natural compartments are built ` ) ;
2026-05-21 22:03:14 +09:00
assert ( seeded . adminDebug . naturalCompartmentCount > metrics . municipalityCount , ` seed ${ seed } : compartments are finer than municipalities ` ) ;
2026-05-22 02:11:18 +09:00
assert ( seeded . adminDebug . targetMunicipalityCount >= 20 && seeded . adminDebug . actualMunicipalityCount >= 18 , ` seed ${ seed } : municipality count is dense enough ` ) ;
2026-05-22 13:57:52 +09:00
assert ( seeded . adminDebug . finalTinyMunicipalityCount <= Math . max ( 3 , Math . ceil ( seeded . adminDebug . finalMunicipalityCount * 0.18 ) ) , ` seed ${ seed } : tiny final municipalities are limited ` ) ;
2026-05-21 22:03:14 +09:00
assert ( seeded . adminDebug . changedAfterCompartmentAssignment > 0 , ` seed ${ seed } : compartment assignment is not a no-op ` ) ;
assert ( Array . isArray ( seeded . adminDebug . compartmentBorders ) && seeded . adminDebug . compartmentBorders . length > seeded . adminBorders . length , ` seed ${ seed } : compartment border debug exists ` ) ;
2026-05-26 15:32:27 +09:00
assert ( seeded . regionalDebug ? . municipalityGraphNodeCount >= metrics . municipalityCount , ` seed ${ seed } : prefecture graph is based on municipalities ` ) ;
2026-08-08 17:41:30 +09:00
assert ( seeded . adminDebug . changedAfterCompartmentAssignment > 0 || seeded . adminDebug . changedAfterLandscapePartition > 0 || seeded . adminDebug . changedAfterUrbanLock > 0 , ` seed ${ seed } : municipal compartment or hierarchy passes change cells ` ) ;
2026-05-21 13:20:19 +09:00
assert ( seededSatellites . largeTooSmall . length === 0 , ` seed ${ seed } : large satellites are not tiny independent municipalities ` ) ;
assert ( seededSatellites . independent . length < 3 || seededSatellites . small . length / seededSatellites . independent . length <= 0.35 , ` seed ${ seed } : tiny satellite municipalities remain uncommon ` ) ;
2026-05-22 02:11:18 +09:00
assert ( metrics . municipalityCount >= 18 , ` seed ${ seed } : municipality count remains reasonable ` ) ;
2026-05-20 17:15:09 +09:00
assert ( metrics . centerValidRatio >= 0.90 , ` seed ${ seed } : municipality centers remain valid ` ) ;
2026-08-08 17:41:30 +09:00
assert ( metrics . maxLandmassComponents <= 5 , ` seed ${ seed } : topology repair limits disconnected fragments ` ) ;
2026-05-20 17:15:09 +09:00
assert ( metrics . avgTarget > 0.14 , ` seed ${ seed } : borders retain terrain-boundary affinity ` ) ;
assert ( metrics . denseUrbanRate < 0.50 , ` seed ${ seed } : borders avoid excessive dense urban cuts ` ) ;
assert ( metrics . voronoiLikeRate < 0.66 , ` seed ${ seed } : weak-terrain Voronoi-like border ratio stays bounded ` ) ;
assert ( metrics . lowScoreFlatRate < 0.50 , ` seed ${ seed } : low-score flat border ratio stays bounded ` ) ;
assert ( metrics . areaDiversity > 1.25 , ` seed ${ seed } : municipality sizes are not overly uniform ` ) ;
assert ( majorCityCoreIntegrity ( seeded ) >= 0.55 , ` seed ${ seed } : major city cores remain coherent ` ) ;
assert ( seeded . prefecturalCapital && seeded . adminId [ indexOf ( seeded . prefecturalCapital . x , seeded . prefecturalCapital . y ) ] >= 0 , ` seed ${ seed } : capital municipality is not deleted ` ) ;
}
2026-08-08 17:41:30 +09:00
}
2026-05-20 13:50:56 +09:00
2026-08-10 13:59:33 +09:00
if ( suiteEnabled ( "patch" ) ) {
const initial = generateTestMap ( DETERMINISM _SEED ) ;
const world = createWorldMap ( initial ) ;
assert ( ! world . sourceMap . sea && ! world . sourceMap . elevation && world . initialQualityReference ? . landCells > 0 , "world metadata omits duplicate fixed-map raster fields while retaining the immutable quality reference" ) ;
const rect = {
x0 : world . originX + 72 ,
y0 : world . originY + 58 ,
x1 : world . originX + 132 ,
y1 : world . originY + 118 ,
} ;
const outsideIndex = ( world . originY + 12 ) * world . width + world . originX + 12 ;
const outsideAdminId = world . fields . adminId ? . [ outsideIndex ] ;
const patchStartedAt = typeof performance !== "undefined" ? performance . now ( ) : Date . now ( ) ;
const patch = generatePatch ( world , rect , {
patchMode : "regeneration" ,
terrainType : "auto" ,
seed : 0x51a7c3d3 ,
variant : 1 ,
maxQualityRetries : 0 ,
qualityTerrainAttempts : 1 ,
includeSeamVisualization : true ,
} ) ;
const patchElapsedMs = ( typeof performance !== "undefined" ? performance . now ( ) : Date . now ( ) ) - patchStartedAt ;
assert ( patch ? . ok === true , "standard patch suite executes generatePatch and returns a preview candidate" ) ;
assert ( patch ? . variant === 1 && patch ? . seed === 0x51a7c3d3 , "executed patch preserves the explicitly requested variant and seed" ) ;
assert ( patchElapsedMs < 30000 , ` small production patch completes within the 30 s budget ( ${ Math . round ( patchElapsedMs ) } ms) ` ) ;
assert ( patch ? . seamDiagnostics ? . hardPass === true && ( patch ? . seamDiagnostics ? . prefectureSeamBreakEdges || 0 ) === 0 , "small Regeneration repairs only the real ownership seam and passes the unchanged hard seam gate" ) ;
const restoredPrefectureCells = patch ? . seamDiagnostics ? . administrativeSeamRepair ? . prefectureCellsRestored || 0 ;
const regeneratedArea = Math . max ( 1 , ( rect . x1 - rect . x0 ) * ( rect . y1 - rect . y0 ) ) ;
// Administrative seam repair is allowed only as a narrow boundary repair.
// Use an area-relative cap rather than an obsolete fixture-specific count:
// this still catches accidental interior rewrites while allowing a handful
// of independent broken ownership edges to be restored deterministically.
const localizedAdminRepairCap = Math . max ( 12 , Math . ceil ( regeneratedArea * 0.005 ) ) ;
assert ( restoredPrefectureCells <= localizedAdminRepairCap ,
` administrative seam repair remains localized instead of rewriting the regenerated interior (restored= ${ restoredPrefectureCells } , cap= ${ localizedAdminRepairCap } ) ` ) ;
assert ( ( patch ? . candidateUnmappedActiveCells || 0 ) === 0 , "executed patch maps every active write cell into the production candidate" ) ;
assert ( world . fields . adminId ? . [ outsideIndex ] === outsideAdminId ,
` strict Regeneration preserves canonical administrative fields outside the selection (before= ${ outsideAdminId } , after= ${ world . fields . adminId ? . [ outsideIndex ] } ) ` ) ;
const serializedRects = JSON . stringify ( patch ? . rects || { } ) ;
const serializedRectKeys = Object . getOwnPropertyNames ( JSON . parse ( serializedRects ) ) ;
const serializedWorkCacheKeys = serializedRectKeys . filter ( ( key ) => key === "patchAlphaCache" || key === "patchSourceIndexCache" ) ;
if ( serializedWorkCacheKeys . length > 0 ) {
failed += 1 ;
logLines . push ( ` NG: worker-only patch caches are absent from the serialized result payload (cacheKeys= ${ serializedWorkCacheKeys . join ( "," ) } ) ` ) ;
} else {
logLines . push ( "OK: worker-only patch caches are absent from the serialized result payload" ) ;
}
const expectedPopulation = [ ... ( world . sourceMap . modernCities || [ ] ) , ... ( world . sourceMap . satelliteCities || [ ] ) ]
. reduce ( ( sum , city ) => sum + ( Number ( city ? . population ) || 0 ) , 0 ) ;
assert ( world . sourceMap . totalPopulation === expectedPopulation , "patch application refreshes total population metadata" ) ;
const generatedPoint = [
... ( world . sourceMap . modernCities || [ ] ) , ... ( world . sourceMap . satelliteCities || [ ] ) ,
... ( world . sourceMap . villages || [ ] ) , ... ( world . sourceMap . markets || [ ] ) ,
] . find ( ( point ) => point ? . patchGenerated && Number . isFinite ( point . regionId ) ) ;
if ( generatedPoint && world . fields . regionId ) {
const wx = Math . round ( ( generatedPoint . worldX ? ? generatedPoint . x + world . originX ) ) ;
const wy = Math . round ( ( generatedPoint . worldY ? ? generatedPoint . y + world . originY ) ) ;
const wi = wy * world . width + wx ;
assert ( generatedPoint . regionId === world . fields . regionId [ wi ] , "patch-generated point regionId matches the persisted world raster regionId" ) ;
} else if ( generatedPoint ) {
// regionId remains point metadata in the current final world schema; the
// internal generation raster is intentionally not persisted by mapOutput.
assert ( Number . isFinite ( generatedPoint . regionId ) , "patch-generated point keeps a finite regionId when no persisted regionId raster exists" ) ;
} else {
assert ( true , "executed patch produced no region-tagged point requiring a regionId check" ) ;
}
2026-08-11 21:51:07 +09:00
const expansionRect = {
x0 : world . originX + MAP _W - 48 ,
y0 : world . originY + 60 ,
x1 : world . originX + MAP _W + 52 ,
y1 : world . originY + 130 ,
} ;
const expansionBeforeGenerated = new Uint8Array ( world . generatedMask ) ;
const expansionBeforeElevation = new Float32Array ( world . fields . elevation ) ;
const expansionBeforeLanduse = new Uint8Array ( world . fields . landuse ) ;
let existingOverlapCells = 0 ;
const expansion = generatePatch ( world , expansionRect , {
patchMode : "expansion" ,
terrainType : "auto" ,
seed : 0x1234abcd ,
variant : 2 ,
maxQualityRetries : 0 ,
qualityTerrainAttempts : 1 ,
includeSeamVisualization : true ,
acceptBestAvailableQuality : true ,
} ) ;
let changedOverlapElevation = 0 ;
let changedOverlapLanduse = 0 ;
for ( let y = expansionRect . y0 ; y < expansionRect . y1 ; y ++ ) {
for ( let x = expansionRect . x0 ; x < expansionRect . x1 ; x ++ ) {
const i = y * world . width + x ;
if ( ! expansionBeforeGenerated [ i ] ) continue ;
existingOverlapCells ++ ;
if ( Math . abs ( world . fields . elevation [ i ] - expansionBeforeElevation [ i ] ) > 1e-6 ) changedOverlapElevation ++ ;
if ( world . fields . landuse [ i ] !== expansionBeforeLanduse [ i ] ) changedOverlapLanduse ++ ;
}
}
assert ( expansion ? . ok === true && existingOverlapCells > 0
&& changedOverlapElevation > Math . max ( 24 , existingOverlapCells * 0.15 )
&& changedOverlapLanduse > 0 ,
` Expansion rewrites selected already-generated overlap instead of freezing it (elevation= ${ changedOverlapElevation } / ${ existingOverlapCells } , landuse= ${ changedOverlapLanduse } ) ` ) ;
const regionalTransport = expansion ? . humanGeography ? . regionalTransportDebug ;
const regionalUrban = expansion ? . humanGeography ? . regionalUrbanRecalculation ;
assert ( ( regionalTransport ? . consideredPaths || 0 ) > 0 && ( regionalTransport ? . reroutedPaths || 0 ) > 0 ,
` Expansion performs deterministic regional transport rerouting beyond the selected area (considered= ${ regionalTransport ? . consideredPaths || 0 } , rerouted= ${ regionalTransport ? . reroutedPaths || 0 } ) ` ) ;
assert ( ( regionalUrban ? . modifiedCells || 0 ) > 0 && ( regionalUrban ? . maxOutsideDistanceModified || 0 ) > 0 ,
` Expansion recalculates urban fields outside the selected area with distance-decaying probability (modified= ${ regionalUrban ? . modifiedCells || 0 } , outside= ${ Math . round ( regionalUrban ? . maxOutsideDistanceModified || 0 ) } ) ` ) ;
2026-08-10 13:59:33 +09:00
}
if ( suiteEnabled ( "patch-large" ) ) {
const initial = generateTestMap ( DETERMINISM _SEED ) ;
const world = createWorldMap ( initial ) ;
const rect = {
x0 : world . originX ,
y0 : world . originY + 64 ,
x1 : world . originX + MAP _W + 1 ,
y1 : world . originY + 64 + PATCH _MIN _HEIGHT ,
} ;
const serialBefore = world . patchGenerationSerial || 0 ;
const largeStartedAt = typeof performance !== "undefined" ? performance . now ( ) : Date . now ( ) ;
const large = generatePatch ( world , rect , {
patchMode : "regeneration" ,
terrainType : "auto" ,
seed : 0x6d2b79f5 ,
variant : 1 ,
maxQualityRetries : 0 ,
qualityTerrainAttempts : 1 ,
includeSeamVisualization : true ,
} ) ;
const largeElapsedMs = ( typeof performance !== "undefined" ? performance . now ( ) : Date . now ( ) ) - largeStartedAt ;
assert ( large ? . ok === true && large ? . tiledRegeneration === true && Number ( large ? . tileCount || 0 ) >= 2 , "large Regeneration must publish a complete canonical-tile preview; rollback alone is not a passing result" ) ;
assert ( largeElapsedMs < 60000 , ` large production Regeneration completes within the 60 s budget ( ${ Math . round ( largeElapsedMs ) } ms) ` ) ;
assert ( large ? . seamDiagnostics ? . hardPass === true , "published large Regeneration passes the whole-selection seam gate" ) ;
assert ( ( large ? . candidateUnmappedActiveCells || 0 ) === 0 , "large Regeneration maps every active write cell across all tiles" ) ;
assert ( ( world . patchGenerationSerial || 0 ) === serialBefore + 1 , "large Regeneration records one logical operation rather than internal tile history" ) ;
}
2026-08-08 17:41:30 +09:00
const elapsedMs = ( typeof performance !== "undefined" && performance . now ? performance . now ( ) : Date . now ( ) ) - TEST _STARTED _AT ;
2026-08-10 13:59:33 +09:00
const shardBudgetMs = Math . max ( 180000 , fullMapGenerations * 75000 ) ;
assert ( elapsedMs < shardBudgetMs , ` test shard ${ TEST _SUITE } completes within its complete-generation workload budget ( ${ Math . round ( elapsedMs ) } / ${ shardBudgetMs } ms) ` ) ;
2026-08-08 17:41:30 +09:00
logLines . push ( ` INFO: suite= ${ TEST _SUITE } ; fullMapGenerations= ${ fullMapGenerations } ; elapsedMs= ${ Math . round ( elapsedMs ) } ` ) ;
2026-05-20 13:50:56 +09:00
result . className = failed === 0 ? "ok" : "ng" ;
result . textContent = ` ${ failed === 0 ? "All tests passed." : ` ${ failed } tests failed. ` } \n \n ${ logLines . join ( "\n" ) } ` ;
2026-08-08 17:41:30 +09:00
if ( ! IS _BROWSER ) {
console . log ( result . textContent ) ;
if ( failed > 0 ) process . exitCode = 1 ;
}
2026-05-20 13:50:56 +09:00
} catch ( error ) {
result . className = "ng" ;
result . textContent = String ( error ? . stack || error ) ;
2026-05-29 22:00:42 +09:00
if ( ! IS _BROWSER ) {
console . error ( result . textContent ) ;
process . exitCode = 1 ;
}
2026-05-20 13:50:56 +09:00
}