tweak
This commit is contained in:
parent
6c10d5d70e
commit
3fe9c31453
12 changed files with 963 additions and 127 deletions
|
|
@ -418,29 +418,52 @@ export function generateRegionalPrefectures(seed, sea, elevation, slope, river,
|
|||
const { compartmentId, compartments } = buildRegionalNaturalCompartments(sea, elevation, slope, river, ridgeField, flowAccum, naturalBarrierScore);
|
||||
const owner = new Int16Array(compartments.length);
|
||||
owner.fill(-1);
|
||||
for (let id = 0; id < seeded.centers.length; id++) {
|
||||
const center = seeded.centers[id];
|
||||
if (!center || !inside(center.x, center.y)) continue;
|
||||
const ci = compartmentId[indexOf(center.x, center.y)];
|
||||
if (ci >= 0) owner[ci] = id;
|
||||
}
|
||||
for (const unit of compartments) {
|
||||
if (!unit || unit.area === 0) continue;
|
||||
const counts = new Map();
|
||||
let anchorCells = 0;
|
||||
for (const i of unit.cells) {
|
||||
if (anchorMask[i]) anchorCells++;
|
||||
const id = beforeRegionId[i];
|
||||
if (id >= 0) counts.set(id, (counts.get(id) || 0) + 1);
|
||||
if (unit.cells.some((i) => anchorMask[i])) owner[unit.id] = 0;
|
||||
}
|
||||
for (let pass = 0; pass < compartments.length + 6; pass++) {
|
||||
let changedThisPass = 0;
|
||||
for (const unit of compartments) {
|
||||
if (!unit || unit.area === 0 || owner[unit.id] >= 0) continue;
|
||||
let bestOwner = -1;
|
||||
let bestScore = -INF;
|
||||
for (const [neighborId, edge] of unit.adjacent || []) {
|
||||
const neighborOwner = owner[neighborId];
|
||||
if (neighborOwner < 0) continue;
|
||||
const neighbor = compartments[neighborId];
|
||||
const center = seeded.centers[neighborOwner];
|
||||
const barrier = edge.target / Math.max(1, edge.count);
|
||||
const sameClass = neighbor?.classId === unit.classId ? 1.0 : 0;
|
||||
const d = center ? Math.hypot(unit.x - center.x, unit.y - center.y) : 0;
|
||||
const score = edge.count * 0.45 + sameClass + neighbor.coastalExposure * 0.08 + neighbor.ridgeExposure * 0.05 - barrier * 2.6 - d * 0.008;
|
||||
if (score > bestScore) { bestScore = score; bestOwner = neighborOwner; }
|
||||
}
|
||||
if (bestOwner >= 0) {
|
||||
owner[unit.id] = bestOwner;
|
||||
changedThisPass++;
|
||||
}
|
||||
}
|
||||
if (anchorCells > 0) {
|
||||
owner[unit.id] = 0;
|
||||
continue;
|
||||
}
|
||||
let bestId = -1;
|
||||
let best = -1;
|
||||
for (const [id, count] of counts) {
|
||||
if (changedThisPass === 0) break;
|
||||
}
|
||||
for (const unit of compartments) {
|
||||
if (!unit || unit.area === 0 || owner[unit.id] >= 0) continue;
|
||||
let bestId = 0;
|
||||
let best = -INF;
|
||||
for (let id = 0; id < seeded.centers.length; id++) {
|
||||
const center = seeded.centers[id];
|
||||
const centerFit = center ? -Math.hypot(center.x - unit.x, center.y - unit.y) * 0.012 : 0;
|
||||
const terrainFit = unit.ridgeExposure * 0.10 + unit.riverExposure * 0.04 + unit.coastalExposure * 0.08;
|
||||
const score = count + centerFit + terrainFit;
|
||||
if (!center) continue;
|
||||
const d = Math.hypot(unit.x - center.x, unit.y - center.y);
|
||||
const score = -d + (id === 0 ? (unit.cells.some((i) => anchorMask[i]) ? 1000 : -12) : 0);
|
||||
if (score > best) { best = score; bestId = id; }
|
||||
}
|
||||
owner[unit.id] = bestId >= 0 ? bestId : 0;
|
||||
owner[unit.id] = bestId;
|
||||
}
|
||||
|
||||
const regionId = new Int16Array(beforeRegionId);
|
||||
|
|
@ -472,6 +495,9 @@ export function generateRegionalPrefectures(seed, sea, elevation, slope, river,
|
|||
regionalNaturalBarrierAverageBefore: beforeNaturalAverage,
|
||||
regionalNaturalBarrierAverageAfter: afterNaturalAverage,
|
||||
regionalCompartmentCount: compartments.filter((unit) => unit.area > 0).length,
|
||||
compartmentCount: compartments.filter((unit) => unit.area > 0).length,
|
||||
changedAfterCompartmentAssignment: changed,
|
||||
borderNaturalBarrierAverage: afterNaturalAverage,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
@ -635,8 +661,33 @@ function buildRegionalNaturalCompartments(sea, elevation, slope, river, ridgeFie
|
|||
ridgeExposure: ridgeExposure / Math.max(1, area),
|
||||
riverExposure: riverExposure / Math.max(1, area),
|
||||
coastalExposure: coastalExposure / Math.max(1, area),
|
||||
adjacent: new Map(),
|
||||
});
|
||||
}
|
||||
for (let y = 0; y < MAP_H; y++) {
|
||||
for (let x = 0; x < MAP_W; x++) {
|
||||
const i = indexOf(x, y);
|
||||
if (sea[i]) continue;
|
||||
const a = compartmentId[i];
|
||||
if (a < 0 || !compartments[a]) continue;
|
||||
for (const [nx, ny] of [[x + 1, y], [x, y + 1]]) {
|
||||
if (!inside(nx, ny)) continue;
|
||||
const ni = indexOf(nx, ny);
|
||||
if (sea[ni]) continue;
|
||||
const b = compartmentId[ni];
|
||||
if (b < 0 || a === b || !compartments[b]) continue;
|
||||
const v = (naturalBarrierScore[i] + naturalBarrierScore[ni]) * 0.5;
|
||||
const edgeA = compartments[a].adjacent.get(b) || { count: 0, target: 0 };
|
||||
edgeA.count++;
|
||||
edgeA.target += v;
|
||||
compartments[a].adjacent.set(b, edgeA);
|
||||
const edgeB = compartments[b].adjacent.get(a) || { count: 0, target: 0 };
|
||||
edgeB.count++;
|
||||
edgeB.target += v;
|
||||
compartments[b].adjacent.set(a, edgeB);
|
||||
}
|
||||
}
|
||||
}
|
||||
return { compartmentId, compartments };
|
||||
}
|
||||
|
||||
|
|
@ -845,6 +896,15 @@ export function applyOutputOptions(map, options = {}) {
|
|||
delete slim.flowAccum;
|
||||
delete slim.erosionField;
|
||||
delete slim.depositionField;
|
||||
delete slim.terrainTemplate;
|
||||
delete slim.ocean;
|
||||
delete slim.lake;
|
||||
delete slim.arcSpineField;
|
||||
delete slim.branchRidgeField;
|
||||
delete slim.depositionalLowland;
|
||||
delete slim.alluvialFanField;
|
||||
delete slim.deltaField;
|
||||
delete slim.naturalBarrierScore;
|
||||
return slim;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue