fix: 圈风/门风/单钓将/四归一加_fanConfig守卫 + 精牌显示 + TileName修复
问题1: 圈风/门风/单钓将/四归一在南昌武汉等非Guobiao玩法中误生成
修复: 4个新识别器加 _fanConfig.ContainsKey() 守卫,只有配了才生成
Guobiao DSL 补充4个番型定义(圈风2/门风2/四归一2/单钓将1)
问题2: 翻牌定精信息未在demo显示
修复: RenderDeal() 显示精牌(翻牌+正精+副精)
问题3: TileName?{tile}→ToStringCore(tile)
修复: 带🀫前缀的数字牌显示 '🀫3万' 而非 '🀫?21'
This commit is contained in:
@ -237,6 +237,16 @@ void RenderDeal(MahjongRoom room)
|
||||
foreach (var p in state.PlayerOrder)
|
||||
Console.WriteLine($" {p}{(p == state.Dealer ? " (庄)" : "")}: {state.Hands[p].Count}张");
|
||||
Console.WriteLine($" 牌墙: {state.Deck.Count} 张");
|
||||
// Show wildcard info if configured
|
||||
var wc = state.Wildcards;
|
||||
if (wc.ConfiguredWildcards.Count > 0)
|
||||
{
|
||||
var wcStr = string.Join(" ", wc.ConfiguredWildcards.Select(t => MahjongTile.ToString(t, wc)));
|
||||
if (wc.RevealedTile.HasValue)
|
||||
Console.WriteLine($" 🀫 精: {wcStr} (翻牌: {MahjongTile.ToString(wc.RevealedTile.Value)})");
|
||||
else
|
||||
Console.WriteLine($" 🀫 宝牌: {wcStr}");
|
||||
}
|
||||
Console.WriteLine($" (手牌已洗牌,按 Enter 查看牌局)");
|
||||
}
|
||||
|
||||
|
||||
@ -52,11 +52,11 @@ public static class MahjongTile
|
||||
}
|
||||
|
||||
private static string TileName(int tile) => tile switch
|
||||
{
|
||||
31 => "东", 32 => "南", 33 => "西", 34 => "北",
|
||||
35 => "中", 36 => "发", 37 => "白",
|
||||
_ => $"?{tile}"
|
||||
};
|
||||
{
|
||||
31 => "东", 32 => "南", 33 => "西", 34 => "北",
|
||||
35 => "中", 36 => "发", 37 => "白",
|
||||
_ => ToStringCore(tile)
|
||||
};
|
||||
|
||||
/// 0=万, 1=条, 2=筒, 3=字, 4=花, 5=宝牌
|
||||
public static int Suit(int tile)
|
||||
|
||||
@ -776,22 +776,24 @@ public class MeldsSolver
|
||||
fans.Add("地胡");
|
||||
|
||||
// 圈风刻: kezi matching current wind round (e.g. 东风圈→有东刻子)
|
||||
if (keziTiles.Any(t => t == state.WindRound))
|
||||
if (_fanConfig.ContainsKey("圈风") && keziTiles.Any(t => t == state.WindRound))
|
||||
fans.Add("圈风");
|
||||
// 门风刻: kezi matching player's seat wind (applies per-hand, identified by state owner)
|
||||
foreach (var (player, seatWind) in state.SeatWinds)
|
||||
if (keziTiles.Any(t => t == seatWind))
|
||||
fans.Add("门风");
|
||||
// 门风刻: kezi matching player's seat wind
|
||||
if (_fanConfig.ContainsKey("门风") && state.SeatWinds.Values.Any(sw => keziTiles.Any(t => t == sw)))
|
||||
fans.Add("门风");
|
||||
|
||||
// 单钓将: detected at self-draw time (single tile→pair completion)
|
||||
if (state.IsSingleWait) fans.Add("单钓将");
|
||||
if (_fanConfig.ContainsKey("单钓将") && state.IsSingleWait) fans.Add("单钓将");
|
||||
}
|
||||
|
||||
// 四归一: 4 identical numbered tiles used across 2+ melds (not in a single kong)
|
||||
var tileCounts = allTiles.Where(t => MahjongTile.IsNumbered(t)).GroupBy(t => t);
|
||||
bool hasSiGuiYi = tileCounts.Any(g =>
|
||||
g.Count() >= 4 && !melds.Any(m => m.Type == "kezi" && m.Tiles.Contains(g.Key) && m.Tiles.All(x => x == g.Key)));
|
||||
if (hasSiGuiYi) fans.Add("四归一");
|
||||
if (_fanConfig.ContainsKey("四归一"))
|
||||
{
|
||||
var tileCounts4 = allTiles.Where(t => MahjongTile.IsNumbered(t)).GroupBy(t => t);
|
||||
bool hasSiGuiYi = tileCounts4.Any(g =>
|
||||
g.Count() >= 4 && !melds.Any(m => m.Type == "kezi" && m.Tiles.Contains(g.Key) && m.Tiles.All(x => x == g.Key)));
|
||||
if (hasSiGuiYi) fans.Add("四归一");
|
||||
}
|
||||
|
||||
// 鸡胡: base-level fan when no other fan with positive value exists.
|
||||
// A fan has positive value if it's in _fanConfig with base_fan>0,
|
||||
|
||||
@ -75,9 +75,14 @@ fan_types:
|
||||
- { name: 断幺九, base_fan: 2, level: 2 }
|
||||
- { name: 平和, base_fan: 2, level: 2 }
|
||||
- { name: 门前清, base_fan: 2, level: 2 }
|
||||
# 2番
|
||||
- { name: 圈风, base_fan: 2, level: 2 }
|
||||
- { name: 门风, base_fan: 2, level: 2 }
|
||||
- { name: 四归一, base_fan: 2, level: 2 }
|
||||
# 1番
|
||||
- { name: 缺一门, base_fan: 1, level: 1 }
|
||||
- { name: 无字, base_fan: 1, level: 1 }
|
||||
- { name: 单钓将, base_fan: 1, level: 1 }
|
||||
# 兜底
|
||||
- { name: 鸡胡, base_fan: 1, level: 0 }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user