Files
card-game-engine/README.md
xiaoou a338dac139 feat: --check 标志只验证DSL覆盖率不跑牌局
用法: dotnet run --project Demo -- --check --dsl new_variant
输出: 能力覆盖率 + 合规检查 + 仅验证模式退出

文档: README + dsl-specification 更新创建流程
2026-07-04 22:09:39 +08:00

149 lines
5.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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_maxDSL 配置 |
| 番型互斥 | 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 == "武汉")` 式的玩法名判断。