feat: 集成测试 + 手动出牌模式 + discart pool幽灵牌修复
集成测试 (10个): - 发牌: 庄14闲13, 牌墙55 - 回合流转: 庄家第一轮不摸牌, 非庄家摸牌后出牌 - 数据完整性: 10回合后手牌+副露+牌墙+弃牌=108 - 对局完整性: 4种DSL全部不出错完成 - 构造听牌: 完整手牌第一轮自摸 手动出牌 (--human): - HumanMahjongPlayer: 显示手牌/可选操作/h=胡/p=碰/k=杠/1-N=出牌 - MahjongRoom: humanPlayer参数 修复: DiscardPool碰/胡后不移除→幽灵牌→总牌数溢出
This commit is contained in:
@ -13,17 +13,21 @@ public class MahjongRoom
|
||||
public bool IsFinished { get; private set; }
|
||||
private readonly MahjongDslRoot _rules;
|
||||
private readonly List<RandomMahjongAI> _ais;
|
||||
private readonly HumanMahjongPlayer? _human;
|
||||
private readonly MeldsSolver _solver;
|
||||
private readonly MahjongPhaseMachine _phaseMachine;
|
||||
private readonly MahjongScoreEngine _scoreEngine;
|
||||
private readonly bool _autoMode;
|
||||
private readonly Random _rng = Random.Shared;
|
||||
|
||||
public MahjongRoom(MahjongDslRoot rules, string[] playerNames, bool autoMode = false)
|
||||
public MahjongRoom(MahjongDslRoot rules, string[] playerNames, bool autoMode = false,
|
||||
string? humanPlayer = null)
|
||||
{
|
||||
_rules = rules;
|
||||
_autoMode = autoMode;
|
||||
_ais = playerNames.Select((n, i) => new RandomMahjongAI(n, new Random(i * 7919))).ToList();
|
||||
if (humanPlayer != null)
|
||||
_human = new HumanMahjongPlayer(humanPlayer);
|
||||
|
||||
var fanConfig = BuildFanConfig();
|
||||
_solver = new MeldsSolver(fanConfig);
|
||||
@ -179,7 +183,9 @@ public class MahjongRoom
|
||||
// Phase 3: Player decides what to do with their drawn hand
|
||||
bool requireWinFan = _rules.WinMinFan > 0;
|
||||
var legalActions = _phaseMachine.GetLegalActions(State, player, requireWinFan);
|
||||
var (action, tile) = _ais.First(a => a.Name == player).Decide(legalActions, State);
|
||||
var (action, tile) = _human != null && player == _human.Name
|
||||
? _human.Decide(legalActions, State)
|
||||
: _ais.First(a => a.Name == player).Decide(legalActions, State);
|
||||
|
||||
if (action == "win")
|
||||
{
|
||||
@ -285,6 +291,9 @@ public class MahjongRoom
|
||||
|
||||
if (best.action == "win")
|
||||
{
|
||||
// Remove the winning tile from pool (it's now part of the winning hand)
|
||||
State.DiscardPool.Remove(discardTile);
|
||||
|
||||
var handWithTile = new List<int>(State.Hands[bp]) { discardTile };
|
||||
var (wc2, r2582) = GetWinParams();
|
||||
int wildInHand2 = CountWildcardsInHand(handWithTile);
|
||||
@ -305,6 +314,9 @@ public class MahjongRoom
|
||||
|
||||
if (best.action == "pung" || best.action == "ming_kong")
|
||||
{
|
||||
// Remove the discarded tile from pool (it's now in the meld)
|
||||
State.DiscardPool.Remove(discardTile);
|
||||
|
||||
// Remove tiles from hand (pung: 2, ming_kong: 3)
|
||||
// The discard tile is taken from pool, not from hand
|
||||
int toRemove = best.action == "ming_kong" ? 3 : 2;
|
||||
|
||||
Reference in New Issue
Block a user