65 lines
1.9 KiB
Python
65 lines
1.9 KiB
Python
from __future__ import annotations
|
||
|
||
import json
|
||
import ast
|
||
from typing import Any
|
||
|
||
|
||
def load_effect_from_str(value: object) -> dict[str, Any]:
|
||
"""
|
||
解析 effects 字符串为 dict:
|
||
- 支持 JSON 格式(双引号)
|
||
- 支持 Python 字面量(单引号,如 {'k': ['v']})
|
||
- value 为 None/空字符串/'nan' 时返回 {}
|
||
- 解析非 dict 则返回 {}
|
||
"""
|
||
if value is None:
|
||
return {}
|
||
if isinstance(value, dict):
|
||
return value
|
||
s = str(value).strip()
|
||
if not s or s == "nan":
|
||
return {}
|
||
try:
|
||
obj = json.loads(s)
|
||
return obj if isinstance(obj, dict) else {}
|
||
except Exception:
|
||
try:
|
||
obj = ast.literal_eval(s)
|
||
return obj if isinstance(obj, dict) else {}
|
||
except Exception:
|
||
return {}
|
||
|
||
|
||
def _merge_effects(base: dict[str, object], addition: dict[str, object]) -> dict[str, object]:
|
||
"""
|
||
合并两个 effects 字典:
|
||
- list 型(如 legal_actions):做去重并集
|
||
- 数值型:相加
|
||
- 其他:后者覆盖前者
|
||
返回新字典,不修改原对象。
|
||
"""
|
||
if not base and not addition:
|
||
return {}
|
||
merged: dict[str, object] = dict(base) if base else {}
|
||
for key, val in (addition or {}).items():
|
||
if key in merged:
|
||
old = merged[key]
|
||
if isinstance(old, list) and isinstance(val, list):
|
||
# 去重并集,保持相对顺序
|
||
seen: set[object] = set()
|
||
result: list[object] = []
|
||
for x in old + val:
|
||
if x in seen:
|
||
continue
|
||
seen.add(x)
|
||
result.append(x)
|
||
merged[key] = result
|
||
elif isinstance(old, (int, float)) and isinstance(val, (int, float)):
|
||
merged[key] = old + val
|
||
else:
|
||
merged[key] = val
|
||
else:
|
||
merged[key] = val
|
||
return merged
|