Reduce MoveOrder.Location to string

This commit is contained in:
Tim Van Baak 2024-08-15 22:00:25 -07:00
parent f21b1e500c
commit 889e9d173b
8 changed files with 43 additions and 34 deletions

View File

@ -1,6 +1,8 @@
using MultiversalDiplomacy.Model; using MultiversalDiplomacy.Model;
using MultiversalDiplomacy.Orders; using MultiversalDiplomacy.Orders;
using static MultiversalDiplomacy.Model.Location;
namespace MultiversalDiplomacy.Adjudicate.Decision; namespace MultiversalDiplomacy.Adjudicate.Decision;
public class MovementDecisions public class MovementDecisions
@ -94,7 +96,7 @@ public class MovementDecisions
(string province, string season) UnitPoint(Unit unit) (string province, string season) UnitPoint(Unit unit)
=> (world.Map.GetLocation(unit.Location).Province.Name, unit.Season.Key); => (world.Map.GetLocation(unit.Location).Province.Name, unit.Season.Key);
(string province, string season) MovePoint(MoveOrder move) (string province, string season) MovePoint(MoveOrder move)
=> (move.Location.Province.Name, move.Season.Key); => (SplitKey(move.Location).province, move.Season.Key);
// Create a hold strength decision with an associated order for every province with a unit. // Create a hold strength decision with an associated order for every province with a unit.
foreach (UnitOrder order in relevantOrders) foreach (UnitOrder order in relevantOrders)
@ -108,13 +110,23 @@ public class MovementDecisions
bool IsIncoming(UnitOrder me, MoveOrder other) bool IsIncoming(UnitOrder me, MoveOrder other)
=> me != other => me != other
&& other.Season == me.Unit.Season && other.Season == me.Unit.Season
&& other.Location.Province.Name == world.Map.GetLocation(me.Unit).Province.Name; && SplitKey(other.Location).province == world.Map.GetLocation(me.Unit).Province.Name;
bool IsSupportFor(SupportMoveOrder me, MoveOrder move)
=> me.Target == move.Unit
&& me.Season == move.Season
&& me.Location.Key == move.Location;
bool AreOpposing(MoveOrder one, MoveOrder two) bool AreOpposing(MoveOrder one, MoveOrder two)
=> one.Season == two.Unit.Season => one.Season == two.Unit.Season
&& two.Season == one.Unit.Season && two.Season == one.Unit.Season
&& one.Location.Province.Name == world.Map.GetLocation(two.Unit).Province.Name && SplitKey(one.Location).province == world.Map.GetLocation(two.Unit).Province.Name
&& two.Location.Province.Name == world.Map.GetLocation(one.Unit).Province.Name; && SplitKey(two.Location).province == world.Map.GetLocation(one.Unit).Province.Name;
bool AreCompeting(MoveOrder one, MoveOrder two)
=> one != two
&& one.Season == two.Season
&& SplitKey(one.Location).province == SplitKey(two.Location).province;
// Create all other relevant decisions for each order in the affected timelines. // Create all other relevant decisions for each order in the affected timelines.
foreach (UnitOrder order in relevantOrders) foreach (UnitOrder order in relevantOrders)
@ -131,7 +143,7 @@ public class MovementDecisions
// Find supports corresponding to this move. // Find supports corresponding to this move.
List<SupportMoveOrder> supports = relevantOrders List<SupportMoveOrder> supports = relevantOrders
.OfType<SupportMoveOrder>() .OfType<SupportMoveOrder>()
.Where(support => support.IsSupportFor(move)) .Where(support => IsSupportFor(support, move))
.ToList(); .ToList();
// Determine if this move is a head-to-head battle. // Determine if this move is a head-to-head battle.
@ -142,7 +154,7 @@ public class MovementDecisions
// Find competing moves. // Find competing moves.
List<MoveOrder> competing = relevantOrders List<MoveOrder> competing = relevantOrders
.OfType<MoveOrder>() .OfType<MoveOrder>()
.Where(move.IsCompeting) .Where(other => AreCompeting(move, other))
.ToList(); .ToList();
// Create the move-related decisions. // Create the move-related decisions.
@ -153,7 +165,7 @@ public class MovementDecisions
DoesMove[move] = new(move, opposingMove, competing); DoesMove[move] = new(move, opposingMove, competing);
// Ensure a hold strength decision exists for the destination. // Ensure a hold strength decision exists for the destination.
HoldStrength.Ensure(MovePoint(move), () => new(move.Location.Province, move.Season)); HoldStrength.Ensure(MovePoint(move), () => new(world.Map.GetLocation(move.Location).Province, move.Season));
} }
else if (order is SupportOrder support) else if (order is SupportOrder support)
{ {

View File

@ -3,6 +3,8 @@ using MultiversalDiplomacy.Adjudicate.Logging;
using MultiversalDiplomacy.Model; using MultiversalDiplomacy.Model;
using MultiversalDiplomacy.Orders; using MultiversalDiplomacy.Orders;
using static MultiversalDiplomacy.Model.Location;
namespace MultiversalDiplomacy.Adjudicate; namespace MultiversalDiplomacy.Adjudicate;
/// <summary> /// <summary>
@ -69,15 +71,15 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
// Trivial check: armies cannot move to water and fleets cannot move to land. // Trivial check: armies cannot move to water and fleets cannot move to land.
AdjudicatorHelpers.InvalidateIfNotMatching( AdjudicatorHelpers.InvalidateIfNotMatching(
order => (order.Unit.Type == UnitType.Army && order.Location.Type == LocationType.Land) order => (order.Unit.Type == UnitType.Army && world.Map.GetLocation(order.Location).Type == LocationType.Land)
|| (order.Unit.Type == UnitType.Fleet && order.Location.Type == LocationType.Water), || (order.Unit.Type == UnitType.Fleet && world.Map.GetLocation(order.Location).Type == LocationType.Water),
ValidationReason.IllegalDestinationType, ValidationReason.IllegalDestinationType,
ref moveOrders, ref moveOrders,
ref validationResults); ref validationResults);
// Trivial check: a unit cannot move to where it already is. // Trivial check: a unit cannot move to where it already is.
AdjudicatorHelpers.InvalidateIfNotMatching( AdjudicatorHelpers.InvalidateIfNotMatching(
order => !(order.Location.Key == order.Unit.Location && order.Season == order.Unit.Season), order => !(order.Location == order.Unit.Location && order.Season == order.Unit.Season),
ValidationReason.DestinationMatchesOrigin, ValidationReason.DestinationMatchesOrigin,
ref moveOrders, ref moveOrders,
ref validationResults); ref validationResults);
@ -90,7 +92,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
ILookup<bool, MoveOrder> moveOrdersByAdjacency = moveOrders ILookup<bool, MoveOrder> moveOrdersByAdjacency = moveOrders
.ToLookup(order => .ToLookup(order =>
// Map adjacency // Map adjacency
world.Map.GetLocation(order.Unit).Adjacents.Contains(order.Location) world.Map.GetLocation(order.Unit).Adjacents.Select(loc => loc.Key).Contains(order.Location)
// Turn adjacency // Turn adjacency
&& Math.Abs(order.Unit.Season.Turn - order.Season.Turn) <= 1 && Math.Abs(order.Unit.Season.Turn - order.Season.Turn) <= 1
// Timeline adjacency // Timeline adjacency
@ -339,7 +341,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
Season moveSeason = doesMove.Order.Season; Season moveSeason = doesMove.Order.Season;
if (doesMove.Outcome == true && createdFutures.TryGetValue(moveSeason, out Season future)) if (doesMove.Outcome == true && createdFutures.TryGetValue(moveSeason, out Season future))
{ {
Unit next = doesMove.Order.Unit.Next(doesMove.Order.Location.Key, future); Unit next = doesMove.Order.Unit.Next(doesMove.Order.Location, future);
logger.Log(3, "Advancing unit to {0}", next); logger.Log(3, "Advancing unit to {0}", next);
createdUnits.Add(next); createdUnits.Add(next);
} }
@ -635,7 +637,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
// If the origin and destination are adjacent, then there is a path. // If the origin and destination are adjacent, then there is a path.
if (// Map adjacency if (// Map adjacency
world.Map.GetLocation(decision.Order.Unit).Adjacents.Contains(decision.Order.Location) world.Map.GetLocation(decision.Order.Unit).Adjacents.Select(loc => loc.Key).Contains(decision.Order.Location)
// Turn adjacency // Turn adjacency
&& Math.Abs(decision.Order.Unit.Season.Turn - decision.Order.Season.Turn) <= 1 && Math.Abs(decision.Order.Unit.Season.Turn - decision.Order.Season.Turn) <= 1
// Timeline adjacency // Timeline adjacency
@ -776,7 +778,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
// If there is a head to head battle, a unit at the destination that isn't moving away, or // If there is a head to head battle, a unit at the destination that isn't moving away, or
// a unit at the destination that will fail to move away, then the attacking unit will have // a unit at the destination that will fail to move away, then the attacking unit will have
// to dislodge it. // to dislodge it.
UnitOrder? destOrder = decisions.HoldStrength[(decision.Order.Location.Province.Name, decision.Order.Season.Key)].Order; UnitOrder? destOrder = decisions.HoldStrength[(SplitKey(decision.Order.Location).province, decision.Order.Season.Key)].Order;
DoesMove? destMoveAway = destOrder is MoveOrder moveAway DoesMove? destMoveAway = destOrder is MoveOrder moveAway
? decisions.DoesMove[moveAway] ? decisions.DoesMove[moveAway]
: null; : null;
@ -955,7 +957,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
// strength. // strength.
NumericAdjudicationDecision defense = decision.OpposingMove != null NumericAdjudicationDecision defense = decision.OpposingMove != null
? decisions.DefendStrength[decision.OpposingMove] ? decisions.DefendStrength[decision.OpposingMove]
: decisions.HoldStrength[(decision.Order.Location.Province.Name, decision.Order.Season.Key)]; : decisions.HoldStrength[(SplitKey(decision.Order.Location).province, decision.Order.Season.Key)];
progress |= ResolveDecision(defense, world, decisions, depth + 1); progress |= ResolveDecision(defense, world, decisions, depth + 1);
// If the attack doesn't beat the defense, resolve the move to false. // If the attack doesn't beat the defense, resolve the move to false.

View File

@ -18,7 +18,7 @@ public static class PathFinder
/// Determines if a convoy path exists for a move order. /// Determines if a convoy path exists for a move order.
/// </summary> /// </summary>
public static bool ConvoyPathExists(World world, MoveOrder order) public static bool ConvoyPathExists(World world, MoveOrder order)
=> ConvoyPathExists(world, order.Unit, order.Location, order.Season); => ConvoyPathExists(world, order.Unit, world.Map.GetLocation(order.Location), order.Season);
private static bool ConvoyPathExists( private static bool ConvoyPathExists(
World world, World world,

View File

@ -53,6 +53,12 @@ public class Location
this.AdjacentList = new List<Location>(); this.AdjacentList = new List<Location>();
} }
public static (string province, string location) SplitKey(string locationKey)
{
var split = locationKey.Split(['/'], 2);
return (split[0], split[1]);
}
public override string ToString() public override string ToString()
{ {
return this.Name == "land" || this.Name == "water" return this.Name == "land" || this.Name == "water"

View File

@ -1,5 +1,7 @@
using MultiversalDiplomacy.Model; using MultiversalDiplomacy.Model;
using static MultiversalDiplomacy.Model.Location;
namespace MultiversalDiplomacy.Orders; namespace MultiversalDiplomacy.Orders;
/// <summary> /// <summary>
@ -15,9 +17,9 @@ public class MoveOrder : UnitOrder
/// <summary> /// <summary>
/// The destination location to which the unit should move. /// The destination location to which the unit should move.
/// </summary> /// </summary>
public Location Location { get; } public string Location { get; }
public MoveOrder(string power, Unit unit, Season season, Location location) public MoveOrder(string power, Unit unit, Season season, string location)
: base (power, unit) : base (power, unit)
{ {
this.Season = season; this.Season = season;
@ -26,14 +28,6 @@ public class MoveOrder : UnitOrder
public override string ToString() public override string ToString()
{ {
return $"{this.Unit} -> {Season.Timeline}-{Location.Province}@{Season.Turn}"; return $"{this.Unit} -> {Season.Timeline}-{SplitKey(Location).province}@{Season.Turn}";
} }
/// <summary>
/// Returns whether another move order has the same destination as this order.
/// </summary>
public bool IsCompeting(MoveOrder other)
=> this != other
&& this.Season == other.Season
&& this.Location.Province == other.Location.Province;
} }

View File

@ -38,9 +38,4 @@ public class SupportMoveOrder : SupportOrder
{ {
return $"{this.Unit} S {this.Target} -> {(this.Province, this.Season).ToShort()}"; return $"{this.Unit} S {this.Target} -> {(this.Province, this.Season).ToShort()}";
} }
public bool IsSupportFor(MoveOrder move)
=> this.Target == move.Unit
&& this.Season == move.Season
&& this.Location == move.Location;
} }

View File

@ -423,7 +423,7 @@ public class TestCaseBuilder
this.PowerContext.Power, this.PowerContext.Power,
this.Unit, this.Unit,
destSeason, destSeason,
destination); destination.Key);
this.Builder.OrderList.Add(moveOrder); this.Builder.OrderList.Add(moveOrder);
return new OrderDefinedContext<MoveOrder>(this, moveOrder); return new OrderDefinedContext<MoveOrder>(this, moveOrder);
} }

View File

@ -74,7 +74,7 @@ class TestCaseBuilderTest
Assert.That(orderBer, Is.InstanceOf<MoveOrder>(), "Unexpected order type"); Assert.That(orderBer, Is.InstanceOf<MoveOrder>(), "Unexpected order type");
Assert.That( Assert.That(
(orderBer as MoveOrder)?.Location, (orderBer as MoveOrder)?.Location,
Is.EqualTo(setup.World.Map.GetLand("Kiel")), Is.EqualTo(setup.World.Map.GetLand("Kiel").Key),
"Unexpected move order destination"); "Unexpected move order destination");
UnitOrder orderPru = orders.Single(OrderForProvince("Prussia")); UnitOrder orderPru = orders.Single(OrderForProvince("Prussia"));