Compare commits

..

3 Commits

Author SHA1 Message Date
Tim Van Baak 24e80af7ef Add test cases for support-move 2024-08-26 17:47:52 +00:00
Tim Van Baak e25191548e Set version to 0.0.2
Some internal milestones may qualify as 0.x, 1.0 will be reserved for when a minimum viable game can be played
2024-08-26 16:47:00 +00:00
Tim Van Baak 33aecf876a Add test cases for support-hold 2024-08-26 16:32:33 +00:00
5 changed files with 191 additions and 5 deletions

View File

@ -5,6 +5,11 @@ using MultiversalDiplomacy.Orders;
namespace MultiversalDiplomacy.Model; namespace MultiversalDiplomacy.Model;
/// <summary>
/// This class defines the regular expressions that are used to build up larger expressions for matching orders
/// and other script inputs. It also provides helper functions to extract the captured order elements as tuples,
/// which function as the structured intermediate representation between raw user input and full Order objects.
/// </summary>
public class OrderRegex(World world) public class OrderRegex(World world)
{ {
public const string Type = "(A|F|Army|Fleet)"; public const string Type = "(A|F|Army|Fleet)";
@ -25,6 +30,8 @@ public class OrderRegex(World world)
public const string MoveVerb = "(-|(?:->)|(?:=>)|(?:attack(?:s)?)|(?:move(?:s)?(?: to)?))"; public const string MoveVerb = "(-|(?:->)|(?:=>)|(?:attack(?:s)?)|(?:move(?:s)?(?: to)?))";
public const string SupportVerb = "(s|support|supports)";
public const string ViaConvoy = "(convoy|via convoy|by convoy)"; public const string ViaConvoy = "(convoy|via convoy|by convoy)";
public Regex Hold => new( public Regex Hold => new(
@ -81,6 +88,84 @@ public class OrderRegex(World world)
match.Groups[12].Value, match.Groups[12].Value,
match.Groups[13].Value); match.Groups[13].Value);
public Regex SupportHold => new(
$"^{UnitSpec} {SupportVerb} {UnitSpec}$",
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)
ParseSupportHold(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);
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) public static bool TryParseUnit(World world, string unitSpec, [NotNullWhen(true)] out Unit? newUnit)
{ {
newUnit = null; newUnit = null;

View File

@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<VersionPrefix>0.0.2</VersionPrefix>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>

View File

@ -52,8 +52,6 @@ public class RegexTest
static IEnumerable<TestCaseData> MoveRegexMatchesTestCases() static IEnumerable<TestCaseData> MoveRegexMatchesTestCases()
{ {
static TestCaseData Test(string order, params string[] expected)
=> new TestCaseData(order, expected).SetName($"{{m}}(\"{order}\")");
// Full specification // Full specification
yield return Test( yield return Test(
"Army a-Munich/l@0 - a-Tyrolia/l@0", "Army a-Munich/l@0 - a-Tyrolia/l@0",
@ -70,10 +68,18 @@ public class RegexTest
yield return Test( yield return Test(
"A F-STP - MOS", "A F-STP - MOS",
"A", "F", "STP", "", "", "-", "", "MOS", "", "", ""); "A", "F", "STP", "", "", "-", "", "MOS", "", "", "");
// No confusion of timeline and hold verb
yield return Test(
"A Mun - h-Tyr",
"A", "", "Mun", "", "", "-", "h", "Tyr", "", "", "");
// No confusion of timeline and support verb
yield return Test(
"A Mun - s-Tyr",
"A", "", "Mun", "", "", "-", "s", "Tyr", "", "", "");
// Elements with spaces // Elements with spaces
yield return Test( yield return Test(
"Fleet Western Mediterranean Sea moves to Gulf of Lyons via convoy", "Western Mediterranean Sea moves to Gulf of Lyons via convoy",
"Fleet", "", "Western Mediterranean Sea", "", "", "moves to", "", "Gulf of Lyons", "", "", "via convoy"); "", "", "Western Mediterranean Sea", "", "", "moves to", "", "Gulf of Lyons", "", "", "via convoy");
// Parenthesis location // Parenthesis location
yield return Test( yield return Test(
"F Spain(nc) - Spain(sc)", "F Spain(nc) - Spain(sc)",
@ -98,4 +104,96 @@ public class RegexTest
Assert.That(actual, Is.EquivalentTo(expected), "Unexpected parse results"); Assert.That(actual, Is.EquivalentTo(expected), "Unexpected parse results");
Assert.That(actual, Is.EqualTo(expected), "Unexpected parse results"); Assert.That(actual, Is.EqualTo(expected), "Unexpected parse results");
} }
static IEnumerable<TestCaseData> SupportHoldRegexMatchesTestCases()
{
// Full specification
yield return Test(
"Army a-Munich/l@0 s A a-Tyrolia/l@0",
"Army", "a", "Munich", "l", "0", "s", "A", "a", "Tyrolia", "l", "0");
// Case insensitivity
yield return Test(
"fleet B-lon/C@0 SUPPORTS B-enc/W@0",
"fleet", "B", "lon", "C", "0", "SUPPORTS", "", "B", "enc", "W", "0");
// All optionals missing
yield return Test(
"ROM s VIE",
"", "", "ROM", "", "", "s", "", "", "VIE", "", "");
// No confusion of unit type and timeline
yield return Test(
"A F-STP s MOS",
"A", "F", "STP", "", "", "s", "", "", "MOS", "", "");
// No confusion of timeline and support verb
yield return Test(
"A Mun s Tyr",
"A", "", "Mun", "", "", "s", "", "", "Tyr", "", "");
// Elements with spaces
yield return Test(
"Western Mediterranean Sea supports Gulf of Lyons",
"", "", "Western Mediterranean Sea", "", "", "supports", "", "", "Gulf of Lyons", "", "");
// Parenthesis location
yield return Test(
"F Spain(nc) s Spain(sc)",
"F", "", "Spain", "nc", "", "s", "", "", "Spain", "sc", "");
// Timeline designation spells out a province
yield return Test(
"A tyr-MUN(vie) s mun-TYR/vie",
"A", "tyr", "MUN", "vie", "", "s", "", "mun", "TYR", "vie", "");
}
[TestCaseSource(nameof(SupportHoldRegexMatchesTestCases))]
public void SupportHoldRegexMatches(string order, string[] expected)
{
OrderRegex re = new(World.WithStandardMap());
var match = re.SupportHold.Match(order);
Assert.True(match.Success, "Match failed");
var (type, timeline, province, location, turn, supportVerb,
targetType, targetTimeline, targetProvince, targetLocation, targetTurn) = OrderRegex.ParseSupportHold(match);
string[] actual = [type, timeline, province, location, turn, supportVerb,
targetType, targetTimeline, targetProvince, targetLocation, targetTurn];
// 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");
}
static IEnumerable<TestCaseData> 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");
}
} }

View File

@ -8,4 +8,4 @@ This project was inspired by [Oliver Lugg's proof-of-concept version](https://gi
This project is not ready for end users yet! This project is not ready for end users yet!
I am working in VS Code on NixOS so currently the developer setup is optimized for that. Code is launch from inside a `nix develop` shell so it gets the environment. I am working in VS Code on NixOS so currently the developer setup is optimized for that. VS Code is launched from inside a `nix develop` shell so it gets the environment. The C# debugger fails to launch on NixOS so I run Code through an Ubuntu 22.04 distrobox when I need that.

View File

@ -10,6 +10,8 @@ When the adjudicator is in a more complete state, this section will declare the
The MDATC (Multiversal Diplomacy Adjudicator Test Cases) document defines test cases that involve multiversal time travel. The MDATC (Multiversal Diplomacy Adjudicator Test Cases) document defines test cases that involve multiversal time travel.
- 4.C.5 (missing nationality in support order), 4.C.6 (wrong nationalist in support order): 5dplomacy does not support specifying the nationalirt of the supported unit.
## Variant rules ## Variant rules
### Multiversal time travel and timeline forks ### Multiversal time travel and timeline forks