using System.Text.RegularExpressions; using MultiversalDiplomacy.Adjudicate; using MultiversalDiplomacy.Model; using MultiversalDiplomacy.Orders; namespace MultiversalDiplomacy.Script; public class GameScriptHandler(Action WriteLine, World world, bool strict = false) : IScriptHandler { public string Prompt => "orders> "; public World World { get; private set; } = world; /// /// Whether unsuccessful commands should terminate the script. /// public bool Strict { get; } = strict; private string? CurrentPower { get; set; } = null; public List Orders { get; } = []; public IScriptHandler? HandleInput(string input) { if (input == "") { CurrentPower = null; return this; } if (input.StartsWith('#')) return this; // "---" submits the orders and allows queries about the outcome if (input == "---") { WriteLine("Submitting orders for adjudication"); var adjudicator = MovementPhaseAdjudicator.Instance; var validation = adjudicator.ValidateOrders(World, Orders); var validOrders = validation .Where(v => v.Valid) .Select(v => v.Order) .ToList(); var adjudication = adjudicator.AdjudicateOrders(World, validOrders); var newWorld = adjudicator.UpdateWorld(World, adjudication); return new AdjudicationQueryScriptHandler(WriteLine, newWorld, Strict); } // "===" submits the orders and moves immediately to taking the next set of orders // i.e. it's "---" twice if (input == "===") { WriteLine("Submitting orders for adjudication"); var adjudicator = MovementPhaseAdjudicator.Instance; var validation = adjudicator.ValidateOrders(World, Orders); var validOrders = validation .Where(v => v.Valid) .Select(v => v.Order) .ToList(); var adjudication = adjudicator.AdjudicateOrders(World, validOrders); World = adjudicator.UpdateWorld(World, adjudication); WriteLine("Ready for orders"); return this; } // A block of orders for a single power beginning with "{name}:" if (World.Powers.FirstOrDefault(p => input.EqualsAnyCase($"{p}:"), null) is string power) { CurrentPower = power; return this; } // If it's not a comment, submit, or order block, assume it's an order. string orderPower; string orderText; if (CurrentPower is not null) { // In a block of orders from a power, the power was specified at the top and each line is an order. orderPower = CurrentPower; orderText = input; } else { // Outside a power block, the power is prefixed to each order. Regex re = new($"^{World.Map.PowerRegex}(?:[:])? (.*)$", RegexOptions.IgnoreCase); var match = re.Match(input); if (!match.Success) { WriteLine($"Could not determine ordering power in \"{input}\""); return Strict ? null : this; } orderPower = match.Groups[1].Value; orderText = match.Groups[2].Value; } if (OrderParser.TryParseOrder(World, orderPower, orderText, out Order? order)) { WriteLine($"Parsed {orderPower} order: {order}"); Orders.Add(order); return this; } WriteLine($"Failed to parse \"{orderText}\""); return Strict ? null : this; } }