namespace HSchool.Simulation; /// Which word list the random-name button draws from. public enum SchoolNameLanguage { Russian = 0, English = 1, } /// /// Suggestions for the "random name" button. Lives here rather than in the client because the /// server is the one that knows which names are already taken. /// public sealed class SchoolNameGenerator(Random? random = null) { private const int AttemptsBeforeNumbering = 24; private readonly record struct Catalog( string[] Kinds, string[] Epithets, string NumberSign, bool NumberSpace, bool EpithetFirst, string FallbackKind); private static readonly Catalog Russian = new( ["Школа", "Гимназия", "Лицей", "Школа-интернат"], [ "Северная", "Приморская", "Заречная", "Нагорная", "Слободская", "Озёрная", "Кленовая", "Рябиновая", "Солнечная", "Луговая", "Тихая", "Ясная", ], "№", false, false, "Школа"); private static readonly Catalog English = new( ["School", "Academy", "Grammar School", "High School"], [ "Northern", "Seaside", "Riverside", "Hillside", "Maple", "Rowan", "Sunny", "Meadow", "Quiet", "Clear", "Oak", "Pine", ], "No.", true, true, "School"); private readonly Random _random = random ?? Random.Shared; /// /// A name that is not in . Falls back to a numbered name so the /// button always produces something, even when the pool is exhausted. /// public string Next(IEnumerable taken, SchoolNameLanguage language = SchoolNameLanguage.Russian) { var catalog = language == SchoolNameLanguage.English ? English : Russian; var used = new HashSet(taken, StringComparer.OrdinalIgnoreCase); for (var attempt = 0; attempt < AttemptsBeforeNumbering; attempt++) { var candidate = Compose(catalog); if (used.Add(candidate)) { return candidate; } } for (var number = 1; ; number++) { var candidate = Numbered(catalog, catalog.FallbackKind, number); if (!used.Contains(candidate)) { return candidate; } } } private string Compose(Catalog catalog) { var kind = catalog.Kinds[_random.Next(catalog.Kinds.Length)]; // Half the names are numbered, half are named — both read like a real school. if (_random.Next(2) == 0) { return Numbered(catalog, kind, _random.Next(1, 100)); } var epithet = catalog.Epithets[_random.Next(catalog.Epithets.Length)]; return catalog.EpithetFirst ? $"{epithet} {kind}" : $"{kind} «{epithet}»"; } private static string Numbered(Catalog catalog, string kind, int number) => catalog.NumberSpace ? $"{kind} {catalog.NumberSign} {number}" : $"{kind} {catalog.NumberSign}{number}"; }