EndConditions: - BuildPhases 现在映射 PhaseConfig.Endconditions (之前 DslLoader 解析但 BuildPhases 忽略) - 4处 _rules.Phases.Any(p => p.ParallelElimination) → _playPhase.ParallelElimination - 新增 _playPhase 字段, 游戏不再依赖原始 DSL 做运行时判断 Random wildcard (骰子翻牌定精): - WildcardRegistry.ComputeNextTiles(): 翻到 X → 正精=X+1, 副精=X+2 (9→1 循环, 字牌序循环) - WildcardRegistry.RevealedTile 记录翻到的牌 - Deal() 发牌后翻一张牌确定精, 支持 random_count 控制精数量 - WildcardConfig 新增 RandomCount 字段 (默认2=正精+副精) - ValidateRuleCompliance 接受 random 类型 南昌麻将 DSL: - 新增 dsl-examples/nanchang.yaml (136张, random精, 无吃) - 引擎加载 7/7, 1000局 0错误, 胡牌率 61% 58 tests pass, 5 种玩法全部 0 错误验证通过
11 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: 100 # 番数上限
pre_hooks: # 可选,结算前执行的hook
- name: check_hua_zhu # 检查花猪(仅血战)
condition: deck_exhausted
- name: check_ting # 检查听牌(仅血战)
condition: deck_exhausted AND not hua_zhu
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 人。
- 花牌计分:
flower_rules.scoring的各字段都支持,但replace_tiles仅在广东鸡平胡(BEFORE_GAME_START)和国标(留空=on_draw replace)下正确。 - pre_hooks: 仅
wildcard_count/check_hua_zhu/check_ting被引擎识别。其他名称会在合规检查中警告。 - 特殊花色: 不区分风圈/箭刻/门风。番型
圈风刻/门风刻/箭刻不在识别列表中。 - 番型组合: 一色三同顺/一色三节高/三色三同顺/花龙/组合龙/推不倒/无番和: 不在识别列表中。
创建新 DSL 的完整流程
- 从现有示例复制模板(推荐
dsl-examples/wuhan.yaml) - 修改
game.name - 选择
deck(牌数) 和requires(能力) - 选择
fan_types(仅使用上表格中的番型名,其他名称得分为0) - 选择
fan_stacking策略 - 选择
phases中的 actions (不列出=不可用) - 如果需要 wildcard/花牌/fu_flag,添加对应段
- 运行
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- 加载时合规检查零警告