diff --git a/RuleEngine/Dsl/DslLoader.cs b/RuleEngine/Dsl/DslLoader.cs index 68ef2b9..8e427db 100644 --- a/RuleEngine/Dsl/DslLoader.cs +++ b/RuleEngine/Dsl/DslLoader.cs @@ -234,6 +234,9 @@ public class ScoringDslConfig public string Mode { get; set; } = "fan_table"; public int MaxCap { get; set; } = int.MaxValue; public List PreHooks { get; set; } = new(); + public int SelfDrawMultiplier { get; set; } = 1; // 自摸: 每家付 baseFan × N + public int DiscardWinMultiplier { get; set; } = 3; // 点炮: 放炮者付 baseFan × N (默认3=传统包赔) + public int DealerMultiplier { get; set; } = 1; // 庄家: 庄家输赢 × N } public class FlowerDslConfig { diff --git a/RuleEngine/MahjongRoom.cs b/RuleEngine/MahjongRoom.cs index d0895bd..2d78891 100644 --- a/RuleEngine/MahjongRoom.cs +++ b/RuleEngine/MahjongRoom.cs @@ -51,7 +51,10 @@ public class MahjongRoom JiHuSelfDrawOnly = _rules.WinRule?.JiHuSelfDrawOnly ?? false, FlowerNormalScore = _rules.FlowerRules?.Scoring?.Normal ?? 0, FlowerMatchScore = _rules.FlowerRules?.Scoring?.Matching?.Value ?? 0, - FlowerMapping = _rules.FlowerRules?.Scoring?.Matching?.Mapping + FlowerMapping = _rules.FlowerRules?.Scoring?.Matching?.Mapping, + SelfDrawMultiplier = _rules.Scoring.SelfDrawMultiplier, + DiscardWinMultiplier = _rules.Scoring.DiscardWinMultiplier, + DealerMultiplier = _rules.Scoring.DealerMultiplier }, _solver, fanConfig); // Init state diff --git a/RuleEngine/Scoring/ScoreEngine.cs b/RuleEngine/Scoring/ScoreEngine.cs index b0f81db..41916d6 100644 --- a/RuleEngine/Scoring/ScoreEngine.cs +++ b/RuleEngine/Scoring/ScoreEngine.cs @@ -13,6 +13,9 @@ public class ScoringConfig public int FlowerNormalScore { get; set; } = 0; public int FlowerMatchScore { get; set; } = 0; public Dictionary>? FlowerMapping { get; set; } + public int SelfDrawMultiplier { get; set; } = 1; + public int DiscardWinMultiplier { get; set; } = 3; + public int DealerMultiplier { get; set; } = 1; } public class MahjongScoreEngine @@ -71,19 +74,29 @@ public class MahjongScoreEngine if (isSelfDraw) { + int perPlayerPay = baseFan * _config.SelfDrawMultiplier; + bool dealerWon = (state.Dealer == winner); foreach (var p in state.AlivePlayers) { if (p == winner) continue; - state.Scores[p] = (state.Scores.GetValueOrDefault(p) - baseFan); - state.Scores[winner] = (state.Scores.GetValueOrDefault(winner) + baseFan); + // 庄家赢→每家付倍数; 闲家赢→仅庄家付倍数 + int mul = (dealerWon || p == state.Dealer) ? _config.DealerMultiplier : 1; + int pay = perPlayerPay * mul; + state.Scores[p] = (state.Scores.GetValueOrDefault(p) - pay); + state.Scores[winner] = (state.Scores.GetValueOrDefault(winner) + pay); } } else { if (state.LastDiscardPlayer != null && state.LastDiscardPlayer != winner) { - state.Scores[state.LastDiscardPlayer] = (state.Scores.GetValueOrDefault(state.LastDiscardPlayer) - baseFan * 3); - state.Scores[winner] = (state.Scores.GetValueOrDefault(winner) + baseFan * 3); + int discardPay = baseFan * _config.DiscardWinMultiplier; + // 庄家赢了或庄家放炮→加倍 + bool dealerInvolved = (state.Dealer == winner || state.Dealer == state.LastDiscardPlayer); + int mul = dealerInvolved ? _config.DealerMultiplier : 1; + int pay = discardPay * mul; + state.Scores[state.LastDiscardPlayer] = (state.Scores.GetValueOrDefault(state.LastDiscardPlayer) - pay); + state.Scores[winner] = (state.Scores.GetValueOrDefault(winner) + pay); } } } diff --git a/dsl-examples/nanchang.yaml b/dsl-examples/nanchang.yaml index ab3aa70..014ec8f 100644 --- a/dsl-examples/nanchang.yaml +++ b/dsl-examples/nanchang.yaml @@ -97,4 +97,7 @@ phases: scoring: mode: fan_table - max_cap: 999 \ No newline at end of file + max_cap: 999 + self_draw_multiplier: 1 # 自摸每家付1倍 + discard_win_multiplier: 1 # 放炮付1倍(南昌麻将放炮不翻倍) + dealer_multiplier: 2 # 庄家输赢×2 \ No newline at end of file