用法: dotnet run --project Demo -- --check --dsl new_variant 输出: 能力覆盖率 + 合规检查 + 仅验证模式退出 文档: README + dsl-specification 更新创建流程
12 KiB
麻将引擎 DSL 生成规范 (AI-readable)
概述
此文档描述 Card Game Engine 麻将规则引擎支持的所有 DSL 字段及其有效值。AI 代理在创建新玩法 YAML 文件时,只能使用本文档列出的字段和值。未列出的字段/值将被引擎拒绝或忽略,导致规则无法正确执行。
引擎通过双层检查确保合规:
- 能力注册检查 (
CapabilityRegistry.Check):requires列表中的每个能力必须已注册,否则拒绝加载 - 规则合规检查 (
ValidateRuleCompliance):逐条检查番型名/条件/hook/模式是否被引擎支持,列出具体 gap
字段索引 (所有支持的 DSL 字段)
game (必需)
game:
name: "玩法名称" # string, 任意
type: mahjong # 固定值
engine_type: mahjong # 固定值
players: { min: 4, max: 4 } # 当前仅支持4人
requires (必需)
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 (必需)
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: 108include_honors: true, include_flowers: false→total: 136include_honors: true, include_flowers: true→total: 144- wildcardCount>0 时额外加对应张数
deal (必需)
deal:
cards_per_player: 13 # 固定值
dealer_extra: 1 # 固定值
wildcard_rules (可选,有癞子时必填)
wildcard_rules:
type: fixed # "fixed"=指定牌当癞子, "random"=骰子翻牌定精
tiles: [红中] # 当type=fixed时,必须使用这些名称
random_count: 2 # 当type=random时,正精+副精的数量(1=仅正精,2=正精+副精)
wildcard_encoding: 50 # 独立癞子牌的起始编码,默认50(范围50-59)
behavior: substitute # 当前仅支持"substitute"
fan_calculation_policy: optimal # 当前仅支持"optimal"
scoring:
per_wildcard_in_win: 1 # 每张癞子额外加番,0=不加
精牌类型:fixed 指定固定牌(如红中)为癞子, random 发牌后翻一张牌确定精——翻到X则X+1为正精, X+2为副精(9→1循环, 字牌按序循环)。
固定癞子牌名映射 (tiles 字段可用值):
| YAML 名称 | 引擎编码 |
|---|---|
| 红中 | 35 |
| 发财 | 36 |
| 白板 | 37 |
限制:behavior 仅支持 substitute,fan_calculation_policy 仅支持 optimal。其他值会在合规检查中警告。
win_condition (可选)
win_condition:
pair_must_be_258: true # bool, 是否要求将牌必须是2/5/8
fan_types (必需)
fan_types:
- name: 清一色 # 番型名(见下方"引擎识别的番型名")
base_fan: 8 # 基础番数
level: 8 # 等级(用于add_max/max_level策略)
excludes: [缺一门, 无字] # 互斥番型(有此番型时不计算被排除的)
conflicts: [暗七对] # 冲突番型(取番数高的)
condition: "" # 条件(见下方"支持的条件字符串")
注意:name 必须是引擎能识别的番型名(见下方列表),否则得分为0。condition 必须是引擎支持的条件字符串。
fan_stacking (必需)
fan_stacking: add # "add"=所有番型相加, "max_level"=仅最高level, "add_max"=每level取最大后相加
max_fan (可选)
max_fan: 100 # 单局最高番数上限,默认无限
win_min_fan (可选)
win_min_fan: 8 # 最低胡牌番数要求(如国标8番起胡), 0=无限制
win_rule (可选)
win_rule:
ji_hu_self_draw_only: true # 鸡胡只能自摸(广东鸡平胡)
phases (必需)
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 (必需)
scoring:
mode: fan_table # 当前仅支持"fan_table"
max_cap: 999 # 番数上限, 默认无限
self_draw_multiplier: 1 # 自摸: 每家付 baseFan × N (默认 1)
discard_win_multiplier: 3 # 点炮: 放炮者付 baseFan × N (默认 3)
dealer_multiplier: 1 # 庄家输赢 × N (默认 1, 南昌=2)
pre_hooks: # 可选, 结算前执行的 hook
- name: check_hua_zhu # 检查花猪 (仅血战)
condition: deck_exhausted
- name: check_ting # 检查听牌 (仅血战)
condition: deck_exhausted AND not hua_zhu
计分倍数规则:
self_draw_multiplier: 自摸胡牌时每位非赢家支付baseFan × N,赢家收入总和discard_win_multiplier: 点炮胡牌时放炮者支付baseFan × N,赢家收入dealer_multiplier: 庄家赢 → 每家付倍数;闲家赢 → 仅庄家付倍数- 不设置时使用默认值,现有玩法向后兼容
pre_hooks (可选)
pre_hooks:
- name: wildcard_count # 统计癞子数量
description: "描述文字"
支持的 pre_hook 名:wildcard_count, check_hua_zhu, check_ting
flower_rules (可选,有花牌时)
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 (可选,过水机制,仅血战到底)
# 在 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)
兜底番型
鸡胡 (当没有其他番型被识别时自动添加)
已知限制 (不会在合规检查中警告,但确实不可用)
- behavior: 仅支持
substitute。不支持universal/multiplier等其他行为。 - fan_calculation_policy: 仅支持
optimal(单次回溯找可行解)。不支持average/fixed。 - scoring.mode: 仅支持
fan_table。不支持multiply_score。 - 牌库生成器: 仅支持
generator: mahjong。不支持其他牌库类型。 - 玩家数: 仅支持 4 人。不支持 2 人/3 人。
- 花牌计分: 完全支持。初始花牌 (
deal_cards_with_flowers) 和游戏中摸到花牌都正确补牌(while 循环处理递归花牌)。 - pre_hooks: 仅
wildcard_count/check_hua_zhu/check_ting被引擎识别。其他名称会在合规检查中警告。 - wildcard type: 支持
fixed(指定牌为癞子)和random(骰子翻牌定精)。 - 番型组合: 一色三同顺/一色三节高/三色三同顺/花龙/组合龙/推不倒/无番和: 不在识别列表中。
- 精的冲关/德国计分: 引擎不支持南昌麻将的冲关(精数×2^N)和德国(无精胡牌加分)复杂计分规则。
创建新 DSL 的完整流程
- 从现有示例复制模板(推荐
dsl-examples/wuhan.yaml) - 修改
game.name - 选择
deck(牌数) 和requires(能力) - 选择
fan_types(仅使用上表格中的番型名,其他名称得分为0) - 选择
fan_stacking策略 - 选择
phases中的 actions (不列出=不可用) - 如果需要 wildcard/花牌/fu_flag/计分倍数,添加对应段
- 仅验证加载覆盖率 (不跑牌局):
输出示例:
dotnet run --project Demo -- --check --dsl your_file如果有合规警告会在适配率下方显示✅ DSL 适配率: 7/7 (100%) — 南昌麻将 ✅ 仅验证模式 — 未运行牌局 - 验证玩法可运行 (100 局压测):
dotnet run --project Demo -- --dsl your_file --auto --count 100
快速检查清单
deck.total与include_honors/include_flowers匹配fan_types所有name在引擎识别列表中fan_types的condition在支持列表中(或为空)phases的 actions 在支持列表中wildcard_rules.behavior= "substitute"wildcard_rules.type= "fixed" 或 "random"scoring.mode= "fan_table"scoring倍数 (self_draw/discard_win/dealer) 设置正确pre_hooks仅含 known hooks- 加载时合规检查零警告