diff --git a/MultiversalDiplomacy/Model/World.cs b/MultiversalDiplomacy/Model/World.cs index 939a3a5..8360bb7 100644 --- a/MultiversalDiplomacy/Model/World.cs +++ b/MultiversalDiplomacy/Model/World.cs @@ -1,3 +1,5 @@ +using System.Collections.ObjectModel; + namespace MultiversalDiplomacy.Model; /// @@ -8,33 +10,33 @@ public class World /// /// The game map. /// - public IEnumerable Provinces { get; } + public ReadOnlyCollection Provinces { get; } /// /// The game powers. /// - public IEnumerable Powers { get; } + public ReadOnlyCollection Powers { get; } /// /// The state of the multiverse. /// - public IEnumerable Seasons { get; } + public ReadOnlyCollection Seasons { get; } /// /// All units in the multiverse. /// - public IEnumerable Units { get; } + public ReadOnlyCollection Units { get; } /// /// Immutable game options. /// public Options Options { get; } - public World( - IEnumerable provinces, - IEnumerable powers, - IEnumerable seasons, - IEnumerable units, + private World( + ReadOnlyCollection provinces, + ReadOnlyCollection powers, + ReadOnlyCollection seasons, + ReadOnlyCollection units, Options options) { this.Provinces = provinces; @@ -45,21 +47,105 @@ public class World } /// - /// Create a new world with no map, powers, or units, and a root season. + /// Create a new world with specified provinces and powers. /// - public static World Empty => new World( - new List(), - new List(), - new List { Season.MakeRoot() }, - new List(), - new Options()); + public static World WithMap(IEnumerable provinces, IEnumerable powers) + => new World( + new(provinces.ToList()), + new(powers.ToList()), + new(new List()), + new(new List()), + new Options()); /// - /// Create a world with a standard map, powers, and initial unit placements. + /// Create a new world with the standard Diplomacy provinces and powers. /// - public static World Standard => Empty + public static World WithStandardMap() + => WithMap(StandardProvinces, StandardPowers); + + /// + /// Create a new world with new seasons. + /// + public World WithSeasons(IEnumerable seasons) + => new World(this.Provinces, this.Powers, new(seasons.ToList()), this.Units, this.Options); + + /// + /// Create a new world with an initial season. + /// + public World WithInitialSeason() + => WithSeasons(new List { Season.MakeRoot() }); + + /// + /// Create a new world with new units. + /// + public World WithUnits(IEnumerable units) + => new World(this.Provinces, this.Powers, this.Seasons, new(units.ToList()), this.Options); + + /// + /// Create a new world with new units created from unit specs. Units specs are in the format + /// " []". If the province or coast name has a space in it, the + /// abbreviation should be used. + /// + public World WithUnits(params string[] unitSpecs) + { + IEnumerable units = unitSpecs.Select(spec => + { + string[] splits = spec.Split(' ', 4); + Power power = this.GetPower(splits[0]); + UnitType type = splits[1] switch + { + "A" => UnitType.Army, + "F" => UnitType.Fleet, + _ => throw new ArgumentOutOfRangeException($"Unknown unit type {splits[1]}") + }; + Location location = type == UnitType.Army + ? this.GetLand(splits[2]) + : splits.Length == 3 + ? this.GetWater(splits[2]) + : this.GetWater(splits[2], splits[3]); + Unit unit = Unit.Build(location, this.Seasons.First(), power, type); + return unit; + }); + return this.WithUnits(units); + } + + /// + /// Create a new world with standard Diplomacy initial unit placements. + /// + public World WithStandardUnits() + { + return this.WithUnits( + "Austria A Bud", + "Austria A Vir", + "Austria F Tri", + "England A Lvp", + "England F Edi", + "England F Lon", + "France A Mar", + "France A Par", + "France F Bre", + "Germany A Ber", + "Germany A Mun", + "Germany F Kie", + "Italy A Rom", + "Italy A Ven", + "Italy F Nap", + "Russia A Mos", + "Russia A War", + "Russia F Sev", + "Russia F Stp wc", + "Turkey A Con", + "Turkey A Smy", + "Turkey F Ank" + ); + } + + /// + /// A standard Diplomacy game setup. + /// + public static World Standard => World .WithStandardMap() - .WithStandardPowers() + .WithInitialSeason() .WithStandardUnits(); /// @@ -68,7 +154,7 @@ public class World private Province GetProvince(string provinceName) { string provinceNameUpper = provinceName.ToUpperInvariant(); - Province? foundProvince = this.Provinces.FirstOrDefault( + Province? foundProvince = this.Provinces.SingleOrDefault( p => p != null && (p.Name.ToUpperInvariant() == provinceNameUpper || p.Abbreviations.Any(a => a.ToUpperInvariant() == provinceNameUpper)), @@ -106,11 +192,11 @@ public class World : GetLocation(provinceName, l => l.Name == coastName || l.Abbreviation == coastName); /// - /// Get a power by name. Throws if the power is not found. + /// Get a power by name. Throws if there is not exactly one such power. /// public Power GetPower(string powerName) { - Power? foundPower = this.Powers.FirstOrDefault( + Power? foundPower = this.Powers.SingleOrDefault( p => p != null && (p.Name == powerName || p.Name.StartsWith(powerName)), @@ -121,416 +207,347 @@ public class World } /// - /// Create a new world from this one with new provinces. + /// Returns a unit in a province. Throws if there is not exactly one such unit. /// - public World WithMap(IEnumerable provinces) + public Unit? GetUnitAt(string provinceName) { - if (this.Units.Any()) throw new InvalidOperationException( - "Provinces cannot be changed once units have been placed on the map"); - return new World(provinces, this.Powers, this.Seasons, this.Units, this.Options); + Province province = GetProvince(provinceName); + Unit? foundUnit = this.Units.SingleOrDefault( + u => u != null && u.Location.Province == province, + null); + return foundUnit; } /// - /// Create a new world from this one with the standard Diplomacy provinces. + /// The standard Diplomacy provinces. /// - public World WithStandardMap() + public static ReadOnlyCollection StandardProvinces { - // Define the provinces of the standard world map. - List standardProvinces = new List + get { - 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) => standardProvinces - .Single(p => p.Name == provinceName || p.Abbreviations.Contains(provinceName)) - .Locations.Single(l => l.Type == LocationType.Land); - Location Water(string provinceName) => standardProvinces - .Single(p => p.Name == provinceName || p.Abbreviations.Contains(provinceName)) - .Locations.Single(l => l.Type == LocationType.Water); - Location Coast(string provinceName, string coastName) => standardProvinces - .Single(p => p.Name == provinceName || p.Abbreviations.Contains(provinceName)) - .Locations.Single(l => l.Name == coastName || l.Abbreviation == coastName); - - Land("NAF").AddBorder(Land("TUN")); - Water("NAF").AddBorder(Water("MAO")); - Water("NAF").AddBorder(Water("WES")); - Water("NAF").AddBorder(Water("TUN")); - - Land("TUN").AddBorder(Land("NAF")); - Water("TUN").AddBorder(Water("NAF")); - Water("TUN").AddBorder(Water("WES")); - Water("TUN").AddBorder(Water("TYS")); - Water("TUN").AddBorder(Water("ION")); - - Land("BOH").AddBorder(Land("MUN")); - Land("BOH").AddBorder(Land("SIL")); - Land("BOH").AddBorder(Land("GAL")); - Land("BOH").AddBorder(Land("VIE")); - Land("BOH").AddBorder(Land("TYR")); - - Land("BUD").AddBorder(Land("VIE")); - Land("BUD").AddBorder(Land("GAL")); - Land("BUD").AddBorder(Land("RUM")); - Land("BUD").AddBorder(Land("SER")); - Land("BUD").AddBorder(Land("TRI")); - - Land("GAL").AddBorder(Land("BOH")); - Land("GAL").AddBorder(Land("SIL")); - Land("GAL").AddBorder(Land("WAR")); - Land("GAL").AddBorder(Land("UKR")); - Land("GAL").AddBorder(Land("RUM")); - Land("GAL").AddBorder(Land("BUD")); - Land("GAL").AddBorder(Land("VIE")); - - Land("TRI").AddBorder(Land("VEN")); - Land("TRI").AddBorder(Land("TYR")); - Land("TRI").AddBorder(Land("VIE")); - Land("TRI").AddBorder(Land("BUD")); - Land("TRI").AddBorder(Land("SER")); - Land("TRI").AddBorder(Land("ALB")); - Water("TRI").AddBorder(Water("ALB")); - Water("TRI").AddBorder(Water("ADR")); - Water("TRI").AddBorder(Water("VEN")); - - Land("TYR").AddBorder(Land("MUN")); - Land("TYR").AddBorder(Land("BOH")); - Land("TYR").AddBorder(Land("VIE")); - Land("TYR").AddBorder(Land("TRI")); - Land("TYR").AddBorder(Land("VEN")); - Land("TYR").AddBorder(Land("PIE")); - - Land("VIE").AddBorder(Land("TYR")); - Land("VIE").AddBorder(Land("BOH")); - Land("VIE").AddBorder(Land("GAL")); - Land("VIE").AddBorder(Land("BUD")); - Land("VIE").AddBorder(Land("TRI")); - - Land("ALB").AddBorder(Land("TRI")); - Land("ALB").AddBorder(Land("SER")); - Land("ALB").AddBorder(Land("GRE")); - Water("ALB").AddBorder(Water("TRI")); - Water("ALB").AddBorder(Water("ADR")); - Water("ALB").AddBorder(Water("ION")); - Water("ALB").AddBorder(Water("GRE")); - - Land("BUL").AddBorder(Land("GRE")); - Land("BUL").AddBorder(Land("SER")); - Land("BUL").AddBorder(Land("RUM")); - Land("BUL").AddBorder(Land("CON")); - Coast("BUL", "ec").AddBorder(Water("BLA")); - Coast("BUL", "ec").AddBorder(Water("CON")); - Coast("BUL", "sc").AddBorder(Water("CON")); - Coast("BUL", "sc").AddBorder(Water("AEG")); - Coast("BUL", "sc").AddBorder(Water("GRE")); - - Land("GRE").AddBorder(Land("ALB")); - Land("GRE").AddBorder(Land("SER")); - Land("GRE").AddBorder(Land("BUL")); - Water("GRE").AddBorder(Water("ALB")); - Water("GRE").AddBorder(Water("ION")); - Water("GRE").AddBorder(Water("AEG")); - Water("GRE").AddBorder(Coast("BUL", "sc")); - - // TODO - - Water("IOS").AddBorder(Water("TUN")); - Water("IOS").AddBorder(Water("TYS")); - Water("IOS").AddBorder(Water("NAP")); - Water("IOS").AddBorder(Water("APU")); - Water("IOS").AddBorder(Water("ADR")); - Water("IOS").AddBorder(Water("ALB")); - Water("IOS").AddBorder(Water("GRE")); - Water("IOS").AddBorder(Water("AEG")); - - // TODO - - return this.WithMap(standardProvinces); - } - - /// - /// Create a new world from this one with new powers. - /// - public World WithPowers(IEnumerable powers) - => new World(this.Provinces, powers, this.Seasons, this.Units, this.Options); - - /// - /// Create a new world from this one with new powers created with the given names. - /// - public World WithPowers(IEnumerable powerNames) - => WithPowers(powerNames.Select(name => new Model.Power(name))); - - /// - /// Create a new world from this one with new powers created with the given names. - /// - public World WithPowers(params string[] powerNames) - => WithPowers(powerNames.AsEnumerable()); - - /// - /// Create a new world from this one with the standard Diplomacy powers. - /// - public World WithStandardPowers() - => WithPowers("Austria", "England", "France", "Germany", "Italy", "Russia", "Turkey"); - - /// - /// Create a new world from this one with new units created from unit specs. Units specs are - /// in the format " []". If the province or coast name has a - /// space in it, the abbreviation should be used. - /// - public World WithUnits(IEnumerable unitSpec) - { - IEnumerable units = unitSpec.Select(spec => - { - string[] splits = spec.Split(' ', 4); - Power power = this.GetPower(splits[0]); - UnitType type = splits[1] switch + // Define the provinces of the standard world map. + List standardProvinces = new List { - "A" => UnitType.Army, - "F" => UnitType.Fleet, - _ => throw new ArgumentOutOfRangeException($"Unknown unit type {splits[1]}") + 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(), }; - Location location = type == UnitType.Army - ? this.GetLand(splits[2]) - : splits.Length == 3 - ? this.GetWater(splits[2]) - : this.GetWater(splits[2], splits[3]); - Unit unit = Unit.Build(location, this.Seasons.First(), power, type); - return unit; - }); - return new World(this.Provinces, this.Powers, this.Seasons, units, this.Options); + + // Declare some helpers for border definitions + Location Land(string provinceName) => standardProvinces + .Single(p => p.Name == provinceName || p.Abbreviations.Contains(provinceName)) + .Locations.Single(l => l.Type == LocationType.Land); + Location Water(string provinceName) => standardProvinces + .Single(p => p.Name == provinceName || p.Abbreviations.Contains(provinceName)) + .Locations.Single(l => l.Type == LocationType.Water); + Location Coast(string provinceName, string coastName) => standardProvinces + .Single(p => p.Name == provinceName || p.Abbreviations.Contains(provinceName)) + .Locations.Single(l => l.Name == coastName || l.Abbreviation == coastName); + + Land("NAF").AddBorder(Land("TUN")); + Water("NAF").AddBorder(Water("MAO")); + Water("NAF").AddBorder(Water("WES")); + Water("NAF").AddBorder(Water("TUN")); + + Land("TUN").AddBorder(Land("NAF")); + Water("TUN").AddBorder(Water("NAF")); + Water("TUN").AddBorder(Water("WES")); + Water("TUN").AddBorder(Water("TYS")); + Water("TUN").AddBorder(Water("ION")); + + Land("BOH").AddBorder(Land("MUN")); + Land("BOH").AddBorder(Land("SIL")); + Land("BOH").AddBorder(Land("GAL")); + Land("BOH").AddBorder(Land("VIE")); + Land("BOH").AddBorder(Land("TYR")); + + Land("BUD").AddBorder(Land("VIE")); + Land("BUD").AddBorder(Land("GAL")); + Land("BUD").AddBorder(Land("RUM")); + Land("BUD").AddBorder(Land("SER")); + Land("BUD").AddBorder(Land("TRI")); + + Land("GAL").AddBorder(Land("BOH")); + Land("GAL").AddBorder(Land("SIL")); + Land("GAL").AddBorder(Land("WAR")); + Land("GAL").AddBorder(Land("UKR")); + Land("GAL").AddBorder(Land("RUM")); + Land("GAL").AddBorder(Land("BUD")); + Land("GAL").AddBorder(Land("VIE")); + + Land("TRI").AddBorder(Land("VEN")); + Land("TRI").AddBorder(Land("TYR")); + Land("TRI").AddBorder(Land("VIE")); + Land("TRI").AddBorder(Land("BUD")); + Land("TRI").AddBorder(Land("SER")); + Land("TRI").AddBorder(Land("ALB")); + Water("TRI").AddBorder(Water("ALB")); + Water("TRI").AddBorder(Water("ADR")); + Water("TRI").AddBorder(Water("VEN")); + + Land("TYR").AddBorder(Land("MUN")); + Land("TYR").AddBorder(Land("BOH")); + Land("TYR").AddBorder(Land("VIE")); + Land("TYR").AddBorder(Land("TRI")); + Land("TYR").AddBorder(Land("VEN")); + Land("TYR").AddBorder(Land("PIE")); + + Land("VIE").AddBorder(Land("TYR")); + Land("VIE").AddBorder(Land("BOH")); + Land("VIE").AddBorder(Land("GAL")); + Land("VIE").AddBorder(Land("BUD")); + Land("VIE").AddBorder(Land("TRI")); + + Land("ALB").AddBorder(Land("TRI")); + Land("ALB").AddBorder(Land("SER")); + Land("ALB").AddBorder(Land("GRE")); + Water("ALB").AddBorder(Water("TRI")); + Water("ALB").AddBorder(Water("ADR")); + Water("ALB").AddBorder(Water("ION")); + Water("ALB").AddBorder(Water("GRE")); + + Land("BUL").AddBorder(Land("GRE")); + Land("BUL").AddBorder(Land("SER")); + Land("BUL").AddBorder(Land("RUM")); + Land("BUL").AddBorder(Land("CON")); + Coast("BUL", "ec").AddBorder(Water("BLA")); + Coast("BUL", "ec").AddBorder(Water("CON")); + Coast("BUL", "sc").AddBorder(Water("CON")); + Coast("BUL", "sc").AddBorder(Water("AEG")); + Coast("BUL", "sc").AddBorder(Water("GRE")); + + Land("GRE").AddBorder(Land("ALB")); + Land("GRE").AddBorder(Land("SER")); + Land("GRE").AddBorder(Land("BUL")); + Water("GRE").AddBorder(Water("ALB")); + Water("GRE").AddBorder(Water("ION")); + Water("GRE").AddBorder(Water("AEG")); + Water("GRE").AddBorder(Coast("BUL", "sc")); + + // TODO + + Water("IOS").AddBorder(Water("TUN")); + Water("IOS").AddBorder(Water("TYS")); + Water("IOS").AddBorder(Water("NAP")); + Water("IOS").AddBorder(Water("APU")); + Water("IOS").AddBorder(Water("ADR")); + Water("IOS").AddBorder(Water("ALB")); + Water("IOS").AddBorder(Water("GRE")); + Water("IOS").AddBorder(Water("AEG")); + + // TODO + + return new(standardProvinces); + } } /// - /// Create a new world from this one with new units created from unit specs. Units specs are - /// in the format " []". + /// The standard Diplomacy powers. /// - public World WithUnits(params string[] unitSpec) - => this.WithUnits(unitSpec.AsEnumerable()); - - /// - /// Create a new world from this one with new units created according to the standard Diplomacy - /// initial unit deployments. - /// - public World WithStandardUnits() + public static ReadOnlyCollection StandardPowers { - return this.WithUnits( - "Austria A Bud", - "Austria A Vir", - "Austria F Tri", - "England A Lvp", - "England F Edi", - "England F Lon", - "France A Mar", - "France A Par", - "France F Bre", - "Germany A Ber", - "Germany A Mun", - "Germany F Kie", - "Italy A Rom", - "Italy A Ven", - "Italy F Nap", - "Russia A Mos", - "Russia A War", - "Russia F Sev", - "Russia F Stp wc", - "Turkey A Con", - "Turkey A Smy", - "Turkey F Ank" - ); + 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/AdjudicatorTests.cs b/MultiversalDiplomacyTests/AdjudicatorTests.cs index 9aa5aea..86ff740 100644 --- a/MultiversalDiplomacyTests/AdjudicatorTests.cs +++ b/MultiversalDiplomacyTests/AdjudicatorTests.cs @@ -15,8 +15,8 @@ public class AdjudicatorTests { return orders.Select(o => o.Validate(ValidationReason.Valid)).ToList(); }); - World world = World.Empty.WithPowers("Power"); - Power power = world.GetPower("Power"); + World world = World.WithStandardMap().WithInitialSeason(); + Power power = world.GetPower("Austria"); Order order = new NullOrder(power); List orders = new List { order }; diff --git a/MultiversalDiplomacyTests/MapTests.cs b/MultiversalDiplomacyTests/MapTests.cs index b349f61..45922e5 100644 --- a/MultiversalDiplomacyTests/MapTests.cs +++ b/MultiversalDiplomacyTests/MapTests.cs @@ -50,7 +50,7 @@ public class MapTests [Test] public void LandAndSeaBorders() { - World map = World.Empty.WithStandardMap(); + World map = World.WithStandardMap(); Assert.That( map.GetLand("NAF").Adjacents.Count(), Is.EqualTo(1), diff --git a/MultiversalDiplomacyTests/UnitTests.cs b/MultiversalDiplomacyTests/UnitTests.cs index aaac446..cbea6f8 100644 --- a/MultiversalDiplomacyTests/UnitTests.cs +++ b/MultiversalDiplomacyTests/UnitTests.cs @@ -9,9 +9,11 @@ public class UnitTests [Test] public void MovementTest() { - World world = World.Empty.WithStandardMap().WithPowers("First"); - Location Mun = world.GetLand("Mun"), Boh = world.GetLand("Boh"), Tyr = world.GetLand("Tyr"); - Power pw1 = world.GetPower("First"); + World world = World.WithStandardMap().WithInitialSeason(); + Location Mun = world.GetLand("Mun"), + Boh = world.GetLand("Boh"), + Tyr = world.GetLand("Tyr"); + Power pw1 = world.GetPower("Austria"); Season s1 = world.Seasons.First(); Unit u1 = Unit.Build(Mun, s1, pw1, UnitType.Army);