Compare commits

...

5 Commits

Author SHA1 Message Date
Tim Van Baak 7749d8df4e Remove reference from Unit.Past 2024-08-14 08:39:19 -07:00
Tim Van Baak 53e208ec31 Remove Location reference from Unit 2024-08-14 08:20:04 -07:00
Tim Van Baak ce25329d27 Refactor away Unit.Province 2024-08-14 08:15:10 -07:00
Tim Van Baak 4df5ef84dc Shift usage of Unit.Location to Unit.LocationId
This is in preparation for removing province and location references from Unit
2024-08-14 07:39:49 -07:00
Tim Van Baak 7400334a3d Always name locations 2024-08-14 06:55:40 -07:00
17 changed files with 149 additions and 163 deletions

View File

@ -91,19 +91,33 @@ public class MovementDecisions
.Distinct()
.ToList();
(Province province, Season season) Point(Unit unit)
=> (world.Map.GetLocation(unit.Location).Province, unit.Season);
// Create a hold strength decision with an associated order for every province with a unit.
foreach (UnitOrder order in relevantOrders)
{
HoldStrength[order.Unit.Point] = new(order.Unit.Point, order);
HoldStrength[Point(order.Unit)] = new(Point(order.Unit), order);
}
bool IsIncoming(UnitOrder me, MoveOrder other)
=> me != other
&& other.Season == me.Unit.Season
&& other.Province == world.Map.GetLocation(me.Unit).Province;
bool AreOpposing(MoveOrder one, MoveOrder two)
=> one.Season == two.Unit.Season
&& two.Season == one.Unit.Season
&& one.Province == world.Map.GetLocation(two.Unit).Province
&& two.Province == world.Map.GetLocation(one.Unit).Province;
// Create all other relevant decisions for each order in the affected timelines.
foreach (UnitOrder order in relevantOrders)
{
// Create a dislodge decision for this unit.
List<MoveOrder> incoming = relevantOrders
.OfType<MoveOrder>()
.Where(order.IsIncoming)
.Where(other => IsIncoming(order, other))
.ToList();
IsDislodged[order.Unit] = new(order, incoming);
@ -118,7 +132,7 @@ public class MovementDecisions
// Determine if this move is a head-to-head battle.
MoveOrder? opposingMove = relevantOrders
.OfType<MoveOrder>()
.FirstOrDefault(other => other!.IsOpposing(move), null);
.FirstOrDefault(other => AreOpposing(move, other!), null);
// Find competing moves.
List<MoveOrder> competing = relevantOrders
@ -142,11 +156,11 @@ public class MovementDecisions
GivesSupport[support] = new(support, incoming);
// Ensure a hold strength decision exists for the target's province.
HoldStrength.Ensure(support.Target.Point, () => new(support.Target.Point));
HoldStrength.Ensure(Point(support.Target), () => new(Point(support.Target)));
if (support is SupportHoldOrder supportHold)
{
HoldStrength[support.Target.Point].Supports.Add(supportHold);
HoldStrength[Point(support.Target)].Supports.Add(supportHold);
}
else if (support is SupportMoveOrder supportMove)
{

View File

@ -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.Location && 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.Location
&& 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
@ -337,7 +337,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
Season moveSeason = doesMove.Order.Season;
if (doesMove.Outcome == true && createdFutures.ContainsKey(moveSeason))
{
Unit next = doesMove.Order.Unit.Next(doesMove.Order.Location, createdFutures[moveSeason]);
Unit next = doesMove.Order.Unit.Next(doesMove.Order.Location.Designation, createdFutures[moveSeason]);
logger.Log(3, "Advancing unit to {0}", next);
createdUnits.Add(next);
}
@ -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).Designation, 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

View File

@ -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));
// 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));

View File

@ -20,12 +20,12 @@ public class Location
/// <summary>
/// The location's full human-readable name.
/// </summary>
public string? Name { get; }
public string Name { get; }
/// <summary>
/// The location's shorthand abbreviation.
/// </summary>
public string? Abbreviation { get; }
public string Abbreviation { get; }
/// <summary>
/// The location's type.
@ -39,7 +39,12 @@ public class Location
public IEnumerable<Location> Adjacents => this.AdjacentList;
private List<Location> AdjacentList { get; set; }
public Location(Province province, string? name, string? abbreviation, LocationType type)
/// <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;
this.Name = name;
@ -50,7 +55,7 @@ public class Location
public override string ToString()
{
return this.Name == null
return this.Name == "land" || this.Name == "water"
? $"{this.Province.Name} ({this.Type})"
: $"{this.Province.Name} ({this.Type}:{this.Name}]";
}

