Skip to content

Card Game Engine ​

Card Game Engine 是一个可扩展、插件化、事件驱动的卡牌游戏引擎核心,使用 Node.js + TypeScript 实现。

引擎核心本身不包含任何具体游戏规则,所有规则、动作、事件处理都通过 Plugin 注入。Engine 只提供通用能力:状态管理、卡牌、牌堆、玩家、区域、动作、规则、事件、回合、组合、快照、回放、状态校验。

核心能力 ​

能力说明
不可变状态通过 stateUtils.* 进行结构性更新,每次更新 version + 1
Action 驱动所有状态变更由 Action 触发,再由 ActionHandler 翻译为 { state, events }
规则引擎RuleEngine 按注册顺序短路校验,拒绝时 state 不变
事件总线EventBus 同步派发事件,支持通配订阅
插件系统GamePlugin 把 Rule / ActionHandler / EventHandler 与可选 setup 打包注册
确定性回放SeededRandomProvider + 相同动作序列 → 相同终态
状态快照createSnapshot / restoreSnapshot,基于深拷贝隔离
状态校验StateValidator 内置不变量 + addStateCheck 注册游戏专属检查
Server Runtime可选的 Koa HTTP + Socket.IO WebSocket 服务运行时(Phase 6)

内置插件 ​

插件说明
StandardDeckPlugin标准 52 张 French deck + SHUFFLE action
TurnPlugin按座位顺序轮转,支持反向 (direction = -1)
DrawPlugin处理 DRAW_CARD,支持弃牌堆自动洗回
SimpleGamePlugin最简 2 人游戏,第一个清空手牌者胜
PokerRulesPlugin把通用 combination 系统以 variable 注入 state
UnoPlugin完整 UNO 规则(108 张牌 + Skip/Reverse/Draw2/Wild/Draw4)
DoudizhuPlugin完整斗地主规则(54 张牌 + 13 种牌型 + 叫/抢地主 + 炸弹/火箭倍率)

UNO 与斗地主的详细 API 由各自子模块的文档提供,本站仅作概要引用。

架构概览 ​

GameEngine
├── GameState          不可变状态(cards / zones / players / variables / version)
├── Action             玩家或插件发起的意图
├── ActionExecutor     Action → { state, events } 纯函数
├── RuleEngine         Action 执行前的合法性校验
├── EventBus           发布已发生的事件
├── PluginManager      插件注册与生命周期
├── ActionQueue        防递归 dispatch,受 maxActionsPerTick 限制
├── StateValidator     状态不变量校验
├── ActionHistory      有序记录已执行动作,支持回放
├── GameSnapshot       状态快照
├── ReplayEngine       基于 (initialState, actionHistory) 确定性回放
└── RandomProvider     随机源抽象(MathRandomProvider / SeededRandomProvider)

设计要点 ​

  • Engine 不知道游戏规则 — 任何游戏专属逻辑都不在 Engine 出现,全部交给 Plugin
  • 不可变 State — Plugin 无法直接修改 engine.state,必须通过 stateUtils.* 或 GameContext mutation primitive
  • Action ≠ Event — Action 是"我要做什么",Event 是"已经发生了什么";Action 触发 Event,Event 处理器可再触发新的 Action
  • ActionQueue 防递归 — EventHandler 内 ctx.dispatch 的新动作进队尾而非递归栈
  • Plugin 隔离 — Plugin 通过 GameContext 与 Engine 交互,不直接拿到 engine 引用
  • 确定性可回放 — 所有随机决策必须经 ctx.random

下一步 ​