Compare commits

..

No commits in common. "7749d8df4e0e5189aa36ad808f9ed395830cc67d" and "b2ff8896b2ff16071afe724f19d0b32a5ddd7964" have entirely different histories.

17 changed files with 163 additions and 149 deletions

View File

@ -91,33 +91,19 @@ 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[Point(order.Unit)] = new(Point(order.Unit), order);
HoldStrength[order.Unit.Point] = new(order.Unit.Point, 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(other => IsIncoming(order, other))
.Where(order.IsIncoming)
.ToList();
IsDislodged[order.Unit] = new(order, incoming);
@ -132,7 +118,7 @@ public class MovementDecisions
// Determine if this move is a head-to-head battle.
MoveOrder? opposingMove = relevantOrders
.OfType<MoveOrder>()
.FirstOrDefault(other => AreOpposing(move, other!), null);
.FirstOrDefault(other => other!.IsOpposing(move), null);
// Find competing moves.
List<MoveOrder> competing = relevantOrders
@ -156,11 +142,11 @@ public class MovementDecisions
GivesSupport[support] = new(support, incoming);
// Ensure a hold strength decision exists for the target's province.
HoldStrength.Ensure(Point(support.Target), () => new(Point(support.Target)));
HoldStrength.Ensure(support.Target.Point, () => new(support.Target.Point));
if (support is SupportHoldOrder supportHold)
{
HoldStrength[Point(support.Target)].Supports.Add(supportHold);
HoldStrength[support.Target.Point].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.Designation == order.Unit.Location && order.Season == order.Unit.Season),
order => !(order.Location == 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
world.Map.GetLocation(order.Unit).Adjacents.Contains(order.Location)
order.Unit.Location.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.Designation == order.Target.Location
order.Location == 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
world.Map.GetLocation(order.Unit).Adjacents.Any(
adjLocation => adjLocation.Province == world.Map.GetLocation(order.Target).Province)
order.Unit.Location.Adjacents.Any(
adjLocation => adjLocation.Province == 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 => world.Map.GetLocation(order.Unit).Province != order.Province,
order => 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
world.Map.GetLocation(order.Unit).Adjacents.Any(
order.Unit.Location.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.Designation, createdFutures[moveSeason]);
Unit next = doesMove.Order.Unit.Next(doesMove.Order.Location, 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(world.Map.GetLocation(order.Unit).Designation, future);
Unit next = order.Unit.Next(order.Unit.Location, 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 = world.Map.GetLocation(order.Unit).Adjacents
var validRetreats = order.Unit.Location.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
world.Map.GetLocation(decision.Order.Unit).Adjacents.Contains(decision.Order.Location)
decision.Order.Unit.Location.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<(string location, Season season), Unit> fleets = world.Units
IDictionary<(Location 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 (world.Map.GetLocation(movingUnit).Type != LocationType.Land) return false;
IEnumerable<Location> originCoasts = world.Map.GetLocation(movingUnit).Province.Locations
if (movingUnit.Location.Type != LocationType.Land) return false;
IEnumerable<Location> originCoasts = 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.Designation, adjSeason))
&& fleets.ContainsKey((adjLocation, 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,12 +39,7 @@ 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)
public Location(Province province, string? name, string? abbreviation, LocationType type)
{
this.Province = province;
this.Name = name;
@ -55,7 +50,7 @@ public class Location
public override string ToString()
{
return this.Name == "land" || this.Name == "water"
return this.Name == null
? $"{this.Province.Name} ({this.Type})"
: $"{this.Province.Name} ({this.Type}:{this.Name}]";
}

View File

@ -17,8 +17,6 @@ public class Map
private List<Province> _Provinces { get; }
private Dictionary<string, Location> LocationLookup { get; }
/// <summary>
/// The game powers.
/// </summary>
@ -31,10 +29,6 @@ public class Map
Type = type;
_Provinces = provinces.ToList();
_Powers = powers.ToList();
LocationLookup = Provinces
.SelectMany(province => province.Locations)
.ToDictionary(location => location.Designation);
}
/// <summary>
@ -47,27 +41,29 @@ 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)
=> 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");
{
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;
}
/// <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)
=> 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);
{
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;
}
/// <summary>
/// Get the sole land location of a province.
@ -125,10 +121,10 @@ public class Map
#region Provinces
Province.Empty("North Africa", "NAF")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Tunis", "TUN")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Empty("Bohemia", "BOH")
.AddLandLocation(),
Province.Supply("Budapest", "BUD")
@ -137,71 +133,71 @@ public class Map
.AddLandLocation(),
Province.Supply("Trieste", "TRI")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Empty("Tyrolia", "TYR")
.AddLandLocation(),
Province.Time("Vienna", "VIE")
.AddLandLocation(),
Province.Empty("Albania", "ALB")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Bulgaria", "BUL")
.AddLandLocation()
.AddCoastLocation("east coast", "ec")
.AddCoastLocation("south coast", "sc"),
Province.Supply("Greece", "GRE")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Rumania", "RUM", "RMA")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Serbia", "SER")
.AddLandLocation(),
Province.Empty("Clyde", "CLY")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Edinburgh", "EDI")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Liverpool", "LVP", "LPL")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Time("London", "LON")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Empty("Wales", "WAL")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Empty("Yorkshire", "YOR")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Brest", "BRE")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Empty("Burgundy", "BUR")
.AddLandLocation(),
Province.Empty("Gascony", "GAS")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Marseilles", "MAR")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Time("Paris", "PAR")
.AddLandLocation(),
Province.Empty("Picardy", "PIC")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Time("Berlin", "BER")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Kiel", "KIE")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Munich", "MUN")
.AddLandLocation(),
Province.Empty("Prussia", "PRU")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Empty("Ruhr", "RUH", "RHR")
.AddLandLocation(),
Province.Empty("Silesia", "SIL")
@ -212,43 +208,43 @@ public class Map
.AddCoastLocation("south coast", "sc"),
Province.Supply("Portugal", "POR")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Empty("Apulia", "APU")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Naples", "NAP")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Empty("Piedmont", "PIE")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Time("Rome", "ROM", "RME")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Empty("Tuscany", "TUS")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Venice", "VEN")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Belgium", "BEL")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Holland", "HOL")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Empty("Finland", "FIN")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Empty("Livonia", "LVN", "LVA")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Time("Moscow", "MOS")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Sevastopol", "SEV")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Saint Petersburg", "STP")
.AddLandLocation()
.AddCoastLocation("north coast", "nc")
@ -259,28 +255,28 @@ public class Map
.AddLandLocation(),
Province.Supply("Denmark", "DEN")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Norway", "NWY")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Sweden", "SWE")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Ankara", "ANK")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Empty("Armenia", "ARM")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Time("Constantinople", "CON")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Supply("Smyrna", "SMY")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
Province.Empty("Syria", "SYR")
.AddLandLocation()
.AddOceanLocation(),
.AddCoastLocation(),
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 = [];
this.LocationList = new List<Location>();
}
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(name, abbreviations, isSupply: false, isTime: false);
=> new Province(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(name, abbreviations, isSupply: true, isTime: false);
=> new Province(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(name, abbreviations, isSupply: true, isTime: true);
=> new Province(name, abbreviations, isSupply: true, isTime: true);
/// <summary>
/// Create a new land location in this province.
/// </summary>
public Province AddLandLocation()
{
Location location = new(this, "land", "l", LocationType.Land);
Location location = new Location(this, name: null, abbreviation: null, LocationType.Land);
this.LocationList.Add(location);
return this;
}
@ -78,7 +78,19 @@ public class Province
/// </summary>
public Province AddOceanLocation()
{
Location location = new(this, "water", "w", LocationType.Water);
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);
this.LocationList.Add(location);
return this;
}
@ -89,7 +101,7 @@ public class Province
/// </summary>
public Province AddCoastLocation(string name, string abbreviation)
{
Location location = new(this, name, abbreviation, LocationType.Water);
Location location = new Location(this, name, abbreviation, LocationType.Water);
this.LocationList.Add(location);
return this;
}

View File

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

View File

@ -1,3 +1,4 @@
using System.Collections.ObjectModel;
using System.Text.Json.Serialization;
namespace MultiversalDiplomacy.Model;
@ -204,7 +205,7 @@ public class World
: splits.Length == 3
? Map.GetWater(splits[2])
: Map.GetWater(splits[2], splits[3]);
Unit unit = Unit.Build(location.Designation, this.RootSeason, power, type);
Unit unit = Unit.Build(location, this.RootSeason, power, type);
return unit;
});
return this.Update(units: units);
@ -327,13 +328,9 @@ public class World
Province province = Map.GetProvince(provinceName);
season ??= RootSeason;
Unit? foundUnit = this.Units.SingleOrDefault(
u => Map.GetLocation(u!).Province == province && u!.Season == season,
u => 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,6 +39,15 @@ 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,4 +16,12 @@ 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.Designation));
Assert.That(world.GetUnitByDesignation(aTyr.Past!).Past, Is.EqualTo(mun0.Order.Unit.Designation));
Assert.That(aTyr.Past, Is.EqualTo(mun1.Order.Unit));
Assert.That(aTyr.Past?.Past, Is.EqualTo(mun0.Order.Unit));
// 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.Designation));
Assert.That(aMun1.Past, Is.EqualTo(originalUnit));
}
[Test]
@ -95,7 +95,7 @@ public class TimeTravelTest
Unit tyr1 = world.GetUnitAt("Tyr", fork);
Assert.That(
tyr1.Past,
Is.EqualTo(mun0.Order.Unit.Designation),
Is.EqualTo(mun0.Order.Unit),
"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.Designation));
Assert.That(u2.Past, Is.EqualTo(mun1.Order.Unit));
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.Designation));
Assert.That(u3.Past, Is.EqualTo(mun2.Order.Unit));
}
[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.Designation));
Assert.That(u2.Past, Is.EqualTo(mun1.Order.Unit));
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.Designation));
Assert.That(u3.Past, Is.EqualTo(u2));
}
}

