Root cause: static HashSet跨测试/跨变体污染+硬编码名→编码映射 Changes: - WildcardRegistry: 实例级wildcard管理(IsWildcard/CountWildcards/Clone) - GameState: 新增Wildcards属性(含Clone) - MahjongTile: 移除static_wildcards,IsWildcard仅查编码50-59 +ToString(tile,wildcards)重载用于游戏上下文显示 - MeldsSolver: _wildcards字段→构造函数注入(WildcardRegistry?) - PhaseMachine: _wildcards字段+构造注入 - Deal(): State.Wildcards.Clear()+AddRange替代static ConfigureWildcards +NameToEncoding查表替代switch硬编码 - RandomMahjongAI/HumanMahjongPlayer: state.Wildcards替代static调用 - HumanMahjongPlayer.CheckTing: 补wildcardCount参数(之前遗漏) - ExecuteWinClaim: IsFinished=true→Settle()(之前Phase漏设) Test: CoreTests清理ConfigureWildcards()→WildcardRegistry测试 Impact: 零static state→不同变体/测试完全隔离,未来支持随机宝牌
51 lines
1.6 KiB
C#
51 lines
1.6 KiB
C#
namespace RuleEngine.Core;
|
|
|
|
/// <summary>
|
|
/// Per-game wildcard configuration — replaces the old static HashSet approach.
|
|
/// Each MahjongGameState owns its own registry so different game variants
|
|
/// don't leak wildcard state between tests or concurrent games.
|
|
/// </summary>
|
|
public class WildcardRegistry
|
|
{
|
|
private readonly HashSet<int> _wildcards = new();
|
|
|
|
/// <summary>Base wildcard encoding range (50-59) for extra tiles added to deck.</summary>
|
|
public const int WildcardBase = 50;
|
|
|
|
/// <summary>Non-extra wildcard tiles — normal tiles (e.g. 红中=35) that ALSO act as wildcards.</summary>
|
|
public IReadOnlySet<int> ConfiguredWildcards => _wildcards;
|
|
|
|
public void Clear() => _wildcards.Clear();
|
|
|
|
public void Add(int tile) => _wildcards.Add(tile);
|
|
|
|
public void AddRange(IEnumerable<int> tiles)
|
|
{
|
|
foreach (var t in tiles) _wildcards.Add(t);
|
|
}
|
|
|
|
/// <summary>Is this tile a wildcard? Checks encoding range AND configured set.</summary>
|
|
public bool IsWildcard(int tile) =>
|
|
(tile >= WildcardBase && tile <= WildcardBase + 9) || _wildcards.Contains(tile);
|
|
|
|
/// <summary>Count how many tiles in a list are wildcards.</summary>
|
|
public int CountWildcards(IReadOnlyList<int> tiles) =>
|
|
tiles.Count(t => IsWildcard(t));
|
|
|
|
/// <summary>Parse wildcard tile names from DSL into encodings.</summary>
|
|
public static int? NameToEncoding(string name) => name switch
|
|
{
|
|
"红中" => 35,
|
|
"发财" => 36,
|
|
"白板" => 37,
|
|
_ => null
|
|
};
|
|
|
|
public WildcardRegistry Clone()
|
|
{
|
|
var r = new WildcardRegistry();
|
|
r.AddRange(_wildcards);
|
|
return r;
|
|
}
|
|
}
|