mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 17:51:24 +01:00
refactor(generation): cultures continue
This commit is contained in:
parent
fa2b873bf8
commit
6d70458aaf
3 changed files with 50 additions and 20 deletions
|
|
@ -40,6 +40,7 @@ export const generateCultures = function (
|
|||
const cultureIds = new Uint16Array(cells.i.length); // cell cultures
|
||||
|
||||
const populatedCellIds = cells.i.filter(cellId => cells.pop[cellId] > 0);
|
||||
const maxSuitability = d3.max(cells.s)!;
|
||||
|
||||
const culturesNumber = getCulturesNumber(populatedCellIds.length);
|
||||
if (!culturesNumber) return {cultureIds, cultures: [wildlands]};
|
||||
|
|
@ -117,12 +118,12 @@ export const generateCultures = function (
|
|||
|
||||
function selectCulturesData(culturesNumber: number) {
|
||||
let defaultCultures = getDefault(culturesNumber);
|
||||
if (defaultCultures.length >= culturesNumber) return defaultCultures;
|
||||
if (defaultCultures.length <= culturesNumber) return defaultCultures;
|
||||
|
||||
const culturesAvailable = Math.min(culturesNumber, defaultCultures.length);
|
||||
const cultures = [];
|
||||
const MAX_ITERATIONS = 200;
|
||||
|
||||
for (let culture, rnd, i = 0; cultures.length < culturesAvailable && i < 200; i++) {
|
||||
for (let culture, rnd, i = 0; cultures.length < culturesNumber && i < MAX_ITERATIONS; i++) {
|
||||
do {
|
||||
rnd = rand(defaultCultures.length - 1);
|
||||
culture = defaultCultures[rnd];
|
||||
|
|
@ -135,34 +136,59 @@ export const generateCultures = function (
|
|||
}
|
||||
|
||||
function placeCenter(sortingString: string) {
|
||||
let spacing = (graphWidth + graphHeight) / 2 / culturesNumber;
|
||||
|
||||
const sorted = sortPopulatedCellByCultureSuitability(sortingString);
|
||||
const MAX = Math.floor(sorted.length / 2);
|
||||
const BIAS_EXPONENT = 6;
|
||||
|
||||
return (function getCellId(): number {
|
||||
const cellId = sorted[biased(0, MAX, BIAS_EXPONENT)];
|
||||
if (centers.find(...cells.p[cellId], spacing) !== undefined) {
|
||||
// to close to another center, try again with reduced spacing
|
||||
spacing *= 0.9;
|
||||
return getCellId(); // call recursively
|
||||
}
|
||||
|
||||
return cellId;
|
||||
})();
|
||||
}
|
||||
|
||||
function sortPopulatedCellByCultureSuitability(sortingString: string) {
|
||||
let cellId: number;
|
||||
|
||||
const sMax = d3.max(cells.s)!;
|
||||
|
||||
const sortingMethods = {
|
||||
n: () => Math.ceil((cells.s[cellId] / sMax) * 3), // normalized cell score
|
||||
n: () => Math.ceil((cells.s[cellId] / maxSuitability) * 3), // normalized cell score
|
||||
|
||||
td: (goalTemp: number) => {
|
||||
const tempDelta = Math.abs(temp[cells.g[cellId]] - goalTemp);
|
||||
return tempDelta ? tempDelta + 1 : 1;
|
||||
},
|
||||
|
||||
bd: (biomes: number[], fee = 4) => {
|
||||
return biomes.includes(cells.biome[cellId]) ? 1 : fee;
|
||||
},
|
||||
|
||||
sf: (fee = 4) => {
|
||||
const haven = cells.haven[cellId];
|
||||
const havenHeature = features[haven];
|
||||
return haven && havenHeature && havenHeature.type !== "lake" ? 1 : fee;
|
||||
},
|
||||
|
||||
t: () => cells.t[cellId],
|
||||
|
||||
h: () => cells.h[cellId],
|
||||
|
||||
s: () => cells.s[cellId]
|
||||
};
|
||||
|
||||
const allSortingMethods = `{${Object.keys(sortingMethods).join(", ")}}`;
|
||||
|
||||
const sortFn = new Function(allSortingMethods, "return " + sortingString);
|
||||
|
||||
const comparator = (a: number, b: number) => {
|
||||
cellId = a;
|
||||
const cellA = sortFn({...sortingMethods});
|
||||
const cellA = sortFn(sortingMethods);
|
||||
|
||||
cellId = b;
|
||||
const cellB = sortFn(sortingMethods);
|
||||
|
|
@ -170,15 +196,8 @@ export const generateCultures = function (
|
|||
return cellB - cellA;
|
||||
};
|
||||
|
||||
let spacing = (graphWidth + graphHeight) / 2 / culturesNumber;
|
||||
const sorted = Array.from(populatedCellIds).sort(comparator);
|
||||
const max = Math.floor(sorted.length / 2);
|
||||
|
||||
do {
|
||||
cellId = sorted[biased(0, max, 5)];
|
||||
spacing *= 0.9;
|
||||
} while (centers.find(...cells.p[cellId], spacing) !== undefined);
|
||||
return cellId;
|
||||
return sorted;
|
||||
}
|
||||
|
||||
// set culture type based on culture center position
|
||||
|
|
@ -230,7 +249,8 @@ export const generateCultures = function (
|
|||
}
|
||||
|
||||
// check if base is in nameBases
|
||||
if (base > nameBases.length) return base;
|
||||
if (base < nameBases.length) return base;
|
||||
|
||||
ERROR && console.error(`Name base ${base} is not available, applying a fallback one`);
|
||||
return base % nameBases.length;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,14 +25,16 @@ const colorSchemeMap: Dict<ColorScheme> = {
|
|||
};
|
||||
|
||||
export function getColors(number: number) {
|
||||
const scheme = colorSchemeMap.bright;
|
||||
if (number <= cardinal12.length) return d3.shuffle(cardinal12.slice(0, number));
|
||||
|
||||
const scheme = colorSchemeMap.bright;
|
||||
const colors = d3.range(number).map(index => {
|
||||
if (index < 12) return cardinal12[index];
|
||||
|
||||
const rgb = scheme((index - 12) / (number - 12))!;
|
||||
return d3.color(rgb)!.formatHex() as Hex;
|
||||
});
|
||||
|
||||
return d3.shuffle(colors);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,9 +49,17 @@ export function rw(object: {[key: string]: number}) {
|
|||
return ra(weightedArray);
|
||||
}
|
||||
|
||||
// return a random integer from min to max biased towards one end based on exponent distribution (the bigger ex the higher bias towards min)
|
||||
export function biased(min: number, max: number, ex: number) {
|
||||
return Math.round(min + (max - min) * Math.pow(Math.random(), ex));
|
||||
// return a random integer from min to max biased towards one end based on exponent distribution
|
||||
// the bigger exponent the higher bias towards min
|
||||
// biased(0, 10, 10): {0: 74%, 1: 9%, 2: 4%, 3: 3%, 4: 2%, 5: 2%, 6: 2%, 7: 1%, 8: 1%, 9: 1%, 10: 0%}
|
||||
// biased(0, 10, 5): {0: 55%, 1: 14%, 2: 7%, 3: 5%, 4: 4%, 5: 4%, 6: 3%, 7%: 3%, 8: 2%, 9: 2%, 10: 1%}
|
||||
// biased(0, 10, 4): {0: 46%, 1: 15%, 2: 8%, 3: 6%, 4: 5%, 5: 4%, 6: 4%, 7%: 3, 8: 3%, 9: 3%, 10: 1%}
|
||||
// biased(0, 10, 3): {0: 36%, 1: 16%, 2: 10%, 3: 8%, 4: 6%, 5: 5%, 6: 5%, 7%: 4, 8: 4%, 9: 4%, 10: 2%}
|
||||
// biased(0, 10, 2): {0: 22%, 1: 17%, 2: 11%, 3: 9%, 4: 8%, 5: 7%, 6: 6%, 7%: 6, 8: 6%, 9: 5%, 10: 2%}
|
||||
// biased{0, 10, 1): {0: 5%, 1: 10%, 2: 10%, 3: 10%, 4: 10%, 5: 10%, 6: 10%, 7%: 10, 8%: 10, 9: 10%, 10: 5%}
|
||||
export function biased(min: number, max: number, exponent: number) {
|
||||
if (exponent <= 1) throw new Error("Exponent must be greater than 1");
|
||||
return Math.round(min + (max - min) * Math.pow(Math.random(), exponent));
|
||||
}
|
||||
|
||||
// get number from string in format "1-3" or "2" or "0.5"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue