Enhance family and roster management in school simulation by implementing support for incomplete families, ensuring proper handling of absent parents while maintaining surname consistency. Update family creation logic to account for single-parent households and revise child identification to prevent ID conflicts. Introduce seat shuffling to prevent siblings from being placed in the same class, improving the realism of student distribution. Update related tests to validate these new functionalities and ensure robustness in family and roster handling.
This commit is contained in:
@@ -89,7 +89,15 @@ public static class YearlyIntake
|
||||
continue;
|
||||
}
|
||||
|
||||
families.Add(new Family(family.Id, keepParents, childIds));
|
||||
// The counter travels with the family: a graduate's id must never come back. So do the
|
||||
// father's name and the surname — a single-mother household still names its children
|
||||
// after the father, and he is not in the roster to be asked.
|
||||
families.Add(family with
|
||||
{
|
||||
ParentIds = keepParents,
|
||||
ChildIds = childIds,
|
||||
NextChild = family.NextChildIndex,
|
||||
});
|
||||
foreach (var parentId in keepParents)
|
||||
{
|
||||
var parent = remainingPeople[parentId];
|
||||
@@ -166,17 +174,25 @@ public static class YearlyIntake
|
||||
var members = family.ParentIds.Concat(family.ChildIds)
|
||||
.Select(id => people[id])
|
||||
.ToArray();
|
||||
if (!members.Any(person => !person.IsStudent && !person.Female))
|
||||
|
||||
// A household with no adult left cannot take in a first-year; nor can one whose
|
||||
// father's name is unknown, since the newcomer's patronymic comes from it.
|
||||
if (!members.Any(person => !person.IsStudent)
|
||||
|| FamilyFactory.FatherGivenOf(family, members) is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var childIndex = NextChildIndex(family);
|
||||
var childIndex = family.NextChildIndex;
|
||||
var rng = new Random(Seed.Mix(schoolSeed, index, Seed.IntakeSalt + yearStart.Year * 10 + childIndex));
|
||||
var child = FamilyFactory.AddChild(catalog, names, rng, family, members, seats[cursor], yearStart, asOf, childIndex);
|
||||
people[child.Id] = child;
|
||||
var familyAt = families.FindIndex(candidate => candidate.Id.Equals(family.Id, StringComparison.Ordinal));
|
||||
families[familyAt] = family with { ChildIds = [.. family.ChildIds, child.Id] };
|
||||
families[familyAt] = family with
|
||||
{
|
||||
ChildIds = [.. family.ChildIds, child.Id],
|
||||
NextChild = childIndex + 1,
|
||||
};
|
||||
foreach (var parentId in family.ParentIds)
|
||||
{
|
||||
people[parentId] = people[parentId] with { IsParent = true };
|
||||
@@ -191,7 +207,7 @@ public static class YearlyIntake
|
||||
}
|
||||
|
||||
var leftover = seats.Skip(cursor).ToArray();
|
||||
foreach (var plan in FamilyPlanner.Plan(schoolSeed, leftover, Math.Max(nextFamilyIndex, 0)))
|
||||
foreach (var plan in FamilyPlanner.Singletons(leftover, Math.Max(nextFamilyIndex, 0)))
|
||||
{
|
||||
var (created, members) = FamilyFactory.Create(catalog, names, schoolSeed, plan, yearStart, asOf);
|
||||
families.Add(created);
|
||||
@@ -238,21 +254,6 @@ public static class YearlyIntake
|
||||
return rng.Next(100) < 40;
|
||||
}
|
||||
|
||||
private static int NextChildIndex(Family family)
|
||||
{
|
||||
var max = -1;
|
||||
foreach (var id in family.ChildIds)
|
||||
{
|
||||
var marker = id.LastIndexOf(".c", StringComparison.Ordinal);
|
||||
if (marker >= 0 && int.TryParse(id.AsSpan(marker + 2), out var index) && index > max)
|
||||
{
|
||||
max = index;
|
||||
}
|
||||
}
|
||||
|
||||
return max + 1;
|
||||
}
|
||||
|
||||
private static int IndexOf(string familyId) =>
|
||||
familyId.Length > 1 && familyId[0] == 'f' && int.TryParse(familyId.AsSpan(1), out var index)
|
||||
? index
|
||||
|
||||
Reference in New Issue
Block a user