Compare commits
No commits in common. "1eeb5115e6bb728eb6d2e7a53760f3d4694066b1" and "ddf951c17eba9e59f6e2c079eeef35d91a1b9555" have entirely different histories.
1eeb5115e6
...
ddf951c17e
|
@ -94,7 +94,7 @@ public class MovementDecisions
|
|||
.ToList();
|
||||
|
||||
(string province, string season) UnitPoint(Unit unit)
|
||||
=> (unit.GetProvince(world).Name, unit.Season.Key);
|
||||
=> (world.Map.GetLocation(unit.Location).Province.Name, unit.Season.Key);
|
||||
(string province, string season) MovePoint(MoveOrder move)
|
||||
=> (SplitKey(move.Location).province, move.Season.Key);
|
||||
|
||||
|
@ -102,7 +102,7 @@ public class MovementDecisions
|
|||
foreach (UnitOrder order in relevantOrders)
|
||||
{
|
||||
HoldStrength[UnitPoint(order.Unit)] = new(
|
||||
order.Unit.GetProvince(world),
|
||||
world.Map.GetLocation(order.Unit.Location).Province,
|
||||
order.Unit.Season,
|
||||
order);
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ public class MovementDecisions
|
|||
bool IsIncoming(UnitOrder me, MoveOrder other)
|
||||
=> me != other
|
||||
&& other.Season == me.Unit.Season
|
||||
&& SplitKey(other.Location).province == me.Unit.GetProvince(world).Name;
|
||||
&& SplitKey(other.Location).province == world.Map.GetLocation(me.Unit).Province.Name;
|
||||
|
||||
bool IsSupportFor(SupportMoveOrder me, MoveOrder move)
|
||||
=> me.Target.Key == move.Unit.Key
|
||||
|
@ -120,8 +120,8 @@ public class MovementDecisions
|
|||
bool AreOpposing(MoveOrder one, MoveOrder two)
|
||||
=> one.Season == two.Unit.Season
|
||||
&& two.Season == one.Unit.Season
|
||||
&& SplitKey(one.Location).province == two.Unit.GetProvince(world).Name
|
||||
&& SplitKey(two.Location).province == one.Unit.GetProvince(world).Name;
|
||||
&& SplitKey(one.Location).province == world.Map.GetLocation(two.Unit).Province.Name
|
||||
&& SplitKey(two.Location).province == world.Map.GetLocation(one.Unit).Province.Name;
|
||||
|
||||
bool AreCompeting(MoveOrder one, MoveOrder two)
|
||||
=> one != two
|
||||
|
@ -174,7 +174,7 @@ public class MovementDecisions
|
|||
|
||||
// Ensure a hold strength decision exists for the target's province.
|
||||
HoldStrength.Ensure(UnitPoint(support.Target), () => new(
|
||||
support.Target.GetProvince(world),
|
||||
world.Map.GetLocation(support.Target.Location).Province,
|
||||
support.Target.Season));
|
||||
|
||||
if (support is SupportHoldOrder supportHold)
|
||||
|
|
|
@ -92,7 +92,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
|||
ILookup<bool, MoveOrder> moveOrdersByAdjacency = moveOrders
|
||||
.ToLookup(order =>
|
||||
// Map adjacency
|
||||
order.Unit.GetLocation(world).Adjacents.Select(loc => loc.Key).Contains(order.Location)
|
||||
world.Map.GetLocation(order.Unit).Adjacents.Select(loc => loc.Key).Contains(order.Location)
|
||||
// Turn adjacency
|
||||
&& Math.Abs(order.Unit.Season.Turn - order.Season.Turn) <= 1
|
||||
// Timeline adjacency
|
||||
|
@ -177,8 +177,8 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
|||
AdjudicatorHelpers.InvalidateIfNotMatching(
|
||||
order =>
|
||||
// Map adjacency with respect to province
|
||||
order.Unit.GetLocation(world).Adjacents.Any(
|
||||
adjLocation => adjLocation.Province == order.Target.GetLocation(world).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
|
||||
|
@ -197,7 +197,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.GetProvince(world) != order.Province,
|
||||
order => world.Map.GetLocation(order.Unit).Province != order.Province,
|
||||
ValidationReason.NoSupportMoveAgainstSelf,
|
||||
ref supportMoveOrders,
|
||||
ref validationResults);
|
||||
|
@ -209,7 +209,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
|||
AdjudicatorHelpers.InvalidateIfNotMatching(
|
||||
order =>
|
||||
// Map adjacency with respect to province
|
||||
order.Unit.GetLocation(world).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
|
||||
|
@ -370,7 +370,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
|||
if (isDislodged.Outcome == false)
|
||||
{
|
||||
// Non-dislodged units continue into the future.
|
||||
Unit next = order.Unit.Next(order.Unit.GetLocation(world).Key, future);
|
||||
Unit next = order.Unit.Next(world.Map.GetLocation(order.Unit).Key, future);
|
||||
logger.Log(3, "Advancing unit to {0}", next);
|
||||
createdUnits.Add(next);
|
||||
}
|
||||
|
@ -379,7 +379,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.GetLocation(world).Adjacents
|
||||
var validRetreats = world.Map.GetLocation(order.Unit).Adjacents
|
||||
.Select(loc => (future, loc))
|
||||
.ToList();
|
||||
RetreatingUnit retreat = new(order.Unit, validRetreats);
|
||||
|
@ -640,7 +640,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
|||
|
||||
// If the origin and destination are adjacent, then there is a path.
|
||||
if (// Map adjacency
|
||||
decision.Order.Unit.GetLocation(world).Adjacents.Select(loc => loc.Key).Contains(decision.Order.Location)
|
||||
world.Map.GetLocation(decision.Order.Unit).Adjacents.Select(loc => loc.Key).Contains(decision.Order.Location)
|
||||
// Turn adjacency
|
||||
&& Math.Abs(decision.Order.Unit.Season.Turn - decision.Order.Season.Turn) <= 1
|
||||
// Timeline adjacency
|
||||
|
|
|
@ -12,7 +12,7 @@ public static class PathFinder
|
|||
/// Determines if a convoy path exists for a move in a convoy order.
|
||||
/// </summary>
|
||||
public static bool ConvoyPathExists(World world, ConvoyOrder order)
|
||||
=> ConvoyPathExists(world, order.Target.GetLocation(world), order.Location, order.Season);
|
||||
=> ConvoyPathExists(world, world.Map.GetLocation(order.Target), order.Location, order.Season);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a convoy path exists for a move order.
|
||||
|
@ -20,7 +20,7 @@ public static class PathFinder
|
|||
public static bool ConvoyPathExists(World world, MoveOrder order)
|
||||
=> ConvoyPathExists(
|
||||
world,
|
||||
order.Unit.GetLocation(world),
|
||||
world.Map.GetLocation(order.Unit),
|
||||
world.Map.GetLocation(order.Location),
|
||||
order.Season);
|
||||
|
||||
|
|
|
@ -72,6 +72,9 @@ public class Map
|
|||
public Location GetLocation(string designation)
|
||||
=> LocationLookup[designation];
|
||||
|
||||
public Location GetLocation(Unit unit)
|
||||
=> GetLocation(unit.Location);
|
||||
|
||||
/// <summary>
|
||||
/// Get the sole land location of a province.
|
||||
/// </summary>
|
||||
|
|
|
@ -259,7 +259,7 @@ public class OrderParser(World world)
|
|||
// and the location is ignored. This also satisfies DATC 4.B.5, which requires that a wrong coast for the
|
||||
// subject be ignored.
|
||||
subject = world.Units.FirstOrDefault(unit
|
||||
=> unit!.GetProvince(world).Name == province.Name
|
||||
=> world.Map.GetLocation(unit!.Location).ProvinceName == province.Name
|
||||
&& unit!.Season.Timeline == timeline
|
||||
&& unit!.Season.Turn == turn,
|
||||
null);
|
||||
|
@ -338,7 +338,7 @@ public class OrderParser(World world)
|
|||
// If the order location didn't disambiguate the coasts, either because it's missing or it's nonsense, the
|
||||
// order can be disambiguated by there being one accessible coast from the order source.
|
||||
if (destLocationKey is null) {
|
||||
Location source = subject.GetLocation(world);
|
||||
Location source = world.Map.GetLocation(subject.Location);
|
||||
var accessibleLocations = destProvince.Locations.Where(loc => loc.Adjacents.Contains(source));
|
||||
if (accessibleLocations.Count() == 1) destLocationKey ??= accessibleLocations.Single().Key;
|
||||
}
|
||||
|
@ -434,7 +434,7 @@ public class OrderParser(World world)
|
|||
// If the order location didn't disambiguate the coasts, either because it's missing or it's nonsense, the
|
||||
// order can be disambiguated by there being one accessible coast from the order source.
|
||||
if (destLocationKey is null) {
|
||||
Location source = target.GetLocation(world);
|
||||
Location source = world.Map.GetLocation(target.Location);
|
||||
var accessibleLocations = destProvince.Locations.Where(loc => loc.Adjacents.Contains(source));
|
||||
if (accessibleLocations.Count() == 1) destLocationKey ??= accessibleLocations.Single().Key;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,11 @@ namespace MultiversalDiplomacy.Model;
|
|||
/// </summary>
|
||||
public class Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// The previous iteration of a unit. This is null if the unit was just built.
|
||||
/// </summary>
|
||||
public string? Past { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The location on the map where the unit is.
|
||||
/// </summary>
|
||||
|
@ -33,8 +38,9 @@ public class Unit
|
|||
[JsonIgnore]
|
||||
public string Key => $"{Type.ToShort()} {Season.Timeline}-{Location}@{Season.Turn}";
|
||||
|
||||
public Unit(string location, Season season, string power, UnitType type)
|
||||
public Unit(string? past, string location, Season season, string power, UnitType type)
|
||||
{
|
||||
this.Past = past;
|
||||
this.Location = location;
|
||||
this.Season = season;
|
||||
this.Power = power;
|
||||
|
@ -49,15 +55,11 @@ public class Unit
|
|||
/// method after accepting a build order.
|
||||
/// </summary>
|
||||
public static Unit Build(string location, Season season, string power, UnitType type)
|
||||
=> new(location, season, power, 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(location, season, this.Power, this.Type);
|
||||
|
||||
public Location GetLocation(World world) => world.Map.GetLocation(Location);
|
||||
|
||||
public Province GetProvince(World world) => GetLocation(world).Province;
|
||||
=> new(past: this.Key, location, season, this.Power, this.Type);
|
||||
}
|
||||
|
|
|
@ -231,7 +231,7 @@ public class World
|
|||
Province province = Map.GetProvince(provinceName);
|
||||
season ??= Season.First;
|
||||
Unit? foundUnit = this.Units.SingleOrDefault(
|
||||
u => u!.GetProvince(this) == 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;
|
||||
|
|
|
@ -100,7 +100,7 @@ public class AdjudicationQueryScriptHandler(
|
|||
=> val.Valid
|
||||
&& val.Order is HoldOrder hold
|
||||
&& hold.Unit.Season == season
|
||||
&& hold.Unit.GetProvince(World).Name == province.Name);
|
||||
&& World.Map.GetLocation(hold.Unit.Location).ProvinceName == province.Name);
|
||||
if (!matchingHolds.Any()) return ScriptResult.Fail("No matching holds");
|
||||
|
||||
return ScriptResult.Succeed(this);
|
||||
|
@ -129,7 +129,7 @@ public class AdjudicationQueryScriptHandler(
|
|||
var matching = Validations.Where(val
|
||||
=> val.Order is UnitOrder order
|
||||
&& order.Unit.Season == season
|
||||
&& order.Unit.GetProvince(World).Name == province.Name);
|
||||
&& World.Map.GetLocation(order.Unit.Location).ProvinceName == province.Name);
|
||||
if (!matching.Any()) return ScriptResult.Fail("No matching validations");
|
||||
|
||||
if (args[0] == "order-valid" && !matching.First().Valid) {
|
||||
|
@ -181,7 +181,7 @@ public class AdjudicationQueryScriptHandler(
|
|||
var matchingDislodges = Adjudications.Where(adj
|
||||
=> adj is IsDislodged dislodge
|
||||
&& dislodge.Order.Unit.Season == season
|
||||
&& dislodge.Order.Unit.GetProvince(World).Name == province.Name);
|
||||
&& World.Map.GetLocation(dislodge.Order.Unit.Location).ProvinceName == province.Name);
|
||||
if (!matchingDislodges.Any()) return ScriptResult.Fail("No matching dislodge decisions");
|
||||
var isDislodged = matchingDislodges.Cast<IsDislodged>().First();
|
||||
|
||||
|
@ -219,7 +219,7 @@ public class AdjudicationQueryScriptHandler(
|
|||
var matchingMoves = Adjudications.Where(adj
|
||||
=> adj is DoesMove moves
|
||||
&& moves.Order.Unit.Season == season
|
||||
&& moves.Order.Unit.GetProvince(World).Name == province.Name);
|
||||
&& World.Map.GetLocation(moves.Order.Unit.Location).ProvinceName == province.Name);
|
||||
if (!matchingMoves.Any()) return ScriptResult.Fail("No matching movement decisions");
|
||||
var doesMove = matchingMoves.Cast<DoesMove>().First();
|
||||
|
||||
|
@ -257,7 +257,7 @@ public class AdjudicationQueryScriptHandler(
|
|||
var matchingSupports = Adjudications.Where(adj
|
||||
=> adj is GivesSupport sup
|
||||
&& sup.Order.Unit.Season == season
|
||||
&& sup.Order.Unit.GetProvince(World).Name == province.Name);
|
||||
&& World.Map.GetLocation(sup.Order.Unit.Location).ProvinceName == province.Name);
|
||||
if (!matchingSupports.Any()) return ScriptResult.Fail("No matching support decisions");
|
||||
var supports = matchingSupports.Cast<GivesSupport>().First();
|
||||
|
||||
|
|
|
@ -47,9 +47,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.Key));
|
||||
Assert.That(world.GetUnitByKey(aTyr.Past!).Past, Is.EqualTo(mun0.Order.Unit.Key));
|
||||
|
||||
// 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.Key));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -91,6 +94,10 @@ public class TimeTravelTest
|
|||
World world = setup.UpdateWorld();
|
||||
Season fork = new("b1");
|
||||
Unit tyr1 = world.GetUnitAt("Tyr", fork);
|
||||
Assert.That(
|
||||
tyr1.Past,
|
||||
Is.EqualTo(mun0.Order.Unit.Key),
|
||||
"Expected A Mun a0 to advance to Tyr b1");
|
||||
Assert.That(
|
||||
world.RetreatingUnits.Count,
|
||||
Is.EqualTo(1),
|
||||
|
|
|
@ -171,7 +171,7 @@ public class MovementAdjudicatorTest
|
|||
|
||||
// Confirm the unit was created
|
||||
Assert.That(updated.Units.Count, Is.EqualTo(2));
|
||||
Unit second = updated.Units.OrderBy(u => -u.Season.Turn).First();
|
||||
Unit second = updated.Units.Single(u => u.Past != null);
|
||||
Assert.That(second.Location, Is.EqualTo(mun.Order.Unit.Location));
|
||||
Assert.That(second.Season.Timeline, Is.EqualTo(mun.Order.Unit.Season.Timeline));
|
||||
|
||||
|
@ -208,6 +208,7 @@ public class MovementAdjudicatorTest
|
|||
Unit u2 = updated.GetUnitAt("Mun", s2);
|
||||
Assert.That(updated.Units.Count, Is.EqualTo(2));
|
||||
Assert.That(u2.Key, Is.Not.EqualTo(mun1.Order.Unit.Key));
|
||||
Assert.That(u2.Past, Is.EqualTo(mun1.Order.Unit.Key));
|
||||
Assert.That(u2.Season, Is.EqualTo(s2));
|
||||
|
||||
setup[("a", 1)]
|
||||
|
@ -227,6 +228,7 @@ public class MovementAdjudicatorTest
|
|||
updated = setup.UpdateWorld();
|
||||
Season s3 = new(s2.Timeline, s2.Turn + 1);
|
||||
Unit u3 = updated.GetUnitAt("Mun", s3);
|
||||
Assert.That(u3.Past, Is.EqualTo(mun2.Order.Unit.Key));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -256,6 +258,7 @@ public class MovementAdjudicatorTest
|
|||
Unit u2 = updated.GetUnitAt("Tyr", s2);
|
||||
Assert.That(updated.Units.Count, Is.EqualTo(2));
|
||||
Assert.That(u2.Key, Is.Not.EqualTo(mun1.Order.Unit.Key));
|
||||
Assert.That(u2.Past, Is.EqualTo(mun1.Order.Unit.Key));
|
||||
Assert.That(u2.Season, Is.EqualTo(s2));
|
||||
|
||||
setup[("a", 1)]
|
||||
|
@ -275,5 +278,6 @@ public class MovementAdjudicatorTest
|
|||
updated = setup.UpdateWorld();
|
||||
Season s3 = new(s2.Timeline, s2.Turn + 1);
|
||||
Unit u3 = updated.GetUnitAt("Mun", s3);
|
||||
Assert.That(u3.Past, Is.EqualTo(u2.Key));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,7 +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.GetProvince(Builder.World),
|
||||
&& hold.Province == Builder.World.Map.GetLocation(unitOrder.Unit).Province,
|
||||
_ => false,
|
||||
}).ToList();
|
||||
return adjudications;
|
||||
|
|
|
@ -133,6 +133,10 @@ public class SerializationTest
|
|||
World world = setup.UpdateWorld();
|
||||
Season fork = new("b1");
|
||||
Unit tyr1 = world.GetUnitAt("Tyr", fork);
|
||||
Assert.That(
|
||||
tyr1.Past,
|
||||
Is.EqualTo(mun0.Order.Unit.Key),
|
||||
"Expected A Mun a0 to advance to Tyr b1");
|
||||
Assert.That(
|
||||
world.RetreatingUnits.Count,
|
||||
Is.EqualTo(1),
|
||||
|
|
|
@ -263,7 +263,7 @@ public class TestCaseBuilder
|
|||
foreach (Unit unit in this.World.Units)
|
||||
{
|
||||
if (unit.Power == power
|
||||
&& unit.GetProvince(World) == location.Province
|
||||
&& World.Map.GetLocation(unit).Province == location.Province
|
||||
&& unit.Season == season)
|
||||
{
|
||||
return unit;
|
||||
|
|
|
@ -68,7 +68,7 @@ class TestCaseBuilderTest
|
|||
List<UnitOrder> orders = setup.Orders.OfType<UnitOrder>().ToList();
|
||||
|
||||
Func<UnitOrder, bool> OrderForProvince(string name)
|
||||
=> order => order.Unit.GetProvince(setup.World).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");
|
||||
|
|
|
@ -22,6 +22,10 @@ public class UnitTests
|
|||
_ = world.WithNewSeason(a1, out Season a2);
|
||||
Unit u3 = u2.Next(Tyr.Key, a2);
|
||||
|
||||
Assert.That(u3.Past, Is.EqualTo(u2.Key), "Missing unit past");
|
||||
Assert.That(u2.Past, Is.EqualTo(u1.Key), "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");
|
||||
|
|
Loading…
Reference in New Issue