fix: 连七对识别器 + 258检查gap + .First() null防御
1. 连七对: IsConsecutiveSameSuitSevenPairs() 检测同色连续7对 TrySevenPairs成功后检查→ 连七对 vs 暗七对/七对 2. 258 check gap: 十三幺/全不靠/一色双龙会路径加 require258Pair 检查 武汉麻将中这些牌型无258将概念→258要求下直接拒绝 3. .First() → .FirstOrDefault() + null return: ExecuteAnKong / ExecuteBuKong 防御性编程 审计JSON: remaining_issues 清空 (所有已知问题已修复)
This commit is contained in:
@ -568,7 +568,8 @@ public class MahjongRoom
|
||||
{
|
||||
var hand = State.Hands[player];
|
||||
var group = hand.GroupBy(t => t)
|
||||
.First(g => g.Count() >= 4 && !State.Wildcards.IsWildcard(g.Key));
|
||||
.FirstOrDefault(g => g.Count() >= 4 && !State.Wildcards.IsWildcard(g.Key));
|
||||
if (group == null) return; // defensive: PhaseMachine should prevent this
|
||||
int tile = group.Key;
|
||||
for (int i = 0; i < 4; i++) State.Hands[player].Remove(tile);
|
||||
State.Exposed[player].Add(new Meld
|
||||
@ -607,7 +608,8 @@ public class MahjongRoom
|
||||
private void ExecuteBuKong(string player)
|
||||
{
|
||||
var exposed = State.Exposed[player];
|
||||
var pung = exposed.First(m => m.Type == "pung" && State.Hands[player].Contains(m.Tiles[0]));
|
||||
var pung = exposed.FirstOrDefault(m => m.Type == "pung" && State.Hands[player].Contains(m.Tiles[0]));
|
||||
if (pung == null) return; // defensive: PhaseMachine should prevent this
|
||||
int tile = pung.Tiles[0];
|
||||
State.Hands[player].Remove(tile);
|
||||
pung.Type = "kong_bu";
|
||||
|
||||
@ -59,7 +59,10 @@ public class MeldsSolver
|
||||
}
|
||||
}
|
||||
}
|
||||
sevenPairs.Fans = new List<string> { FanName("暗七对", "七对") };
|
||||
sevenPairs.Fans = new List<string> {
|
||||
IsConsecutiveSameSuitSevenPairs(sevenPairs.Melds) ? "连七对"
|
||||
: FanName("暗七对", "七对")
|
||||
};
|
||||
sevenPairs.Fans = ApplyFanExclusions(
|
||||
sevenPairs.Fans.Concat(IdentifyFans(sevenPairs)).Distinct().ToList());
|
||||
return sevenPairs;
|
||||
@ -69,6 +72,7 @@ public class MeldsSolver
|
||||
var thirteen = TryThirteenOrphans(tiles, wildcardCount);
|
||||
if (thirteen != null)
|
||||
{
|
||||
if (require258Pair) return new MeldsResult { IsWin = false }; // 十三幺无258将概念
|
||||
thirteen.Fans = new List<string> { "十三幺" };
|
||||
thirteen.Fans = ApplyFanExclusions(
|
||||
thirteen.Fans.Concat(IdentifyFans(thirteen)).Distinct().ToList());
|
||||
@ -79,6 +83,7 @@ public class MeldsSolver
|
||||
var allOrphans = TryAllOrphans(tiles, wildcardCount);
|
||||
if (allOrphans != null)
|
||||
{
|
||||
if (require258Pair) return new MeldsResult { IsWin = false }; // 全不靠无将牌概念
|
||||
allOrphans.Fans = new List<string> { "全不靠" };
|
||||
allOrphans.Fans = ApplyFanExclusions(
|
||||
allOrphans.Fans.Concat(IdentifyFans(allOrphans)).Distinct().ToList());
|
||||
@ -89,6 +94,7 @@ public class MeldsSolver
|
||||
var doubleDragon = TryDoubleDragon(tiles, wildcardCount);
|
||||
if (doubleDragon != null)
|
||||
{
|
||||
if (require258Pair) return new MeldsResult { IsWin = false }; // 一色双龙会无258将概念
|
||||
doubleDragon.Fans = new List<string> { "一色双龙会" };
|
||||
doubleDragon.Fans = ApplyFanExclusions(
|
||||
doubleDragon.Fans.Concat(IdentifyFans(doubleDragon)).Distinct().ToList());
|
||||
@ -386,6 +392,20 @@ public class MeldsSolver
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Check if 7 pairs form 连七对: same suit, consecutive ranks 1-7/2-8/3-9.</summary>
|
||||
private static bool IsConsecutiveSameSuitSevenPairs(List<Meld> melds)
|
||||
{
|
||||
if (melds.Count != 7) return false;
|
||||
var tiles = melds.Select(m => m.Tiles[0]).ToList();
|
||||
// All must be numbered (no honors) and same suit
|
||||
if (!tiles.All(MahjongTile.IsNumbered)) return false;
|
||||
int suit = MahjongTile.Suit(tiles[0]);
|
||||
if (!tiles.All(t => MahjongTile.Suit(t) == suit)) return false;
|
||||
// Ranks must form consecutive 1-7, 2-8, or 3-9
|
||||
var ranks = tiles.Select(MahjongTile.Rank).OrderBy(r => r).ToList();
|
||||
return ranks.SequenceEqual(Enumerable.Range(ranks[0], 7)) && ranks[0] <= 3;
|
||||
}
|
||||
|
||||
// === 十三幺 ===
|
||||
private MeldsResult? TryThirteenOrphans(List<int> tiles, int wildcardCount)
|
||||
{
|
||||
|
||||
@ -26,20 +26,6 @@
|
||||
"鸡胡识别缺失 → allZeroValue检查 + DSL配置鸡胡"
|
||||
]
|
||||
},
|
||||
"remaining_issues": [
|
||||
{
|
||||
"severity": "med",
|
||||
"file": "MeldsSolver.cs",
|
||||
"issue": "约10个番型识别器缺失: 将一色,大四喜,大三元,小四喜,小三元,一色四同顺,连七对,五门齐,全带幺,全求人",
|
||||
"impact": "这些番型被引擎标记为well-known(可通过filter), 但IdentifyFans中部分无自动识别逻辑。DSL配置后FanValue可正常查找(通过_fanConfig), 但引擎需在这些模式出现时自动添加番型名。",
|
||||
"status": "部分已实现(将一色/大四喜/大三元/小四喜/小三元/一色四同顺/五门齐/全求人已有识别逻辑), 全带幺通过FanName(\"带幺九\",\"全带幺\")处理, 连七对通过七对路径+名称匹配"
|
||||
},
|
||||
{
|
||||
"severity": "med",
|
||||
"file": "MeldsSolver.cs:45-65",
|
||||
"issue": "258将检查仅对七对路径实施, 标准回溯路径另有检查。但十三幺/全不靠/一色双龙会绕过258检查",
|
||||
"impact": "武汉麻将的258要求在这些特殊牌型中不生效。但实际游戏中这些牌型几乎不会出现258争议。"
|
||||
}
|
||||
],
|
||||
"note": "本文件为历史审计快照。所有5个HIGH已修复。剩余MED问题影响极小, 实际游戏中几乎不触发。"
|
||||
"remaining_issues": [],
|
||||
"note": "本文件为历史审计快照。所有已知问题已修复。连七对识别器、258检查gap、.First() null防御已在本轮补充修复。"
|
||||
}
|
||||
Reference in New Issue
Block a user