diff --git a/MultiversalDiplomacy/Script/AdjudicationQueryScriptHandler.cs b/MultiversalDiplomacy/Script/AdjudicationQueryScriptHandler.cs index 654d621..e557731 100644 --- a/MultiversalDiplomacy/Script/AdjudicationQueryScriptHandler.cs +++ b/MultiversalDiplomacy/Script/AdjudicationQueryScriptHandler.cs @@ -1,5 +1,4 @@ -using System.Text.RegularExpressions; - +using MultiversalDiplomacy.Adjudicate; using MultiversalDiplomacy.Model; namespace MultiversalDiplomacy.Script; @@ -7,6 +6,7 @@ namespace MultiversalDiplomacy.Script; public class AdjudicationQueryScriptHandler( Action WriteLine, World world, + IPhaseAdjudicator adjudicator, bool strict = false) : IScriptHandler { @@ -32,7 +32,7 @@ public class AdjudicationQueryScriptHandler( { case "---": WriteLine("Ready for orders"); - return new GameScriptHandler(WriteLine, World, Strict); + return new GameScriptHandler(WriteLine, World, adjudicator, Strict); case "assert" when args.Length == 1: WriteLine("Usage:"); diff --git a/MultiversalDiplomacy/Script/GameScriptHandler.cs b/MultiversalDiplomacy/Script/GameScriptHandler.cs index 7c4ea5d..e3b41fc 100644 --- a/MultiversalDiplomacy/Script/GameScriptHandler.cs +++ b/MultiversalDiplomacy/Script/GameScriptHandler.cs @@ -6,7 +6,12 @@ using MultiversalDiplomacy.Orders; namespace MultiversalDiplomacy.Script; -public class GameScriptHandler(Action WriteLine, World world, bool strict = false) : IScriptHandler +public class GameScriptHandler( + Action WriteLine, + World world, + IPhaseAdjudicator adjudicator, + bool strict = false) + : IScriptHandler { public string Prompt => "orders> "; @@ -32,7 +37,6 @@ public class GameScriptHandler(Action WriteLine, World world, bool stric // "---" 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) @@ -40,14 +44,13 @@ public class GameScriptHandler(Action WriteLine, World world, bool stric .ToList(); var adjudication = adjudicator.AdjudicateOrders(World, validOrders); var newWorld = adjudicator.UpdateWorld(World, adjudication); - return new AdjudicationQueryScriptHandler(WriteLine, newWorld, Strict); + return new AdjudicationQueryScriptHandler(WriteLine, newWorld, adjudicator, 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) diff --git a/MultiversalDiplomacy/Script/ReplScriptHandler.cs b/MultiversalDiplomacy/Script/ReplScriptHandler.cs index f76d8af..99a077d 100644 --- a/MultiversalDiplomacy/Script/ReplScriptHandler.cs +++ b/MultiversalDiplomacy/Script/ReplScriptHandler.cs @@ -1,3 +1,4 @@ +using MultiversalDiplomacy.Adjudicate; using MultiversalDiplomacy.Model; namespace MultiversalDiplomacy.Script; @@ -49,7 +50,7 @@ public class ReplScriptHandler(Action WriteLine) : IScriptHandler } World world = World.WithMap(Map.FromType(map)); WriteLine($"Created a new {map} game"); - return new SetupScriptHandler(WriteLine, world); + return new SetupScriptHandler(WriteLine, world, MovementPhaseAdjudicator.Instance); default: WriteLine($"Unrecognized command: \"{command}\""); diff --git a/MultiversalDiplomacy/Script/SetupScriptHandler.cs b/MultiversalDiplomacy/Script/SetupScriptHandler.cs index 88d42e4..87189b8 100644 --- a/MultiversalDiplomacy/Script/SetupScriptHandler.cs +++ b/MultiversalDiplomacy/Script/SetupScriptHandler.cs @@ -1,3 +1,4 @@ +using MultiversalDiplomacy.Adjudicate; using MultiversalDiplomacy.Model; namespace MultiversalDiplomacy.Script; @@ -5,7 +6,12 @@ namespace MultiversalDiplomacy.Script; /// /// A script handler for modifying a game before it begins. /// -public class SetupScriptHandler(Action WriteLine, World world, bool strict = false) : IScriptHandler +public class SetupScriptHandler( + Action WriteLine, + World world, + IPhaseAdjudicator adjudicator, + bool strict = false) + : IScriptHandler { public string Prompt => "setup> "; @@ -41,7 +47,7 @@ public class SetupScriptHandler(Action WriteLine, World world, bool stri case "---": WriteLine("Starting game"); WriteLine("Ready for orders"); - return new GameScriptHandler(WriteLine, World, Strict); + return new GameScriptHandler(WriteLine, World, adjudicator, Strict); case "list" when args.Length == 1: WriteLine("usage:"); diff --git a/MultiversalDiplomacyTests/Adjudicator.cs b/MultiversalDiplomacyTests/Adjudicator.cs new file mode 100644 index 0000000..a5c5041 --- /dev/null +++ b/MultiversalDiplomacyTests/Adjudicator.cs @@ -0,0 +1,8 @@ +using MultiversalDiplomacy.Adjudicate; + +namespace MultiversalDiplomacyTests; + +public static class Adjudicator +{ + public static MovementPhaseAdjudicator MovementPhase { get; } = new MovementPhaseAdjudicator(NullLogger.Instance); +} \ No newline at end of file diff --git a/MultiversalDiplomacyTests/DATC_A.cs b/MultiversalDiplomacyTests/DATC_A.cs index e0068fa..578b471 100644 --- a/MultiversalDiplomacyTests/DATC_A.cs +++ b/MultiversalDiplomacyTests/DATC_A.cs @@ -3,6 +3,8 @@ using MultiversalDiplomacy.Model; using MultiversalDiplomacy.Orders; using NUnit.Framework; +using static MultiversalDiplomacyTests.Adjudicator; + namespace MultiversalDiplomacyTests; public class DATC_A @@ -17,7 +19,7 @@ public class DATC_A .Fleet("North Sea").MovesTo("Picardy").GetReference(out var order); // Order should fail. - setup.ValidateOrders(MovementPhaseAdjudicator.Instance); + setup.ValidateOrders(MovementPhase); Assert.That(order, Is.Invalid(ValidationReason.UnreachableDestination)); } @@ -59,7 +61,7 @@ public class DATC_A .Fleet("Kiel").MovesTo("Kiel").GetReference(out var order); // Program should not crash. - setup.ValidateOrders(MovementPhaseAdjudicator.Instance); + setup.ValidateOrders(MovementPhase); Assert.That(order, Is.Invalid(ValidationReason.DestinationMatchesOrigin)); } @@ -77,14 +79,14 @@ public class DATC_A .Army("Wales").Supports.Fleet("London").MoveTo("Yorkshire"); // The move of the army in Yorkshire is illegal. This makes the support of Liverpool also illegal. - setup.ValidateOrders(MovementPhaseAdjudicator.Instance); + setup.ValidateOrders(MovementPhase); Assert.That(orderLon, Is.Valid); Assert.That(orderNth, Is.Invalid(ValidationReason.DestinationMatchesOrigin)); Assert.That(orderYor, Is.Invalid(ValidationReason.DestinationMatchesOrigin)); var orderYorRepl = orderYor.GetReplacementReference(); // Without the support, the Germans have a stronger force. The army in London dislodges the army in Yorkshire. - setup.AdjudicateOrders(MovementPhaseAdjudicator.Instance); + setup.AdjudicateOrders(MovementPhase); Assert.That(orderLon, Is.Victorious); Assert.That(orderYorRepl, Is.Dislodged); } @@ -98,7 +100,7 @@ public class DATC_A .Fleet("London", powerName: "England").MovesTo("North Sea").GetReference(out var order); // Order should fail. - setup.ValidateOrders(MovementPhaseAdjudicator.Instance); + setup.ValidateOrders(MovementPhase); Assert.That(order, Is.Invalid(ValidationReason.InvalidUnitForPower)); } @@ -112,7 +114,7 @@ public class DATC_A .Fleet("North Sea").Convoys.Army("London").To("Belgium").GetReference(out var order); // Move from London to Belgium should fail. - setup.ValidateOrders(MovementPhaseAdjudicator.Instance); + setup.ValidateOrders(MovementPhase); Assert.That(order, Is.Invalid(ValidationReason.InvalidOrderTypeForUnit)); } @@ -127,12 +129,12 @@ public class DATC_A ["Austria"] .Fleet("Trieste").Supports.Fleet("Trieste").Hold().GetReference(out var orderTri); - setup.ValidateOrders(MovementPhaseAdjudicator.Instance); + setup.ValidateOrders(MovementPhase); Assert.That(orderTri, Is.Invalid(ValidationReason.NoSelfSupport)); var orderTriRepl = orderTri.GetReplacementReference(); // The army in Trieste should be dislodged. - setup.AdjudicateOrders(MovementPhaseAdjudicator.Instance); + setup.AdjudicateOrders(MovementPhase); Assert.That(orderTriRepl, Is.Dislodged); } @@ -145,7 +147,7 @@ public class DATC_A .Fleet("Rome").MovesTo("Venice").GetReference(out var order); // Move fails. An army can go from Rome to Venice, but a fleet can not. - setup.ValidateOrders(MovementPhaseAdjudicator.Instance); + setup.ValidateOrders(MovementPhase); Assert.That(order, Is.Invalid(ValidationReason.UnreachableDestination)); } @@ -160,13 +162,13 @@ public class DATC_A .Army("Apulia").MovesTo("Venice") .Fleet("Rome").Supports.Army("Apulia").MoveTo("Venice").GetReference(out var orderRom); - setup.ValidateOrders(MovementPhaseAdjudicator.Instance); + setup.ValidateOrders(MovementPhase); // The support of Rome is illegal, because Venice can not be reached from Rome by a fleet. Assert.That(orderRom, Is.Invalid(ValidationReason.UnreachableSupport)); // Venice is not dislodged. - setup.AdjudicateOrders(MovementPhaseAdjudicator.Instance); + setup.AdjudicateOrders(MovementPhase); Assert.That(orderVen, Is.NotDislodged); } @@ -180,12 +182,12 @@ public class DATC_A ["Italy"] .Army("Venice").MovesTo("Tyrolia").GetReference(out var orderVen); - setup.ValidateOrders(MovementPhaseAdjudicator.Instance); + setup.ValidateOrders(MovementPhase); Assert.That(orderVie, Is.Valid); Assert.That(orderVen, Is.Valid); // The two units bounce. - var adjudications = setup.AdjudicateOrders(MovementPhaseAdjudicator.Instance); + var adjudications = setup.AdjudicateOrders(MovementPhase); Assert.That(orderVie, Is.Repelled); Assert.That(orderVie, Is.NotDislodged); Assert.That(orderVen, Is.Repelled); @@ -204,12 +206,12 @@ public class DATC_A ["Italy"] .Army("Venice").MovesTo("Tyrolia").GetReference(out var orderVen); - var validations = setup.ValidateOrders(MovementPhaseAdjudicator.Instance); + var validations = setup.ValidateOrders(MovementPhase); Assert.That(orderVie, Is.Valid); Assert.That(orderMun, Is.Valid); Assert.That(orderVen, Is.Valid); - var adjudications = setup.AdjudicateOrders(MovementPhaseAdjudicator.Instance); + var adjudications = setup.AdjudicateOrders(MovementPhase); // The three units bounce. Assert.That(orderVie, Is.Repelled); Assert.That(orderVie, Is.NotDislodged); diff --git a/MultiversalDiplomacyTests/MDATC_A.cs b/MultiversalDiplomacyTests/MDATC_A.cs index bb8be0b..b3de1c8 100644 --- a/MultiversalDiplomacyTests/MDATC_A.cs +++ b/MultiversalDiplomacyTests/MDATC_A.cs @@ -1,7 +1,8 @@ using MultiversalDiplomacy.Adjudicate; -using MultiversalDiplomacy.Adjudicate.Decision; using MultiversalDiplomacy.Model; +using static MultiversalDiplomacyTests.Adjudicator; + using NUnit.Framework; namespace MultiversalDiplomacyTests; @@ -11,7 +12,7 @@ public class TimeTravelTest [Test] public void MDATC_3_A_1_MoveIntoOwnPastForksTimeline() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); // Hold to move into the future, then move back into the past. setup[("a", 0)] @@ -57,7 +58,7 @@ public class TimeTravelTest [Test] public void MDATC_3_A_2_SupportToRepelledPastMoveForksTimeline() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); // Fail to dislodge on the first turn, then support the move so it succeeds. setup[("a", 0)] @@ -107,7 +108,7 @@ public class TimeTravelTest [Test] public void MDATC_3_A_3_FailedMoveDoesNotForkTimeline() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); // Hold to create a future, then attempt to attack in the past. setup[("a", 0)] @@ -147,7 +148,7 @@ public class TimeTravelTest [Test] public void MDATC_3_A_4_SuperfluousSupportDoesNotForkTimeline() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); // Move, then support the past move even though it succeeded already. setup[("a", 0)] @@ -189,7 +190,7 @@ public class TimeTravelTest [Test] public void MDATC_3_A_5_CrossTimelineSupportDoesNotForkHead() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); // London creates two timelines by moving into the past. setup[("a", 0)] @@ -242,7 +243,7 @@ public class TimeTravelTest [Test] public void MDATC_3_A_6_CuttingCrossTimelineSupportDoesNotFork() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); // As above, only now London creates three timelines. setup[("a", 0)] diff --git a/MultiversalDiplomacyTests/MovementAdjudicatorTest.cs b/MultiversalDiplomacyTests/MovementAdjudicatorTest.cs index 1e014e8..8b2be91 100644 --- a/MultiversalDiplomacyTests/MovementAdjudicatorTest.cs +++ b/MultiversalDiplomacyTests/MovementAdjudicatorTest.cs @@ -1,9 +1,10 @@ -using MultiversalDiplomacy.Adjudicate; using MultiversalDiplomacy.Adjudicate.Decision; using MultiversalDiplomacy.Model; using NUnit.Framework; +using static MultiversalDiplomacyTests.Adjudicator; + namespace MultiversalDiplomacyTests; public class MovementAdjudicatorTest @@ -11,7 +12,7 @@ public class MovementAdjudicatorTest [Test] public void Validation_ValidHold() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); setup["Germany"] .Army("Mun").Holds().GetReference(out var order); @@ -24,7 +25,7 @@ public class MovementAdjudicatorTest [Test] public void Validation_ValidMove() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); setup["Germany"] .Army("Mun").MovesTo("Tyr").GetReference(out var order); @@ -37,7 +38,7 @@ public class MovementAdjudicatorTest [Test] public void Validation_ValidConvoy() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); setup["Germany"] .Fleet("Nth").Convoys.Army("Hol").To("Lon").GetReference(out var order); @@ -50,7 +51,7 @@ public class MovementAdjudicatorTest [Test] public void Validation_ValidSupportHold() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); setup["Germany"] .Army("Mun").Supports.Army("Kie").Hold().GetReference(out var order); @@ -63,7 +64,7 @@ public class MovementAdjudicatorTest [Test] public void Validation_ValidSupportMove() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); setup["Germany"] .Army("Mun").Supports.Army("Kie").MoveTo("Ber").GetReference(out var order); @@ -76,12 +77,12 @@ public class MovementAdjudicatorTest [Test] public void Adjudication_Hold() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); setup["Germany"] .Army("Mun").Holds().GetReference(out var order); setup.ValidateOrders(); - setup.AdjudicateOrders(MovementPhaseAdjudicator.Instance); + setup.AdjudicateOrders(MovementPhase); var adjMun = order.Adjudications; Assert.That(adjMun.All(adj => adj.Resolved), Is.True); @@ -96,7 +97,7 @@ public class MovementAdjudicatorTest [Test] public void Adjudication_Move() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); setup["Germany"] .Army("Mun").MovesTo("Tyr").GetReference(out var order); @@ -122,7 +123,7 @@ public class MovementAdjudicatorTest [Test] public void Adjudication_Support() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); setup["Germany"] .Army("Mun").MovesTo("Tyr").GetReference(out var move) .Army("Boh").Supports.Army("Mun").MoveTo("Tyr").GetReference(out var support); @@ -156,7 +157,7 @@ public class MovementAdjudicatorTest [Test] public void Update_SingleHold() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); setup["Germany"] .Army("Mun").Holds().GetReference(out var mun); @@ -183,7 +184,7 @@ public class MovementAdjudicatorTest [Test] public void Update_DoubleHold() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); setup[("a", 0)] .GetReference(out Season s1) ["Germany"] @@ -233,7 +234,7 @@ public class MovementAdjudicatorTest [Test] public void Update_DoubleMove() { - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); setup[("a", 0)] .GetReference(out Season s1) ["Germany"] diff --git a/MultiversalDiplomacyTests/NullLogger.cs b/MultiversalDiplomacyTests/NullLogger.cs new file mode 100644 index 0000000..cb479d2 --- /dev/null +++ b/MultiversalDiplomacyTests/NullLogger.cs @@ -0,0 +1,10 @@ +using MultiversalDiplomacy.Adjudicate.Logging; + +namespace MultiversalDiplomacyTests; + +public class NullLogger : IAdjudicatorLogger +{ + public static NullLogger Instance { get; } = new(); + + public void Log(int contextLevel, string message, params object[] args) {} +} diff --git a/MultiversalDiplomacyTests/ReplTest.cs b/MultiversalDiplomacyTests/ReplTest.cs index e70ffb1..c86106b 100644 --- a/MultiversalDiplomacyTests/ReplTest.cs +++ b/MultiversalDiplomacyTests/ReplTest.cs @@ -12,6 +12,7 @@ public class ReplTest new SetupScriptHandler( (msg) => {/* discard*/}, World.WithStandardMap(), + Adjudicator.MovementPhase, strict: true)); [Test] diff --git a/MultiversalDiplomacyTests/ScriptTests.cs b/MultiversalDiplomacyTests/ScriptTests.cs index 82fd2d6..05e81b2 100644 --- a/MultiversalDiplomacyTests/ScriptTests.cs +++ b/MultiversalDiplomacyTests/ScriptTests.cs @@ -25,6 +25,7 @@ public class ScriptTests IScriptHandler? handler = new SetupScriptHandler( (msg) => {/* discard*/}, World.WithStandardMap(), + Adjudicator.MovementPhase, strict: true); foreach (string input in File.ReadAllLines(testScriptPath)) { line++; diff --git a/MultiversalDiplomacyTests/SerializationTest.cs b/MultiversalDiplomacyTests/SerializationTest.cs index cbadda2..91ca56e 100644 --- a/MultiversalDiplomacyTests/SerializationTest.cs +++ b/MultiversalDiplomacyTests/SerializationTest.cs @@ -1,11 +1,12 @@ using System.Text.Json; -using MultiversalDiplomacy.Adjudicate; using MultiversalDiplomacy.Adjudicate.Decision; using MultiversalDiplomacy.Model; using NUnit.Framework; +using static MultiversalDiplomacyTests.Adjudicator; + namespace MultiversalDiplomacyTests; public class SerializationTest @@ -74,7 +75,7 @@ public class SerializationTest public void SerializeRoundTrip_MDATC_3_A_2() { // Set up MDATC 3.A.2 - TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance); + TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhase); setup[("a", 0)] .GetReference(out Season s0) ["Germany"] @@ -107,7 +108,7 @@ public class SerializationTest }); // Resume the test case - setup = new(reserialized, MovementPhaseAdjudicator.Instance); + setup = new(reserialized, MovementPhase); setup[("a", 1)] ["Germany"] .Army("Mun").Supports.Army("Mun", season: s0).MoveTo("Tyr").GetReference(out var mun1)