99 lines
3.2 KiB
C#
99 lines
3.2 KiB
C#
namespace HSchool.Simulation;
|
|
|
|
/// <summary>Which word list the random-name button draws from.</summary>
|
|
public enum SchoolNameLanguage
|
|
{
|
|
Russian = 0,
|
|
English = 1,
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
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;
|
|
|
|
/// <summary>
|
|
/// A name that is not in <paramref name="taken"/>. Falls back to a numbered name so the
|
|
/// button always produces something, even when the pool is exhausted.
|
|
/// </summary>
|
|
public string Next(IEnumerable<string> taken, SchoolNameLanguage language = SchoolNameLanguage.Russian)
|
|
{
|
|
var catalog = language == SchoolNameLanguage.English ? English : Russian;
|
|
var used = new HashSet<string>(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}";
|
|
}
|