第 1 卷第 1 章:1–9 年
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
"""事件显著度评分与小人物过滤。
|
||||
|
||||
真实数据给的教训:40 万条事件里绝大多数是流水账
|
||||
(change hf state 7.3 万、change hf job 5.8 万、written content composed 3.9 万),
|
||||
直接按类型切章会得到 5910 章,毫无叙事价值。
|
||||
|
||||
因此策略是:
|
||||
1. 只保留天然有叙事张力的事件类型(攻城、灭国、神器、死亡、结盟……)
|
||||
2. 再按"参与者有多重要"做二次排序,让编年史跟着大人物走
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import Counter
|
||||
|
||||
from dfannals.legends import Event, World
|
||||
|
||||
# 事件类型 → 基础分。0 分表示不单独叙事(流水账)
|
||||
NARRATIVE: dict[str, int] = {
|
||||
# ---- 天崩地裂级
|
||||
"destroyed site": 100,
|
||||
"razed structure": 100,
|
||||
"entity overthrown": 100,
|
||||
"hf destroyed site": 95,
|
||||
"plundered site": 95,
|
||||
"field battle": 95,
|
||||
"entity dissolved": 90,
|
||||
"holy city declaration": 90,
|
||||
"site taken over": 90,
|
||||
"entity breach feature layer": 90,
|
||||
"entity alliance formed": 85,
|
||||
"peace accepted": 85,
|
||||
"hf enslaved": 85,
|
||||
"hf revived": 80,
|
||||
"entity relocate": 80,
|
||||
"hf ransomed": 80,
|
||||
"peace rejected": 78,
|
||||
# ---- 重大
|
||||
"created site": 75,
|
||||
"reclaim site": 72,
|
||||
"attacked site": 70,
|
||||
"hf attacked site": 70,
|
||||
"entity created": 70,
|
||||
"artifact destroyed": 70,
|
||||
"new site leader": 65,
|
||||
"created world construction": 60,
|
||||
"entity persecuted": 60,
|
||||
"hf convicted": 60,
|
||||
"site dispute": 55,
|
||||
"failed intrigue corruption": 55,
|
||||
"artifact recovered": 60,
|
||||
"artifact possessed": 60,
|
||||
# ---- 值得一记
|
||||
"artifact created": 45,
|
||||
"artifact lost": 45,
|
||||
"creature devoured": 42,
|
||||
"hf abducted": 40,
|
||||
"assume identity": 40,
|
||||
"knowledge discovered": 38,
|
||||
"artifact given": 36,
|
||||
"agreement formed": 36,
|
||||
"hf gains secret goal": 36,
|
||||
"item stolen": 34,
|
||||
"hf performed horrible experiments": 45,
|
||||
"failed frame attempt": 40,
|
||||
"hf profaned structure": 38,
|
||||
"changed creature type": 36,
|
||||
"hf interrogated": 34,
|
||||
"created structure": 30,
|
||||
"hf wounded": 30,
|
||||
"hf learns secret": 34,
|
||||
"changed hf body state": 30,
|
||||
}
|
||||
|
||||
# 死亡单独处理:分数取决于死者本身有多重要
|
||||
DEATH_TYPES = ("hf died",)
|
||||
|
||||
CATEGORIES: list[tuple[tuple[str, ...], str]] = [
|
||||
(("war", "battle", "siege", "raid", "attack", "plunder", "destroy", "sack", "taken over"), "战事"),
|
||||
(("died", "death", "slain", "murder", "assassin", "enslaved", "ransomed", "revived"), "生死"),
|
||||
(("created site", "reclaim", "relocate", "dissolved", "overthrown", "alliance", "entity created"), "兴亡"),
|
||||
(("artifact", "masterpiece", "construction", "structure", "razed"), "器物"),
|
||||
(("peace", "agreement", "tribute", "persecuted", "convicted", "dispute", "intrigue"), "政争"),
|
||||
(("knowledge", "secret", "abducted", "identity", "experiment", "profaned", "devoured"), "异闻"),
|
||||
]
|
||||
|
||||
|
||||
def category(event: Event) -> str:
|
||||
t = event.type.lower()
|
||||
for keys, label in CATEGORIES:
|
||||
if any(k in t for k in keys):
|
||||
return label
|
||||
return "杂记"
|
||||
|
||||
|
||||
def prominence(world: World) -> Counter[int]:
|
||||
"""每个人物被卷入的事件次数——用来衡量他在史料里有多重要。"""
|
||||
counts: Counter[int] = Counter()
|
||||
for e in world.events:
|
||||
seen: set[int] = set()
|
||||
for tag in ("hfid", "slayer_hfid", "target_hfid", "source_hfid", "deity", "worshipper_hfid"):
|
||||
for fid in e.ids(tag):
|
||||
seen.add(fid)
|
||||
counts.update(seen)
|
||||
return counts
|
||||
|
||||
|
||||
def _participants(event: Event) -> list[int]:
|
||||
out: list[int] = []
|
||||
for tag in ("hfid", "slayer_hfid", "target_hfid", "source_hfid", "deity"):
|
||||
out.extend(event.ids(tag))
|
||||
return out
|
||||
|
||||
|
||||
# 人物重要度阈值:参与事件数达到这个量级才算"要角"
|
||||
PROMINENT = 60
|
||||
|
||||
|
||||
def significance(event: Event, prom: Counter[int] | None = None, prominent: int = PROMINENT) -> int:
|
||||
"""事件的故事价值。0 表示不值得单独写。"""
|
||||
t = event.type.lower()
|
||||
base = NARRATIVE.get(t, 0)
|
||||
people = _participants(event)
|
||||
top = max((prom.get(p, 0) for p in people), default=0) if prom else 0
|
||||
|
||||
if t in DEATH_TYPES:
|
||||
# 无名死者不写;要角之死按重要度加分
|
||||
if top < prominent:
|
||||
return 0
|
||||
return 55 + min(45, top // 10)
|
||||
|
||||
if base == 0:
|
||||
return 0
|
||||
|
||||
# 参与者越重要,越值得写;但不要盖过类型本身的分量
|
||||
bonus = min(25, top // 25) if prom else 0
|
||||
return base + bonus
|
||||
|
||||
|
||||
def is_narrative(event: Event, prom: Counter[int] | None = None) -> bool:
|
||||
return significance(event, prom) > 0
|
||||
Reference in New Issue
Block a user