From 4ce5faaac2703465fa80352de78c41dbea9f8dc4 Mon Sep 17 00:00:00 2001 From: Tim Van Baak Date: Mon, 9 Sep 2024 11:58:59 -0700 Subject: [PATCH] Replace Map lookup methods with Unit methods This makes the flow of data easier to read and is slightly shorter in some cases. This pattern will be better for replacing more reference members with keys. --- .../Adjudicate/Decision/MovementDecisions.cs | 12 ++++++------ .../Adjudicate/MovementPhaseAdjudicator.cs | 16 ++++++++-------- MultiversalDiplomacy/Adjudicate/PathFinder.cs | 4 ++-- MultiversalDiplomacy/Model/Map.cs | 3 --- MultiversalDiplomacy/Model/OrderParser.cs | 6 +++--- MultiversalDiplomacy/Model/Unit.cs | 4 ++++ MultiversalDiplomacy/Model/World.cs | 2 +- .../Script/AdjudicationQueryScriptHandler.cs | 10 +++++----- MultiversalDiplomacyTests/OrderReference.cs | 2 +- MultiversalDiplomacyTests/TestCaseBuilder.cs | 2 +- MultiversalDiplomacyTests/TestCaseBuilderTest.cs | 2 +- 11 files changed, 32 insertions(+), 31 deletions(-) diff --git a/MultiversalDiplomacy/Adjudicate/Decision/MovementDecisions.cs b/MultiversalDiplomacy/Adjudicate/Decision/MovementDecisions.cs index c1cee56..ef0b1e2 100644 --- a/MultiversalDiplomacy/Adjudicate/Decision/MovementDecisions.cs +++ b/MultiversalDiplomacy/Adjudicate/Decision/MovementDecisions.cs @@ -94,7 +94,7 @@ public class MovementDecisions .ToList(); (string province, string season) UnitPoint(Unit unit) - => (world.Map.GetLocation(unit.Location).Province.Name, unit.Season.Key); + => (unit.GetProvince(world).Name, unit.Season.Key); (string province, string season) MovePoint(MoveOrder move) => (SplitKey(move.Location).province, move.Season.Key); @@ -102,7 +102,7 @@ public class MovementDecisions foreach (UnitOrder order in relevantOrders) { HoldStrength[UnitPoint(order.Unit)] = new( - world.Map.GetLocation(order.Unit.Location).Province, + order.Unit.GetProvince(world), order.Unit.Season, order); } @@ -110,7 +110,7 @@ public class MovementDecisions bool IsIncoming(UnitOrder me, MoveOrder other) => me != other && other.Season == me.Unit.Season - && SplitKey(other.Location).province == world.Map.GetLocation(me.Unit).Province.Name; + && SplitKey(other.Location).province == me.Unit.GetProvince(world).Name; bool IsSupportFor(SupportMoveOrder me, MoveOrder move) => me.Target.Key == move.Unit.Key @@ -120,8 +120,8 @@ public class MovementDecisions bool AreOpposing(MoveOrder one, MoveOrder two) => one.Season == two.Unit.Season && two.Season == one.Unit.Season - && SplitKey(one.Location).province == world.Map.GetLocation(two.Unit).Province.Name - && SplitKey(two.Location).province == world.Map.GetLocation(one.Unit).Province.Name; + && SplitKey(one.Location).province == two.Unit.GetProvince(world).Name + && SplitKey(two.Location).province == one.Unit.GetProvince(world).Name; bool AreCompeting(MoveOrder one, MoveOrder two) => one != two @@ -174,7 +174,7 @@ public class MovementDecisions // Ensure a hold strength decision exists for the target's province. HoldStrength.Ensure(UnitPoint(support.Target), () => new( - world.Map.GetLocation(support.Target.Location).Province, + support.Target.GetProvince(world), support.Target.Season)); if (support is SupportHoldOrder supportHold) diff --git a/MultiversalDiplomacy/Adjudicate/MovementPhaseAdjudicator.cs b/MultiversalDiplomacy/Adjudicate/MovementPhaseAdjudicator.cs index 75bf374..4b8b667 100644 --- a/MultiversalDiplomacy/Adjudicate/MovementPhaseAdjudicator.cs +++ b/MultiversalDiplomacy/Adjudicate/MovementPhaseAdjudicator.cs @@ -92,7 +92,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator ILookup moveOrdersByAdjacency = moveOrders .ToLookup(order => // Map adjacency - world.Map.GetLocation(order.Unit).Adjacents.Select(loc => loc.Key).Contains(order.Location) + order.Unit.GetLocation(world).Adjacents.Select(loc => loc.Key).Contains(order.Location) // Turn adjacency && Math.Abs(order.Unit.Season.Turn - order.Season.Turn) <= 1 // Timeline adjacency @@ -177,8 +177,8 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator AdjudicatorHelpers.InvalidateIfNotMatching( order => // Map adjacency with respect to province - world.Map.GetLocation(order.Unit).Adjacents.Any( - adjLocation => adjLocation.Province == world.Map.GetLocation(order.Target).Province) + order.Unit.GetLocation(world).Adjacents.Any( + adjLocation => adjLocation.Province == order.Target.GetLocation(world).Province) // Turn adjacency && Math.Abs(order.Unit.Season.Turn - order.Target.Season.Turn) <= 1 // Timeline adjacency @@ -197,7 +197,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator // Support-move orders are invalid if the unit supports a move to any location in its own // province. AdjudicatorHelpers.InvalidateIfNotMatching( - order => world.Map.GetLocation(order.Unit).Province != order.Province, + order => order.Unit.GetProvince(world) != order.Province, ValidationReason.NoSupportMoveAgainstSelf, ref supportMoveOrders, ref validationResults); @@ -209,7 +209,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator AdjudicatorHelpers.InvalidateIfNotMatching( order => // Map adjacency with respect to province - world.Map.GetLocation(order.Unit).Adjacents.Any( + order.Unit.GetLocation(world).Adjacents.Any( adjLocation => adjLocation.Province == order.Province) // Turn adjacency && Math.Abs(order.Unit.Season.Turn - order.Season.Turn) <= 1 @@ -370,7 +370,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator if (isDislodged.Outcome == false) { // Non-dislodged units continue into the future. - Unit next = order.Unit.Next(world.Map.GetLocation(order.Unit).Key, future); + Unit next = order.Unit.Next(order.Unit.GetLocation(world).Key, future); logger.Log(3, "Advancing unit to {0}", next); createdUnits.Add(next); } @@ -379,7 +379,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator // Create a retreat for each dislodged unit. // TODO check valid retreats and disbands logger.Log(3, "Creating retreat for {0}", order.Unit); - var validRetreats = world.Map.GetLocation(order.Unit).Adjacents + var validRetreats = order.Unit.GetLocation(world).Adjacents .Select(loc => (future, loc)) .ToList(); RetreatingUnit retreat = new(order.Unit, validRetreats); @@ -640,7 +640,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator // If the origin and destination are adjacent, then there is a path. if (// Map adjacency - world.Map.GetLocation(decision.Order.Unit).Adjacents.Select(loc => loc.Key).Contains(decision.Order.Location) + decision.Order.Unit.GetLocation(world).Adjacents.Select(loc => loc.Key).Contains(decision.Order.Location) // Turn adjacency && Math.Abs(decision.Order.Unit.Season.Turn - decision.Order.Season.Turn) <= 1 // Timeline adjacency diff --git a/MultiversalDiplomacy/Adjudicate/PathFinder.cs b/MultiversalDiplomacy/Adjudicate/PathFinder.cs index 50b8868..e64d5e2 100644 --- a/MultiversalDiplomacy/Adjudicate/PathFinder.cs +++ b/MultiversalDiplomacy/Adjudicate/PathFinder.cs @@ -12,7 +12,7 @@ public static class PathFinder /// Determines if a convoy path exists for a move in a convoy order. /// public static bool ConvoyPathExists(World world, ConvoyOrder order) - => ConvoyPathExists(world, world.Map.GetLocation(order.Target), order.Location, order.Season); + => ConvoyPathExists(world, order.Target.GetLocation(world), order.Location, order.Season); /// /// Determines if a convoy path exists for a move order. @@ -20,7 +20,7 @@ public static class PathFinder public static bool ConvoyPathExists(World world, MoveOrder order) => ConvoyPathExists( world, - world.Map.GetLocation(order.Unit), + order.Unit.GetLocation(world), world.Map.GetLocation(order.Location), order.Season); diff --git a/MultiversalDiplomacy/Model/Map.cs b/MultiversalDiplomacy/Model/Map.cs index d1f76a0..3fd0277 100644 --- a/MultiversalDiplomacy/Model/Map.cs +++ b/MultiversalDiplomacy/Model/Map.cs @@ -72,9 +72,6 @@ public class Map public Location GetLocation(string designation) => LocationLookup[designation]; - public Location GetLocation(Unit unit) - => GetLocation(unit.Location); - /// /// Get the sole land location of a province. /// diff --git a/MultiversalDiplomacy/Model/OrderParser.cs b/MultiversalDiplomacy/Model/OrderParser.cs index b8c223d..6a9e01b 100644 --- a/MultiversalDiplomacy/Model/OrderParser.cs +++ b/MultiversalDiplomacy/Model/OrderParser.cs @@ -259,7 +259,7 @@ public class OrderParser(World world) // and the location is ignored. This also satisfies DATC 4.B.5, which requires that a wrong coast for the // subject be ignored. subject = world.Units.FirstOrDefault(unit - => world.Map.GetLocation(unit!.Location).ProvinceName == province.Name + => unit!.GetProvince(world).Name == province.Name && unit!.Season.Timeline == timeline && unit!.Season.Turn == turn, null); @@ -338,7 +338,7 @@ public class OrderParser(World world) // If the order location didn't disambiguate the coasts, either because it's missing or it's nonsense, the // order can be disambiguated by there being one accessible coast from the order source. if (destLocationKey is null) { - Location source = world.Map.GetLocation(subject.Location); + Location source = subject.GetLocation(world); var accessibleLocations = destProvince.Locations.Where(loc => loc.Adjacents.Contains(source)); if (accessibleLocations.Count() == 1) destLocationKey ??= accessibleLocations.Single().Key; } @@ -434,7 +434,7 @@ public class OrderParser(World world) // If the order location didn't disambiguate the coasts, either because it's missing or it's nonsense, the // order can be disambiguated by there being one accessible coast from the order source. if (destLocationKey is null) { - Location source = world.Map.GetLocation(target.Location); + Location source = target.GetLocation(world); var accessibleLocations = destProvince.Locations.Where(loc => loc.Adjacents.Contains(source)); if (accessibleLocations.Count() == 1) destLocationKey ??= accessibleLocations.Single().Key; } diff --git a/MultiversalDiplomacy/Model/Unit.cs b/MultiversalDiplomacy/Model/Unit.cs index cba5d0c..305d39f 100644 --- a/MultiversalDiplomacy/Model/Unit.cs +++ b/MultiversalDiplomacy/Model/Unit.cs @@ -62,4 +62,8 @@ public class Unit /// public Unit Next(string location, Season season) => new(past: this.Key, location, season, this.Power, this.Type); + + public Location GetLocation(World world) => world.Map.GetLocation(Location); + + public Province GetProvince(World world) => GetLocation(world).Province; } diff --git a/MultiversalDiplomacy/Model/World.cs b/MultiversalDiplomacy/Model/World.cs index 4aa6b9f..db4d3e9 100644 --- a/MultiversalDiplomacy/Model/World.cs +++ b/MultiversalDiplomacy/Model/World.cs @@ -231,7 +231,7 @@ public class World Province province = Map.GetProvince(provinceName); season ??= Season.First; Unit? foundUnit = this.Units.SingleOrDefault( - u => Map.GetLocation(u!).Province == province && u!.Season == season, + u => u!.GetProvince(this) == province && u!.Season == season, null) ?? throw new KeyNotFoundException($"Unit at {province} at {season} not found"); return foundUnit; diff --git a/MultiversalDiplomacy/Script/AdjudicationQueryScriptHandler.cs b/MultiversalDiplomacy/Script/AdjudicationQueryScriptHandler.cs index 5128a64..43ca9e3 100644 --- a/MultiversalDiplomacy/Script/AdjudicationQueryScriptHandler.cs +++ b/MultiversalDiplomacy/Script/AdjudicationQueryScriptHandler.cs @@ -100,7 +100,7 @@ public class AdjudicationQueryScriptHandler( => val.Valid && val.Order is HoldOrder hold && hold.Unit.Season == season - && World.Map.GetLocation(hold.Unit.Location).ProvinceName == province.Name); + && hold.Unit.GetProvince(World).Name == province.Name); if (!matchingHolds.Any()) return ScriptResult.Fail("No matching holds"); return ScriptResult.Succeed(this); @@ -129,7 +129,7 @@ public class AdjudicationQueryScriptHandler( var matching = Validations.Where(val => val.Order is UnitOrder order && order.Unit.Season == season - && World.Map.GetLocation(order.Unit.Location).ProvinceName == province.Name); + && order.Unit.GetProvince(World).Name == province.Name); if (!matching.Any()) return ScriptResult.Fail("No matching validations"); if (args[0] == "order-valid" && !matching.First().Valid) { @@ -181,7 +181,7 @@ public class AdjudicationQueryScriptHandler( var matchingDislodges = Adjudications.Where(adj => adj is IsDislodged dislodge && dislodge.Order.Unit.Season == season - && World.Map.GetLocation(dislodge.Order.Unit.Location).ProvinceName == province.Name); + && dislodge.Order.Unit.GetProvince(World).Name == province.Name); if (!matchingDislodges.Any()) return ScriptResult.Fail("No matching dislodge decisions"); var isDislodged = matchingDislodges.Cast().First(); @@ -219,7 +219,7 @@ public class AdjudicationQueryScriptHandler( var matchingMoves = Adjudications.Where(adj => adj is DoesMove moves && moves.Order.Unit.Season == season - && World.Map.GetLocation(moves.Order.Unit.Location).ProvinceName == province.Name); + && moves.Order.Unit.GetProvince(World).Name == province.Name); if (!matchingMoves.Any()) return ScriptResult.Fail("No matching movement decisions"); var doesMove = matchingMoves.Cast().First(); @@ -257,7 +257,7 @@ public class AdjudicationQueryScriptHandler( var matchingSupports = Adjudications.Where(adj => adj is GivesSupport sup && sup.Order.Unit.Season == season - && World.Map.GetLocation(sup.Order.Unit.Location).ProvinceName == province.Name); + && sup.Order.Unit.GetProvince(World).Name == province.Name); if (!matchingSupports.Any()) return ScriptResult.Fail("No matching support decisions"); var supports = matchingSupports.Cast().First(); diff --git a/MultiversalDiplomacyTests/OrderReference.cs b/MultiversalDiplomacyTests/OrderReference.cs index f5fff03..e058cfc 100644 --- a/MultiversalDiplomacyTests/OrderReference.cs +++ b/MultiversalDiplomacyTests/OrderReference.cs @@ -108,7 +108,7 @@ public abstract class OrderReference DefendStrength defend => defend.Order == this.Order, PreventStrength prevent => prevent.Order == this.Order, HoldStrength hold => this.Order is UnitOrder unitOrder - && hold.Province == Builder.World.Map.GetLocation(unitOrder.Unit).Province, + && hold.Province == unitOrder.Unit.GetProvince(Builder.World), _ => false, }).ToList(); return adjudications; diff --git a/MultiversalDiplomacyTests/TestCaseBuilder.cs b/MultiversalDiplomacyTests/TestCaseBuilder.cs index c6148d2..d0c0208 100644 --- a/MultiversalDiplomacyTests/TestCaseBuilder.cs +++ b/MultiversalDiplomacyTests/TestCaseBuilder.cs @@ -263,7 +263,7 @@ public class TestCaseBuilder foreach (Unit unit in this.World.Units) { if (unit.Power == power - && World.Map.GetLocation(unit).Province == location.Province + && unit.GetProvince(World) == location.Province && unit.Season == season) { return unit; diff --git a/MultiversalDiplomacyTests/TestCaseBuilderTest.cs b/MultiversalDiplomacyTests/TestCaseBuilderTest.cs index d653cf1..c7b93f5 100644 --- a/MultiversalDiplomacyTests/TestCaseBuilderTest.cs +++ b/MultiversalDiplomacyTests/TestCaseBuilderTest.cs @@ -68,7 +68,7 @@ class TestCaseBuilderTest List orders = setup.Orders.OfType().ToList(); Func OrderForProvince(string name) - => order => setup.World.Map.GetLocation(order.Unit).Province.Name == name; + => order => order.Unit.GetProvince(setup.World).Name == name; UnitOrder orderBer = orders.Single(OrderForProvince("Berlin")); Assert.That(orderBer, Is.InstanceOf(), "Unexpected order type");