用法: dotnet run --project Demo -- --check --dsl new_variant 输出: 能力覆盖率 + 合规检查 + 仅验证模式退出 文档: README + dsl-specification 更新创建流程
149 lines
5.9 KiB
Markdown
149 lines
5.9 KiB
Markdown
# Card Game Engine — YAML DSL 驱动的麻将规则引擎
|
||
|
||
一份 YAML 配置文件 = 一种麻将玩法。引擎加载后自动运行,零玩法特定代码。
|
||
|
||
## 核心理念
|
||
|
||
**DSL 定义规则,引擎暴露能力。** 玩法变体之间的差异全部通过 DSL 字段表达:
|
||
番型表、精牌类型、计分倍数、操作列表、回合结束条件——引擎不判断玩法名,
|
||
只读 DSL 参数。
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
card-game-engine/
|
||
├── docs/
|
||
│ ├── dsl-specification.md # DSL 完整字段参考 (AI 可读)
|
||
│ ├── fan-recognizer-inventory.md # 39 种番型识别器清单
|
||
│ ├── macos-build-deploy.md # macOS 构建指南
|
||
│ └── architecture-plan.md # 架构设计历史
|
||
├── RuleEngine/ # C# 引擎核心 (~3000 行)
|
||
│ ├── Core/ # 牌编码 / 牌堆 / 状态 / 癞子注册表
|
||
│ ├── Patterns/ # 胡牌判断 (MeldsSolver) + 番型识别
|
||
│ ├── Phase/ # 回合状态机 + 合法操作
|
||
│ ├── Scoring/ # 计分引擎 + 花牌/癞子 bonus
|
||
│ ├── Dsl/ # YAML 加载 + 双层合规检查
|
||
│ └── AI/ # 随机 AI + 人类玩家 CLI
|
||
├── RuleEngine.Tests/ # 58 个单元测试
|
||
├── dsl-examples/ # 5 种麻将玩法 DSL
|
||
│ ├── xuezhandaodi.yaml # 四川血战到底 (108 张)
|
||
│ ├── wuhan.yaml # 武汉麻将 (136 张, 红中癞子, 258 将)
|
||
│ ├── guangdong_jipinghu.yaml # 广东鸡平胡 (144 张, 花牌)
|
||
│ ├── guobiao.yaml # 国标麻将 (144 张, 81 番种, 8 番起胡)
|
||
│ └── nanchang.yaml # 南昌麻将 (136 张, 骰子翻牌定精, 庄×2)
|
||
└── Demo/ # 控制台 Demo
|
||
```
|
||
|
||
## 已实现能力
|
||
|
||
### 胡牌判断
|
||
| 能力 | 说明 |
|
||
|------|------|
|
||
| 标准胡牌 (4 面子 + 1 对) | 回溯搜索,支持癞子缺口填充 O(w×2^w) |
|
||
| 七对 | 纯对子形态,癞子配对 |
|
||
| 十三幺 | 13 种幺九 + 1 重复 |
|
||
| 全不靠 | 147/258/369 + 字牌 16 位模板 |
|
||
| 一色双龙会 | 同色 1-9 各至少 2 张 |
|
||
| 258 将检查 | 武汉麻将专用,DSL `pair_must_be_258` |
|
||
|
||
### 番型识别 (39 种)
|
||
结构性 (24): 清一色/混一色/字一色/对对胡/碰碰胡/碰碰和/暗七对/七对/将一色/
|
||
带幺九/全带幺/混幺九/缺一门/平胡/平和/断幺九/无字/全大/全中/全小/全双/
|
||
大于五/小于五/大四喜/大三元/小四喜/小三元/一色四同顺/五门齐
|
||
|
||
特殊牌型 (4): 十三幺/全不靠/一色双龙会/连七对
|
||
|
||
状态/事件 (9): 全求人/门前清/杠上开花/海底捞月/抢杠胡/天胡/地胡/癞子胡
|
||
|
||
兜底 (1): 鸡胡
|
||
|
||
### 回合控制
|
||
| 能力 | 说明 |
|
||
|------|------|
|
||
| 摸→打→碰杠胡回合 | DSL 控制操作列表 |
|
||
| 优先级仲裁 (胡>杠>碰>吃) | DSL `priority_policy` |
|
||
| 血战到底 (胡后继续) | DSL `parallel_elimination` |
|
||
| 查叫/查花猪 | 血战专用 |
|
||
| 花牌 (摸到即补, 开局补花) | while 循环递归补花 |
|
||
| 8 番起胡 | DSL `win_min_fan`, 非硬编码 |
|
||
|
||
### 精牌 (Wildcard)
|
||
| 类型 | 说明 |
|
||
|------|------|
|
||
| 固定精 (fixed) | DSL 指定牌名 (红中/发财/白板) 为癞子 |
|
||
| 翻牌定精 (random) | 发牌后翻一张牌,X+1 正精、X+2 副精 (9→1 循环) |
|
||
|
||
### 计分
|
||
| 能力 | 说明 |
|
||
|------|------|
|
||
| 番型叠加策略 | add / max_level / add_max,DSL 配置 |
|
||
| 番型互斥 | excludes / conflicts 图,引擎自动应用 |
|
||
| 计分倍数 | self_draw / discard_win / dealer 倍数,DSL 可配 |
|
||
| 花牌计分 | 每张 +1 番 + 座位配对额外分 |
|
||
| 癞子 bonus | 胡牌手牌中每张癞子加分 |
|
||
|
||
## 5 种玩法 DSL 覆盖率
|
||
|
||
```
|
||
血战 武汉 广东 国标 南昌
|
||
声明式 DSL 9 3 9 11 9
|
||
内置算法 7 7 7 6 9
|
||
引擎能力 (capability) 7 7 7 10 7
|
||
番型识别 14 14 14 22 14
|
||
─────────────────────────────────────────────
|
||
覆盖完整性 ✓ ✓ ✓ ✓ ✓
|
||
```
|
||
|
||
> 覆盖完整性 = 所有 DSL 配置的番型/条件/hook 均被引擎消费。
|
||
> `ValidateRuleCompliance()` 双层检查确保零假阳性。
|
||
|
||
## 用法
|
||
|
||
```bash
|
||
# DSL 覆盖验证 (只加载不跑牌局)
|
||
dotnet run --project Demo -- --check --dsl your_variant
|
||
dotnet run --project Demo -- --check # 默认血战
|
||
|
||
# 交互模式 (逐局展示)
|
||
dotnet run --project Demo
|
||
dotnet run --project Demo -- --dsl wuhan
|
||
dotnet run --project Demo -- --dsl nanchang
|
||
|
||
# 人类玩家模式
|
||
dotnet run --project Demo -- --human --dsl wuhan
|
||
|
||
# 压测模式
|
||
dotnet run --project Demo -- --auto --count 1000
|
||
|
||
# 测试
|
||
dotnet test # 58 个测试
|
||
dotnet test --filter "听牌" # 听牌检测相关
|
||
dotnet test --filter "鬼牌" # 癞子相关
|
||
```
|
||
|
||
## 压测结果
|
||
|
||
| 玩法 | 胡牌率 | 性能 | 零和 |
|
||
|------|--------|------|------|
|
||
| 血战到底 | ~10% | 7ms/局 | ✓ |
|
||
| 武汉麻将 | ~40% | 8ms/局 | ✓ |
|
||
| 广东鸡平胡 | ~20% | 7ms/局 | ✓ |
|
||
| 国标麻将 | ~15% | 7ms/局 | ✓ |
|
||
| 南昌麻将 | ~60% | 7ms/局 | ✓ |
|
||
|
||
1000 局 × 5 种玩法压测 0 错误,全部零和结算。
|
||
|
||
## 引擎代码规模
|
||
|
||
| 文件 | 行数 | 职责 |
|
||
|------|------|------|
|
||
| MahjongRoom.cs | 866 | 牌局编排 |
|
||
| MeldsSolver.cs | 808 | 胡牌 + 番型 |
|
||
| DslLoader.cs | 299 | DSL 加载 |
|
||
| PhaseMachine.cs | 260 | 回合状态机 |
|
||
| ScoreEngine.cs | 174 | 计分引擎 |
|
||
| 其余 7 个文件 | ~581 | 牌编码 / 状态 / AI |
|
||
| **总计** | **2988** | — |
|
||
|
||
> 引擎 95% 通用逻辑,5% 变体特殊逻辑(已通过 DSL 参数化)。
|
||
> 零 `if (gameName == "武汉")` 式的玩法名判断。 |