diff --git a/MultiversalDiplomacy/Model/Regex.cs b/MultiversalDiplomacy/Model/Regex.cs index d2eaae3..7667481 100644 --- a/MultiversalDiplomacy/Model/Regex.cs +++ b/MultiversalDiplomacy/Model/Regex.cs @@ -121,6 +121,51 @@ public class OrderRegex(World world) : match.Groups[12].Value, match.Groups[13].Value); + public Regex SupportMove => new( + $"{UnitSpec} {SupportVerb} {UnitSpec} {MoveVerb} {FullLocation}$", + RegexOptions.IgnoreCase); + + public static ( + string type, + string timeline, + string province, + string location, + string turn, + string supportVerb, + string targetType, + string targetTimeline, + string targetProvince, + string targetLocation, + string targetTurn, + string moveVerb, + string destTimeline, + string destProvince, + string destLocation, + string destTurn) + ParseSupportMove(Match match) => ( + match.Groups[1].Value, + match.Groups[2].Value, + match.Groups[3].Value, + match.Groups[4].Length > 0 + ? match.Groups[4].Value + : match.Groups[5].Value, + match.Groups[6].Value, + match.Groups[7].Value, + match.Groups[8].Value, + match.Groups[9].Value, + match.Groups[10].Value, + match.Groups[11].Length > 0 + ? match.Groups[11].Value + : match.Groups[12].Value, + match.Groups[13].Value, + match.Groups[14].Value, + match.Groups[15].Value, + match.Groups[16].Value, + match.Groups[17].Length > 0 + ? match.Groups[17].Value + : match.Groups[18].Value, + match.Groups[19].Value); + public static bool TryParseUnit(World world, string unitSpec, [NotNullWhen(true)] out Unit? newUnit) { newUnit = null; diff --git a/MultiversalDiplomacyTests/RegexTest.cs b/MultiversalDiplomacyTests/RegexTest.cs index 1e07da2..2f8b7ab 100644 --- a/MultiversalDiplomacyTests/RegexTest.cs +++ b/MultiversalDiplomacyTests/RegexTest.cs @@ -52,8 +52,6 @@ public class RegexTest static IEnumerable MoveRegexMatchesTestCases() { - static TestCaseData Test(string order, params string[] expected) - => new TestCaseData(order, expected).SetName($"{{m}}(\"{order}\")"); // Full specification yield return Test( "Army a-Munich/l@0 - a-Tyrolia/l@0", @@ -109,8 +107,6 @@ public class RegexTest static IEnumerable SupportHoldRegexMatchesTestCases() { - static TestCaseData Test(string order, params string[] expected) - => new TestCaseData(order, expected).SetName($"{{m}}(\"{order}\")"); // Full specification yield return Test( "Army a-Munich/l@0 s A a-Tyrolia/l@0", @@ -159,4 +155,45 @@ public class RegexTest Assert.That(actual, Is.EquivalentTo(expected), "Unexpected parse results"); Assert.That(actual, Is.EqualTo(expected), "Unexpected parse results"); } + + static IEnumerable SupportMoveRegexMatchesTestCases() + { + // Full specification + yield return Test( + "Army a-Munich/l@0 s A a-Tyrolia/l@0 - a-Vienna/l@0", + "Army", "a", "Munich", "l", "0", "s", "A", "a", "Tyrolia", "l", "0", "-", "a", "Vienna", "l", "0"); + // Case insensitivity + yield return Test( + "fleet B-lon/C@0 SUPPORTS B-enc/W@0 MOVE TO B-nts/W@0", + "fleet", "B", "lon", "C", "0", "SUPPORTS", "", "B", "enc", "W", "0", "MOVE TO", "B", "nts", "W", "0"); + // All optionals missing + yield return Test( + "ROM s VIE - TYR", + "", "", "ROM", "", "", "s", "", "", "VIE", "", "", "-", "", "TYR", "", ""); + // No confusion of unit type and timeline + yield return Test( + "A F-STP S MOS - A-UKR", + "A", "F", "STP", "", "", "S", "", "", "MOS", "", "", "-", "A", "UKR", "", ""); + // Elements with spaces + yield return Test( + "Western Mediterranean Sea supports Gulf of Lyons move to North Sea", + "", "", "Western Mediterranean Sea", "", "", "supports", "", "", "Gulf of Lyons", "", "", "move to", "", "North Sea", "", ""); + } + + [TestCaseSource(nameof(SupportMoveRegexMatchesTestCases))] + public void SupportMoveRegexMatches(string order, string[] expected) + { + OrderRegex re = new(World.WithStandardMap()); + var match = re.SupportMove.Match(order); + Assert.True(match.Success, "Match failed"); + var (type, timeline, province, location, turn, supportVerb, + targetType, targetTimeline, targetProvince, targetLocation, targetTurn, moveVerb, + destTimeline, destProvince, destLocation, destTurn) = OrderRegex.ParseSupportMove(match); + string[] actual = [type, timeline, province, location, turn, supportVerb, + targetType, targetTimeline, targetProvince, targetLocation, targetTurn, moveVerb, + destTimeline, destProvince, destLocation, destTurn]; + // Use EquivalentTo for more detailed error message + Assert.That(actual, Is.EquivalentTo(expected), "Unexpected parse results"); + Assert.That(actual, Is.EqualTo(expected), "Unexpected parse results"); + } }