From 5b60255f023d274b4670c7eb2b1fef9f6c113f64 Mon Sep 17 00:00:00 2001 From: xiaoou Date: Sat, 4 Jul 2026 20:53:40 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20AI-readable=20DSL=E8=A7=84=E8=8C=83+?= =?UTF-8?q?=E7=95=AA=E5=9E=8B=E8=AF=86=E5=88=AB=E5=99=A8=E6=B8=85=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dsl-specification.md: 新玩法生成指南 - 全部支持的DSL字段+有效值+约束 - 39种引擎识别番型名 - 支持的条件字符串/action/pre_hook - 已知限制清单 - 创建新DSL的完整流程+检查清单 fan-recognizer-inventory.md: 番型识别器清单 - 每种番型的检测条件 - 事件番型的标志位映射 - 未实现的番型列表(使用将得分为0) 验证: AI按规范生成的南昌麻将(fixed wildcard发财) → 100%合规零警告,正常运行 --- docs/dsl-specification.md | 286 +++++++++++++++++++++++++++++++ docs/fan-recognizer-inventory.md | 82 +++++++++ 2 files changed, 368 insertions(+) create mode 100644 docs/dsl-specification.md create mode 100644 docs/fan-recognizer-inventory.md diff --git a/docs/dsl-specification.md b/docs/dsl-specification.md new file mode 100644 index 0000000..0b4e656 --- /dev/null +++ b/docs/dsl-specification.md @@ -0,0 +1,286 @@ +# 麻将引擎 DSL 生成规范 (AI-readable) + +## 概述 + +此文档描述 Card Game Engine 麻将规则引擎支持的所有 DSL 字段及其有效值。AI 代理在创建新玩法 YAML 文件时,**只能使用本文档列出的字段和值**。未列出的字段/值将被引擎拒绝或忽略,导致规则无法正确执行。 + +引擎通过双层检查确保合规: +1. **能力注册检查** (`CapabilityRegistry.Check`):`requires` 列表中的每个能力必须已注册,否则拒绝加载 +2. **规则合规检查** (`ValidateRuleCompliance`):逐条检查番型名/条件/hook/模式是否被引擎支持,列出具体 gap + +--- + +## 字段索引 (所有支持的 DSL 字段) + +### game (必需) +```yaml +game: + name: "玩法名称" # string, 任意 + type: mahjong # 固定值 + engine_type: mahjong # 固定值 + players: { min: 4, max: 4 } # 当前仅支持4人 +``` + +### requires (必需) +```yaml +requires: + - deck.generator_mahjong + - meldsolver.standard_win + - meldsolver.seven_pairs + - meldsolver.thirteen_orphans # 可选,需要十三幺时加 + - meldsolver.all_orphans # 可选,需要全不靠时加 + - meldsolver.double_dragon # 可选,需要一色双龙会时加 + - meldsolver.wildcard # 可选,有癞子时加 + - deck.flower_cards # 可选,有花牌时加 + - phase.mahjong_turn + - phase.parallel_elimination # 可选,血战模式时加 + - phase.priority_arbitration + - scoring.fan_exclusion + - scoring.pre_hooks # 可选,需要结算前hook时加 +``` + +### deck (必需) +```yaml +deck: + generator: mahjong # 固定值 + include_honors: true # bool, 是否含字牌(东南西北中发白) + include_flowers: true # bool, 是否含花牌(春夏秋冬梅兰竹菊) + total: 136 # 牌库总张数。108=无字无花, 136=有字无花, 144=有字有花 +``` +**注意**:`total` 必须匹配 `include_honors` + `include_flowers` 组合,否则引擎加载时抛异常。 +- `include_honors: false, include_flowers: false` → `total: 108` +- `include_honors: true, include_flowers: false` → `total: 136` +- `include_honors: true, include_flowers: true` → `total: 144` +- wildcardCount>0 时额外加对应张数 + +### deal (必需) +```yaml +deal: + cards_per_player: 13 # 固定值 + dealer_extra: 1 # 固定值 +``` + +### wildcard_rules (可选,有癞子时必填) +```yaml +wildcard_rules: + type: fixed # "fixed"=指定牌当癞子 或 留空=编码50+的独立癞子牌 + tiles: [红中] # 当type=fixed时,b必须使用这些名称 + wildcard_encoding: 50 # 独立癞子牌的起始编码,默认50(范围50-59) + behavior: substitute # 当前仅支持"substitute" + fan_calculation_policy: optimal # 当前仅支持"optimal" + scoring: + per_wildcard_in_win: 1 # 每张癞子额外加番,0=不加 +``` +**固定癞子牌名映射** (tiles 字段可用值): +| YAML 名称 | 引擎编码 | +|-----------|---------| +| 红中 | 35 | +| 发财 | 36 | +| 白板 | 37 | + +**限制**:`behavior` 仅支持 `substitute`,`fan_calculation_policy` 仅支持 `optimal`。其他值会在合规检查中警告。 + +### win_condition (可选) +```yaml +win_condition: + pair_must_be_258: true # bool, 是否要求将牌必须是2/5/8 +``` + +### fan_types (必需) +```yaml +fan_types: + - name: 清一色 # 番型名(见下方"引擎识别的番型名") + base_fan: 8 # 基础番数 + level: 8 # 等级(用于add_max/max_level策略) + excludes: [缺一门, 无字] # 互斥番型(有此番型时不计算被排除的) + conflicts: [暗七对] # 冲突番型(取番数高的) + condition: "" # 条件(见下方"支持的条件字符串") +``` +**注意**:`name` 必须是引擎能识别的番型名(见下方列表),否则得分为0。`condition` 必须是引擎支持的条件字符串。 + +### fan_stacking (必需) +```yaml +fan_stacking: add # "add"=所有番型相加, "max_level"=仅最高level, "add_max"=每level取最大后相加 +``` + +### max_fan (可选) +```yaml +max_fan: 100 # 单局最高番数上限,默认无限 +``` + +### win_min_fan (可选) +```yaml +win_min_fan: 8 # 最低胡牌番数要求(如国标8番起胡), 0=无限制 +``` + +### win_rule (可选) +```yaml +win_rule: + ji_hu_self_draw_only: true # 鸡胡只能自摸(广东鸡平胡) +``` + +### phases (必需) +```yaml +phases: + - name: deal + type: auto + action: deal_cards # 标准发牌。有花牌+开局换花用 deal_cards_with_flowers + next: play + + - name: play + type: mahjong_turn + turn_order: counter_clockwise + parallel_elimination: false # true=血战到底模式 + sub_phases: + draw: + type: auto + action: draw_card + on_draw_flower: replace # 摸到花牌时补牌(有花牌的变体) + on_empty_deck: exhausted # 牌墙耗尽行为 + self_action: + options: + - { action: discard } + - { action: an_kong } # 可选,有暗杠时加 + - { action: bu_kong, condition: has_punged_pair } # 可选,有加杠时加 + - { action: win, condition: can_win_tumo } # 可选,可自摸时加 + others_reaction: + options: + - { action: chi, priority: 1, condition: can_chi } # 可选,有吃时加 + - { action: pung, priority: 2, condition: has_two_same } + - { action: ming_kong, priority: 3, condition: has_three_same } + - { action: win, priority: 4, condition: can_win } + - { action: pass, priority: 0 } + priority_policy: highest_wins + on_win: game_over + end_conditions: + - { type: player_wins, action: settle } + - { type: deck_exhausted, action: draw_game } + + - name: settle + type: auto + action: calculate_scores + next: null +``` +**action 选项**:可用的 self_action:discard/an_kong/bu_kong/win。可用的 others_reaction:chi/pung/ming_kong/win/pass。**不列出的 action 将不可用**。 + +**支持的条件字符串**: +| 条件 | 含义 | +|------|------| +| `can_win_tumo` | 可以自摸胡 | +| `can_win_tumo_and_fan_ge_8` | 自摸+番数≥8 | +| `can_win` | 可以吃胡 | +| `can_win_and_fan_ge_8` | 吃胡+番数≥8 | +| `has_punged_pair` | 有碰过的对子(加杠) | +| `has_two_same` | 手中有2张相同 | +| `has_three_same` | 手中有3张相同 | +| `can_chi` | 可以吃 | + +### scoring (必需) +```yaml +scoring: + mode: fan_table # 当前仅支持"fan_table" + max_cap: 100 # 番数上限 + pre_hooks: # 可选,结算前执行的hook + - name: check_hua_zhu # 检查花猪(仅血战) + condition: deck_exhausted + - name: check_ting # 检查听牌(仅血战) + condition: deck_exhausted AND not hua_zhu +``` + +### pre_hooks (可选) +```yaml +pre_hooks: + - name: wildcard_count # 统计癞子数量 + description: "描述文字" +``` +**支持的 pre_hook 名**:`wildcard_count`, `check_hua_zhu`, `check_ting` + +### flower_rules (可选,有花牌时) +```yaml +flower_rules: + on_draw: replace_and_draw # 摸花牌时补牌 + replace_tiles: BEFORE_GAME_START # 开局前换花牌(广东) 或留空=游戏中换花牌(国标) + scoring: + normal: 1 # 每张花牌基础分 + matching: + value: 1 # 配对花牌额外分 + mapping: + 1: [春, 梅] + 2: [夏, 兰] + 3: [秋, 竹] + 4: [冬, 菊] +``` + +### fu_flag (可选,过水机制,仅血战到底) +```yaml +# 在 phases.play 下: + fu_flag: + type: dirty_flag + set_on: can_win_but_pass + clear_on: next_discard_self + effect: block_win_on_current_tile +``` + +--- + +## 引擎识别的番型名 (39种) + +以下番型名可以被引擎的结构识别器检测到。**使用这些名称时引擎会正确识别并计分,使用其他名称则得分为0。** + +### 结构性番型 (始终可识别) +清一色, 混一色, 字一色, 对对胡, 碰碰胡, 碰碰和, 暗七对, 七对, +将一色, 带幺九, 全带幺, 混幺九, 缺一门, 无字, 平胡, 平和, 断幺九, +全大, 全中, 全小, 全双, 大于五, 小于五, +大四喜, 大三元, 小四喜, 小三元, 一色四同顺, 五门齐 + +### 特殊牌型 (在 CheckWin 特定路径中识别) +十三幺, 全不靠, 一色双龙会, 连七对 + +### 状态相关 (需要游戏上下文) +全求人, 门前清 + +### 事件番型 (需要引擎设置对应标志位) +杠上开花, 海底捞月, 抢杠胡, 天胡, 地胡 + +### 条件番型 +癞子胡 (条件: hand_contains_wildcard) + +### 兜底番型 +鸡胡 (当没有其他番型被识别时自动添加) + +--- + +## 已知限制 (不会在合规检查中警告,但确实不可用) + +1. **behavior**: 仅支持 `substitute`。不支持 `universal`/`multiplier` 等其他行为。 +2. **fan_calculation_policy**: 仅支持 `optimal`(单次回溯找可行解)。不支持 `average`/`fixed`。 +3. **scoring.mode**: 仅支持 `fan_table`。不支持 `multiply_score`。 +4. **牌库生成器**: 仅支持 `generator: mahjong`。不支持其他牌库类型。 +5. **玩家数**: 仅支持 4 人。不支持 2 人/3 人。 +6. **花牌计分**: `flower_rules.scoring` 的各字段都支持,但 `replace_tiles` 仅在广东鸡平胡(BEFORE_GAME_START)和国标(留空=on_draw replace)下正确。 +7. **pre_hooks**: 仅 `wildcard_count`/`check_hua_zhu`/`check_ting` 被引擎识别。其他名称会在合规检查中警告。 +8. **特殊花色**: 不区分风圈/箭刻/门风。番型 `圈风刻`/`门风刻`/`箭刻` 不在识别列表中。 +9. **番型组合: 一色三同顺/一色三节高/三色三同顺/花龙/组合龙/推不倒/无番和**: 不在识别列表中。 + +--- + +## 创建新 DSL 的完整流程 + +1. 从现有示例复制模板(推荐 `dsl-examples/wuhan.yaml`) +2. 修改 `game.name` +3. 选择 `deck` (牌数) 和 `requires` (能力) +4. 选择 `fan_types` (仅使用上表格中的番型名,其他名称得分为0) +5. 选择 `fan_stacking` 策略 +6. 选择 `phases` 中的 actions (不列出=不可用) +7. 如果需要 wildcard/花牌/fu_flag,添加对应段 +8. 运行 `dotnet run --project Demo -- --dsl your_file --count 5` 验证 + +### 快速检查清单 +- [ ] `deck.total` 与 `include_honors/include_flowers` 匹配 +- [ ] `fan_types` 所有 `name` 在引擎识别列表中 +- [ ] `fan_types` 的 `condition` 在支持列表中(或为空) +- [ ] `phases` 的 actions 在支持列表中 +- [ ] `wildcard_rules.behavior` = "substitute" +- [ ] `scoring.mode` = "fan_table" +- [ ] `pre_hooks` 仅含 known hooks +- [ ] 加载时合规检查零警告 diff --git a/docs/fan-recognizer-inventory.md b/docs/fan-recognizer-inventory.md new file mode 100644 index 0000000..39c5c81 --- /dev/null +++ b/docs/fan-recognizer-inventory.md @@ -0,0 +1,82 @@ +# 番型识别器清单 (39种) + +此文档列出引擎 `IdentifyFans(result, state?)` 能识别的全部番型名及其检测条件。 + +## 结构性番型 (基于手牌 melds/pair 结构检测) + +| 番型名 | 检测条件 | 别名 | +|--------|---------|------| +| 清一色 | 全部数牌同花色,无字牌 | - | +| 混一色 | 全部数牌同花色+含字牌 | - | +| 字一色 | 全部为字牌 | - | +| 对对胡 | 全部面子为刻子 | 碰碰胡, 碰碰和 | +| 暗七对 | 全部面子为对子(来自七对路径) | 七对 | +| 将一色 | 全部为2/5/8数牌 | - | +| 带幺九 | 全部面子含幺九牌,将对为幺九 | 全带幺 | +| 混幺九 | 全部为幺九或字牌,且两者都有 | - | +| 缺一门 | 数牌最多2种花色 | - | +| 无字 | 全部为数牌,无字牌 | - | +| 平胡 | 全部面子为顺子 | 平和 | +| 断幺九 | 全部为中张数牌(2-8,无幺九无字) | - | +| 全大 | 全部数牌rank≥7 | - | +| 全中 | 全部数牌rank 4-6 | - | +| 全小 | 全部数牌rank≤3 | - | +| 全双 | 全部数牌rank为偶数 | - | +| 大于五 | 全部数牌rank>5 | - | +| 小于五 | 全部数牌rank<5 | - | +| 大四喜 | 4个风刻(东南西北) | - | +| 大三元 | 3个箭刻(中发白) | - | +| 小四喜 | 3个风刻+风将 | - | +| 小三元 | 2个箭刻+箭将 | - | +| 一色四同顺 | 4个完全相同的顺子 | - | +| 五门齐 | 3种数牌+字牌共计4类 | - | + +## 特殊牌型 (在 CheckWin 特定路径中,不经过标准面子提取) + +| 番型名 | 检测路径 | 说明 | +|--------|---------|------| +| 十三幺 | TryThirteenOrphans | 13种幺九+1对 | +| 全不靠 | TryAllOrphans | 147/258/369+字牌 | +| 一色双龙会 | TryDoubleDragon | 同花色1-9各2张 | +| 连七对 | TrySevenPairs(同色连7对) | 同花色的连续7对(未单独实现,由七对路径检测后通过DSL名匹配) | + +## 状态相关番型 (需要传入 state 参数) + +| 番型名 | 检测条件 | +|--------|---------| +| 全求人 | melds=0 且 allTiles≤2 (即全部副露) | +| 门前清 | state.Exposed 全部为空(无碰/杠/吃) | + +## 事件番型 (需要 state 中的事件标志位) + +| 番型名 | 标志位 | 设置时机 | +|--------|--------|---------| +| 杠上开花 | state.IsKongDraw | 杠后摸牌时 | +| 海底捞月 | state.IsLastTile | 摸牌前deck只剩1张 | +| 抢杠胡 | state.IsRobbedKong | 加杠时 | +| 天胡 | state.IsFirstTurn && state.DealerOnFirstTurn | 庄家首轮 | +| 地胡 | state.IsFirstTurn && !state.DealerOnFirstTurn | 非庄家首轮 | + +## 条件番型 + +| 番型名 | 条件 | 检测方式 | +|--------|------|---------| +| 癞子胡 | hand_contains_wildcard | state.Wildcards.CountWildcards(allTiles) > 0 | + +## 兜底番型 + +| 番型名 | 触发条件 | +|--------|---------| +| 鸡胡 | 上述所有番型都未识别时自动添加 | + +--- + +## 未实现的番型 (使用这些名称将得分为0) + +以下番型引擎无法识别,在合规检查中会列出警告: + +**结构类**: 绿一色, 九莲宝灯, 四杠子, 一色三同顺, 一色三节高, 三色三同顺, 三色三节高, 一色三步高, 三色三步高, 花龙, 组合龙, 推不倒, 无番和, 清龙, 三色双龙会, 全带五, 一色三高, 一色四高, 三风刻, 三杠, 四归一, 双暗刻, 双同刻, 双暗杠, 双明杠, 老少副, 连六, 喜相逢, 一般高, 幺九刻 + +**事件类**: 圈风刻, 门风刻, 箭刻, 不求人, 自摸(作为独立番型) + +**条件类**: 边张, 坎张, 单钓将