View File

@ -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.Location);
/// <summary>
/// Get the sole land location of a province.
@ -121,10 +125,10 @@ public class Map
#region Provinces
Province.Empty("North Africa", "NAF")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Tunis", "TUN")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Empty("Bohemia", "BOH")
.AddLandLocation(),
Province.Supply("Budapest", "BUD")
@ -133,71 +137,71 @@ public class Map
.AddLandLocation(),
Province.Supply("Trieste", "TRI")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Empty("Tyrolia", "TYR")
.AddLandLocation(),
Province.Time("Vienna", "VIE")
.AddLandLocation(),
Province.Empty("Albania", "ALB")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Bulgaria", "BUL")
.AddLandLocation()
.AddCoastLocation("east coast", "ec")
.AddCoastLocation("south coast", "sc"),
Province.Supply("Greece", "GRE")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Rumania", "RUM", "RMA")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Serbia", "SER")
.AddLandLocation(),
Province.Empty("Clyde", "CLY")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Edinburgh", "EDI")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Liverpool", "LVP", "LPL")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Time("London", "LON")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Empty("Wales", "WAL")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Empty("Yorkshire", "YOR")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Brest", "BRE")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Empty("Burgundy", "BUR")
.AddLandLocation(),
Province.Empty("Gascony", "GAS")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Marseilles", "MAR")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Time("Paris", "PAR")
.AddLandLocation(),
Province.Empty("Picardy", "PIC")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Time("Berlin", "BER")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Kiel", "KIE")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Munich", "MUN")
.AddLandLocation(),
Province.Empty("Prussia", "PRU")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Empty("Ruhr", "RUH", "RHR")
.AddLandLocation(),
Province.Empty("Silesia", "SIL")
@ -208,43 +212,43 @@ public class Map
.AddCoastLocation("south coast", "sc"),
Province.Supply("Portugal", "POR")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Empty("Apulia", "APU")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Naples", "NAP")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Empty("Piedmont", "PIE")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Time("Rome", "ROM", "RME")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Empty("Tuscany", "TUS")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Venice", "VEN")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Belgium", "BEL")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Holland", "HOL")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Empty("Finland", "FIN")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Empty("Livonia", "LVN", "LVA")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Time("Moscow", "MOS")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Sevastopol", "SEV")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Saint Petersburg", "STP")
.AddLandLocation()
.AddCoastLocation("north coast", "nc")
@ -255,28 +259,28 @@ public class Map
.AddLandLocation(),
Province.Supply("Denmark", "DEN")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Norway", "NWY")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Sweden", "SWE")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Ankara", "ANK")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Empty("Armenia", "ARM")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Time("Constantinople", "CON")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Supply("Smyrna", "SMY")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Empty("Syria", "SYR")
.AddLandLocation()
.AddCoastLocation(),
.AddOceanLocation(),
Province.Empty("Barents Sea", "BAR")
.AddOceanLocation(),
Province.Empty("English Channel", "ENC", "ECH")

View File

