Compare commits
No commits in common. "b4f8f621ca4bb33df6aacaf9130a0ff280cc1fc8" and "ebeb17898429ee90983f1843b49e4b2fe52c9e98" have entirely different histories.
b4f8f621ca
...
ebeb178984
|
@ -19,7 +19,7 @@ public class OrderRegex(World world)
|
||||||
|
|
||||||
public string FullLocation => $"(?:{Timeline}-)?{world.Map.ProvinceRegex}(?:{SlashLocation}|{ParenLocation})?(?:@{Turn})?";
|
public string FullLocation => $"(?:{Timeline}-)?{world.Map.ProvinceRegex}(?:{SlashLocation}|{ParenLocation})?(?:@{Turn})?";
|
||||||
|
|
||||||
public string UnitSpec => $"(?:{Type} )?{FullLocation}";
|
public string UnitSpec => $"(?:(?:{world.Map.PowerRegex} )?{Type} )?{FullLocation}";
|
||||||
|
|
||||||
public const string HoldVerb = "(h|hold|holds)";
|
public const string HoldVerb = "(h|hold|holds)";
|
||||||
|
|
||||||
|
@ -27,59 +27,59 @@ public class OrderRegex(World world)
|
||||||
|
|
||||||
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($"^{Unit} {HoldVerb}$");
|
||||||
$"^{UnitSpec} {HoldVerb}$",
|
|
||||||
RegexOptions.IgnoreCase);
|
|
||||||
|
|
||||||
public static (
|
public static (
|
||||||
|
string power,
|
||||||
string type,
|
string type,
|
||||||
string timeline,
|
string timeline,
|
||||||
string province,
|
string province,
|
||||||
string location,
|
string location,
|
||||||
string turn,
|
string turn,
|
||||||
string holdVerb)
|
string verb)
|
||||||
ParseHold(Match match) => (
|
ParseHold(Match match)
|
||||||
match.Groups[1].Value,
|
=> (match.Groups[1].Value,
|
||||||
match.Groups[2].Value,
|
match.Groups[2].Value,
|
||||||
match.Groups[3].Value,
|
match.Groups[3].Value,
|
||||||
match.Groups[4].Length > 0
|
match.Groups[4].Value,
|
||||||
? match.Groups[4].Value
|
match.Groups[5].Length > 0
|
||||||
: match.Groups[5].Value,
|
? match.Groups[5].Value
|
||||||
match.Groups[6].Value,
|
: match.Groups[6].Value,
|
||||||
match.Groups[7].Value);
|
match.Groups[7].Value,
|
||||||
|
match.Groups[8].Value);
|
||||||
|
|
||||||
public Regex Move => new(
|
public Regex Move => new($"^{UnitSpec} {MoveVerb} {FullLocation}$(?: {ViaConvoy})?");
|
||||||
$"^{UnitSpec} {MoveVerb} {FullLocation}(?: {ViaConvoy})?$",
|
|
||||||
RegexOptions.IgnoreCase);
|
|
||||||
|
|
||||||
public static (
|
public static (
|
||||||
|
string power,
|
||||||
string type,
|
string type,
|
||||||
string timeline,
|
string timeline,
|
||||||
string province,
|
string province,
|
||||||
string location,
|
string location,
|
||||||
string turn,
|
string turn,
|
||||||
string moveVerb,
|
string verb,
|
||||||
string destTimeline,
|
string timeline2,
|
||||||
string destProvince,
|
string province2,
|
||||||
string destLocation,
|
string location2,
|
||||||
string destTurn,
|
string turn2,
|
||||||
string viaConvoy)
|
string viaConvoy)
|
||||||
ParseMove(Match match) => (
|
ParseMove(Match match)
|
||||||
match.Groups[1].Value,
|
=> (match.Groups[1].Value,
|
||||||
match.Groups[2].Value,
|
match.Groups[2].Value,
|
||||||
match.Groups[3].Value,
|
match.Groups[3].Value,
|
||||||
match.Groups[4].Length > 0
|
match.Groups[4].Value,
|
||||||
? match.Groups[4].Value
|
match.Groups[5].Length > 0
|
||||||
: match.Groups[5].Value,
|
? match.Groups[5].Value
|
||||||
match.Groups[6].Value,
|
: match.Groups[6].Value,
|
||||||
match.Groups[7].Value,
|
match.Groups[7].Value,
|
||||||
match.Groups[8].Value,
|
match.Groups[8].Value,
|
||||||
match.Groups[9].Value,
|
match.Groups[9].Value,
|
||||||
match.Groups[10].Length > 0
|
match.Groups[10].Value,
|
||||||
? match.Groups[10].Value
|
match.Groups[11].Length > 1
|
||||||
: match.Groups[11].Value,
|
? match.Groups[11].Value
|
||||||
match.Groups[12].Value,
|
: match.Groups[12].Value,
|
||||||
match.Groups[13].Value);
|
match.Groups[13].Value,
|
||||||
|
match.Groups[14].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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -71,8 +71,8 @@ public class GameScriptHandler(World world, bool strict = false) : IScriptHandle
|
||||||
|
|
||||||
if (OrderRegex.TryParseOrder(World, orderPower, orderText, out Order? order)) {
|
if (OrderRegex.TryParseOrder(World, orderPower, orderText, out Order? order)) {
|
||||||
Console.WriteLine($"Parsed {orderPower} order \"{orderText}\" but doing anything with it isn't implemented yet");
|
Console.WriteLine($"Parsed {orderPower} order \"{orderText}\" but doing anything with it isn't implemented yet");
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine($"Failed to parse \"{orderText}\"");
|
Console.WriteLine($"Failed to parse \"{orderText}\"");
|
||||||
return Strict ? null : this;
|
return Strict ? null : this;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
using MultiversalDiplomacy.Model;
|
using MultiversalDiplomacy.Model;
|
||||||
|
@ -6,96 +8,62 @@ namespace MultiversalDiplomacyTests;
|
||||||
|
|
||||||
public class RegexTest
|
public class RegexTest
|
||||||
{
|
{
|
||||||
private static TestCaseData Test(string order, params string[] expected)
|
[Test]
|
||||||
=> new TestCaseData(order, expected).SetName($"{{m}}(\"{order}\")");
|
public void UnitTokenizer()
|
||||||
|
|
||||||
static IEnumerable<TestCaseData> HoldRegexMatchesTestCases()
|
|
||||||
{
|
{
|
||||||
// Full specification
|
World world = World.WithStandardMap();
|
||||||
yield return Test(
|
OrderRegex re = new(world);
|
||||||
"Army a-Munich/l@0 holds",
|
|
||||||
"Army", "a", "Munich", "l", "0", "holds");
|
|
||||||
// Case insensitivity
|
|
||||||
yield return Test(
|
|
||||||
"fleet B-lon/C@0 H",
|
|
||||||
"fleet", "B", "lon", "C", "0", "H");
|
|
||||||
// All optionals missing
|
|
||||||
yield return Test(
|
|
||||||
"ROM h",
|
|
||||||
"", "", "ROM", "", "", "h");
|
|
||||||
// No confusion of unit type and timeline
|
|
||||||
yield return Test(
|
|
||||||
"A F-STP hold",
|
|
||||||
"A", "F", "STP", "", "", "hold");
|
|
||||||
// Province with space in name
|
|
||||||
yield return Test(
|
|
||||||
"Fleet North Sea Hold",
|
|
||||||
"Fleet", "", "North Sea", "", "", "Hold");
|
|
||||||
// Parenthesis location
|
|
||||||
yield return Test(
|
|
||||||
"F Spain(nc) holds",
|
|
||||||
"F", "", "Spain", "nc", "", "holds");
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCaseSource(nameof(HoldRegexMatchesTestCases))]
|
var match = re.Hold.Match("Germany Army a-Munich/l@0 holds");
|
||||||
public void HoldRegexMatches(string order, string[] expected)
|
Assert.That(match.Success, Is.True);
|
||||||
{
|
var hold = OrderRegex.ParseHold(match);
|
||||||
OrderRegex re = new(World.WithStandardMap());
|
Assert.That(hold.power, Is.EqualTo("Germany"));
|
||||||
var match = re.Hold.Match(order);
|
Assert.That(hold.type, Is.EqualTo("Army"));
|
||||||
Assert.True(match.Success, "Match failed");
|
Assert.That(hold.timeline, Is.EqualTo("a"));
|
||||||
var (type, timeline, province, location, turn, holdVerb) = OrderRegex.ParseHold(match);
|
Assert.That(hold.province, Is.EqualTo("Munich"));
|
||||||
string[] actual = [type, timeline, province, location, turn, holdVerb];
|
Assert.That(hold.location, Is.EqualTo("l"));
|
||||||
// Use EquivalentTo for more detailed error message
|
Assert.That(hold.turn, Is.EqualTo("0"));
|
||||||
Assert.That(actual, Is.EquivalentTo(expected), "Unexpected parse results");
|
Assert.That(hold.verb, Is.EqualTo("holds"));
|
||||||
Assert.That(actual, Is.EqualTo(expected), "Unexpected parse results");
|
|
||||||
}
|
|
||||||
|
|
||||||
static IEnumerable<TestCaseData> MoveRegexMatchesTestCases()
|
match = re.Hold.Match("F Venice hold");
|
||||||
{
|
Assert.That(match.Success, Is.True);
|
||||||
static TestCaseData Test(string order, params string[] expected)
|
hold = OrderRegex.ParseHold(match);
|
||||||
=> new TestCaseData(order, expected).SetName($"{{m}}(\"{order}\")");
|
Assert.That(hold.power, Is.EqualTo(""));
|
||||||
// Full specification
|
Assert.That(hold.type, Is.EqualTo("F"));
|
||||||
yield return Test(
|
Assert.That(hold.timeline, Is.EqualTo(""));
|
||||||
"Army a-Munich/l@0 - a-Tyrolia/l@0",
|
Assert.That(hold.province, Is.EqualTo("Venice"));
|
||||||
"Army", "a", "Munich", "l", "0", "-", "a", "Tyrolia", "l", "0", "");
|
Assert.That(hold.location, Is.EqualTo(""));
|
||||||
// Case insensitivity
|
Assert.That(hold.turn, Is.EqualTo(""));
|
||||||
yield return Test(
|
Assert.That(hold.verb, Is.EqualTo("hold"));
|
||||||
"fleet B-lon/C@0 - B-enc/W@0",
|
|
||||||
"fleet", "B", "lon", "C", "0", "-", "B", "enc", "W", "0", "");
|
|
||||||
// All optionals missing
|
|
||||||
yield return Test(
|
|
||||||
"ROM - VIE",
|
|
||||||
"", "", "ROM", "", "", "-", "", "VIE", "", "", "");
|
|
||||||
// No confusion of unit type and timeline
|
|
||||||
yield return Test(
|
|
||||||
"A F-STP - MOS",
|
|
||||||
"A", "F", "STP", "", "", "-", "", "MOS", "", "", "");
|
|
||||||
// Elements with spaces
|
|
||||||
yield return Test(
|
|
||||||
"Fleet Western Mediterranean Sea moves to Gulf of Lyons via convoy",
|
|
||||||
"Fleet", "", "Western Mediterranean Sea", "", "", "moves to", "", "Gulf of Lyons", "", "", "via convoy");
|
|
||||||
// Parenthesis location
|
|
||||||
yield return Test(
|
|
||||||
"F Spain(nc) - Spain(sc)",
|
|
||||||
"F", "", "Spain", "nc", "", "-", "", "Spain", "sc", "", "");
|
|
||||||
// Timeline designation spells out a province
|
|
||||||
yield return Test(
|
|
||||||
"A tyr-MUN(vie) - mun-TYR/vie",
|
|
||||||
"A", "tyr", "MUN", "vie", "", "-", "mun", "TYR", "vie", "", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCaseSource(nameof(MoveRegexMatchesTestCases))]
|
match = re.Move.Match("F Gascony - Spain(nc)");
|
||||||
public void MoveRegexMatches(string order, string[] expected)
|
Assert.That(match.Success, Is.True);
|
||||||
{
|
var move = OrderRegex.ParseMove(match);
|
||||||
OrderRegex re = new(World.WithStandardMap());
|
Assert.That(move.power, Is.EqualTo(""));
|
||||||
var match = re.Move.Match(order);
|
Assert.That(move.type, Is.EqualTo("F"));
|
||||||
Assert.True(match.Success, "Match failed");
|
Assert.That(move.timeline, Is.EqualTo(""));
|
||||||
var (type, timeline, province, location, turn, moveVerb,
|
Assert.That(move.province, Is.EqualTo("Gascony"));
|
||||||
destTimeline, destProvince, destLocation, destTurn, viaConvoy) = OrderRegex.ParseMove(match);
|
Assert.That(move.location, Is.EqualTo(""));
|
||||||
string[] actual = [type, timeline, province, location, turn, moveVerb,
|
Assert.That(move.turn, Is.EqualTo(""));
|
||||||
destTimeline, destProvince, destLocation, destTurn, viaConvoy];
|
Assert.That(move.verb, Is.EqualTo("-"));
|
||||||
// Use EquivalentTo for more detailed error message
|
Assert.That(move.timeline2, Is.EqualTo(""));
|
||||||
Assert.That(actual, Is.EquivalentTo(expected), "Unexpected parse results");
|
Assert.That(move.province2, Is.EqualTo("Spain"));
|
||||||
Assert.That(actual, Is.EqualTo(expected), "Unexpected parse results");
|
Assert.That(move.location2, Is.EqualTo("nc"));
|
||||||
|
Assert.That(move.turn2, Is.EqualTo(""));
|
||||||
|
|
||||||
|
match = re.Move.Match("F North Sea - Picardy");
|
||||||
|
Assert.That(match.Success, Is.True);
|
||||||
|
move = OrderRegex.ParseMove(match);
|
||||||
|
Assert.That(move.power, Is.EqualTo(""));
|
||||||
|
Assert.That(move.type, Is.EqualTo("F"));
|
||||||
|
Assert.That(move.timeline, Is.EqualTo(""));
|
||||||
|
Assert.That(move.province, Is.EqualTo("North Sea"));
|
||||||
|
Assert.That(move.location, Is.EqualTo(""));
|
||||||
|
Assert.That(move.turn, Is.EqualTo(""));
|
||||||
|
Assert.That(move.verb, Is.EqualTo("-"));
|
||||||
|
Assert.That(move.timeline2, Is.EqualTo(""));
|
||||||
|
Assert.That(move.province2, Is.EqualTo("Picardy"));
|
||||||
|
Assert.That(move.location2, Is.EqualTo(""));
|
||||||
|
Assert.That(move.turn2, Is.EqualTo(""));
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue