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