namespace HSchool.People;
///
/// Per-family streams derived from the school seed. Family N never consumes family N-1's rolls,
/// so appending a thirteenth family leaves the first twelve unchanged.
///
public static class Seed
{
public const int ChildCountSalt = 1;
public const int AppearanceSalt = 2;
public const int IntakeSalt = 3;
public const int SeatShuffleSalt = 4;
public const int HouseholdSalt = 5;
public const int ApplicantSalt = 6;
public const int CommuteSalt = 7;
public const int SkillGrantSalt = 8;
public const int NativeLanguageSalt = 9;
public const int ClimatePresetSalt = 10;
public const int ApparelSalt = 11;
public const int WhisperSalt = 12;
/// A stream that belongs to the school rather than to one family.
public static int ForSchool(int schoolSeed, int salt) => Mix(schoolSeed, familyIndex: -1, salt);
public static int Mix(int schoolSeed, int familyIndex, int salt)
{
var z = Mix64((uint)schoolSeed);
z = Mix64(z ^ (uint)(familyIndex + 1));
z = Mix64(z ^ (uint)(salt + 1));
return (int)z;
}
/// A stream that belongs to one person on one calendar day — commute slack, not looks.
public static int Mix(int schoolSeed, string personId, int dayNumber, int salt)
{
ArgumentNullException.ThrowIfNull(personId);
var z = Mix64((uint)schoolSeed);
z = Mix64(z ^ Stable(personId));
z = Mix64(z ^ (uint)(dayNumber + 1));
z = Mix64(z ^ (uint)(salt + 1));
return (int)z;
}
private static uint Stable(string value)
{
ulong z = 0;
foreach (var character in value)
{
z = Mix64(z ^ character);
}
return (uint)z;
}
private static ulong Mix64(ulong z)
{
z += 0x9E3779B97F4A7C15UL;
z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9UL;
z = (z ^ (z >> 27)) * 0x94D049BB133111EBUL;
return z ^ (z >> 31);
}
}