Shift usage of Unit.Location to Unit.LocationId
This is in preparation for removing province and location references from Unit
This commit is contained in:
parent
442015b942
commit
abaa7f7a92
@ -77,7 +77,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||
|
||||
// Trivial check: a unit cannot move to where it already is.
|
||||
AdjudicatorHelpers.InvalidateIfNotMatching(
|
||||
order => !(order.Location == order.Unit.Location && order.Season == order.Unit.Season),
|
||||
order => !(order.Location.Designation == order.Unit.LocationId && order.Season == order.Unit.Season),
|
||||
ValidationReason.DestinationMatchesOrigin,
|
||||
ref moveOrders,
|
||||
ref validationResults);
|
||||
@ -90,7 +90,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||
ILookup<bool, MoveOrder> moveOrdersByAdjacency = moveOrders
|
||||
.ToLookup(order =>
|
||||
// Map adjacency
|
||||
order.Unit.Location.Adjacents.Contains(order.Location)
|
||||
world.Map.GetLocation(order.Unit).Adjacents.Contains(order.Location)
|
||||
// Turn adjacency
|
||||
&& Math.Abs(order.Unit.Season.Turn - order.Season.Turn) <= 1
|
||||
// Timeline adjacency
|
||||
@ -138,7 +138,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||
// Trivial check: cannot convoy a unit to its own location
|
||||
AdjudicatorHelpers.InvalidateIfNotMatching(
|
||||
order => !(
|
||||
order.Location == order.Target.Location
|
||||
order.Location.Designation == order.Target.LocationId
|
||||
&& order.Season == order.Target.Season),
|
||||
ValidationReason.DestinationMatchesOrigin,
|
||||
ref convoyOrders,
|
||||
@ -175,8 +175,8 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||
AdjudicatorHelpers.InvalidateIfNotMatching(
|
||||
order =>
|
||||
// Map adjacency with respect to province
|
||||
order.Unit.Location.Adjacents.Any(
|
||||
adjLocation => adjLocation.Province == order.Target.Province)
|
||||
world.Map.GetLocation(order.Unit).Adjacents.Any(
|
||||
adjLocation => adjLocation.Province == world.Map.GetLocation(order.Target).Province)
|
||||
// Turn adjacency
|
||||
&& Math.Abs(order.Unit.Season.Turn - order.Target.Season.Turn) <= 1
|
||||
// Timeline adjacency
|
||||
@ -195,7 +195,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 => order.Unit.Province != order.Province,
|
||||
order => world.Map.GetLocation(order.Unit).Province != order.Province,
|
||||
ValidationReason.NoSupportMoveAgainstSelf,
|
||||
ref supportMoveOrders,
|
||||
ref validationResults);
|
||||
@ -207,7 +207,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||
AdjudicatorHelpers.InvalidateIfNotMatching(
|
||||
order =>
|
||||
// Map adjacency with respect to province
|
||||
order.Unit.Location.Adjacents.Any(
|
||||
world.Map.GetLocation(order.Unit).Adjacents.Any(
|
||||
adjLocation => adjLocation.Province == order.Province)
|
||||
// Turn adjacency
|
||||
&& Math.Abs(order.Unit.Season.Turn - order.Season.Turn) <= 1
|
||||
@ -366,7 +366,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||
if (isDislodged.Outcome == false)
|
||||
{
|
||||
// Non-dislodged units continue into the future.
|
||||
Unit next = order.Unit.Next(order.Unit.Location, future);
|
||||
Unit next = order.Unit.Next(world.Map.GetLocation(order.Unit), future);
|
||||
logger.Log(3, "Advancing unit to {0}", next);
|
||||
createdUnits.Add(next);
|
||||
}
|
||||
@ -375,7 +375,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 = order.Unit.Location.Adjacents
|
||||
var validRetreats = world.Map.GetLocation(order.Unit).Adjacents
|
||||
.Select(loc => (future, loc))
|
||||
.ToList();
|
||||
RetreatingUnit retreat = new(order.Unit, validRetreats);
|
||||
@ -633,7 +633,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||
|
||||
// If the origin and destination are adjacent, then there is a path.
|
||||
if (// Map adjacency
|
||||
decision.Order.Unit.Location.Adjacents.Contains(decision.Order.Location)
|
||||
world.Map.GetLocation(decision.Order.Unit).Adjacents.Contains(decision.Order.Location)
|
||||
// Turn adjacency
|
||||
&& Math.Abs(decision.Order.Unit.Season.Turn - decision.Order.Season.Turn) <= 1
|
||||
// Timeline adjacency
|
||||
|
@ -30,13 +30,13 @@ public static class PathFinder
|
||||
// also have coasts, and between those coasts there is a path of adjacent sea provinces
|
||||
// (not coastal) that are occupied by fleets. The move order is valid even if the fleets
|
||||
// belong to another power or were not given convoy orders; it will simply fail.
|
||||
IDictionary<(Location location, Season season), Unit> fleets = world.Units
|
||||
IDictionary<(string location, Season season), Unit> fleets = world.Units
|
||||
.Where(unit => unit.Type == UnitType.Fleet)
|
||||
.ToDictionary(unit => (unit.Location, unit.Season));
|
||||
.ToDictionary(unit => (unit.LocationId, unit.Season));
|
||||
|
||||
// Verify that the origin is a coastal province.
|
||||
if (movingUnit.Location.Type != LocationType.Land) return false;
|
||||
IEnumerable<Location> originCoasts = movingUnit.Province.Locations
|
||||
if (world.Map.GetLocation(movingUnit).Type != LocationType.Land) return false;
|
||||
IEnumerable<Location> originCoasts = world.Map.GetLocation(movingUnit).Province.Locations
|
||||
.Where(location => location.Type == LocationType.Water);
|
||||
if (!originCoasts.Any()) return false;
|
||||
|
||||
@ -69,7 +69,7 @@ public static class PathFinder
|
||||
// If not, add this location to the to-visit set if it isn't a coast, has a fleet,
|
||||
// and hasn't already been visited.
|
||||
if (!adjLocation.Province.Locations.Any(l => l.Type == LocationType.Land)
|
||||
&& fleets.ContainsKey((adjLocation, adjSeason))
|
||||
&& fleets.ContainsKey((adjLocation.Designation, adjSeason))
|
||||
&& !visited.Contains((adjLocation, adjSeason)))
|
||||
{
|
||||
toVisit.Enqueue((adjLocation, adjSeason));
|
||||
|
@ -39,6 +39,11 @@ public class Location
|
||||
public IEnumerable<Location> Adjacents => this.AdjacentList;
|
||||
private List<Location> AdjacentList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The unique name of this location in the map.
|
||||
/// </summary>
|
||||
public string Designation => $"{this.ProvinceName}/{this.Abbreviation}";
|
||||
|
||||
public Location(Province province, string name, string abbreviation, LocationType type)
|
||||
{
|
||||
this.Province = province;
|
||||
|
@ -17,6 +17,8 @@ public class Map
|
||||
|
||||
private List<Province> _Provinces { get; }
|
||||
|
||||
private Dictionary<string, Location> LocationLookup { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The game powers.
|
||||
/// </summary>
|
||||
@ -29,6 +31,10 @@ public class Map
|
||||
Type = type;
|
||||
_Provinces = provinces.ToList();
|
||||
_Powers = powers.ToList();
|
||||
|
||||
LocationLookup = Provinces
|
||||
.SelectMany(province => province.Locations)
|
||||
.ToDictionary(location => location.Designation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -41,29 +47,27 @@ public class Map
|
||||
/// Get a province by name. Throws if the province is not found.
|
||||
/// </summary>
|
||||
private static Province GetProvince(string provinceName, IEnumerable<Province> provinces)
|
||||
{
|
||||
string provinceNameUpper = provinceName.ToUpperInvariant();
|
||||
Province? foundProvince = provinces.SingleOrDefault(
|
||||
p => p!.Name.ToUpperInvariant() == provinceNameUpper
|
||||
|| p.Abbreviations.Any(a => a.ToUpperInvariant() == provinceNameUpper),
|
||||
null);
|
||||
if (foundProvince == null) throw new KeyNotFoundException(
|
||||
$"Province {provinceName} not found");
|
||||
return foundProvince;
|
||||
}
|
||||
=> provinces.SingleOrDefault(
|
||||
p => p!.Name.Equals(provinceName, StringComparison.InvariantCultureIgnoreCase)
|
||||
|| p.Abbreviations.Any(
|
||||
a => a.Equals(provinceName, StringComparison.InvariantCultureIgnoreCase)),
|
||||
null)
|
||||
?? throw new KeyNotFoundException($"Province {provinceName} not found");
|
||||
|
||||
/// <summary>
|
||||
/// Get the location in a province matching a predicate. Throws if there is not exactly one
|
||||
/// such location.
|
||||
/// </summary>
|
||||
private Location GetLocation(string provinceName, Func<Location, bool> predicate)
|
||||
{
|
||||
Location? foundLocation = GetProvince(provinceName).Locations.SingleOrDefault(
|
||||
l => l != null && predicate(l), null);
|
||||
if (foundLocation == null) throw new KeyNotFoundException(
|
||||
$"No such location in {provinceName}");
|
||||
return foundLocation;
|
||||
}
|
||||
=> GetProvince(provinceName).Locations.SingleOrDefault(
|
||||
l => l != null && predicate(l), null)
|
||||
?? throw new KeyNotFoundException($"No such location in {provinceName}");
|
||||
|
||||
public Location GetLocation(string designation)
|
||||
=> LocationLookup[designation];
|
||||
|
||||
public Location GetLocation(Unit unit)
|
||||
=> GetLocation(unit.LocationId);
|
||||
|
||||
/// <summary>
|
||||
/// Get the sole land location of a province.
|
||||
|
@ -17,6 +17,8 @@ public class Unit
|
||||
/// </summary>
|
||||
public Location Location { get; }
|
||||
|
||||
public string LocationId => Location.Designation;
|
||||
|
||||
/// <summary>
|
||||
/// The province where the unit is.
|
||||
/// </summary>
|
||||
|
@ -328,7 +328,7 @@ public class World
|
||||
Province province = Map.GetProvince(provinceName);
|
||||
season ??= RootSeason;
|
||||
Unit? foundUnit = this.Units.SingleOrDefault(
|
||||
u => u!.Province == province && u.Season == season,
|
||||
u => Map.GetLocation(u!).Province == province && u!.Season == season,
|
||||
null)
|
||||
?? throw new KeyNotFoundException($"Unit at {province} at {season} not found");
|
||||
return foundUnit;
|
||||
|
@ -179,7 +179,7 @@ public class MovementAdjudicatorTest
|
||||
// Confirm the unit was created
|
||||
Assert.That(updated.Units.Count, Is.EqualTo(2));
|
||||
Unit second = updated.Units.Single(u => u.Past != null);
|
||||
Assert.That(second.Location, Is.EqualTo(mun.Order.Unit.Location));
|
||||
Assert.That(second.LocationId, Is.EqualTo(mun.Order.Unit.LocationId));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -39,8 +39,8 @@ class TestCaseBuilderTest
|
||||
Assert.That(fleetSTP.Power.Name, Is.EqualTo("Russia"), "Unit created with wrong power");
|
||||
Assert.That(fleetSTP.Type, Is.EqualTo(UnitType.Fleet), "Unit created with wrong type");
|
||||
Assert.That(
|
||||
fleetSTP.Location,
|
||||
Is.EqualTo(setup.World.Map.GetWater("STP", "wc")),
|
||||
fleetSTP.LocationId,
|
||||
Is.EqualTo(setup.World.Map.GetWater("STP", "wc").Designation),
|
||||
"Unit created on wrong coast");
|
||||
}
|
||||
|
||||
@ -127,8 +127,8 @@ class TestCaseBuilderTest
|
||||
Is.EqualTo(setup.World.Map.GetPower("Germany")),
|
||||
"Wrong power");
|
||||
Assert.That(
|
||||
orderMun.Order.Unit.Location,
|
||||
Is.EqualTo(setup.World.Map.GetLand("Mun")),
|
||||
orderMun.Order.Unit.LocationId,
|
||||
Is.EqualTo(setup.World.Map.GetLand("Mun").Designation),
|
||||
"Wrong unit");
|
||||
|
||||
Assert.That(
|
||||
|
@ -31,8 +31,8 @@ public class UnitTests
|
||||
Assert.That(u2.Season, Is.EqualTo(a1), "Unexpected unit season");
|
||||
Assert.That(u3.Season, Is.EqualTo(a2), "Unexpected unit season");
|
||||
|
||||
Assert.That(u1.Location, Is.EqualTo(Mun), "Unexpected unit location");
|
||||
Assert.That(u2.Location, Is.EqualTo(Boh), "Unexpected unit location");
|
||||
Assert.That(u3.Location, Is.EqualTo(Tyr), "Unexpected unit location");
|
||||
Assert.That(u1.LocationId, Is.EqualTo(Mun.Designation), "Unexpected unit location");
|
||||
Assert.That(u2.LocationId, Is.EqualTo(Boh.Designation), "Unexpected unit location");
|
||||
Assert.That(u3.LocationId, Is.EqualTo(Tyr.Designation), "Unexpected unit location");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user