@ -37,7 +37,7 @@ public class Province
this.Abbreviations = abbreviations;
this.IsSupplyCenter = isSupply;
this.IsTimeCenter = isTime;
this.LocationList = new List<Location>();
this.LocationList = [];
}
public override string ToString()
@ -49,26 +49,26 @@ public class Province
/// Create a new province with no supply center.
/// </summary>
public static Province Empty(string name, params string[] abbreviations)
=> new Province(name, abbreviations, isSupply: false, isTime: false);
=> new(name, abbreviations, isSupply: false, isTime: false);
/// <summary>
/// Create a new province with a supply center.
/// </summary>
public static Province Supply(string name, params string[] abbreviations)
=> new Province(name, abbreviations, isSupply: true, isTime: false);
=> new(name, abbreviations, isSupply: true, isTime: false);
/// <summary>
/// Create a new province with a time center.
/// </summary>
public static Province Time(string name, params string[] abbreviations)
=> new Province(name, abbreviations, isSupply: true, isTime: true);
=> new(name, abbreviations, isSupply: true, isTime: true);
/// <summary>
/// Create a new land location in this province.
/// </summary>
public Province AddLandLocation()
{
Location location = new Location(this, name: null, abbreviation: null, LocationType.Land);
Location location = new(this, "land", "l", LocationType.Land);
this.LocationList.Add(location);
return this;
}
@ -78,19 +78,7 @@ public class Province
/// </summary>
public Province AddOceanLocation()
{
Location location = new Location(this, name: null, abbreviation: null, LocationType.Water);
this.LocationList.Add(location);
return this;
}
/// <summary>
/// Create a new coastal location. Coastal locations must have names to disambiguate them
/// from the single land location in coastal provinces.
/// </summary>
public Province AddCoastLocation()
{
// Use a default name for provinces with only one coastal location
Location location = new Location(this, "coast", "c", LocationType.Water);
Location location = new(this, "water", "w", LocationType.Water);
this.LocationList.Add(location);
return this;
}
@ -101,7 +89,7 @@ public class Province
/// </summary>
public Province AddCoastLocation(string name, string abbreviation)
{
Location location = new Location(this, name, abbreviation, LocationType.Water);
Location location = new(this, name, abbreviation, LocationType.Water);
this.LocationList.Add(location);
return this;
}

View File

@ -1,5 +1,3 @@
using System.Text.Json.Serialization;
namespace MultiversalDiplomacy.Model;
/// <summary>
@ -10,18 +8,12 @@ public class Unit
/// <summary>
/// The previous iteration of a unit. This is null if the unit was just built.
/// </summary>
public Unit? Past { get; }
public string? Past { get; }
/// <summary>
/// The location on the map where the unit is.
/// </summary>
public Location Location { get; }
/// <summary>
/// The province where the unit is.
/// </summary>
[JsonIgnore]
public Province Province => this.Location.Province;
public string Location { get; }
/// <summary>
/// The season in time when the unit is.
@ -39,11 +31,11 @@ public class Unit
public UnitType Type { get; }
/// <summary>
/// The unit's spatiotemporal location as a province-season tuple.
/// A unique designation for this unit.
/// </summary>
public (Province province, Season season) Point => (this.Province, this.Season);
public string Designation => $"{Type.ToShort()} {Season.Timeline}-{Location}@{Season.Turn}";
private Unit(Unit? past, Location location, Season season, Power power, UnitType type)
private Unit(string? past, string location, Season season, Power power, UnitType type)
{
this.Past = past;
this.Location = location;
@ -53,20 +45,18 @@ public class Unit
}
public override string ToString()
{
return $"{this.Power.Name[0]} {this.Type.ToShort()} {(this.Province, this.Season).ToShort()}";
}
=> $"{Power.Name[0]} {Type.ToShort()} {Season.Timeline}-{Location}@{Season.Turn}";
/// <summary>
/// Create a new unit. No validation is performed; the adjudicator should only call this
/// method after accepting a build order.
/// </summary>
public static Unit Build(Location location, Season season, Power power, UnitType type)
public static Unit Build(string location, Season season, Power power, UnitType type)
=> new(past: null, location, season, power, type);
/// <summary>
/// Advance this unit's timeline to a new location and season.
/// </summary>
public Unit Next(Location location, Season season)
=> new(past: this, location, season, this.Power, this.Type);
public Unit Next(string location, Season season)
=> new(past: this.Designation, location, season, this.Power, this.Type);
}

View File

@ -1,4 +1,3 @@
using System.Collections.ObjectModel;
using System.Text.Json.Serialization;
namespace MultiversalDiplomacy.Model;
@ -205,7 +204,7 @@ public class World
: splits.Length == 3
? Map.GetWater(splits[2])
: Map.GetWater(splits[2], splits[3]);
Unit unit = Unit.Build(location, this.RootSeason, power, type);
Unit unit = Unit.Build(location.Designation, this.RootSeason, power, type);
return unit;
});
return this.Update(units: units);
@ -328,9 +327,13 @@ 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;
}
public Unit GetUnitByDesignation(string designation)
=> Units.SingleOrDefault(u => u!.Designation == designation, null)
?? throw new KeyNotFoundException($"Unit {designation} not found");
}

