fix: incorrect relationship for new avatar

This commit is contained in:
bridge
2026-01-19 21:14:20 +08:00
parent 31d0c060e8
commit bf13cdf2d2
2 changed files with 136 additions and 6 deletions

View File

@@ -236,7 +236,9 @@ class PopulationPlanner:
planned_surname[a] = surname
planned_surname[b] = surname
planned_gender[a] = Gender.MALE
planned_relations[(a, b)] = Relation.CHILD
# 设定 a 为父b 为子
# (a, b) = PARENT -> a.relations[b] = PARENT (a 视 b 为子)
planned_relations[(a, b)] = Relation.PARENT
else:
mother = a if random.random() < 0.5 else b
child = b if mother == a else a
@@ -248,7 +250,8 @@ class PopulationPlanner:
if s != mom_surname:
planned_surname[child] = s
break
planned_relations[(mother, child)] = Relation.CHILD
# (mother, child) = PARENT -> mother.relations[child] = PARENT
planned_relations[(mother, child)] = Relation.PARENT
leftover = unused_indices[:]
@@ -448,10 +451,11 @@ class AvatarFactory:
if attach_relations:
if plan.parent_avatar is not None:
# plan.parent_avatar 是长辈
# 设置关系:长辈.set_relation(自己, CHILD)
# 底层逻辑:长辈.relations[自己] = CHILD (长辈认为自己是孩子)
# 自己.relations[长辈] = PARENT (自己认为长辈是父母)
plan.parent_avatar.set_relation(avatar, Relation.CHILD)
# 设置关系:长辈.set_relation(自己, PARENT)
# 底层逻辑:长辈.relations[自己] = PARENT (长辈认为自己是父母 -> 错误,是长辈认为自己是子女?)
# 修正Relation.PARENT 映射显示为“儿子/女儿”,即 relations[X]=PARENT 意味着 X 是儿子/女儿
# 所以 plan.parent_avatar.relations[avatar] = PARENT 是正确的,表示 parent 视 avatar 为子女
plan.parent_avatar.set_relation(avatar, Relation.PARENT)
if plan.master_avatar is not None:
# plan.master_avatar 是师傅
# 设置关系:师傅.set_relation(自己, APPRENTICE)

View File

@@ -0,0 +1,126 @@
import pytest
from src.classes.world import World
from src.classes.calendar import MonthStamp
from src.classes.age import Age
from src.classes.avatar import Avatar, Gender
from src.classes.relation import Relation, get_relation_label
from src.classes.cultivation import CultivationProgress, Realm
from src.utils.id_generator import get_avatar_id
from src.sim.new_avatar import create_random_mortal, MortalPlanner, AvatarFactory, PopulationPlanner
@pytest.fixture
def mock_world(base_world):
return base_world
def test_single_mortal_relation(mock_world):
"""测试单个新角色生成时的亲子关系方向是否正确"""
# 1. 创建一个假设的父母角色
parent_avatar = Avatar(
world=mock_world,
name="Parent",
id=get_avatar_id(),
birth_month_stamp=MonthStamp(0),
age=Age(100, Realm.Core_Formation),
gender=Gender.FEMALE,
cultivation_progress=CultivationProgress(60), # 金丹期
pos_x=0,
pos_y=0
)
# 加入世界管理器
mock_world.avatar_manager.register_avatar(parent_avatar)
# 2. 创建一个新角色,作为子女
# 我们通过强制指定 parent_avatar 来测试关系设置逻辑
# 由于 create_random_mortal 内部逻辑有随机性,这里直接使用底层 factory 并构造 plan
child_age = Age(20, Realm.Qi_Refinement)
plan = MortalPlanner.plan(mock_world, "Child", child_age, level=10, allow_relations=False)
# 手动指定父母,模拟 random 选中的情况
plan.parent_avatar = parent_avatar
child_avatar = AvatarFactory.build_from_plan(
mock_world,
mock_world.month_stamp,
name="Child",
age=child_age,
plan=plan,
attach_relations=True
)
# 3. 验证关系
# 父母看子女:应该是 PARENT (映射为 儿子/女儿)
rel_from_parent = parent_avatar.get_relation(child_avatar)
assert rel_from_parent == Relation.PARENT, f"父母看子女应该是 PARENT, 但得到了 {rel_from_parent}"
label_from_parent = get_relation_label(rel_from_parent, parent_avatar, child_avatar)
# 因为 child 性别随机,可能是 儿子 或 女儿
assert label_from_parent in ["儿子", "女儿"], f"父母看子女的称谓错误: {label_from_parent}"
# 子女看父母:应该是 CHILD (映射为 父亲/母亲)
rel_from_child = child_avatar.get_relation(parent_avatar)
assert rel_from_child == Relation.CHILD, f"子女看父母应该是 CHILD, 但得到了 {rel_from_child}"
label_from_child = get_relation_label(rel_from_child, child_avatar, parent_avatar)
assert label_from_child == "母亲", f"子女看母亲的称谓错误: {label_from_child}" # parent 是 FEMALE
def test_population_planner_relations(mock_world):
"""测试批量生成时的亲子关系方向是否正确"""
# 强制生成一组角色,通过大量生成来触发家庭关系
# 为了提高概率,我们直接调用 PopulationPlanner 内部逻辑或者检查生成后的结果
# 尝试生成 20 个角色,期望出现家庭关系
count = 20
avatars_dict = PopulationPlanner.plan_group(count, existed_sects=None)
# 检查计划中的关系
relations = avatars_dict.relations
if not relations:
pytest.skip("本次随机未生成任何关系,跳过测试")
return
found_parent_relation = False
for (a_idx, b_idx), rel in relations.items():
if rel == Relation.PARENT:
found_parent_relation = True
# 在 plan_group 中,(a, b) = PARENT 意味着 a 是父母b 是子女
# 这里的语义是a 的 relations 中,对 b 的记录是 PARENT
pass
# 如果找到了 PARENT 关系,说明代码中使用了 Relation.PARENT 而不是之前的 Relation.CHILD
# 之前的代码是用 Relation.CHILD修正后应该是 Relation.PARENT
# 进一步:实际构建角色并验证
avatars_map = AvatarFactory.build_group(mock_world, mock_world.month_stamp, avatars_dict)
avatars = list(avatars_map.values())
# 由于 build_group 返回的是 dict[id, Avatar],且顺序可能打乱,我们需要重新映射 index
# 但我们其实只需要遍历所有 Avatar 检查关系即可
for av in avatars:
for target, rel in av.relations.items():
if rel == Relation.PARENT:
# av 认为是父母 -> target 是子女
# 验证年龄:父母应该比子女大
assert av.age.age > target.age.age, f"父母({av.name}, {av.age.age}) 应该比子女({target.name}, {target.age.age}) 大"
# 验证称谓
label = get_relation_label(rel, av, target)
assert label in ["儿子", "女儿"]
elif rel == Relation.CHILD:
# av 认为是子女 -> target 是父母
# 验证年龄:子女应该比父母小
assert av.age.age < target.age.age, f"子女({av.name}, {av.age.age}) 应该比父母({target.name}, {target.age.age}) 小"
# 验证称谓
label = get_relation_label(rel, av, target)
assert label in ["父亲", "母亲"]
if not found_parent_relation:
# 如果随机没随到家庭,我们可以认为只要没报错且逻辑通顺就行,
# 或者可以 mock random 来强制覆盖路径,但在集成测试中只要多跑几次通常能覆盖
pass