Compare commits

..

2 Commits

Author SHA1 Message Date
Tim Van Baak 128f5a4230 Enable 6.A.5 and 6.A.7 2024-09-08 02:14:18 +00:00
Tim Van Baak 1a44021e00 Add convoy order parsing 2024-09-07 03:01:44 +00:00
5 changed files with 87 additions and 11 deletions

View File

@ -194,6 +194,21 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
// unit can move to the destination.
List<SupportMoveOrder> supportMoveOrders = unitOrders.OfType<SupportMoveOrder>().ToList();
// Trivial check: armies cannot move to water and fleets cannot move to land.
AdjudicatorHelpers.InvalidateIfNotMatching(
order => (order.Target.Type == UnitType.Army && order.Location.Type == LocationType.Land)
|| (order.Target.Type == UnitType.Fleet && order.Location.Type == LocationType.Water),
ValidationReason.IllegalDestinationType,
ref supportMoveOrders,
ref validationResults);
// Trivial check: a unit cannot move to where it already is.
AdjudicatorHelpers.InvalidateIfNotMatching(
order => !(order.Location.Key == order.Target.Location && order.Season == order.Unit.Season),
ValidationReason.DestinationMatchesOrigin,
ref supportMoveOrders,
ref validationResults);
// Support-move orders are invalid if the unit supports a move to any location in its own
// province.
AdjudicatorHelpers.InvalidateIfNotMatching(

View File

@ -266,15 +266,28 @@ public class OrderParser(World world)
order = null;
OrderParser re = new(world);
if (re.Hold.Match(command) is Match holdMatch && holdMatch.Success) {
if (re.Hold.Match(command) is Match holdMatch && holdMatch.Success)
{
return TryParseHoldOrder(world, power, holdMatch, out order);
} else if (re.Move.Match(command) is Match moveMatch && moveMatch.Success) {
}
else if (re.Move.Match(command) is Match moveMatch && moveMatch.Success)
{
return TryParseMoveOrder(world, power, moveMatch, out order);
} else if (re.SupportHold.Match(command) is Match sholdMatch && sholdMatch.Success) {
}
else if (re.SupportHold.Match(command) is Match sholdMatch && sholdMatch.Success)
{
return TryParseSupportHoldOrder(world, power, sholdMatch, out order);
} else if (re.SupportMove.Match(command) is Match smoveMatch && smoveMatch.Success) {
}
else if (re.SupportMove.Match(command) is Match smoveMatch && smoveMatch.Success)
{
return TryParseSupportMoveOrder(world, power, smoveMatch, out order);
} else {
}
else if (re.Convoy.Match(command) is Match convoyMatch && convoyMatch.Success)
{
return TryParseConvoyOrder(world, power, convoyMatch, out order);
}
else
{
return false;
}
}
@ -495,4 +508,45 @@ public class OrderParser(World world)
order = new SupportMoveOrder(power, subject, target, new(destTimeline, destTurn), destLocation);
return true;
}
public static bool TryParseConvoyOrder(
World world,
string power,
Match match,
[NotNullWhen(true)] out Order? order)
{
order = null;
var convoy = ParseConvoy(match);
if (!TryParseOrderSubject(world, convoy.timeline, convoy.turn, convoy.province, out Unit? subject)) {
return false;
}
if (!TryParseOrderSubject(
world, convoy.targetTimeline, convoy.targetTurn, convoy.targetProvince, out Unit? target))
{
return false;
}
string destTimeline = convoy.destTimeline.Length > 0
? convoy.destTimeline
// If the destination is unspecified, use the target's
: target.Season.Timeline;
int destTurn = convoy.destTurn.Length > 0
? int.Parse(convoy.destTurn)
// If the destination is unspecified, use the unit's
: target.Season.Turn;
var destProvince = world.Map.Provinces.Single(province => province.Is(convoy.destProvince));
// Only armies can be convoyed, which means the destination location can only be land.
var landLocations = destProvince.Locations.Where(loc => loc.Type == LocationType.Land);
if (!landLocations.Any()) return false; // Can't convoy to water
string destLocationKey = landLocations.First().Key;
var destLocation = world.Map.GetLocation(destLocationKey);
order = new ConvoyOrder(power, subject, target, new(destTimeline, destTurn), destLocation);
return true;
}
}

View File

@ -373,4 +373,17 @@ public class OrderParserTest
Is.False,
"Should not parse ambiguous coastal support");
}
[Test]
public void DisambiguateConvoyDestination()
{
World world = World.WithStandardMap().AddUnits("France F MID", "France A Brest");
Assert.That(
OrderParser.TryParseOrder(world, "France", "MID C Brest - Spain", out Order? order),
"Failed to parse convoy order");
Assert.That(order, Is.TypeOf<ConvoyOrder>(), "Unexpected order type");
Location dest = ((ConvoyOrder)order!).Location;
Assert.That(dest.Name, Is.EqualTo("land"), "Unexpected destination location");
}
}

View File

@ -1,9 +1,6 @@
# 6.A.5. TEST CASE, MOVE TO OWN SECTOR WITH CONVOY
# Moving to the same sector is still illegal with convoy (2023 rulebook, page 7, "Note: An Army can move across water provinces from one coastal province to another...").
# TODO convoy order parsing
#test:skip
unit England F North Sea
unit England A Yorkshire
unit England A Liverpool

View File

@ -1,9 +1,6 @@
# 6.A.7. TEST CASE, ONLY ARMIES CAN BE CONVOYED
# A fleet cannot be convoyed.
# TODO convoy order parsing
#test:skip
unit England F London
unit England F North Sea