using System.Collections.ObjectModel;
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 ReadOnlyCollection Provinces { get; }
///
/// The game powers.
///
public ReadOnlyCollection Powers { get; }
private Map(MapType type, 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