View File

@ -108,7 +108,8 @@ 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.Province
: false,
_ => 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.Designation),
Is.EqualTo(mun0.Order.Unit),
"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
&& World.Map.GetLocation(unit).Province == location.Province
&& unit.Province == location.Province
&& unit.Season == season)
{
return unit;
@ -270,7 +270,7 @@ public class TestCaseBuilder
}
// Not found
Unit newUnit = Unit.Build(location.Designation, season, power, type);
Unit newUnit = Unit.Build(location, 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").Designation),
Is.EqualTo(setup.World.Map.GetWater("STP", "wc")),
"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 => setup.World.Map.GetLocation(order.Unit).Province.Name == name;
=> order => 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").Designation),
Is.EqualTo(setup.World.Map.GetLand("Mun")),
"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.Designation, a0, pw1, UnitType.Army);
Unit u1 = Unit.Build(Mun, a0, pw1, UnitType.Army);
world = world.ContinueOrFork(a0, out Season a1);
Unit u2 = u1.Next(Boh.Designation, a1);
Unit u2 = u1.Next(Boh, a1);
_ = world.ContinueOrFork(a1, out Season a2);
Unit u3 = u2.Next(Tyr.Designation, a2);
Unit u3 = u2.Next(Tyr, a2);
Assert.That(u3.Past, Is.EqualTo(u2.Designation), "Missing unit past");
Assert.That(u2.Past, Is.EqualTo(u1.Designation), "Missing unit past");
Assert.That(u3.Past, Is.EqualTo(u2), "Missing unit past");
Assert.That(u2.Past, Is.EqualTo(u1), "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.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");
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");
}
}