View File

@ -39,15 +39,6 @@ public class MoveOrder : UnitOrder
return $"{this.Unit} -> {(this.Province, this.Season).ToShort()}";
}
/// <summary>
/// Returns whether another move order is in a head-to-head battle with this order.
/// </summary>
public bool IsOpposing(MoveOrder other)
=> this.Season == other.Unit.Season
&& other.Season == this.Unit.Season
&& this.Province == other.Unit.Province
&& other.Province == this.Unit.Province;
/// <summary>
/// Returns whether another move order has the same destination as this order.
/// </summary>

View File

@ -16,12 +16,4 @@ public abstract class UnitOrder : Order
{
this.Unit = unit;
}
/// <summary>
/// Returns whether a move order is moving into this order's unit's province.
/// </summary>
public bool IsIncoming(MoveOrder other)
=> this != other
&& other.Season == this.Unit.Season
&& other.Province == this.Unit.Province;
}

View File

@ -46,12 +46,12 @@ public class TimeTravelTest
Unit originalUnit = world.GetUnitAt("Mun", s0);
Unit aMun0 = world.GetUnitAt("Mun", s1);
Unit aTyr = world.GetUnitAt("Tyr", fork);
Assert.That(aTyr.Past, Is.EqualTo(mun1.Order.Unit));
Assert.That(aTyr.Past?.Past, Is.EqualTo(mun0.Order.Unit));
Assert.That(aTyr.Past, Is.EqualTo(mun1.Order.Unit.Designation));
Assert.That(world.GetUnitByDesignation(aTyr.Past!).Past, Is.EqualTo(mun0.Order.Unit.Designation));
// Confirm that there is a unit in Mun b1 originating from Mun a0
Unit aMun1 = world.GetUnitAt("Mun", fork);
Assert.That(aMun1.Past, Is.EqualTo(originalUnit));
Assert.That(aMun1.Past, Is.EqualTo(originalUnit.Designation));
}
[Test]
@ -95,7 +95,7 @@ public class TimeTravelTest
Unit tyr1 = world.GetUnitAt("Tyr", fork);
Assert.That(
tyr1.Past,
Is.EqualTo(mun0.Order.Unit),
Is.EqualTo(mun0.Order.Unit.Designation),
"Expected A Mun a0 to advance to Tyr b1");
Assert.That(
world.RetreatingUnits.Count,

View File

@ -209,7 +209,7 @@ public class MovementAdjudicatorTest
Unit u2 = updated.GetUnitAt("Mun", s2);
Assert.That(updated.Units.Count, Is.EqualTo(2));
Assert.That(u2, Is.Not.EqualTo(mun1.Order.Unit));
Assert.That(u2.Past, Is.EqualTo(mun1.Order.Unit));
Assert.That(u2.Past, Is.EqualTo(mun1.Order.Unit.Designation));
Assert.That(u2.Season, Is.EqualTo(s2));
setup[("a", 1)]
@ -229,7 +229,7 @@ public class MovementAdjudicatorTest
updated = setup.UpdateWorld();
Season s3 = updated.GetSeason(s2.Timeline, s2.Turn + 1);
Unit u3 = updated.GetUnitAt("Mun", s3);
Assert.That(u3.Past, Is.EqualTo(mun2.Order.Unit));
Assert.That(u3.Past, Is.EqualTo(mun2.Order.Unit.Designation));
}
[Test]
@ -259,7 +259,7 @@ public class MovementAdjudicatorTest
Unit u2 = updated.GetUnitAt("Tyr", s2);
Assert.That(updated.Units.Count, Is.EqualTo(2));
Assert.That(u2, Is.Not.EqualTo(mun1.Order.Unit));
Assert.That(u2.Past, Is.EqualTo(mun1.Order.Unit));
Assert.That(u2.Past, Is.EqualTo(mun1.Order.Unit.Designation));
Assert.That(u2.Season, Is.EqualTo(s2));
setup[("a", 1)]
@ -279,6 +279,6 @@ public class MovementAdjudicatorTest
updated = setup.UpdateWorld();
Season s3 = updated.GetSeason(s2.Timeline, s2.Turn + 1);
Unit u3 = updated.GetUnitAt("Mun", s3);
Assert.That(u3.Past, Is.EqualTo(u2));
Assert.That(u3.Past, Is.EqualTo(u2.Designation));
}
}

