feat: EndConditions映射 + 骰子翻牌定精(random wildcard)

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 错误验证通过
This commit is contained in:
xiaoou
2026-07-04 21:06:16 +08:00
parent 5b60255f02
commit ae9c4c4142
5 changed files with 178 additions and 8 deletions

View File

@ -90,6 +90,14 @@ public class CapabilityRegistry
&& rules.WildcardRules.Behavior != "substitute")
warnings.Add($"wildcard_rules.behavior={rules.WildcardRules.Behavior} 引擎仅支持substitute→忽略");
// Wildcard type: random is now supported
if (rules.WildcardRules != null && !string.IsNullOrEmpty(rules.WildcardRules.Type))
{
var validTypes = new HashSet<string> { "fixed", "random" };
if (!validTypes.Contains(rules.WildcardRules.Type))
warnings.Add($"wildcard_rules.type={rules.WildcardRules.Type} 引擎仅支持fixed/random→忽略");
}
// Fu flag (过水) — now implemented
// No warning needed
@ -152,6 +160,7 @@ public class WildcardConfig
public string Type { get; set; } = "";
public string Behavior { get; set; } = "";
public int WildcardEncoding { get; set; } = 50;
public int RandomCount { get; set; } = 2; // random type: how many next-tiles are 精 (1=正精 only, 2=正精+副精)
public List<string>? Tiles { get; set; }
public WildcardScoringConfig? Scoring { get; set; }
public string FanCalculationPolicy { get; set; } = "optimal";