diff --git a/MultiversalDiplomacy/Script/AdjudicationQueryScriptHandler.cs b/MultiversalDiplomacy/Script/AdjudicationQueryScriptHandler.cs index bbccf70..620b63d 100644 --- a/MultiversalDiplomacy/Script/AdjudicationQueryScriptHandler.cs +++ b/MultiversalDiplomacy/Script/AdjudicationQueryScriptHandler.cs @@ -1,6 +1,7 @@ using System.Text.RegularExpressions; using MultiversalDiplomacy.Adjudicate; +using MultiversalDiplomacy.Adjudicate.Decision; using MultiversalDiplomacy.Model; using MultiversalDiplomacy.Orders; @@ -9,6 +10,7 @@ namespace MultiversalDiplomacy.Script; public class AdjudicationQueryScriptHandler( Action WriteLine, List validations, + List adjudications, World world, IPhaseAdjudicator adjudicator) : IScriptHandler @@ -17,6 +19,8 @@ public class AdjudicationQueryScriptHandler( public List Validations { get; } = validations; + public List Adjudications { get; } = adjudications; + public World World { get; private set; } = world; public ScriptResult HandleInput(string input) @@ -122,10 +126,42 @@ public class AdjudicationQueryScriptHandler( // Assert a unit was dislodged case "moves": - // Assert a unit successfully moved - case "no-move": - // Assert a unit did not move + re = new(World); + prov = new($"^{re.FullLocation}$", RegexOptions.IgnoreCase); + match = prov.Match(args[1]); + if (!match.Success) return ScriptResult.Fail($"Could not parse province from \"{args[1]}\"", this); + + timeline = match.Groups[1].Length > 0 + ? match.Groups[1].Value + : Season.First.Timeline; + seasonsInTimeline = World.Timelines.Seasons.Where(season => season.Timeline == timeline); + if (!seasonsInTimeline.Any()) return ScriptResult.Fail($"No seasons in timeline {timeline}", this); + + 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 = new(timeline, turn); + + province = World.Map.Provinces.Single(province => province.Is(match.Groups[2].Value)); + + var matchingMoves = Adjudications.Where(adj + => adj is DoesMove moves + && moves.Order.Unit.Season == season + && World.Map.GetLocation(moves.Order.Unit.Location).ProvinceName == province.Name); + if (!matchingMoves.Any()) return ScriptResult.Fail("No matching movement decisions"); + var doesMove = matchingMoves.Cast().First(); + + if (args[0] == "moves" && doesMove.Outcome != true) { + return ScriptResult.Fail($"Adjudication {doesMove} is false"); + } + if (args[0] == "no-move" && doesMove.Outcome != false) { + return ScriptResult.Fail($"Adjudication {doesMove} is true"); + } + return ScriptResult.Succeed(this); case "supports": // Assert a unit's support was given diff --git a/MultiversalDiplomacy/Script/GameScriptHandler.cs b/MultiversalDiplomacy/Script/GameScriptHandler.cs index 50f794a..bfe614b 100644 --- a/MultiversalDiplomacy/Script/GameScriptHandler.cs +++ b/MultiversalDiplomacy/Script/GameScriptHandler.cs @@ -39,7 +39,7 @@ public class GameScriptHandler( var adjudication = adjudicator.AdjudicateOrders(World, validOrders); var newWorld = adjudicator.UpdateWorld(World, adjudication); return ScriptResult.Succeed(new AdjudicationQueryScriptHandler( - WriteLine, validation, newWorld, adjudicator)); + WriteLine, validation, adjudication, newWorld, adjudicator)); } // "===" submits the orders and moves immediately to taking the next set of orders diff --git a/MultiversalDiplomacyTests/ReplTest.cs b/MultiversalDiplomacyTests/ReplTest.cs index 330d41b..45339c2 100644 --- a/MultiversalDiplomacyTests/ReplTest.cs +++ b/MultiversalDiplomacyTests/ReplTest.cs @@ -124,16 +124,18 @@ public class ReplTest --- """); - // Assertion should pass for a season's past + // Expected past repl.Execute("assert has-past a1>a0"); - // Assertion should fail for an incorrect past + // Incorrect past repl.AssertFails("assert has-past a0>a1"); + repl.AssertFails("assert has-past a1>a1"); + // Missing season + repl.AssertFails("assert has-past a2>a1"); } [Test] - public void AssertHolds() + public void AssertMovement() { - Assert.Ignore(); var repl = StandardRepl(); repl.ExecuteAll(""" @@ -144,10 +146,19 @@ public class ReplTest --- """); - // Assertion should pass for a repelled move - repl.Execute("assert holds Tyr"); - // Assertion should fail for a repelled move - repl.Execute("assert dislodged Tyr"); + // Movement fails + repl.Execute("assert no-move Mun"); + repl.AssertFails("assert moves Mun"); + + repl.ExecuteAll(""" + --- + Germany Mun - Boh + --- + """); + + // Movement succeeds + repl.Execute("assert moves Mun"); + repl.AssertFails("assert no-move Mun"); } [Test]