View File

@ -108,8 +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 == unitOrder.Unit.Province
: false,
&& hold.Province == Builder.World.Map.GetLocation(unitOrder.Unit).Province,
_ => false,
}).ToList();
return adjudications;

View File

@ -94,7 +94,7 @@ public class SerializationTest
Unit tyr1 = world.GetUnitAt("Tyr", fork);
Assert.That(
tyr1.Past,
Is.EqualTo(mun0.Order.Unit),
Is.EqualTo(mun0.Order.Unit.Designation),
"Expected A Mun a0 to advance to Tyr b1");
Assert.That(
world.RetreatingUnits.Count,

View File

@ -262,7 +262,7 @@ public class TestCaseBuilder
foreach (Unit unit in this.World.Units)
{
if (unit.Power == power
&& unit.Province == location.Province
&& World.Map.GetLocation(unit).Province == location.Province
&& unit.Season == season)
{
return unit;
@ -270,7 +270,7 @@ public class TestCaseBuilder
}
// Not found
Unit newUnit = Unit.Build(location, season, power, type);
Unit newUnit = Unit.Build(location.Designation, season, power, type);
this.World = this.World.Update(units: this.World.Units.Append(newUnit));
return newUnit;
}

View File

@ -40,7 +40,7 @@ class TestCaseBuilderTest
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")),
Is.EqualTo(setup.World.Map.GetWater("STP", "wc").Designation),
"Unit created on wrong coast");
}
@ -68,7 +68,7 @@ class TestCaseBuilderTest
List<UnitOrder> orders = setup.Orders.OfType<UnitOrder>().ToList();
Func<UnitOrder, bool> OrderForProvince(string name)
=> order => order.Unit.Province.Name == name;
=> order => setup.World.Map.GetLocation(order.Unit).Province.Name == name;
UnitOrder orderBer = orders.Single(OrderForProvince("Berlin"));
Assert.That(orderBer, Is.InstanceOf<MoveOrder>(), "Unexpected order type");
@ -128,7 +128,7 @@ class TestCaseBuilderTest
"Wrong power");
Assert.That(
orderMun.Order.Unit.Location,
Is.EqualTo(setup.World.Map.GetLand("Mun")),
Is.EqualTo(setup.World.Map.GetLand("Mun").Designation),
"Wrong unit");
Assert.That(

View File

@ -15,24 +15,24 @@ public class UnitTests
Tyr = world.Map.GetLand("Tyr");
Power pw1 = world.Map.GetPower("Austria");
Season a0 = world.RootSeason;
Unit u1 = Unit.Build(Mun, a0, pw1, UnitType.Army);
Unit u1 = Unit.Build(Mun.Designation, a0, pw1, UnitType.Army);
world = world.ContinueOrFork(a0, out Season a1);
Unit u2 = u1.Next(Boh, a1);
Unit u2 = u1.Next(Boh.Designation, a1);
_ = world.ContinueOrFork(a1, out Season a2);
Unit u3 = u2.Next(Tyr, a2);
Unit u3 = u2.Next(Tyr.Designation, a2);
Assert.That(u3.Past, Is.EqualTo(u2), "Missing unit past");
Assert.That(u2.Past, Is.EqualTo(u1), "Missing unit past");
Assert.That(u3.Past, Is.EqualTo(u2.Designation), "Missing unit past");
Assert.That(u2.Past, Is.EqualTo(u1.Designation), "Missing unit past");
Assert.That(u1.Past, Is.Null, "Unexpected unit past");
Assert.That(u1.Season, Is.EqualTo(a0), "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(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.Location, Is.EqualTo(Mun.Designation), "Unexpected unit location");
Assert.That(u2.Location, Is.EqualTo(Boh.Designation), "Unexpected unit location");
Assert.That(u3.Location, Is.EqualTo(Tyr.Designation), "Unexpected unit location");
}
}