chinko
This commit is contained in:
parent
0359bb2445
commit
b17be0e0d2
21 changed files with 8034 additions and 2737 deletions
63
names.js
63
names.js
|
|
@ -1,24 +1,13 @@
|
|||
import { MAP_H, MAP_W, hash2, indexOf, inside } from "./mapUtils.js";
|
||||
import { MAP_H, MAP_W, hash2, indexOf, inside } from "./mapUtils.js";
|
||||
|
||||
export const CUSTOM_NAME_LIST = ["加茂", "春日", "新庄", "常盤", "追分", "清水", "曙", "暁", "旭", "鳥羽", "長門", "吉野", "吉田", "美郷", "美里", "美山", "八幡", "相生",];
|
||||
|
||||
function nameCharCount(value) {
|
||||
return Array.from(String(value || "")).length;
|
||||
}
|
||||
|
||||
function isAtomicNamePart(value) {
|
||||
// The generator used to create visibly synthetic three-part names by joining
|
||||
// a prefix with a compound terrain word. For template generation, keep each
|
||||
// lexical slot atomic so a generated root is at most two visible elements.
|
||||
return nameCharCount(value) <= 1;
|
||||
}
|
||||
export const CUSTOM_NAME_LIST = ["加茂", "瑞穂", "天神", "弁天", "千歳", "朝日", "春日", "新庄", "常盤", "追分", "清水", "曙", "暁", "旭", "鳥羽", "長門", "吉野", "吉田", "美郷", "美里", "美山"];
|
||||
|
||||
export const NAME_KANJI_POOLS = {
|
||||
modifiers: [
|
||||
"大", "小", "上", "下", "中", "奥", "脇",
|
||||
"東", "西", "南", "北",
|
||||
"新", "古", "本",
|
||||
"高", "長", "広", "深", "浅", "明", "重", "荒",
|
||||
"高", "長", "広", "深", "浅", "明", "重", "荒", "富",
|
||||
"白", "黒", "青", "赤", "藍",
|
||||
"奥", "前", "後", "内", "外",
|
||||
"美", "吉", "福", "幸", "徳",
|
||||
|
|
@ -26,7 +15,7 @@ export const NAME_KANJI_POOLS = {
|
|||
"霞", "朝", "日", "天",
|
||||
"土", "砂", "石", "岩",
|
||||
"卯", "辰",
|
||||
"駒", "羽", "鳴", "横", "永", "早", "清", "芳", "安", "泰", "真", "丸", "平", "勝", "吹", "舞", "鎌", "釜", "笠", "掘", "鎚", "綾", "槌", "徳", "栄"
|
||||
"串","駒", "来", "武", "箱", "羽", "鳴", "横", "永", "早", "清", "芳", "安", "泰", "真", "丸", "平", "勝", "吹", "舞", "鎌", "釜", "笠", "掘", "鎚", "綾", "槌", "徳", "栄"
|
||||
],
|
||||
|
||||
inlandTerrain: [
|
||||
|
|
@ -37,7 +26,7 @@ export const NAME_KANJI_POOLS = {
|
|||
"塚", "牧", "畑", "田", "森", "幡多", "幡", "畠", "秦", "植", "生",
|
||||
"郷", "里",
|
||||
"馬", "鹿", "亀", "鷲", "鷹", "鶴", "鴨", "竜", "龍", "牛", "鳥",
|
||||
"湯", "宍",
|
||||
"湯",
|
||||
],
|
||||
|
||||
waterTerrain: [
|
||||
|
|
@ -60,20 +49,20 @@ export const NAME_KANJI_POOLS = {
|
|||
"松", "杉", "桜", "梅", "栗",
|
||||
"竹", "楠", "藤", "萩", "葦",
|
||||
"菅", "榎", "椿", "桐", "柳",
|
||||
"橘", "柏", "槙", "柿", "桃", "稲", "花", "草", "菊",
|
||||
"橘", "柏", "槙", "柿", "桃", "稲",
|
||||
"梨", "桑", "麻", "芦", "茅", "根",
|
||||
"粟", "稲", "稗", "米", "飯", "糠", "茜", "葵", "篠",
|
||||
"粟", "稲", "稗", "米", "飯", "糠", "茜", "葵", "篠", "芝", "柴",
|
||||
"榊", "楢", "檜", "椎", "茨", "葛", "蘆", "菖", "蒲", "蓮", "桑", "瓜"
|
||||
],
|
||||
|
||||
postfixes: [
|
||||
"田", "川", "山", "岡", "森", "林",
|
||||
"島",
|
||||
"島", "尻",
|
||||
"江", "瀬", "井", "戸", "口",
|
||||
"辺", "里", "郷", "村", "町",
|
||||
"宿", "庄", "台", "坂", "橋", "明",
|
||||
"本", "内", "窪", "平", "塚", "根",
|
||||
"畑", "牧", "前", "見", "中", "羽", "生", "駒", "塚", "部", "栄", "永", "平",
|
||||
"本", "内", "窪", "平", "塚", "根", "串",
|
||||
"畑", "牧", "前", "見", "中", "羽", "生", "駒", "来", "富", "塚", "部", "栄", "永", "平",
|
||||
],
|
||||
|
||||
archaicPrefixes: [
|
||||
|
|
@ -88,7 +77,7 @@ export const NAME_KANJI_POOLS = {
|
|||
"和", "輪",
|
||||
"出", "播", "但",
|
||||
"因", "伯", "筑", "肥", "豊",
|
||||
"日", "紀", "志", "尾", "駿",
|
||||
"日", "紀", "志", "尾",
|
||||
"甲", "信", "越", "備", "能",
|
||||
"薩", "隠", "美", "三", "若",
|
||||
"遠", "近", "能", "加", "賀", "度", "飾",
|
||||
|
|
@ -117,7 +106,7 @@ export const NAME_KANJI_POOLS = {
|
|||
],
|
||||
|
||||
settlementWords: [
|
||||
"里", "郷", "村", "町", "宿", "垣", "坪", "軒", "惣", "條",
|
||||
"里", "郷", "村", "町", "宿", "垣", "坪", "軒", "惣",
|
||||
"庄", "ノ庄", "之庄", "院", "宮", "ノ宮", "之宮", "寺", "社", "堂",
|
||||
"城", "館", "屋", "家", "所",
|
||||
"市", "場", "関", "地蔵", "辻", "角", "堰", "通", "路", "道", "筋",
|
||||
|
|
@ -429,8 +418,7 @@ export function createNameDebug(probabilities = NAME_PROBABILITIES, pools = NAME
|
|||
customNameListUsed: 0,
|
||||
invalidNamesRejected: 0,
|
||||
repeatedKanjiNamesRejected: 0,
|
||||
oneCharacterNamesPrevented: 0,
|
||||
rejectedOneCharacterNames: 0,
|
||||
shortNamesRejected: 0,
|
||||
duplicateRetries: 0,
|
||||
fallbackAttempts: 0,
|
||||
legacyFallbackUsed: 0,
|
||||
|
|
@ -480,9 +468,8 @@ export function validateGeneratedName(name, options = {}) {
|
|||
if (!options.allowAsciiDiagnostic && value.startsWith(ASCII_DIAGNOSTIC_PREFIX) && /^N[0-9A-Z]+$/.test(value)) {
|
||||
return { valid: false, reason: "asciiDiagnostic" };
|
||||
}
|
||||
if (!options.allowOneCharacter && length < 2) return { valid: false, reason: "oneCharacter" };
|
||||
if (Number.isFinite(options.minLength) && length < options.minLength) return { valid: false, reason: "tooShort" };
|
||||
if (Number.isFinite(options.maxLength) && length > options.maxLength) return { valid: false, reason: "tooLong" };
|
||||
if (!options.allowLong && length > 4) return { valid: false, reason: "tooLong" };
|
||||
if (!options.allowRepeatedKanji && hasRepeatedKanji(value)) return { valid: false, reason: "repeatedKanji" };
|
||||
return { valid: true, reason: "valid" };
|
||||
}
|
||||
|
|
@ -500,8 +487,6 @@ function generateTemplateNameDetails(seed, id, entity, fields, attempt, usedName
|
|||
const context = chooseNameContext(entity, fields);
|
||||
const templateKey = chooseTemplate(context, seed, id, attempt);
|
||||
const template = NAME_TEMPLATES[templateKey];
|
||||
// Do not generate old-style three-part random toponyms; names are now either
|
||||
// curated list entries or at most two lexical elements plus any administrative suffix.
|
||||
if (!template || (template.slots?.length || 0) > 2) return { name: null, context, templateKey: null };
|
||||
|
||||
const parts = [];
|
||||
|
|
@ -509,15 +494,13 @@ function generateTemplateNameDetails(seed, id, entity, fields, attempt, usedName
|
|||
const slot = template.slots[slotIndex];
|
||||
const slotPool = resolveSlotPool(slot, context, pools, probabilities, seed, id, attempt + slotIndex);
|
||||
if (!slotPool?.pool?.length) return { name: null, context, templateKey };
|
||||
const atomicPool = slotPool.pool.filter(isAtomicNamePart);
|
||||
if (!atomicPool.length) return { name: null, context, templateKey };
|
||||
const part = pick(atomicPool, seed, id, attempt, 2503 + slotIndex * 127 + stableHash(slotPool.key));
|
||||
const part = pick(slotPool.pool, seed, id, attempt, 2503 + slotIndex * 127 + stableHash(slotPool.key));
|
||||
if (!part) return { name: null, context, templateKey };
|
||||
parts.push(part);
|
||||
}
|
||||
|
||||
const name = parts.join("");
|
||||
const validation = validateGeneratedName(name, { allowLong: false, maxLength: 2 });
|
||||
const validation = validateGeneratedName(name);
|
||||
if (!validation.valid) return { name: null, context, templateKey, invalidReason: validation.reason };
|
||||
if (usedNames?.has(name)) return { name: null, context, templateKey, duplicate: true };
|
||||
return { name, context, templateKey };
|
||||
|
|
@ -548,15 +531,10 @@ function tryCustomNameList(seed, id, usedNames, debug) {
|
|||
const start = Math.floor(roll(seed, id, 0, 3539) * CUSTOM_NAME_LIST.length) % CUSTOM_NAME_LIST.length;
|
||||
for (let offset = 0; offset < CUSTOM_NAME_LIST.length; offset++) {
|
||||
const customName = CUSTOM_NAME_LIST[(start + offset) % CUSTOM_NAME_LIST.length];
|
||||
if (nameCharCount(customName) > 2) {
|
||||
debug.invalidNamesRejected++;
|
||||
continue;
|
||||
}
|
||||
const validation = validateGeneratedName(customName, { allowAsciiDiagnostic: true });
|
||||
if (!validation.valid) {
|
||||
if (validation.reason === "oneCharacter") {
|
||||
debug.oneCharacterNamesPrevented++;
|
||||
debug.rejectedOneCharacterNames++;
|
||||
if (validation.reason === "tooShort") {
|
||||
debug.shortNamesRejected++;
|
||||
} else if (validation.reason === "repeatedKanji") {
|
||||
debug.repeatedKanjiNamesRejected++;
|
||||
} else {
|
||||
|
|
@ -589,9 +567,8 @@ export function generateEntityName(seed, id, entity, fields, usedNames = null, d
|
|||
continue;
|
||||
}
|
||||
if (result.invalidReason) {
|
||||
if (result.invalidReason === "oneCharacter") {
|
||||
debug.oneCharacterNamesPrevented++;
|
||||
debug.rejectedOneCharacterNames++;
|
||||
if (result.invalidReason === "tooShort") {
|
||||
debug.shortNamesRejected++;
|
||||
}
|
||||
else if (result.invalidReason === "repeatedKanji") debug.repeatedKanjiNamesRejected++;
|
||||
else debug.invalidNamesRejected++;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue