用 DeepSeek-V4-Pro + Hermes Agent还原了三体的黑暗森林


只是一个测试demo,功能上实现上略有不足,仅供参考,源码可以在文末获取。


《三体》里罗辑对 187J3X1 恒星发出的那条"咒语",可能是科幻史上最优雅的博弈论推演:不需要亲自消灭敌人,只需要把它的坐标广播给宇宙,自然有人代劳。

我一直想把这个机制跑起来看看——不是读小说想象,而是真的让几十个不同性格的文明在一个宇宙里生存、探测、猜疑、背叛,看看黑暗森林法则到底能不能自发涌现。

📦 项目概览

项目地址:https://github.com/mengkecoding/dark-forest

git clone https://github.com/mengkecoding/dark-forest.git
cd dark-forest
pip install fastapi uvicorn pydantic
python3 -m uvicorn api.main:app --port 8000

浏览器打开 http://localhost:8000,你会看到 12 个彩色光点在 500 光年的宇宙里互相试探。

⚙️ 核心架构:6 种设计模式撑起 11 个博弈系统

做这种项目最怕的就是越写越乱——加一个外交系统要改战斗代码,加威慑机制要动探测逻辑。所以一开始就定了架构基调:每个领域独立,互不污染。

engine/
├── core/        # 基础层:坐标/枚举/事件总线/状态机
├── civ/         # 文明层:聚合根 + 4个组件 + 5种策略 + 工厂
├── systems/     # 系统层:9个纯逻辑系统(无状态)
├── universe.py  # Mediator:所有文明交互的统一协调者
└── runner.py    # 回合编排

选型思路:

问题 方案 A(朴素) 方案 B(本项目) 选择理由
决策逻辑 全塞 Civilization 类里 if/elif Strategy 模式,5 个独立策略类 加清理者策略不改任何旧代码
状态管理 散落各处的 bool 变量 StateMachine(和平/警戒/威慑/战争/同盟) 状态流转规则显式化,非法转换直接报错
文明间交互 直接调用对方方法 Mediator + EventBus 攻击事件发布后,连锁暴露系统自动响应
数据组织 全扁平字段 Component 模式(经济/军事/外交/记忆) 改外交不影响战斗,加组件不改聚合根

没有用 ECS。ECS 适合几千个实体,我们只有 12 个文明,Component 模式更直观。

🚀 五种文明,五种生存哲学

🔵 隐藏者 — 极限隐蔽,暗中科研。被威胁时才反击
🔴 侵略者 — 发现弱目标就打,军力相当时搞军备竞赛
🟢 外交家 — 通讯建交,签约结盟。被背叛后转为隐藏者
🟡 观察者 — 暗中探测,记录一切,从不暴露
🟣 清理者 — 不扩张不外交,但收到广播信号 100% 光粒打击

每种策略都是一个独立类,继承 BaseStrategy,实现一个 decide() 方法:

class CleanerStrategy(BaseStrategy):
    def decide(self, civ, universe):
        for signal in universe.get_broadcast_signals():
            return Action.ATTACK  # 必定响应
        return Action.RESEARCH    # 没有信号就默默研发

加新策略只需三步:建新文件 → 注册工厂 → 枚举加值。不改任何旧代码。

🛠️ 几个有意思的博弈系统

咒语系统(广播别人坐标)

这是整个黑暗森林的核心。不是广播自己,而是把别人的坐标发给全宇宙。所有文明的 memory.known_civs 立刻被注入目标信息,清理者优先级最高,光粒打击不限距离。

def broadcast_target_coords(broadcaster, target, universe):
    broadcaster.military.reduce_stealth(0.5)
    for civ in universe.civilizations:
        civ.memory.add(target.id, target_data)
    process_global_strikes(target, universe)

威慑系统(同归于尽)

罗辑对三体的博弈:"攻击我,我就广播你的坐标。"实现中不是军力比决定胜负,而是决心属性(resolve)。一个信誉很差但决心极高的骗子,威慑反而更强。

def check_deterrence_stability(declarer, target, universe):
    if declarer.traits.resolve < 0.3:
        return False  # 执剑人软弱 → 威慑崩塌
    if not declarer.military.has_broadcast_capability:
        return False  # 根本没有广播能力
    return True

猜疑链(信任骰子)

外交家想签条约,但对方是否可信?这里不是简单的信誉判断:

def evaluate_trust(reputation, suspicion_level):
    base_trust = reputation * 0.7
    suspicion_penalty = suspicion_level * 0.3
    trust = base_trust - suspicion_penalty
    return trust + random.uniform(-0.1, 0.1)  # 掷信任骰子

多疑度(paranoia)越高,每次掷骰的惩罚越大。外交家面对高多疑度的邻居,就算对方信誉完美也很难建立信任——这正是猜疑链的游戏化。

📖 前端:Canvas 星图 + 动画回放

没有用任何前端框架,纯原生 JS + Canvas 2D:

  • 文明渲染:径向渐变辉光 + 探测范围半透明圈 + 广播脉冲动画
  • 交互:拖拽平移、滚轮缩放、点击选中文明
  • 动画回放:每步调 API 拿新帧,可调速(1-20 档)
  • 事件日志:按攻击/广播/毁灭分类着色,过滤无意义消息

💡 避坑指南

  • 环形宇宙的距离计算:不是简单的 sqrt(dx²+dy²),而是 min(dx, width-dx) 处理边界回卷。忘了这个会导致边境文明永远是孤岛
  • 策略标签泄漏:Python 的 for strategy in strategies: 循环变量在循环外仍可访问。如果用它做日志输出,最后一个值会覆盖所有记录——应该用 civ.strategy.label
  • 名字池全局变量:工厂类用模块级 list 做名字池,多次创建模拟时名字会耗尽(全变成"三体人-2")。每次 create_civilizations() 前必须 reset_name_pools()
  • Canvas 3 位 hex 颜色#888#888888 解析会拿到 NaN——需要补全:hex.length===3 ? hex[0]+hex[0]+... : hex
  • 攻击冷却:侵略者每次都挑最弱的打,打完如果对方没死会立刻再打——无限循环攻击同一个人。加 _recent_attack_targets 集合记录最近 3 个目标,避免重复
  • 同步函数里调 asyncio.create_task:FastAPI 的同步 endpoint 跑在 thread pool 里,没有事件循环。WebSocket broadcast 功能要么去掉,要么异步化

该项目仅为测试deepseek-v4-pro的代码生成能力,使用过程中未加载新的skills,代码完全可以跑通,但是功能实现上 有些地方不准,但是反馈给模型后,也可以精准找到错误点,deepseek-v4-pro性价比真的很高。

DeepSeek-V4-Pro 的代码生成能力整体不错,但在跨文件的耦合逻辑上偶尔会遗漏——需要人类把关。

如果你对多智能体模拟或者三体感兴趣,欢迎 Star 或提 Issue。完整代码在 github.com/mengkecoding/dark-forest

agent面试题库
agent面试题库
agent面试题库
了解更多