namespace RuleEngine.AI; using RuleEngine.Core; using RuleEngine.Phase; public class RandomMahjongAI { public string Name { get; } private readonly Random _rng; public RandomMahjongAI(string name, Random? rng = null) { Name = name; _rng = rng ?? Random.Shared; } public (string action, int? tile) Decide(List legalActions, MahjongGameState state) { if (legalActions.Count == 0) return ("pass", null); // Priority: win > kong > pung > chi > discard var win = legalActions.FirstOrDefault(a => a.Action == "win"); if (win != null) return ("win", null); var mingKong = legalActions.FirstOrDefault(a => a.Action == "ming_kong"); if (mingKong != null) return ("ming_kong", null); var anKong = legalActions.FirstOrDefault(a => a.Action == "an_kong"); if (anKong != null) return ("an_kong", null); var pung = legalActions.FirstOrDefault(a => a.Action == "pung"); if (pung != null) return ("pung", null); var chi = legalActions.FirstOrDefault(a => a.Action == "chi"); if (chi != null) return ("chi", null); // Discard: random non-wildcard tile var discards = legalActions.Where(a => a.Action == "discard").ToList(); if (discards.Count > 0) { var hand = state.Hands.GetValueOrDefault(Name, new List()); var nonWildTiles = hand.Where(t => !state.Wildcards.IsWildcard(t)).ToList(); if (nonWildTiles.Count > 0) return ("discard", nonWildTiles[_rng.Next(nonWildTiles.Count)]); // Only wildcards left — discard one if (hand.Count > 0) return ("discard", hand[_rng.Next(hand.Count)]); } return ("pass", null); } }