diff --git a/MultiversalDiplomacy/Model/Regex.cs b/MultiversalDiplomacy/Model/Regex.cs new file mode 100644 index 0000000..b6cdbe9 --- /dev/null +++ b/MultiversalDiplomacy/Model/Regex.cs @@ -0,0 +1,82 @@ +using System.Text.RegularExpressions; + +namespace MultiversalDiplomacy.Model; + +public class OrderRegex(World world) +{ + static IEnumerable AllProvinceNames(Province prov) => prov.Abbreviations.Append(prov.Name); + + public string Power = $"({string.Join("|", world.Powers)})"; + + public string Province = $"({string.Join("|", world.Provinces.SelectMany(AllProvinceNames))})"; + + public const string Type = "(A|F|Army|Fleet)"; + + public const string Timeline = "([A-Za-z]+)"; + + public const string Turn = "([0-9]+)"; + + public const string SlashLocation = "(?:/([A-Za-z]+))"; + + public const string ParenLocation = "(?:\\(([A-Za-z ]+)\\))"; + + public string FullLocation => $"(?:{Timeline}-)?{Province}(?:{SlashLocation}|{ParenLocation})?(?:@{Turn})?"; + + public string Unit => $"(?:(?:{Power} )?{Type} )?{FullLocation}"; + + public const string HoldVerb = "(h|hold|holds)"; + + public const string MoveVerb = "(-|(?:->)|(?:=>)|(?:attack(?:s)?)|(?:move(?:s)?(?: to)?))"; + + public Regex Hold => new($"^{Unit} {HoldVerb}$"); + + public static ( + string power, + string type, + string timeline, + string province, + string location, + string turn, + string verb) + ParseHold(Match match) + => (match.Groups[1].Value, + match.Groups[2].Value, + match.Groups[3].Value, + match.Groups[4].Value, + match.Groups[5].Length > 0 + ? match.Groups[5].Value + : match.Groups[6].Value, + match.Groups[7].Value, + match.Groups[8].Value); + + public Regex Move => new($"^{Unit} {MoveVerb} {FullLocation}$"); + + public static ( + string power, + string type, + string timeline, + string province, + string location, + string turn, + string verb, + string timeline2, + string province2, + string location2, + string turn2) + ParseMove(Match match) + => (match.Groups[1].Value, + match.Groups[2].Value, + match.Groups[3].Value, + match.Groups[4].Value, + match.Groups[5].Length > 0 + ? 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 > 1 + ? match.Groups[11].Value + : match.Groups[12].Value, + match.Groups[13].Value); +} \ No newline at end of file diff --git a/MultiversalDiplomacyTests/RegexTest.cs b/MultiversalDiplomacyTests/RegexTest.cs new file mode 100644 index 0000000..1f396ad --- /dev/null +++ b/MultiversalDiplomacyTests/RegexTest.cs @@ -0,0 +1,54 @@ +using System.Text.RegularExpressions; + +using NUnit.Framework; + +using MultiversalDiplomacy.Model; + +namespace MultiversalDiplomacyTests; + +public class RegexTest +{ + [Test] + public void UnitTokenizer() + { + World world = World.WithStandardMap(); + OrderRegex re = new(world); + + var match = re.Hold.Match("Germany Army a-Munich/l@0 holds"); + Assert.That(match.Success, Is.True); + var hold = OrderRegex.ParseHold(match); + Assert.That(hold.power, Is.EqualTo("Germany")); + Assert.That(hold.type, Is.EqualTo("Army")); + Assert.That(hold.timeline, Is.EqualTo("a")); + Assert.That(hold.province, Is.EqualTo("Munich")); + Assert.That(hold.location, Is.EqualTo("l")); + Assert.That(hold.turn, Is.EqualTo("0")); + Assert.That(hold.verb, Is.EqualTo("holds")); + + match = re.Hold.Match("F Venice hold"); + Assert.That(match.Success, Is.True); + hold = OrderRegex.ParseHold(match); + Assert.That(hold.power, Is.EqualTo("")); + Assert.That(hold.type, Is.EqualTo("F")); + Assert.That(hold.timeline, Is.EqualTo("")); + Assert.That(hold.province, Is.EqualTo("Venice")); + Assert.That(hold.location, Is.EqualTo("")); + Assert.That(hold.turn, Is.EqualTo("")); + Assert.That(hold.verb, Is.EqualTo("hold")); + + match = re.Move.Match("F Gascony - Spain(nc)"); + Assert.That(match.Success, Is.True); + var 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("Gascony")); + 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("Spain")); + Assert.That(move.location2, Is.EqualTo("nc")); + Assert.That(move.turn2, Is.EqualTo("")); + } +} \ No newline at end of file