namespace MultiversalDiplomacy.Model;
///
/// Encapsulation of the world map and playable powers constituting a Diplomacy variant.
///
public class Map
{
///
/// The map type.
///
public MapType Type { get; }
///
/// The game map.
///
public IReadOnlyCollection Provinces => _Provinces.AsReadOnly();
private List _Provinces { get; }
private Dictionary LocationLookup { get; }
///
/// The game powers.
///
public IReadOnlyCollection Powers => _Powers.AsReadOnly();
private List _Powers { get; }
private Map(MapType type, IEnumerable provinces, IEnumerable powers)
{
Type = type;
_Provinces = provinces.ToList();
_Powers = powers.ToList();
LocationLookup = Provinces
.SelectMany(province => province.Locations)
.ToDictionary(location => location.Key);
}
///
/// A regex that matches any of the power names for this variant.
///
public string PowerRegex => $"({string.Join("|", Powers)})";
///
/// A regex that matches any of the province names or abbreviations for this variant.
///
public string ProvinceRegex => $"({string.Join("|", Provinces.SelectMany(p => p.AllNames))})";
///
/// 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)
=> provinces.SingleOrDefault(
p => p!.Name.Equals(provinceName, StringComparison.InvariantCultureIgnoreCase)
|| p.Abbreviations.Any(
a => a.Equals(provinceName, StringComparison.InvariantCultureIgnoreCase)),
null)
?? throw new KeyNotFoundException($"Province {provinceName} not found");
///
/// 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)
=> GetProvince(provinceName).Locations.SingleOrDefault(
l => l != null && predicate(l), null)
?? throw new KeyNotFoundException($"No such location in {provinceName}");
public Location GetLocation(string designation)
=> LocationLookup[designation];
public Location GetLocation(Unit unit)
=> GetLocation(unit.Location);
///
/// 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 full or partial name. Throws if there is not exactly one such power.
///
public string GetPower(string powerName)
=> Powers.SingleOrDefault(p => p!.EqualsAnyCase(powerName) || p!.StartsWithAnyCase(powerName), null)
?? throw new KeyNotFoundException($"Power {powerName} not found (powers: {string.Join(", ", Powers)})");
public static Map FromType(MapType type)
=> type switch {
MapType.Test => Test,
MapType.Classical => Classical,
_ => throw new NotImplementedException($"Unknown variant {type}"),
};
public static Map Test => _Test.Value;
private static readonly Lazy