using System.Text.RegularExpressions; using MultiversalDiplomacy.Adjudicate; using MultiversalDiplomacy.Model; using MultiversalDiplomacy.Orders; namespace MultiversalDiplomacy.Script; public class AdjudicationQueryScriptHandler( Action WriteLine, List validations, World world, IPhaseAdjudicator adjudicator, bool strict = false) : IScriptHandler { public string Prompt => "valid> "; public List Validations { get; } = validations; public World World { get; private set; } = world; /// /// Whether unsuccessful commands should terminate the script. /// public bool Strict { get; } = strict; public IScriptHandler? HandleInput(string input) { var args = input.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries); if (args.Length == 0 || input.StartsWith('#')) { return this; } var command = args[0]; switch (command) { case "---": WriteLine("Ready for orders"); return new GameScriptHandler(WriteLine, World, adjudicator, Strict); case "assert" when args.Length == 1: WriteLine("Usage:"); break; case "assert": if (!EvaluateAssertion(args[1])) return Strict ? null : this; break; case "status": throw new NotImplementedException(); default: WriteLine($"Unrecognized command: \"{command}\""); if (Strict) return null; break; } return this; } private bool EvaluateAssertion(string assertion) { var args = assertion.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries); switch (args[0]) { case "true": return true; case "false": return false; case "order-valid": case "order-invalid": OrderParser re = new(World); Regex prov = new($"^{re.FullLocation}$", RegexOptions.IgnoreCase); Match match = prov.Match(args[1]); if (!match.Success) { WriteLine($"Could not parse province from \"{args[1]}\""); return !Strict; } string timeline = match.Groups[1].Length > 0 ? match.Groups[1].Value : Season.First.Timeline; var seasonsInTimeline = World.Timelines.Seasons.Where(season => season.Timeline == timeline); if (!seasonsInTimeline.Any()) return false; int turn = match.Groups[4].Length > 0 ? int.Parse(match.Groups[4].Value) // If turn is unspecified, use the second-latest turn in the timeline, // since we want to assert against the subjects of the orders just adjudicated, // and adjudication created a new set of seasons. : seasonsInTimeline.Max(season => season.Turn) - 1; Season season = new(timeline, turn); Province province = World.Map.Provinces.Single(province => province.Is(match.Groups[2].Value)); var matching = Validations.Where(val => val.Order is UnitOrder order && order.Unit.Season == season && World.Map.GetLocation(order.Unit.Location).ProvinceName == province.Name); if (!matching.Any()) return false; return args[0] == "order-valid" ? matching.First().Valid : !matching.First().Valid; case "has-past": // Assert a timeline's past case "holds": // Assert a unit successfully held case "dislodged": // Assert a unit was dislodged case "moves": // Assert a unit successfully moved case "no-move": // Assert a unit did not move case "supports": // Assert a unit's support was given case "cut": // Assert a unit's support was cut default: WriteLine($"Unknown assertion \"{args[0]}\""); return !Strict; } } }