From dab37c239b196ae80bfde5f216c2c52a5b2f1ae9 Mon Sep 17 00:00:00 2001 From: Tim Van Baak Date: Sun, 11 Aug 2024 21:01:05 -0700 Subject: [PATCH] Refactor province and power information into Map --- MultiversalDiplomacy/Model/Map.cs | 560 ++++++++++++++++++ MultiversalDiplomacy/Model/MapType.cs | 16 + MultiversalDiplomacy/Model/World.cs | 560 +----------------- MultiversalDiplomacyTests/MapTests.cs | 8 +- MultiversalDiplomacyTests/TestCaseBuilder.cs | 36 +- .../TestCaseBuilderTest.cs | 12 +- MultiversalDiplomacyTests/UnitTests.cs | 8 +- 7 files changed, 626 insertions(+), 574 deletions(-) create mode 100644 MultiversalDiplomacy/Model/Map.cs create mode 100644 MultiversalDiplomacy/Model/MapType.cs diff --git a/MultiversalDiplomacy/Model/Map.cs b/MultiversalDiplomacy/Model/Map.cs new file mode 100644 index 0000000..1ce0c57 --- /dev/null +++ b/MultiversalDiplomacy/Model/Map.cs @@ -0,0 +1,560 @@ +using System.Collections.ObjectModel; + +namespace MultiversalDiplomacy.Model; + +/// +/// Encapsulation of the world map and playable powers constituting a Diplomacy variant. +/// +public class Map { + /// + /// The game map. + /// + public ReadOnlyCollection Provinces { get; } + + /// + /// The game powers. + /// + public ReadOnlyCollection Powers { get; } + + private Map(IEnumerable provinces, IEnumerable powers) + { + Provinces = new(provinces.ToList()); + Powers = new(powers.ToList()); + } + + /// + /// Get a province by name. Throws if the province is not found. + /// + public Province GetProvince(string provinceName) + => GetProvince(provinceName, this.Provinces); + + /// + /// Get a province by name. Throws if the province is not found. + /// + private static Province GetProvince(string provinceName, IEnumerable provinces) + { + string provinceNameUpper = provinceName.ToUpperInvariant(); + Province? foundProvince = provinces.SingleOrDefault( + p => p!.Name.ToUpperInvariant() == provinceNameUpper + || p.Abbreviations.Any(a => a.ToUpperInvariant() == provinceNameUpper), + null); + if (foundProvince == null) throw new KeyNotFoundException( + $"Province {provinceName} not found"); + return foundProvince; + } + + /// + /// Get the location in a province matching a predicate. Throws if there is not exactly one + /// such location. + /// + private Location GetLocation(string provinceName, Func predicate) + { + Location? foundLocation = GetProvince(provinceName).Locations.SingleOrDefault( + l => l != null && predicate(l), null); + if (foundLocation == null) throw new KeyNotFoundException( + $"No such location in {provinceName}"); + return foundLocation; + } + + /// + /// Get the sole land location of a province. + /// + public Location GetLand(string provinceName) + => GetLocation(provinceName, l => l.Type == LocationType.Land); + + /// + /// Get the sole water location of a province, optionally specifying a named coast. + /// + public Location GetWater(string provinceName, string? coastName = null) + => coastName == null + ? GetLocation(provinceName, l => l.Type == LocationType.Water) + : GetLocation(provinceName, l => l.Name == coastName || l.Abbreviation == coastName); + + /// + /// Get a power by name. Throws if there is not exactly one such power. + /// + public Power GetPower(string powerName) + => Powers.SingleOrDefault(p => p!.Name == powerName || p.Name.StartsWith(powerName), null) + ?? throw new KeyNotFoundException($"Power {powerName} not found"); + + public static Map FromType(MapType type) + => type switch { + MapType.Test => Test, + MapType.Classical => Test, + _ => throw new NotImplementedException($"Unknown variant {type}"), + }; + +#region Variants + + public static Map Test => _Test.Value; + + private static readonly Lazy _Test = new(() => { + Province lef = Province.Time("Left", "Lef") + .AddLandLocation(); + Province cen = Province.Empty("Center", "Cen") + .AddLandLocation(); + Province rig = Province.Time("Right", "Rig") + .AddLandLocation(); + Location center = cen.Locations.First(); + center.AddBorder(lef.Locations.First()); + center.AddBorder(rig.Locations.First()); + + Power a = new("Alpha"); + Power b = new("Beta"); + + return new([lef, cen, rig], [a, b]); + }); + + public static Map Classical => _Classical.Value; + + private static readonly Lazy _Classical = new(() => { + // Define the provinces of the standard world map. + List provinces = + [ + Province.Empty("North Africa", "NAF") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Tunis", "TUN") + .AddLandLocation() + .AddCoastLocation(), + Province.Empty("Bohemia", "BOH") + .AddLandLocation(), + Province.Supply("Budapest", "BUD") + .AddLandLocation(), + Province.Empty("Galacia", "GAL") + .AddLandLocation(), + Province.Supply("Trieste", "TRI") + .AddLandLocation() + .AddCoastLocation(), + Province.Empty("Tyrolia", "TYR") + .AddLandLocation(), + Province.Time("Vienna", "VIE") + .AddLandLocation(), + Province.Empty("Albania", "ALB") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Bulgaria", "BUL") + .AddLandLocation() + .AddCoastLocation("east coast", "ec") + .AddCoastLocation("south coast", "sc"), + Province.Supply("Greece", "GRE") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Rumania", "RUM", "RMA") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Serbia", "SER") + .AddLandLocation(), + Province.Empty("Clyde", "CLY") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Edinburgh", "EDI") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Liverpool", "LVP", "LPL") + .AddLandLocation() + .AddCoastLocation(), + Province.Time("London", "LON") + .AddLandLocation() + .AddCoastLocation(), + Province.Empty("Wales", "WAL") + .AddLandLocation() + .AddCoastLocation(), + Province.Empty("Yorkshire", "YOR") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Brest", "BRE") + .AddLandLocation() + .AddCoastLocation(), + Province.Empty("Burgundy", "BUR") + .AddLandLocation(), + Province.Empty("Gascony", "GAS") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Marseilles", "MAR") + .AddLandLocation() + .AddCoastLocation(), + Province.Time("Paris", "PAR") + .AddLandLocation(), + Province.Empty("Picardy", "PIC") + .AddLandLocation() + .AddCoastLocation(), + Province.Time("Berlin", "BER") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Kiel", "KIE") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Munich", "MUN") + .AddLandLocation(), + Province.Empty("Prussia", "PRU") + .AddLandLocation() + .AddCoastLocation(), + Province.Empty("Ruhr", "RUH", "RHR") + .AddLandLocation(), + Province.Empty("Silesia", "SIL") + .AddLandLocation(), + Province.Supply("Spain", "SPA") + .AddLandLocation() + .AddCoastLocation("north coast", "nc") + .AddCoastLocation("south coast", "sc"), + Province.Supply("Portugal", "POR") + .AddLandLocation() + .AddCoastLocation(), + Province.Empty("Apulia", "APU") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Naples", "NAP") + .AddLandLocation() + .AddCoastLocation(), + Province.Empty("Piedmont", "PIE") + .AddLandLocation() + .AddCoastLocation(), + Province.Time("Rome", "ROM", "RME") + .AddLandLocation() + .AddCoastLocation(), + Province.Empty("Tuscany", "TUS") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Venice", "VEN") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Belgium", "BEL") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Holland", "HOL") + .AddLandLocation() + .AddCoastLocation(), + Province.Empty("Finland", "FIN") + .AddLandLocation() + .AddCoastLocation(), + Province.Empty("Livonia", "LVN", "LVA") + .AddLandLocation() + .AddCoastLocation(), + Province.Time("Moscow", "MOS") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Sevastopol", "SEV") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Saint Petersburg", "STP") + .AddLandLocation() + .AddCoastLocation("north coast", "nc") + .AddCoastLocation("west coast", "wc"), + Province.Empty("Ukraine", "UKR") + .AddLandLocation(), + Province.Supply("Warsaw", "WAR") + .AddLandLocation(), + Province.Supply("Denmark", "DEN") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Norway", "NWY") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Sweden", "SWE") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Ankara", "ANK") + .AddLandLocation() + .AddCoastLocation(), + Province.Empty("Armenia", "ARM") + .AddLandLocation() + .AddCoastLocation(), + Province.Time("Constantinople", "CON") + .AddLandLocation() + .AddCoastLocation(), + Province.Supply("Smyrna", "SMY") + .AddLandLocation() + .AddCoastLocation(), + Province.Empty("Syria", "SYR") + .AddLandLocation() + .AddCoastLocation(), + Province.Empty("Barents Sea", "BAR") + .AddOceanLocation(), + Province.Empty("English Channel", "ENC", "ECH") + .AddOceanLocation(), + Province.Empty("Heligoland Bight", "HEL", "HGB") + .AddOceanLocation(), + Province.Empty("Irish Sea", "IRS", "IRI") + .AddOceanLocation(), + Province.Empty("Mid-Atlantic Ocean", "MAO", "MID") + .AddOceanLocation(), + Province.Empty("North Atlantic Ocean", "NAO", "NAT") + .AddOceanLocation(), + Province.Empty("North Sea", "NTH", "NTS") + .AddOceanLocation(), + Province.Empty("Norwegian Sea", "NWS", "NWG") + .AddOceanLocation(), + Province.Empty("Skagerrak", "SKA", "SKG") + .AddOceanLocation(), + Province.Empty("Baltic Sea", "BAL") + .AddOceanLocation(), + Province.Empty("Guld of Bothnia", "GOB", "BOT") + .AddOceanLocation(), + Province.Empty("Adriatic Sea", "ADS", "ADR") + .AddOceanLocation(), + Province.Empty("Aegean Sea", "AEG") + .AddOceanLocation(), + Province.Empty("Black Sea", "BLA") + .AddOceanLocation(), + Province.Empty("Eastern Mediterranean Sea", "EMS", "EAS") + .AddOceanLocation(), + Province.Empty("Gulf of Lyons", "GOL", "LYO") + .AddOceanLocation(), + Province.Empty("Ionian Sea", "IOS", "ION", "INS") + .AddOceanLocation(), + Province.Empty("Tyrrhenian Sea", "TYS", "TYN") + .AddOceanLocation(), + Province.Empty("Western Mediterranean Sea", "WMS", "WES") + .AddOceanLocation(), + ]; + + // Declare some helpers for border definitions + Location Land(string provinceName) => GetProvince(provinceName, provinces) + .Locations.Single(l => l.Type == LocationType.Land); + Location Water(string provinceName) => GetProvince(provinceName, provinces) + .Locations.Single(l => l.Type == LocationType.Water); + Location Coast(string provinceName, string coastName) + => GetProvince(provinceName, provinces) + .Locations.Single(l => l.Name == coastName || l.Abbreviation == coastName); + + static void AddBordersTo(Location location, Func LocationType, params string[] borders) + { + foreach (string bordering in borders) + { + location.AddBorder(LocationType(bordering)); + } + } + void AddBorders(string provinceName, Func LocationType, params string[] borders) + => AddBordersTo(LocationType(provinceName), LocationType, borders); + + AddBorders("NAF", Land, "TUN"); + AddBorders("NAF", Water, "MAO", "WES", "TUN"); + + AddBorders("TUN", Land, "NAF"); + AddBorders("TUN", Water, "NAF", "WES", "TYS", "ION"); + + AddBorders("BOH", Land, "MUN", "SIL", "GAL", "VIE", "TYR"); + + AddBorders("BUD", Land, "VIE", "GAL", "RUM", "SER", "TRI"); + + AddBorders("GAL", Land, "BOH", "SIL", "WAR", "UKR", "RUM", "BUD", "VIE"); + + AddBorders("TRI", Land, "TYR", "VIE", "BUD", "SER", "ALB"); + AddBorders("TRI", Water, "ALB", "ADR", "VEN"); + + AddBorders("TYR", Land, "MUN", "BOH", "VIE", "TRI", "VEN", "PIE"); + + AddBorders("VIE", Land, "TYR", "BOH", "GAL", "BUD", "TRI"); + + AddBorders("ALB", Land, "TRI", "SER", "GRE"); + AddBorders("ALB", Water, "TRI", "ADR", "ION", "GRE"); + + AddBorders("BUL", Land, "GRE", "SER", "RUM", "CON"); + AddBordersTo(Coast("BUL", "ec"), Water, "BLA", "CON"); + AddBordersTo(Coast("BUL", "sc"), Water, "CON", "AEG", "GRE"); + + AddBorders("GRE", Land, "ALB", "SER", "BUL"); + AddBorders("GRE", Water, "ALB", "ION", "AEG"); + Water("GRE").AddBorder(Coast("BUL", "sc")); + + AddBorders("RUM", Land, "BUL", "SER", "BUD", "GAL", "UKR", "SEV"); + AddBorders("RUM", Water, "SEV", "BLA"); + Water("RUM").AddBorder(Coast("BUL", "ec")); + + AddBorders("SER", Land, "BUD", "RUM", "BUL", "GRE", "ALB", "TRI"); + + AddBorders("CLY", Land, "EDI", "LVP"); + AddBorders("CLY", Water, "LVP", "NAO", "NWG", "EDI"); + + AddBorders("EDI", Land, "YOR", "LVP", "CLY"); + AddBorders("EDI", Water, "CLY", "NWG", "NTH", "YOR"); + + AddBorders("LVP", Land, "CLY", "EDI", "YOR", "WAL"); + AddBorders("LVP", Water, "WAL", "IRS", "NAO", "CLY"); + + AddBorders("LON", Land, "WAL", "YOR"); + AddBorders("LON", Water, "WAL", "ENC", "NTH", "YOR"); + + AddBorders("WAL", Land, "LVP", "YOR", "LON"); + AddBorders("WAL", Water, "LON", "ENC", "IRS", "LVP"); + + AddBorders("YOR", Land, "LON", "WAL", "LVP", "EDI"); + AddBorders("YOR", Water, "EDI", "NTH", "LON"); + + AddBorders("BRE", Land, "PIC", "PAR", "GAS"); + AddBorders("BRE", Water, "GAS", "MAO", "ENC", "PIC"); + + AddBorders("BUR", Land, "BEL", "RUH", "MUN", "MAR", "GAS", "PAR", "PIC"); + + AddBorders("GAS", Land, "BRE", "PAR", "BUR", "MAR", "SPA"); + AddBorders("GAS", Water, "MAO", "BRE"); + Water("GAS").AddBorder(Coast("SPA", "nc")); + + AddBorders("MAR", Land, "SPA", "GAS", "BUR", "PIE"); + AddBorders("MAR", Water, "LYO", "PIE"); + Water("MAR").AddBorder(Coast("SPA", "sc")); + + AddBorders("PAR", Land, "PIC", "BUR", "GAS", "BRE"); + + AddBorders("PIC", Land, "BEL", "BUR", "PAR", "BRE"); + AddBorders("PIC", Water, "BRE", "ENC", "BEL"); + + AddBorders("BER", Land, "PRU", "SIL", "MUN", "KIE"); + AddBorders("BER", Water, "KIE", "BAL", "PRU"); + + AddBorders("KIE", Land, "BER", "MUN", "RUH", "HOL", "DEN"); + AddBorders("KIE", Water, "HOL", "HEL", "DEN", "BAL", "BER"); + + AddBorders("MUN", Land, "BUR", "RUH", "KIE", "BER", "SIL", "BOH", "TYR"); + + AddBorders("PRU", Land, "LVN", "WAR", "SIL", "BER"); + AddBorders("PRU", Water, "BER", "BAL", "LVN"); + + AddBorders("RUH", Land, "KIE", "MUN", "BUR", "BEL", "HOL"); + + AddBorders("SIL", Land, "PRU", "WAR", "GAL", "BOH", "MUN", "BER"); + + AddBorders("SPA", Land, "POR", "GAS", "MAR"); + AddBordersTo(Coast("SPA", "nc"), Water, "POR", "MAO", "GAS"); + AddBordersTo(Coast("SPA", "sc"), Water, "POR", "MAO", "WES", "LYO", "MAR"); + + AddBorders("POR", Land, "SPA"); + AddBorders("POR", Water, "MAO"); + Water("POR").AddBorder(Coast("SPA", "nc")); + Water("POR").AddBorder(Coast("SPA", "sc")); + + AddBorders("APU", Land, "NAP", "ROM", "VEN"); + AddBorders("APU", Water, "VEN", "ADR", "IOS", "NAP"); + + AddBorders("NAP", Land, "ROM", "APU"); + AddBorders("NAP", Water, "APU", "IOS", "TYS", "ROM"); + + AddBorders("PIE", Land, "MAR", "TYR", "VEN", "TUS"); + AddBorders("PIE", Water, "TUS", "LYO", "MAR"); + + AddBorders("ROM", Land, "TUS", "VEN", "APU", "NAP"); + AddBorders("ROM", Water, "NAP", "TYS", "TUS"); + + AddBorders("TUS", Land, "PIE", "VEN", "ROM"); + AddBorders("TUS", Water, "ROM", "TYS", "LYO", "PIE"); + + AddBorders("VEN", Land, "APU", "ROM", "TUS", "PIE", "TYR", "TRI"); + AddBorders("VEN", Water, "TRI", "ADR", "APU"); + + AddBorders("BEL", Land, "HOL", "RUH", "BUR", "PIC"); + AddBorders("BEL", Water, "PIC", "ENC", "NTH", "HOL"); + + AddBorders("HOL", Land, "BEL", "RUH", "KIE"); + AddBorders("HOL", Water, "NTH", "HEL"); + + AddBorders("FIN", Land, "SWE", "NWY", "STP"); + AddBorders("FIN", Water, "SWE", "BOT"); + Water("FIN").AddBorder(Coast("STP", "wc")); + + AddBorders("LVN", Land, "STP", "MOS", "WAR", "PRU"); + AddBorders("LVN", Water, "PRU", "BAL", "BOT"); + Water("LVN").AddBorder(Coast("STP", "wc")); + + AddBorders("MOS", Land, "SEV", "UKR", "WAR", "LVN", "STP"); + + AddBorders("SEV", Land, "RUM", "UKR", "MOS", "ARM"); + AddBorders("SEV", Water, "ARM", "BLA", "RUM"); + + AddBorders("STP", Land, "MOS", "LVN", "FIN"); + AddBordersTo(Coast("STP", "nc"), Water, "BAR", "NWY"); + AddBordersTo(Coast("STP", "wc"), Water, "LVN", "BOT", "FIN"); + + AddBorders("UKR", Land, "MOS", "SEV", "RUM", "GAL", "WAR"); + + AddBorders("WAR", Land, "PRU", "LVN", "MOS", "UKR", "GAL", "SIL"); + + AddBorders("DEN", Land, "KIE", "SWE"); + AddBorders("DEN", Water, "KIE", "HEL", "NTH", "SKA", "BAL", "SWE"); + + AddBorders("NWY", Land, "STP", "FIN", "SWE"); + AddBorders("NWY", Water, "BAR", "NWG", "NTH", "SKA", "SWE"); + Water("NWY").AddBorder(Coast("STP", "nc")); + + AddBorders("SWE", Land, "NWY", "FIN", "DEN"); + AddBorders("SWE", Water, "FIN", "BOT", "BAL", "DEN", "SKA", "NWY"); + + AddBorders("ANK", Land, "ARM", "SMY", "CON"); + AddBorders("ANK", Water, "CON", "BLA", "ARM"); + + AddBorders("ARM", Land, "SEV", "SYR", "SMY", "ANK"); + AddBorders("ARM", Water, "ANK", "BLA", "SEV"); + + AddBorders("CON", Land, "BUL", "ANK", "SMY"); + AddBorders("CON", Water, "BLA", "ANK", "SMY", "AEG"); + Water("CON").AddBorder(Coast("BUL", "ec")); + Water("CON").AddBorder(Coast("BUL", "sc")); + + AddBorders("SMY", Land, "CON", "ANK", "ARM", "SYR"); + AddBorders("SMY", Water, "SYR", "EAS", "AEG", "CON"); + + AddBorders("SYR", Land, "SMY", "ARM"); + AddBorders("SYR", Water, "EAS", "SMY"); + + AddBorders("BAR", Water, "NWG", "NWY"); + Water("BAR").AddBorder(Coast("STP", "nc")); + + AddBorders("ENC", Water, "LON", "NTH", "BEL", "PIC", "BRE", "MAO", "IRS", "WAL"); + + AddBorders("HEL", Water, "NTH", "DEN", "BAL", "KIE", "HOL"); + + AddBorders("IRS", Water, "NAO", "LVP", "WAL", "ENC", "MAO"); + + AddBorders("MAO", Water, "NAO", "IRS", "ENC", "BRE", "GAS", "POR", "NAF"); + Water("MAO").AddBorder(Coast("SPA", "nc")); + Water("MAO").AddBorder(Coast("SPA", "sc")); + + AddBorders("NAO", Water, "NWG", "CLY", "LVP", "IRS", "MAO"); + + AddBorders("NTH", Water, "NWG", "NWY", "SKA", "DEN", "HEL", "HOL", "BEL", "ENC", "LON", "YOR", "EDI"); + + AddBorders("NWG", Water, "BAR", "NWY", "NTH", "EDI", "CLY", "NAO"); + + AddBorders("SKA", Water, "NWY", "SWE", "BAL", "DEN", "NTH"); + + AddBorders("BAL", Water, "BOT", "LVN", "PRU", "BER", "KIE", "HEL", "DEN", "SWE"); + + AddBorders("BOT", Water, "LVN", "BAL", "SWE", "FIN"); + Water("BOT").AddBorder(Coast("STP", "wc")); + + AddBorders("ADR", Water, "IOS", "APU", "VEN", "TRI", "ALB"); + + AddBorders("AEG", Water, "CON", "SMY", "EAS", "IOS", "GRE"); + Water("AEG").AddBorder(Coast("BUL", "sc")); + + AddBorders("BLA", Water, "RUM", "SEV", "ARM", "ANK", "CON"); + Water("BLA").AddBorder(Coast("BUL", "ec")); + + AddBorders("EAS", Water, "IOS", "AEG", "SMY", "SYR"); + + AddBorders("LYO", Water, "MAR", "PIE", "TUS", "TYS", "WES"); + Water("LYO").AddBorder(Coast("SPA", "sc")); + + AddBorders("IOS", Water, "TUN", "TYS", "NAP", "APU", "ADR", "ALB", "GRE", "AEG"); + + AddBorders("TYS", Water, "LYO", "TUS", "ROM", "NAP", "IOS", "TUN", "WES"); + + AddBorders("WES", Water, "LYO", "TYS", "TUN", "NAF", "MAO"); + Water("WES").AddBorder(Coast("SPA", "sc")); + + List powers = + [ + new("Austria"), + new("England"), + new("France"), + new("Germany"), + new("Italy"), + new("Russia"), + new("Turkey"), + ]; + + return new(provinces, powers); + }); + +#endregion Variants +} \ No newline at end of file diff --git a/MultiversalDiplomacy/Model/MapType.cs b/MultiversalDiplomacy/Model/MapType.cs new file mode 100644 index 0000000..1a9ee13 --- /dev/null +++ b/MultiversalDiplomacy/Model/MapType.cs @@ -0,0 +1,16 @@ +using System.Text.Json.Serialization; + +namespace MultiversalDiplomacy.Model; + +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum MapType { + /// + /// A minimal test map. + /// + Test, + + /// + /// The standard Diplomacy map. + /// + Classical, +} diff --git a/MultiversalDiplomacy/Model/World.cs b/MultiversalDiplomacy/Model/World.cs index 799933e..ed3e959 100644 --- a/MultiversalDiplomacy/Model/World.cs +++ b/MultiversalDiplomacy/Model/World.cs @@ -9,15 +9,20 @@ namespace MultiversalDiplomacy.Model; /// public class World { + /// + /// The map variant of the game. + /// + public readonly Map Map; + /// /// The game map. /// - public ReadOnlyCollection Provinces { get; } + public ReadOnlyCollection Provinces => this.Map.Provinces; /// /// The game powers. /// - public ReadOnlyCollection Powers { get; } + public ReadOnlyCollection Powers => this.Map.Powers; /// /// The state of the multiverse. @@ -53,8 +58,7 @@ public class World /// Create a new World, providing all state data. /// private World( - ReadOnlyCollection provinces, - ReadOnlyCollection powers, + Map map, ReadOnlyCollection seasons, Season rootSeason, ReadOnlyCollection units, @@ -62,8 +66,7 @@ public class World ReadOnlyDictionary orderHistory, Options options) { - this.Provinces = provinces; - this.Powers = powers; + this.Map = map; this.Seasons = seasons; this.RootSeason = rootSeason; this.Units = units; @@ -77,16 +80,13 @@ public class World /// private World( World previous, - ReadOnlyCollection? provinces = null, - ReadOnlyCollection? powers = null, ReadOnlyCollection? seasons = null, ReadOnlyCollection? units = null, ReadOnlyCollection? retreatingUnits = null, ReadOnlyDictionary? orderHistory = null, Options? options = null) : this( - provinces ?? previous.Provinces, - powers ?? previous.Powers, + previous.Map, seasons ?? previous.Seasons, previous.RootSeason, // Can't change the root season units ?? previous.Units, @@ -99,12 +99,11 @@ public class World /// /// Create a new world with specified provinces and powers and an initial season. /// - public static World WithMap(IEnumerable provinces, IEnumerable powers) + public static World WithMap(Map map) { Season root = Season.MakeRoot(); return new World( - new(provinces.ToList()), - new(powers.ToList()), + map, new(new List { root }), root, new(new List()), @@ -117,7 +116,7 @@ public class World /// Create a new world with the standard Diplomacy provinces and powers. /// public static World WithStandardMap() - => WithMap(StandardProvinces, StandardPowers); + => WithMap(Map.Classical); public World Update( IEnumerable? seasons = null, @@ -149,7 +148,7 @@ public class World IEnumerable units = unitSpecs.Select(spec => { string[] splits = spec.Split(' ', 4); - Power power = this.GetPower(splits[0]); + Power power = Map.GetPower(splits[0]); UnitType type = splits[1] switch { "A" => UnitType.Army, @@ -157,10 +156,10 @@ public class World _ => throw new ApplicationException($"Unknown unit type {splits[1]}") }; Location location = type == UnitType.Army - ? this.GetLand(splits[2]) + ? Map.GetLand(splits[2]) : splits.Length == 3 - ? this.GetWater(splits[2]) - : this.GetWater(splits[2], splits[3]); + ? Map.GetWater(splits[2]) + : Map.GetWater(splits[2], splits[3]); Unit unit = Unit.Build(location, this.RootSeason, power, type); return unit; }); @@ -205,54 +204,6 @@ public class World .WithStandardMap() .AddStandardUnits(); - /// - /// Get a province by name. Throws if the province is not found. - /// - private Province GetProvince(string provinceName) - => GetProvince(provinceName, this.Provinces); - - /// - /// Get a province by name. Throws if the province is not found. - /// - private static Province GetProvince(string provinceName, IEnumerable provinces) - { - string provinceNameUpper = provinceName.ToUpperInvariant(); - Province? foundProvince = provinces.SingleOrDefault( - p => p!.Name.ToUpperInvariant() == provinceNameUpper - || p.Abbreviations.Any(a => a.ToUpperInvariant() == provinceNameUpper), - null); - if (foundProvince == null) throw new KeyNotFoundException( - $"Province {provinceName} not found"); - return foundProvince; - } - - /// - /// Get the location in a province matching a predicate. Throws if there is not exactly one - /// such location. - /// - private Location GetLocation(string provinceName, Func predicate) - { - Location? foundLocation = GetProvince(provinceName).Locations.SingleOrDefault( - l => l != null && predicate(l), null); - if (foundLocation == null) throw new KeyNotFoundException( - $"No such location in {provinceName}"); - return foundLocation; - } - - /// - /// Get the sole land location of a province. - /// - public Location GetLand(string provinceName) - => GetLocation(provinceName, l => l.Type == LocationType.Land); - - /// - /// Get the sole water location of a province, optionally specifying a named coast. - /// - public Location GetWater(string provinceName, string? coastName = null) - => coastName == null - ? GetLocation(provinceName, l => l.Type == LocationType.Water) - : GetLocation(provinceName, l => l.Name == coastName || l.Abbreviation == coastName); - /// /// Get a season by coordinate. Throws if the season is not found. /// @@ -266,25 +217,12 @@ public class World return foundSeason; } - /// - /// Get a power by name. Throws if there is not exactly one such power. - /// - public Power GetPower(string powerName) - { - Power? foundPower = this.Powers.SingleOrDefault( - p => p!.Name == powerName || p.Name.StartsWith(powerName), - null); - if (foundPower == null) throw new KeyNotFoundException( - $"Power {powerName} not found"); - return foundPower; - } - /// /// Returns a unit in a province. Throws if there are duplicate units. /// public Unit GetUnitAt(string provinceName, (int turn, int timeline)? seasonCoord = null) { - Province province = GetProvince(provinceName); + Province province = Map.GetProvince(provinceName); seasonCoord ??= (this.RootSeason.Turn, this.RootSeason.Timeline); Season season = GetSeason(seasonCoord.Value.turn, seasonCoord.Value.timeline); Unit? foundUnit = this.Units.SingleOrDefault( @@ -294,466 +232,4 @@ public class World $"Unit at {province} at {season} not found"); return foundUnit; } - - /// - /// The standard Diplomacy provinces. - /// - public static ReadOnlyCollection StandardProvinces - { - get - { - // Define the provinces of the standard world map. - List standardProvinces = new List - { - Province.Empty("North Africa", "NAF") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Tunis", "TUN") - .AddLandLocation() - .AddCoastLocation(), - Province.Empty("Bohemia", "BOH") - .AddLandLocation(), - Province.Supply("Budapest", "BUD") - .AddLandLocation(), - Province.Empty("Galacia", "GAL") - .AddLandLocation(), - Province.Supply("Trieste", "TRI") - .AddLandLocation() - .AddCoastLocation(), - Province.Empty("Tyrolia", "TYR") - .AddLandLocation(), - Province.Time("Vienna", "VIE") - .AddLandLocation(), - Province.Empty("Albania", "ALB") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Bulgaria", "BUL") - .AddLandLocation() - .AddCoastLocation("east coast", "ec") - .AddCoastLocation("south coast", "sc"), - Province.Supply("Greece", "GRE") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Rumania", "RUM", "RMA") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Serbia", "SER") - .AddLandLocation(), - Province.Empty("Clyde", "CLY") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Edinburgh", "EDI") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Liverpool", "LVP", "LPL") - .AddLandLocation() - .AddCoastLocation(), - Province.Time("London", "LON") - .AddLandLocation() - .AddCoastLocation(), - Province.Empty("Wales", "WAL") - .AddLandLocation() - .AddCoastLocation(), - Province.Empty("Yorkshire", "YOR") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Brest", "BRE") - .AddLandLocation() - .AddCoastLocation(), - Province.Empty("Burgundy", "BUR") - .AddLandLocation(), - Province.Empty("Gascony", "GAS") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Marseilles", "MAR") - .AddLandLocation() - .AddCoastLocation(), - Province.Time("Paris", "PAR") - .AddLandLocation(), - Province.Empty("Picardy", "PIC") - .AddLandLocation() - .AddCoastLocation(), - Province.Time("Berlin", "BER") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Kiel", "KIE") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Munich", "MUN") - .AddLandLocation(), - Province.Empty("Prussia", "PRU") - .AddLandLocation() - .AddCoastLocation(), - Province.Empty("Ruhr", "RUH", "RHR") - .AddLandLocation(), - Province.Empty("Silesia", "SIL") - .AddLandLocation(), - Province.Supply("Spain", "SPA") - .AddLandLocation() - .AddCoastLocation("north coast", "nc") - .AddCoastLocation("south coast", "sc"), - Province.Supply("Portugal", "POR") - .AddLandLocation() - .AddCoastLocation(), - Province.Empty("Apulia", "APU") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Naples", "NAP") - .AddLandLocation() - .AddCoastLocation(), - Province.Empty("Piedmont", "PIE") - .AddLandLocation() - .AddCoastLocation(), - Province.Time("Rome", "ROM", "RME") - .AddLandLocation() - .AddCoastLocation(), - Province.Empty("Tuscany", "TUS") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Venice", "VEN") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Belgium", "BEL") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Holland", "HOL") - .AddLandLocation() - .AddCoastLocation(), - Province.Empty("Finland", "FIN") - .AddLandLocation() - .AddCoastLocation(), - Province.Empty("Livonia", "LVN", "LVA") - .AddLandLocation() - .AddCoastLocation(), - Province.Time("Moscow", "MOS") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Sevastopol", "SEV") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Saint Petersburg", "STP") - .AddLandLocation() - .AddCoastLocation("north coast", "nc") - .AddCoastLocation("west coast", "wc"), - Province.Empty("Ukraine", "UKR") - .AddLandLocation(), - Province.Supply("Warsaw", "WAR") - .AddLandLocation(), - Province.Supply("Denmark", "DEN") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Norway", "NWY") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Sweden", "SWE") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Ankara", "ANK") - .AddLandLocation() - .AddCoastLocation(), - Province.Empty("Armenia", "ARM") - .AddLandLocation() - .AddCoastLocation(), - Province.Time("Constantinople", "CON") - .AddLandLocation() - .AddCoastLocation(), - Province.Supply("Smyrna", "SMY") - .AddLandLocation() - .AddCoastLocation(), - Province.Empty("Syria", "SYR") - .AddLandLocation() - .AddCoastLocation(), - Province.Empty("Barents Sea", "BAR") - .AddOceanLocation(), - Province.Empty("English Channel", "ENC", "ECH") - .AddOceanLocation(), - Province.Empty("Heligoland Bight", "HEL", "HGB") - .AddOceanLocation(), - Province.Empty("Irish Sea", "IRS", "IRI") - .AddOceanLocation(), - Province.Empty("Mid-Atlantic Ocean", "MAO", "MID") - .AddOceanLocation(), - Province.Empty("North Atlantic Ocean", "NAO", "NAT") - .AddOceanLocation(), - Province.Empty("North Sea", "NTH", "NTS") - .AddOceanLocation(), - Province.Empty("Norwegian Sea", "NWS", "NWG") - .AddOceanLocation(), - Province.Empty("Skagerrak", "SKA", "SKG") - .AddOceanLocation(), - Province.Empty("Baltic Sea", "BAL") - .AddOceanLocation(), - Province.Empty("Guld of Bothnia", "GOB", "BOT") - .AddOceanLocation(), - Province.Empty("Adriatic Sea", "ADS", "ADR") - .AddOceanLocation(), - Province.Empty("Aegean Sea", "AEG") - .AddOceanLocation(), - Province.Empty("Black Sea", "BLA") - .AddOceanLocation(), - Province.Empty("Eastern Mediterranean Sea", "EMS", "EAS") - .AddOceanLocation(), - Province.Empty("Gulf of Lyons", "GOL", "LYO") - .AddOceanLocation(), - Province.Empty("Ionian Sea", "IOS", "ION", "INS") - .AddOceanLocation(), - Province.Empty("Tyrrhenian Sea", "TYS", "TYN") - .AddOceanLocation(), - Province.Empty("Western Mediterranean Sea", "WMS", "WES") - .AddOceanLocation(), - }; - - // Declare some helpers for border definitions - Location Land(string provinceName) => GetProvince(provinceName, standardProvinces) - .Locations.Single(l => l.Type == LocationType.Land); - Location Water(string provinceName) => GetProvince(provinceName, standardProvinces) - .Locations.Single(l => l.Type == LocationType.Water); - Location Coast(string provinceName, string coastName) - => GetProvince(provinceName, standardProvinces) - .Locations.Single(l => l.Name == coastName || l.Abbreviation == coastName); - - static void AddBordersTo(Location location, Func LocationType, params string[] borders) - { - foreach (string bordering in borders) - { - location.AddBorder(LocationType(bordering)); - } - } - void AddBorders(string provinceName, Func LocationType, params string[] borders) - => AddBordersTo(LocationType(provinceName), LocationType, borders); - - AddBorders("NAF", Land, "TUN"); - AddBorders("NAF", Water, "MAO", "WES", "TUN"); - - AddBorders("TUN", Land, "NAF"); - AddBorders("TUN", Water, "NAF", "WES", "TYS", "ION"); - - AddBorders("BOH", Land, "MUN", "SIL", "GAL", "VIE", "TYR"); - - AddBorders("BUD", Land, "VIE", "GAL", "RUM", "SER", "TRI"); - - AddBorders("GAL", Land, "BOH", "SIL", "WAR", "UKR", "RUM", "BUD", "VIE"); - - AddBorders("TRI", Land, "TYR", "VIE", "BUD", "SER", "ALB"); - AddBorders("TRI", Water, "ALB", "ADR", "VEN"); - - AddBorders("TYR", Land, "MUN", "BOH", "VIE", "TRI", "VEN", "PIE"); - - AddBorders("VIE", Land, "TYR", "BOH", "GAL", "BUD", "TRI"); - - AddBorders("ALB", Land, "TRI", "SER", "GRE"); - AddBorders("ALB", Water, "TRI", "ADR", "ION", "GRE"); - - AddBorders("BUL", Land, "GRE", "SER", "RUM", "CON"); - AddBordersTo(Coast("BUL", "ec"), Water, "BLA", "CON"); - AddBordersTo(Coast("BUL", "sc"), Water, "CON", "AEG", "GRE"); - - AddBorders("GRE", Land, "ALB", "SER", "BUL"); - AddBorders("GRE", Water, "ALB", "ION", "AEG"); - Water("GRE").AddBorder(Coast("BUL", "sc")); - - AddBorders("RUM", Land, "BUL", "SER", "BUD", "GAL", "UKR", "SEV"); - AddBorders("RUM", Water, "SEV", "BLA"); - Water("RUM").AddBorder(Coast("BUL", "ec")); - - AddBorders("SER", Land, "BUD", "RUM", "BUL", "GRE", "ALB", "TRI"); - - AddBorders("CLY", Land, "EDI", "LVP"); - AddBorders("CLY", Water, "LVP", "NAO", "NWG", "EDI"); - - AddBorders("EDI", Land, "YOR", "LVP", "CLY"); - AddBorders("EDI", Water, "CLY", "NWG", "NTH", "YOR"); - - AddBorders("LVP", Land, "CLY", "EDI", "YOR", "WAL"); - AddBorders("LVP", Water, "WAL", "IRS", "NAO", "CLY"); - - AddBorders("LON", Land, "WAL", "YOR"); - AddBorders("LON", Water, "WAL", "ENC", "NTH", "YOR"); - - AddBorders("WAL", Land, "LVP", "YOR", "LON"); - AddBorders("WAL", Water, "LON", "ENC", "IRS", "LVP"); - - AddBorders("YOR", Land, "LON", "WAL", "LVP", "EDI"); - AddBorders("YOR", Water, "EDI", "NTH", "LON"); - - AddBorders("BRE", Land, "PIC", "PAR", "GAS"); - AddBorders("BRE", Water, "GAS", "MAO", "ENC", "PIC"); - - AddBorders("BUR", Land, "BEL", "RUH", "MUN", "MAR", "GAS", "PAR", "PIC"); - - AddBorders("GAS", Land, "BRE", "PAR", "BUR", "MAR", "SPA"); - AddBorders("GAS", Water, "MAO", "BRE"); - Water("GAS").AddBorder(Coast("SPA", "nc")); - - AddBorders("MAR", Land, "SPA", "GAS", "BUR", "PIE"); - AddBorders("MAR", Water, "LYO", "PIE"); - Water("MAR").AddBorder(Coast("SPA", "sc")); - - AddBorders("PAR", Land, "PIC", "BUR", "GAS", "BRE"); - - AddBorders("PIC", Land, "BEL", "BUR", "PAR", "BRE"); - AddBorders("PIC", Water, "BRE", "ENC", "BEL"); - - AddBorders("BER", Land, "PRU", "SIL", "MUN", "KIE"); - AddBorders("BER", Water, "KIE", "BAL", "PRU"); - - AddBorders("KIE", Land, "BER", "MUN", "RUH", "HOL", "DEN"); - AddBorders("KIE", Water, "HOL", "HEL", "DEN", "BAL", "BER"); - - AddBorders("MUN", Land, "BUR", "RUH", "KIE", "BER", "SIL", "BOH", "TYR"); - - AddBorders("PRU", Land, "LVN", "WAR", "SIL", "BER"); - AddBorders("PRU", Water, "BER", "BAL", "LVN"); - - AddBorders("RUH", Land, "KIE", "MUN", "BUR", "BEL", "HOL"); - - AddBorders("SIL", Land, "PRU", "WAR", "GAL", "BOH", "MUN", "BER"); - - AddBorders("SPA", Land, "POR", "GAS", "MAR"); - AddBordersTo(Coast("SPA", "nc"), Water, "POR", "MAO", "GAS"); - AddBordersTo(Coast("SPA", "sc"), Water, "POR", "MAO", "WES", "LYO", "MAR"); - - AddBorders("POR", Land, "SPA"); - AddBorders("POR", Water, "MAO"); - Water("POR").AddBorder(Coast("SPA", "nc")); - Water("POR").AddBorder(Coast("SPA", "sc")); - - AddBorders("APU", Land, "NAP", "ROM", "VEN"); - AddBorders("APU", Water, "VEN", "ADR", "IOS", "NAP"); - - AddBorders("NAP", Land, "ROM", "APU"); - AddBorders("NAP", Water, "APU", "IOS", "TYS", "ROM"); - - AddBorders("PIE", Land, "MAR", "TYR", "VEN", "TUS"); - AddBorders("PIE", Water, "TUS", "LYO", "MAR"); - - AddBorders("ROM", Land, "TUS", "VEN", "APU", "NAP"); - AddBorders("ROM", Water, "NAP", "TYS", "TUS"); - - AddBorders("TUS", Land, "PIE", "VEN", "ROM"); - AddBorders("TUS", Water, "ROM", "TYS", "LYO", "PIE"); - - AddBorders("VEN", Land, "APU", "ROM", "TUS", "PIE", "TYR", "TRI"); - AddBorders("VEN", Water, "TRI", "ADR", "APU"); - - AddBorders("BEL", Land, "HOL", "RUH", "BUR", "PIC"); - AddBorders("BEL", Water, "PIC", "ENC", "NTH", "HOL"); - - AddBorders("HOL", Land, "BEL", "RUH", "KIE"); - AddBorders("HOL", Water, "NTH", "HEL"); - - AddBorders("FIN", Land, "SWE", "NWY", "STP"); - AddBorders("FIN", Water, "SWE", "BOT"); - Water("FIN").AddBorder(Coast("STP", "wc")); - - AddBorders("LVN", Land, "STP", "MOS", "WAR", "PRU"); - AddBorders("LVN", Water, "PRU", "BAL", "BOT"); - Water("LVN").AddBorder(Coast("STP", "wc")); - - AddBorders("MOS", Land, "SEV", "UKR", "WAR", "LVN", "STP"); - - AddBorders("SEV", Land, "RUM", "UKR", "MOS", "ARM"); - AddBorders("SEV", Water, "ARM", "BLA", "RUM"); - - AddBorders("STP", Land, "MOS", "LVN", "FIN"); - AddBordersTo(Coast("STP", "nc"), Water, "BAR", "NWY"); - AddBordersTo(Coast("STP", "wc"), Water, "LVN", "BOT", "FIN"); - - AddBorders("UKR", Land, "MOS", "SEV", "RUM", "GAL", "WAR"); - - AddBorders("WAR", Land, "PRU", "LVN", "MOS", "UKR", "GAL", "SIL"); - - AddBorders("DEN", Land, "KIE", "SWE"); - AddBorders("DEN", Water, "KIE", "HEL", "NTH", "SKA", "BAL", "SWE"); - - AddBorders("NWY", Land, "STP", "FIN", "SWE"); - AddBorders("NWY", Water, "BAR", "NWG", "NTH", "SKA", "SWE"); - Water("NWY").AddBorder(Coast("STP", "nc")); - - AddBorders("SWE", Land, "NWY", "FIN", "DEN"); - AddBorders("SWE", Water, "FIN", "BOT", "BAL", "DEN", "SKA", "NWY"); - - AddBorders("ANK", Land, "ARM", "SMY", "CON"); - AddBorders("ANK", Water, "CON", "BLA", "ARM"); - - AddBorders("ARM", Land, "SEV", "SYR", "SMY", "ANK"); - AddBorders("ARM", Water, "ANK", "BLA", "SEV"); - - AddBorders("CON", Land, "BUL", "ANK", "SMY"); - AddBorders("CON", Water, "BLA", "ANK", "SMY", "AEG"); - Water("CON").AddBorder(Coast("BUL", "ec")); - Water("CON").AddBorder(Coast("BUL", "sc")); - - AddBorders("SMY", Land, "CON", "ANK", "ARM", "SYR"); - AddBorders("SMY", Water, "SYR", "EAS", "AEG", "CON"); - - AddBorders("SYR", Land, "SMY", "ARM"); - AddBorders("SYR", Water, "EAS", "SMY"); - - AddBorders("BAR", Water, "NWG", "NWY"); - Water("BAR").AddBorder(Coast("STP", "nc")); - - AddBorders("ENC", Water, "LON", "NTH", "BEL", "PIC", "BRE", "MAO", "IRS", "WAL"); - - AddBorders("HEL", Water, "NTH", "DEN", "BAL", "KIE", "HOL"); - - AddBorders("IRS", Water, "NAO", "LVP", "WAL", "ENC", "MAO"); - - AddBorders("MAO", Water, "NAO", "IRS", "ENC", "BRE", "GAS", "POR", "NAF"); - Water("MAO").AddBorder(Coast("SPA", "nc")); - Water("MAO").AddBorder(Coast("SPA", "sc")); - - AddBorders("NAO", Water, "NWG", "CLY", "LVP", "IRS", "MAO"); - - AddBorders("NTH", Water, "NWG", "NWY", "SKA", "DEN", "HEL", "HOL", "BEL", "ENC", "LON", "YOR", "EDI"); - - AddBorders("NWG", Water, "BAR", "NWY", "NTH", "EDI", "CLY", "NAO"); - - AddBorders("SKA", Water, "NWY", "SWE", "BAL", "DEN", "NTH"); - - AddBorders("BAL", Water, "BOT", "LVN", "PRU", "BER", "KIE", "HEL", "DEN", "SWE"); - - AddBorders("BOT", Water, "LVN", "BAL", "SWE", "FIN"); - Water("BOT").AddBorder(Coast("STP", "wc")); - - AddBorders("ADR", Water, "IOS", "APU", "VEN", "TRI", "ALB"); - - AddBorders("AEG", Water, "CON", "SMY", "EAS", "IOS", "GRE"); - Water("AEG").AddBorder(Coast("BUL", "sc")); - - AddBorders("BLA", Water, "RUM", "SEV", "ARM", "ANK", "CON"); - Water("BLA").AddBorder(Coast("BUL", "ec")); - - AddBorders("EAS", Water, "IOS", "AEG", "SMY", "SYR"); - - AddBorders("LYO", Water, "MAR", "PIE", "TUS", "TYS", "WES"); - Water("LYO").AddBorder(Coast("SPA", "sc")); - - AddBorders("IOS", Water, "TUN", "TYS", "NAP", "APU", "ADR", "ALB", "GRE", "AEG"); - - AddBorders("TYS", Water, "LYO", "TUS", "ROM", "NAP", "IOS", "TUN", "WES"); - - AddBorders("WES", Water, "LYO", "TYS", "TUN", "NAF", "MAO"); - Water("WES").AddBorder(Coast("SPA", "sc")); - - return new(standardProvinces); - } - } - - /// - /// The standard Diplomacy powers. - /// - public static ReadOnlyCollection StandardPowers - { - get => new(new List - { - new Power("Austria"), - new Power("England"), - new Power("France"), - new Power("Germany"), - new Power("Italy"), - new Power("Russia"), - new Power("Turkey"), - }); - } } \ No newline at end of file diff --git a/MultiversalDiplomacyTests/MapTests.cs b/MultiversalDiplomacyTests/MapTests.cs index 45922e5..c9d9290 100644 --- a/MultiversalDiplomacyTests/MapTests.cs +++ b/MultiversalDiplomacyTests/MapTests.cs @@ -6,10 +6,10 @@ namespace MultiversalDiplomacyTests; public class MapTests { - IEnumerable LocationClosure(Location location) + static IEnumerable LocationClosure(Location location) { - IEnumerable visited = new List(); - IEnumerable toVisit = new List() { location }; + IEnumerable visited = []; + IEnumerable toVisit = [location]; while (toVisit.Any()) { @@ -50,7 +50,7 @@ public class MapTests [Test] public void LandAndSeaBorders() { - World map = World.WithStandardMap(); + Map map = Map.Classical; Assert.That( map.GetLand("NAF").Adjacents.Count(), Is.EqualTo(1), diff --git a/MultiversalDiplomacyTests/TestCaseBuilder.cs b/MultiversalDiplomacyTests/TestCaseBuilder.cs index 5d601ad..ee63bf6 100644 --- a/MultiversalDiplomacyTests/TestCaseBuilder.cs +++ b/MultiversalDiplomacyTests/TestCaseBuilder.cs @@ -331,7 +331,7 @@ public class TestCaseBuilder => this.Builder[(seasonCoord.turn, seasonCoord.timeline)]; public IPowerContext this[string powerName] - => new PowerContext(this, this.Builder.World.GetPower(powerName)); + => new PowerContext(this, this.Builder.World.Map.GetPower(powerName)); public ISeasonContext GetReference(out Season season) { @@ -363,8 +363,8 @@ public class TestCaseBuilder { Power power = powerName == null ? this.Power - : this.Builder.World.GetPower(powerName); - Location location = this.Builder.World.GetLand(provinceName); + : this.Builder.World.Map.GetPower(powerName); + Location location = this.Builder.World.Map.GetLand(provinceName); Unit unit = this.Builder.GetOrBuildUnit( power, location, this.SeasonContext.Season, UnitType.Army); return new UnitContext(this, unit); @@ -374,8 +374,8 @@ public class TestCaseBuilder { Power power = powerName == null ? this.Power - : this.Builder.World.GetPower(powerName); - Location location = this.Builder.World.GetWater(provinceName, coast); + : this.Builder.World.Map.GetPower(powerName); + Location location = this.Builder.World.Map.GetWater(provinceName, coast); Unit unit = this.Builder.GetOrBuildUnit( power, location, this.SeasonContext.Season, UnitType.Fleet); return new UnitContext(this, unit); @@ -413,8 +413,8 @@ public class TestCaseBuilder string? coast = null) { Location destination = this.Unit.Type == UnitType.Army - ? this.Builder.World.GetLand(provinceName) - : this.Builder.World.GetWater(provinceName, coast); + ? this.Builder.World.Map.GetLand(provinceName) + : this.Builder.World.Map.GetWater(provinceName, coast); Season destSeason = season ?? this.SeasonContext.Season; MoveOrder moveOrder = new MoveOrder( this.PowerContext.Power, @@ -451,8 +451,8 @@ public class TestCaseBuilder { Power power = powerName == null ? this.PowerContext.Power - : this.Builder.World.GetPower(powerName); - Location location = this.Builder.World.GetLand(provinceName); + : this.Builder.World.Map.GetPower(powerName); + Location location = this.Builder.World.Map.GetLand(provinceName); Unit unit = this.Builder.GetOrBuildUnit( power, location, this.SeasonContext.Season, UnitType.Army); return new ConvoyDestinationContext(this, unit); @@ -465,8 +465,8 @@ public class TestCaseBuilder { Power power = powerName == null ? this.PowerContext.Power - : this.Builder.World.GetPower(powerName); - Location location = this.Builder.World.GetWater(provinceName, coast); + : this.Builder.World.Map.GetPower(powerName); + Location location = this.Builder.World.Map.GetWater(provinceName, coast); Unit unit = this.Builder.GetOrBuildUnit( power, location, this.SeasonContext.Season, UnitType.Fleet); return new ConvoyDestinationContext(this, unit); @@ -492,7 +492,7 @@ public class TestCaseBuilder public IOrderDefinedContext To(string provinceName) { - Location location = this.Builder.World.GetLand(provinceName); + Location location = this.Builder.World.Map.GetLand(provinceName); ConvoyOrder order = new ConvoyOrder( this.PowerContext.Power, this.UnitContext.Unit, @@ -526,8 +526,8 @@ public class TestCaseBuilder { Power power = powerName == null ? this.PowerContext.Power - : this.Builder.World.GetPower(powerName); - Location location = this.Builder.World.GetLand(provinceName); + : this.Builder.World.Map.GetPower(powerName); + Location location = this.Builder.World.Map.GetLand(provinceName); Season destSeason = season ?? this.SeasonContext.Season; Unit unit = this.Builder.GetOrBuildUnit( power, location, destSeason, UnitType.Army); @@ -541,8 +541,8 @@ public class TestCaseBuilder { Power power = powerName == null ? this.PowerContext.Power - : this.Builder.World.GetPower(powerName); - Location location = this.Builder.World.GetWater(provinceName, coast); + : this.Builder.World.Map.GetPower(powerName); + Location location = this.Builder.World.Map.GetWater(provinceName, coast); Unit unit = this.Builder.GetOrBuildUnit( power, location, this.SeasonContext.Season, UnitType.Fleet); return new SupportTypeContext(this, unit); @@ -582,8 +582,8 @@ public class TestCaseBuilder string? coast = null) { Location destination = this.Target.Type == UnitType.Army - ? this.Builder.World.GetLand(provinceName) - : this.Builder.World.GetWater(provinceName, coast); + ? this.Builder.World.Map.GetLand(provinceName) + : this.Builder.World.Map.GetWater(provinceName, coast); Season targetDestSeason = season ?? this.Target.Season; SupportMoveOrder order = new SupportMoveOrder( this.PowerContext.Power, diff --git a/MultiversalDiplomacyTests/TestCaseBuilderTest.cs b/MultiversalDiplomacyTests/TestCaseBuilderTest.cs index 0d6fda0..109e5a2 100644 --- a/MultiversalDiplomacyTests/TestCaseBuilderTest.cs +++ b/MultiversalDiplomacyTests/TestCaseBuilderTest.cs @@ -40,7 +40,7 @@ class TestCaseBuilderTest Assert.That(fleetSTP.Type, Is.EqualTo(UnitType.Fleet), "Unit created with wrong type"); Assert.That( fleetSTP.Location, - Is.EqualTo(setup.World.GetWater("STP", "wc")), + Is.EqualTo(setup.World.Map.GetWater("STP", "wc")), "Unit created on wrong coast"); } @@ -74,7 +74,7 @@ class TestCaseBuilderTest Assert.That(orderBer, Is.InstanceOf(), "Unexpected order type"); Assert.That( (orderBer as MoveOrder)?.Location, - Is.EqualTo(setup.World.GetLand("Kiel")), + Is.EqualTo(setup.World.Map.GetLand("Kiel")), "Unexpected move order destination"); UnitOrder orderPru = orders.Single(OrderForProvince("Prussia")); @@ -88,7 +88,7 @@ class TestCaseBuilderTest "Unexpected convoy order target"); Assert.That( (orderNth as ConvoyOrder)?.Location, - Is.EqualTo(setup.World.GetLand("Holland")), + Is.EqualTo(setup.World.Map.GetLand("Holland")), "Unexpected convoy order destination"); UnitOrder orderKie = orders.Single(OrderForProvince("Kiel")); @@ -99,7 +99,7 @@ class TestCaseBuilderTest "Unexpected convoy order target"); Assert.That( (orderKie as SupportMoveOrder)?.Location, - Is.EqualTo(setup.World.GetLand("Holland")), + Is.EqualTo(setup.World.Map.GetLand("Holland")), "Unexpected convoy order destination"); UnitOrder orderMun = orders.Single(OrderForProvince("Munich")); @@ -124,11 +124,11 @@ class TestCaseBuilderTest Assert.That(orderMun, Is.Not.Null, "Expected order reference"); Assert.That( orderMun.Order.Power, - Is.EqualTo(setup.World.GetPower("Germany")), + Is.EqualTo(setup.World.Map.GetPower("Germany")), "Wrong power"); Assert.That( orderMun.Order.Unit.Location, - Is.EqualTo(setup.World.GetLand("Mun")), + Is.EqualTo(setup.World.Map.GetLand("Mun")), "Wrong unit"); Assert.That( diff --git a/MultiversalDiplomacyTests/UnitTests.cs b/MultiversalDiplomacyTests/UnitTests.cs index c73bb12..50e387e 100644 --- a/MultiversalDiplomacyTests/UnitTests.cs +++ b/MultiversalDiplomacyTests/UnitTests.cs @@ -10,10 +10,10 @@ public class UnitTests public void MovementTest() { World world = World.WithStandardMap(); - Location Mun = world.GetLand("Mun"), - Boh = world.GetLand("Boh"), - Tyr = world.GetLand("Tyr"); - Power pw1 = world.GetPower("Austria"); + Location Mun = world.Map.GetLand("Mun"), + Boh = world.Map.GetLand("Boh"), + Tyr = world.Map.GetLand("Tyr"); + Power pw1 = world.Map.GetPower("Austria"); Season s1 = world.RootSeason; Unit u1 = Unit.Build(Mun, s1, pw1, UnitType.Army);