Enhance staffing management with uncovered teacher tracking
ci / server (push) Failing after 3m43s
ci / client (push) Successful in 14s

- Updated `protocol.md` to clarify the concept of uncovered subjects and the number of additional teachers required.
- Introduced `teachersShort` property in the `StaffingSubject` interface to indicate how many more teachers are needed for a subject.
- Enhanced localization strings to reflect the new uncovered teacher information in both English and Russian.
- Updated the management panel UI to display the number of teachers short for each uncovered subject.
- Revised the `Uncovered` method in the staffing logic to return detailed information about uncovered subjects, including the shortfall of teachers.
- Added tests to validate the new uncovered teacher tracking functionality and ensure accurate reporting in the staffing API.
- Marked related tasks as complete in the documentation for the golden fixtures phase.
This commit is contained in:
Leonid Pershin
2026-08-19 23:53:37 +03:00
parent c27d43f66a
commit e5a0ae5b9d
27 changed files with 16055 additions and 38 deletions
@@ -0,0 +1,100 @@
using System.Net.Http.Json;
using System.Text.Json;
namespace HSchool.AppHost.Tests;
[Collection(AppHostCollection.Name)]
public class GoldenSaveTests(AppHostFixture fixture)
{
[Fact]
public async Task CurrentFormatSave_LoadsTheSamePeopleAndTime()
{
using var client = fixture.App.CreateHttpClient("server");
await SchoolApiTests.ResetAsync(client);
await InstallAsync(client, "current");
var state = await SchoolApiTests.GetSchoolsAsync(client);
var school = Assert.Single(state.Schools);
Assert.Equal(1, school.Id);
Assert.Equal("Золотая", school.Name);
Assert.Equal(new DateTime(2012, 3, 31, 6, 0, 0, DateTimeKind.Utc), school.GameTime);
Assert.False(school.Running);
var people = await PeopleAsync(client, school.Id);
Assert.Equal(ExpectedNames(), people.Select(row => row.FullName).OrderBy(name => name, StringComparer.Ordinal).ToArray());
Assert.Contains(people, person => person.Roles.Contains("student"));
}
[Fact]
public async Task SaveWithoutNativeLanguage_LoadsWithoutReshuffling()
{
using var client = fixture.App.CreateHttpClient("server");
await SchoolApiTests.ResetAsync(client);
await InstallAsync(client, "legacy-no-native");
var state = await SchoolApiTests.GetSchoolsAsync(client);
var school = Assert.Single(state.Schools);
Assert.Equal("Золотая", school.Name);
var people = await PeopleAsync(client, school.Id);
Assert.Equal(ExpectedNames(), people.Select(row => row.FullName).OrderBy(name => name, StringComparer.Ordinal).ToArray());
}
private async Task InstallAsync(HttpClient client, string folder)
{
var directory = await SavesDirectoryAsync(client);
var source = Path.Combine(AppContext.BaseDirectory, "golden", folder);
foreach (var file in Directory.EnumerateFiles(source))
{
File.Copy(file, Path.Combine(directory, Path.GetFileName(file)), overwrite: true);
}
using var reload = await client.PostAsync("/api/dev/reload-schools", content: null, TestContext.Current.CancellationToken);
reload.EnsureSuccessStatusCode();
}
private static async Task<string> SavesDirectoryAsync(HttpClient client)
{
var payload = await client.GetFromJsonAsync<SavesDirectoryResponse>(
"/api/dev/saves-directory",
TestContext.Current.CancellationToken);
Assert.NotNull(payload);
Assert.False(string.IsNullOrWhiteSpace(payload.Path));
return payload.Path;
}
private static async Task<IReadOnlyList<PersonRow>> PeopleAsync(HttpClient client, int schoolId)
{
var page = await client.GetFromJsonAsync<PeoplePage>(
$"/api/schools/{schoolId}/people?pageSize=100",
TestContext.Current.CancellationToken);
Assert.NotNull(page);
return page.People
.OrderBy(row => row.Id, StringComparer.Ordinal)
.ToArray();
}
private static string[] ExpectedNames()
{
var json = File.ReadAllText(Path.Combine(AppContext.BaseDirectory, "golden", "current", "1.people.json"));
using var document = JsonDocument.Parse(json);
return document.RootElement.GetProperty("people")
.EnumerateArray()
.Select(person =>
{
var name = person.GetProperty("name");
var surname = name.GetProperty("surname").GetString() ?? "";
var given = name.GetProperty("given").GetString() ?? "";
var patronymic = name.GetProperty("patronymic").GetString() ?? "";
return string.Join(' ', new[] { surname, given, patronymic }.Where(part => part.Length > 0));
})
.OrderBy(full => full, StringComparer.Ordinal)
.ToArray();
}
private sealed record SavesDirectoryResponse(string Path);
private sealed record PeoplePage(IReadOnlyList<PersonRow> People);
private sealed record PersonRow(string Id, string FullName, IReadOnlyList<string> Roles);
}
@@ -26,4 +26,10 @@
<Using Include="Xunit" />
</ItemGroup>
<ItemGroup>
<Content Include="golden\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
@@ -32,7 +32,8 @@ public class StaffingApiTests(AppHostFixture fixture)
Assert.Equal(32, staffing.Applicants.Count);
Assert.Empty(staffing.Staff);
Assert.Contains(staffing.Uncovered, subject => subject.DefName == "Mathematics");
Assert.Contains(staffing.Uncovered, subject => subject.DefName == "PrimarySchool");
var primary = Assert.Single(staffing.Uncovered, subject => subject.DefName == "PrimarySchool");
Assert.Equal(3, primary.TeachersShort);
Assert.NotEmpty(staffing.Positions);
Assert.Contains(staffing.Positions, position => position.DefName == "Teacher");
Assert.Contains(staffing.Subjects, subject => subject.DefName == "Mathematics");
@@ -331,7 +332,7 @@ public class StaffingApiTests(AppHostFixture fixture)
IReadOnlyList<DefLabelResponse> Positions,
IReadOnlyList<UncoveredSubjectResponse> Subjects);
private sealed record UncoveredSubjectResponse(string DefName, string Label, int GradeMin, int GradeMax, int HoursPerWeek);
private sealed record UncoveredSubjectResponse(string DefName, string Label, int GradeMin, int GradeMax, int HoursPerWeek, int TeachersShort);
private sealed record ApplicantResponse(
string Id,
@@ -0,0 +1,14 @@
# Golden saves
`current/` is a school file of today's format. `legacy-no-native/` is the same school without
`nativeLanguage`, so a missing field still has to mean "first language of the name set" rather
than a new roll.
These files live forever: a new save field must load `current/` and must not reshuffle
`legacy-no-native/`. A real format change adds a new folder; it does not rewrite the old one.
Regenerate after an intentional roster change (same commit):
```
WRITE_GOLDEN=1 dotnet test tests/HSchool.People.Tests/HSchool.People.Tests.csproj --filter Dump_HostSaveFixtures
```
@@ -0,0 +1,63 @@
{
"format": 2,
"id": 1,
"name": "Золотая",
"gameTime": "2012-03-31T06:00:00Z",
"running": false,
"speedIndex": 1,
"modIds": [
"core"
],
"map": {
"territory": {
"id": "yard",
"def": "SchoolYard"
},
"buildings": [
{
"id": "main",
"def": "MainBuilding"
}
],
"floors": [
{
"id": "floor-1",
"def": "StandardFloor",
"building": "main",
"label": "1"
}
],
"rooms": [
{
"id": "classroom-00",
"def": "Classroom",
"building": "main",
"floor": "floor-1",
"label": "101",
"seats": 16,
"slots": []
},
{
"id": "classroom-01",
"def": "Classroom",
"building": "main",
"floor": "floor-1",
"label": "102",
"seats": 16,
"slots": []
}
],
"links": [
{
"a": "yard",
"b": "classroom-00"
},
{
"a": "yard",
"b": "classroom-01"
}
]
},
"nameSetId": "Slavic",
"nativeLanguage": "RussianLanguage"
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,62 @@
{
"format": 2,
"id": 1,
"name": "Золотая",
"gameTime": "2012-03-31T06:00:00Z",
"running": false,
"speedIndex": 1,
"modIds": [
"core"
],
"map": {
"territory": {
"id": "yard",
"def": "SchoolYard"
},
"buildings": [
{
"id": "main",
"def": "MainBuilding"
}
],
"floors": [
{
"id": "floor-1",
"def": "StandardFloor",
"building": "main",
"label": "1"
}
],
"rooms": [
{
"id": "classroom-00",
"def": "Classroom",
"building": "main",
"floor": "floor-1",
"label": "101",
"seats": 16,
"slots": []
},
{
"id": "classroom-01",
"def": "Classroom",
"building": "main",
"floor": "floor-1",
"label": "102",
"seats": 16,
"slots": []
}
],
"links": [
{
"a": "yard",
"b": "classroom-00"
},
{
"a": "yard",
"b": "classroom-01"
}
]
},
"nameSetId": "Slavic"
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,27 @@
namespace HSchool.People.Tests;
public class GoldenRosterTests
{
private const string Native = "RussianLanguage";
[Fact]
public void GoldenRoster_MatchesFixture()
{
var roster = Fixtures.Generate(Fixtures.Classrooms(4));
var actual = RosterFingerprint.Format(roster, Fixtures.SchoolSeed, "Slavic", Native);
var relative = Path.Combine("golden", "roster.txt");
var output = Path.Combine(AppContext.BaseDirectory, relative);
var source = Path.Combine(Fixtures.RepoRoot(), "tests", "HSchool.People.Tests", relative);
if (string.Equals(Environment.GetEnvironmentVariable("WRITE_GOLDEN"), "1", StringComparison.Ordinal))
{
Directory.CreateDirectory(Path.GetDirectoryName(source)!);
File.WriteAllText(source, actual);
Directory.CreateDirectory(Path.GetDirectoryName(output)!);
File.WriteAllText(output, actual);
}
Assert.True(File.Exists(output), $"Golden roster is missing at {output}.");
RosterFingerprint.AssertEqual(File.ReadAllText(output), actual);
}
}
@@ -0,0 +1,103 @@
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Nodes;
using HSchool.Content;
namespace HSchool.People.Tests;
/// <summary>
/// Writes the host golden save files. Not a correctness test — run with WRITE_GOLDEN=1 after an
/// intentional generation change, then commit the AppHost fixtures in the same change.
/// </summary>
public class GoldenSaveDump
{
[Fact]
public void Dump_HostSaveFixtures_WhenAsked()
{
if (!string.Equals(Environment.GetEnvironmentVariable("WRITE_GOLDEN"), "1", StringComparison.Ordinal))
{
return;
}
var catalog = Fixtures.Catalog();
var map = TwoClassrooms();
var roster = RosterGenerator.Generate(catalog, map, schoolSeed: 1, "Slavic", Fixtures.AsOf, "RussianLanguage");
var pool = ApplicantPool.Create(catalog, roster, schoolSeed: 1, "Slavic", Fixtures.AsOf, "RussianLanguage");
var people = RosterJson.Serialize(RosterDocument.From(1, roster, pool));
var mapNode = JsonNode.Parse(JsonSerializer.Serialize(map, Jsonc.SerializerOptions));
var current = SchoolJson(mapNode, includeNative: true);
var legacy = SchoolJson(mapNode, includeNative: false);
var root = Path.Combine(Fixtures.RepoRoot(), "tests", "HSchool.AppHost.Tests", "golden");
Write(Path.Combine(root, "current", "1.json"), current);
Write(Path.Combine(root, "current", "1.people.json"), people);
Write(Path.Combine(root, "legacy-no-native", "1.json"), legacy);
Write(Path.Combine(root, "legacy-no-native", "1.people.json"), people);
}
internal static MapLayout TwoClassrooms() =>
new()
{
Territory = new TerritoryNode { Id = "yard", Def = "SchoolYard" },
Buildings = [new BuildingNode { Id = "main", Def = "MainBuilding" }],
Floors = [new FloorNode { Id = "floor-1", Def = "StandardFloor", Building = "main", Label = "1" }],
Rooms =
[
new RoomNode
{
Id = "classroom-00",
Def = "Classroom",
Building = "main",
Floor = "floor-1",
Label = "101",
Seats = 16,
},
new RoomNode
{
Id = "classroom-01",
Def = "Classroom",
Building = "main",
Floor = "floor-1",
Label = "102",
Seats = 16,
},
],
Links =
[
new MapLink { A = "yard", B = "classroom-00" },
new MapLink { A = "yard", B = "classroom-01" },
],
};
private static string SchoolJson(JsonNode? map, bool includeNative)
{
var root = new JsonObject
{
["format"] = 2,
["id"] = 1,
["name"] = "Золотая",
["gameTime"] = "2012-03-31T06:00:00Z",
["running"] = false,
["speedIndex"] = 1,
["modIds"] = new JsonArray("core"),
["map"] = map?.DeepClone(),
["nameSetId"] = "Slavic",
};
if (includeNative)
{
root["nativeLanguage"] = "RussianLanguage";
}
return root.ToJsonString(new JsonSerializerOptions
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
});
}
private static void Write(string path, string contents)
{
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
File.WriteAllText(path, contents);
}
}
@@ -26,6 +26,9 @@
<Link>vanilla\%(RecursiveDir)%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="golden\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
@@ -0,0 +1,78 @@
namespace HSchool.People.Tests;
/// <summary>
/// One line per class and person, sorted, so a generator change shows up as the first
/// mismatched line instead of "the snapshots differ".
/// </summary>
internal static class RosterFingerprint
{
public static string Format(Roster roster, int seed, string nameSet, string native)
{
var lines = new List<string>
{
$"# seed={seed} nameset={nameSet} native={native} people={roster.People.Count} classes={roster.Classes.Count}",
};
foreach (var schoolClass in roster.Classes.OrderBy(row => row.Id, StringComparer.Ordinal))
{
var pupils = string.Join(',', schoolClass.PupilIds.Order(StringComparer.Ordinal));
lines.Add(
$"class {schoolClass.Id} year={schoolClass.Year} letter={schoolClass.Letter} room={schoolClass.RoomId} capacity={schoolClass.Capacity} pupils={pupils}");
}
foreach (var person in roster.People.OrderBy(row => row.Id, StringComparer.Ordinal))
{
lines.Add(PersonLine(person));
}
return string.Join('\n', lines) + '\n';
}
public static void AssertEqual(string expected, string actual)
{
var left = expected.Replace("\r\n", "\n", StringComparison.Ordinal).Split('\n');
var right = actual.Replace("\r\n", "\n", StringComparison.Ordinal).Split('\n');
var count = Math.Min(left.Length, right.Length);
for (var i = 0; i < count; i++)
{
if (!string.Equals(left[i], right[i], StringComparison.Ordinal))
{
Assert.Fail($"first mismatch at line {i + 1}\nexpected: {left[i]}\nactual: {right[i]}");
}
}
if (left.Length != right.Length)
{
Assert.Fail($"line count {left.Length} vs {right.Length}");
}
}
private static string PersonLine(Person person)
{
var roles = string.Join(',', Roles(person));
var traits = string.Join(',', person.Traits.Order(StringComparer.Ordinal));
var skills = string.Join(
',',
person.Skills.OrderBy(pair => pair.Key, StringComparer.Ordinal).Select(pair => $"{pair.Key}={pair.Value}"));
return
$"person {person.Id} {person.Name.Full} female={person.Female} roles={roles} class={person.ClassId ?? "-"} born={person.BirthDate:yyyy-MM-dd} traits={traits} skills={skills}";
}
private static IEnumerable<string> Roles(Person person)
{
if (person.IsStudent)
{
yield return "student";
}
if (person.IsStaff)
{
yield return "staff";
}
if (person.IsParent)
{
yield return "parent";
}
}
}
@@ -232,6 +232,28 @@ public class StaffingTests
Assert.Contains(Staffing.Uncovered(catalog, assigned.Roster), subject => subject.DefName == "PrimarySchool");
}
[Fact]
public void PrimarySchool_OnVanillaMap_NeedsThreeTeachers_AndASecondDoesNotCloseIt()
{
var (catalog, map, roster, pool) = Fresh();
var rules = catalog.StaffingRules!;
Assert.Equal(80f, Staffing.SubjectHours(catalog, roster, "PrimarySchool"));
Assert.Equal(3, Staffing.TeachersToCover(80f, rules.MaxWeeklyHours));
var empty = Staffing.Uncovered(catalog, roster).Single(subject => subject.DefName == "PrimarySchool");
Assert.Equal(3, empty.TeachersShort);
var outcome = new StaffingOutcome(StaffingError.None, roster, pool, 0, 0, 0, 0);
outcome = HireAndAssign(catalog, map, outcome, "PrimarySchool");
Assert.Equal(2, Staffing.Uncovered(catalog, outcome.Roster).Single(subject => subject.DefName == "PrimarySchool").TeachersShort);
outcome = HireAndAssign(catalog, map, outcome, "PrimarySchool");
Assert.Equal(1, Staffing.Uncovered(catalog, outcome.Roster).Single(subject => subject.DefName == "PrimarySchool").TeachersShort);
outcome = HireAndAssign(catalog, map, outcome, "PrimarySchool");
Assert.DoesNotContain(Staffing.Uncovered(catalog, outcome.Roster), subject => subject.DefName == "PrimarySchool");
}
[Fact]
public void PeopleJson_RoundTripsHiredStaffAndSubjects()
{
@@ -274,6 +296,20 @@ public class StaffingTests
return (catalog, map, roster, pool);
}
private static StaffingOutcome HireAndAssign(
DefCatalog catalog,
MapLayout map,
StaffingOutcome current,
string subject)
{
var applicant = current.Pool.Applicants[0];
var hired = Staffing.Hire(catalog, map, current.Roster, current.Pool, applicant.Person.Id, Staffing.TeacherPosition, 500_000f);
Assert.Equal(StaffingError.None, hired.Error);
var assigned = Staffing.AssignSubject(catalog, hired.Roster, hired.Pool, applicant.Person.Id, subject, 500_000f);
Assert.Equal(StaffingError.None, assigned.Error);
return assigned;
}
private static Applicant WithAsk(Applicant applicant, float hourlyAsk) =>
applicant with { HourlyWageAsk = hourlyAsk };
}
@@ -0,0 +1,14 @@
# Golden roster
`roster.txt` is the fingerprint of `RosterGenerator` for a fixed seed, four classrooms, Slavic
names and Russian as the native language.
Update it **in the same commit that changes generation**, and say in the commit message what
changed (a new skill, a related-language roll, a different birth window). A red golden test is
the question "did you mean to?", not an order to revert.
To rewrite the file after an intentional change:
```
WRITE_GOLDEN=1 dotnet test tests/HSchool.People.Tests/HSchool.People.Tests.csproj --filter GoldenRoster_MatchesFixture
```
@@ -0,0 +1,135 @@
# seed=20260818 nameset=Slavic native=RussianLanguage people=130 classes=4
class class-classroom-00 year=1 letter=А room=classroom-00 capacity=16 pupils=f1.c1,f1.c2,f13.c0,f18.c0,f19.c0,f24.c1,f26.c1,f27.c1,f27.c2,f28.c2,f32.c1,f33.c0,f34.c0,f6.c0,f6.c2,f8.c0
class class-classroom-01 year=2 letter=А room=classroom-01 capacity=16 pupils=f0.c1,f12.c0,f12.c1,f12.c2,f13.c1,f13.c2,f14.c2,f20.c0,f23.c1,f26.c0,f27.c0,f29.c0,f31.c0,f4.c0,f7.c0,f9.c0
class class-classroom-02 year=3 letter=А room=classroom-02 capacity=16 pupils=f10.c0,f14.c0,f16.c0,f17.c1,f2.c0,f21.c0,f22.c1,f23.c0,f25.c0,f28.c0,f3.c0,f3.c1,f32.c0,f32.c2,f5.c0,f6.c1
class class-classroom-03 year=4 letter=А room=classroom-03 capacity=16 pupils=f0.c0,f1.c0,f11.c0,f14.c1,f15.c0,f17.c0,f17.c2,f20.c1,f22.c0,f24.c0,f28.c1,f30.c0,f30.c1,f8.c1,f9.c1,f9.c2
person f0.c0 Андреев Сергей Валериевич female=False roles=student class=class-classroom-03 born=2000-10-23 traits=Quiet skills=Agility=23,BelarusianLanguage=6,Biology=57,Communication=29,Endurance=51,Literature=20,Mathematics=14,PhysicalEducation=77,RussianLanguage=32,Strength=43,UkrainianLanguage=24
person f0.c1 Андреев Александр Валериевич female=False roles=student class=class-classroom-01 born=2002-11-09 traits=Curious,Quiet skills=Agility=47,BelarusianLanguage=14,Biology=56,Communication=42,Endurance=51,Literature=40,Mathematics=35,PhysicalEducation=41,RussianLanguage=45,Strength=45,UkrainianLanguage=40
person f0.p0 Андреев Валерий Николаевич female=False roles=parent class=- born=1971-06-03 traits=Diligent,Quiet skills=Agility=43,Communication=58,Endurance=61,English=62,RussianLanguage=46,Strength=63,UkrainianLanguage=37
person f0.p1 Андреева Марина Артемовна female=True roles=parent class=- born=1971-09-30 traits= skills=Agility=30,Communication=35,Endurance=46,English=58,Informatics=59,Librarianship=63,Medicine=73,PhysicalEducation=45,RussianLanguage=68,Strength=52
person f1.c0 Александрова Людмила Борисовна female=True roles=student class=class-classroom-03 born=2001-01-26 traits= skills=Agility=72,Biology=49,Communication=37,Endurance=39,Literature=69,Mathematics=66,PhysicalEducation=65,RussianLanguage=41,Strength=45,UkrainianLanguage=27
person f1.c1 Александров Евгений Борисович female=False roles=student class=class-classroom-00 born=2004-04-01 traits=Diligent,Kind skills=Agility=59,BelarusianLanguage=40,Biology=62,Communication=16,Endurance=56,Literature=83,Mathematics=36,PhysicalEducation=45,RussianLanguage=46,Strength=45
person f1.c2 Александров Юрий Борисович female=False roles=student class=class-classroom-00 born=2003-10-28 traits= skills=Agility=44,BelarusianLanguage=27,Biology=73,Communication=24,Endurance=67,Literature=70,Mathematics=24,PhysicalEducation=54,RussianLanguage=15,Strength=45
person f1.p0 Александров Борис Ильич female=False roles=parent class=- born=1968-10-25 traits= skills=Agility=45,Communication=74,Endurance=34,English=63,Librarianship=51,Mathematics=66,RussianLanguage=59,Strength=68,UkrainianLanguage=24
person f1.p1 Александрова Елизавета Романовна female=True roles=parent class=- born=1972-01-25 traits=Diligent skills=Agility=61,BelarusianLanguage=29,Communication=35,Endurance=39,English=52,Mathematics=72,RussianLanguage=61,Strength=45,UkrainianLanguage=21
person f10.c0 Захаров Пётр Виталиевич female=False roles=student class=class-classroom-02 born=2001-11-08 traits= skills=Agility=64,BelarusianLanguage=27,Biology=49,Communication=37,Endurance=47,Literature=51,Mathematics=30,PhysicalEducation=42,RussianLanguage=35,Strength=37,UkrainianLanguage=24
person f10.p0 Захаров Виталий Борисович female=False roles=parent class=- born=1976-09-07 traits=HotTempered,Leader skills=Agility=44,Chemistry=93,Communication=66,Endurance=82,English=31,RussianLanguage=60,Strength=40
person f10.p1 Захарова Любовь Валериевна female=True roles=parent class=- born=1978-11-03 traits=AbsentMinded,Neat skills=Administration=66,Agility=36,BelarusianLanguage=38,Communication=64,Endurance=79,Informatics=51,Medicine=64,RussianLanguage=63,Strength=80,UkrainianLanguage=40
person f11.c0 Андреева Дарья Ивановна female=True roles=student class=class-classroom-03 born=2001-05-20 traits= skills=Agility=60,BelarusianLanguage=22,Biology=60,Communication=36,Endurance=54,Literature=42,Mathematics=54,PhysicalEducation=48,RussianLanguage=35,Strength=45,UkrainianLanguage=22
person f11.p0 Андреев Иван Алексеевич female=False roles=parent class=- born=1976-06-01 traits= skills=Agility=38,BelarusianLanguage=27,Communication=52,Endurance=82,RussianLanguage=72,Strength=30
person f11.p1 Андреева София Александровна female=True roles=parent class=- born=1978-04-24 traits= skills=Agility=39,BelarusianLanguage=18,Communication=41,Endurance=50,English=55,Geography=59,Informatics=47,RussianLanguage=62,Strength=45
person f12.c0 Кузьмин Олег Владиславович female=False roles=student class=class-classroom-01 born=2003-03-20 traits=AbsentMinded,Bully skills=Agility=51,BelarusianLanguage=30,Biology=64,Communication=54,Endurance=40,Literature=54,Mathematics=32,PhysicalEducation=54,RussianLanguage=40,Strength=70,UkrainianLanguage=18
person f12.c1 Кузьмин Егор Владиславович female=False roles=student class=class-classroom-01 born=2003-05-31 traits=HotTempered,Kind skills=Agility=19,BelarusianLanguage=10,Biology=45,Communication=43,Endurance=42,Literature=60,Mathematics=24,PhysicalEducation=50,RussianLanguage=38,Strength=45
person f12.c2 Кузьмина Дарья Владиславовна female=True roles=student class=class-classroom-01 born=2002-10-29 traits=Curious skills=Agility=43,Biology=42,Communication=37,Endurance=34,Literature=44,Mathematics=25,PhysicalEducation=57,RussianLanguage=38,Strength=45,UkrainianLanguage=18
person f12.p0 Кузьмин Владислав Александрович female=False roles=parent class=- born=1975-01-17 traits= skills=Agility=25,BelarusianLanguage=27,Communication=68,Endurance=35,Literature=53,Mathematics=41,RussianLanguage=43,Strength=65,UkrainianLanguage=14
person f12.p1 Кузьмина Ольга Кирилловна female=True roles=parent class=- born=1979-10-15 traits=Kind,Lazy skills=Administration=58,Agility=54,BelarusianLanguage=15,Communication=65,Endurance=40,English=50,Physics=34,RussianLanguage=52,Strength=63,UkrainianLanguage=16
person f13.c0 Яковлев Константин Владиславович female=False roles=student class=class-classroom-00 born=2004-06-16 traits=HotTempered skills=Agility=67,Biology=45,Communication=21,Endurance=49,Literature=60,Mathematics=14,PhysicalEducation=63,RussianLanguage=30,Strength=39,UkrainianLanguage=18
person f13.c1 Яковлев Юрий Владиславович female=False roles=student class=class-classroom-01 born=2003-07-23 traits=Kind skills=Agility=77,Biology=69,Communication=26,Endurance=55,Literature=54,Mathematics=27,PhysicalEducation=41,RussianLanguage=48,Strength=45
person f13.c2 Яковлева Алина Владиславовна female=True roles=student class=class-classroom-01 born=2003-02-01 traits=Lazy,Neat skills=Agility=42,BelarusianLanguage=22,Biology=66,Communication=43,Endurance=59,Literature=42,Mathematics=38,PhysicalEducation=72,RussianLanguage=40,Strength=54
person f13.p0 Яковлев Владислав Андреевич female=False roles=parent class=- born=1974-09-23 traits=AbsentMinded,Kind skills=Administration=61,Agility=25,Communication=42,Endurance=35,Geography=31,German=44,History=68,RussianLanguage=44,Strength=52
person f14.c0 Александров Степан Денисович female=False roles=student class=class-classroom-02 born=2002-01-03 traits=Bully,Lazy skills=Agility=26,BelarusianLanguage=20,Biology=42,Communication=45,Endurance=58,Literature=54,Mathematics=5,PhysicalEducation=51,RussianLanguage=29,Strength=49,UkrainianLanguage=17
person f14.c1 Александрова Вероника Денисовна female=True roles=student class=class-classroom-03 born=2001-08-11 traits=AbsentMinded skills=Agility=52,BelarusianLanguage=22,Biology=59,Communication=38,Endurance=40,Literature=52,Mathematics=9,PhysicalEducation=62,RussianLanguage=53,Strength=43
person f14.c2 Александров Константин Денисович female=False roles=student class=class-classroom-01 born=2003-08-21 traits= skills=Agility=45,BelarusianLanguage=22,Biology=35,Communication=16,Endurance=36,Literature=62,Mathematics=47,PhysicalEducation=65,RussianLanguage=26,Strength=51
person f14.p1 Александрова Виктория Викторовна female=True roles=parent class=- born=1973-07-23 traits= skills=Agility=45,BelarusianLanguage=23,Communication=72,Cooking=33,Endurance=64,English=36,PhysicalEducation=61,RussianLanguage=55,Strength=42
person f15.c0 Воробьёв Игорь Сергеевич female=False roles=student class=class-classroom-03 born=2000-09-20 traits=Diligent skills=Agility=40,BelarusianLanguage=12,Biology=42,Communication=51,Endurance=51,Literature=37,Mathematics=16,PhysicalEducation=31,RussianLanguage=11,Strength=51,UkrainianLanguage=11
person f15.p0 Воробьёв Сергей Никитич female=False roles=parent class=- born=1974-10-22 traits=Neat,Quiet skills=Agility=45,BelarusianLanguage=28,Communication=54,Endurance=45,English=62,RussianLanguage=70,Strength=33,UkrainianLanguage=16
person f15.p1 Воробьёва Вера Виталиевна female=True roles=parent class=- born=1972-09-07 traits=Curious skills=Agility=60,Communication=60,Endurance=52,Geography=42,History=40,RussianLanguage=40,Strength=64,UkrainianLanguage=25
person f16.c0 Фролова Елизавета Игоревна female=True roles=student class=class-classroom-02 born=2002-06-29 traits=Lazy,Quiet skills=Agility=65,BelarusianLanguage=14,Biology=19,Communication=30,Endurance=34,Literature=33,Mathematics=27,PhysicalEducation=42,RussianLanguage=17,Strength=67
person f16.p0 Фролов Игорь Виталиевич female=False roles=parent class=- born=1968-07-25 traits= skills=Agility=57,BelarusianLanguage=37,Communication=58,Endurance=63,English=52,RussianLanguage=52,Strength=49,UkrainianLanguage=20
person f16.p1 Фролова Татьяна Олеговна female=True roles=parent class=- born=1970-06-17 traits=Curious,Diligent skills=Agility=80,BelarusianLanguage=5,Communication=63,Endurance=71,RussianLanguage=71,Strength=52
person f17.c0 Иванов Андрей Александрович female=False roles=student class=class-classroom-03 born=2001-06-27 traits= skills=Agility=44,BelarusianLanguage=13,Biology=29,Communication=39,Endurance=60,Literature=49,Mathematics=34,PhysicalEducation=60,RussianLanguage=24,Strength=55
person f17.c1 Иванова Ксения Александровна female=True roles=student class=class-classroom-02 born=2001-09-10 traits= skills=Agility=45,BelarusianLanguage=21,Biology=25,Communication=28,Endurance=64,Literature=66,Mathematics=37,PhysicalEducation=59,RussianLanguage=58,Strength=45
person f17.c2 Иванова Полина Александровна female=True roles=student class=class-classroom-03 born=2001-05-21 traits=HotTempered,Kind skills=Agility=36,Biology=53,Communication=45,Endurance=45,Literature=43,Mathematics=29,PhysicalEducation=51,RussianLanguage=42,Strength=45,UkrainianLanguage=23
person f17.p0 Иванов Александр Владимирович female=False roles=parent class=- born=1967-12-24 traits=Diligent,HotTempered skills=Agility=47,Communication=74,Cooking=58,Endurance=52,English=20,RussianLanguage=61,Strength=55
person f17.p1 Иванова Александра Ивановна female=True roles=parent class=- born=1967-04-25 traits= skills=Agility=40,BelarusianLanguage=7,Communication=69,Endurance=63,Geography=64,Literature=72,RussianLanguage=73,Strength=40
person f18.c0 Лебедев Александр Валериевич female=False roles=student class=class-classroom-00 born=2004-02-16 traits= skills=Agility=49,BelarusianLanguage=28,Biology=36,Communication=39,Endurance=28,Literature=38,Mathematics=32,PhysicalEducation=36,RussianLanguage=37,Strength=21
person f18.p0 Лебедев Валерий Романович female=False roles=parent class=- born=1985-03-29 traits=Neat,Quiet skills=Agility=25,Communication=59,Endurance=35,English=60,Mathematics=59,Medicine=44,Pedagogy=62,Physics=45,RussianLanguage=67,Strength=33,UkrainianLanguage=19
person f18.p1 Лебедева Юлия Михаиловна female=True roles=parent class=- born=1981-01-26 traits=Leader skills=Agility=44,Communication=73,Endurance=86,Geography=30,Medicine=45,Pedagogy=43,RussianLanguage=57,Strength=41,UkrainianLanguage=36
person f19.c0 Воробьёв Григорий Михаилович female=False roles=student class=class-classroom-00 born=2004-08-29 traits=Quiet skills=Agility=62,Biology=45,Communication=36,Endurance=50,Literature=42,Mathematics=12,PhysicalEducation=56,RussianLanguage=54,Strength=37
person f19.p0 Воробьёв Михаил Егорович female=False roles=parent class=- born=1978-11-03 traits=Lazy skills=Agility=40,BelarusianLanguage=34,Communication=56,Cooking=54,Endurance=46,History=51,RussianLanguage=61,Strength=40
person f19.p1 Воробьёва Вера Алексеевна female=True roles=parent class=- born=1982-08-29 traits=HotTempered skills=Administration=50,Agility=45,BelarusianLanguage=20,Communication=67,Cooking=21,Endurance=57,Geography=41,PhysicalEducation=46,RussianLanguage=36,Strength=40,UkrainianLanguage=25
person f2.c0 Алексеев Григорий Константинович female=False roles=student class=class-classroom-02 born=2002-07-24 traits=AbsentMinded,Curious skills=Agility=35,BelarusianLanguage=27,Biology=50,Communication=30,Endurance=68,Literature=50,Mathematics=8,PhysicalEducation=72,RussianLanguage=9,Strength=45,UkrainianLanguage=17
person f2.p0 Алексеев Константин Романович female=False roles=parent class=- born=1974-12-11 traits=Neat skills=Administration=52,Agility=36,Communication=60,Cooking=55,Endurance=49,English=30,Geography=52,Mathematics=65,RussianLanguage=64,Strength=47,UkrainianLanguage=9
person f2.p1 Алексеева Ольга Романовна female=True roles=parent class=- born=1970-07-22 traits=HotTempered skills=Administration=45,Agility=45,BelarusianLanguage=22,Communication=82,Endurance=54,English=46,History=43,Librarianship=65,RussianLanguage=65,Strength=64
person f20.c0 Павлова Елена Игоревна female=True roles=student class=class-classroom-01 born=2002-11-09 traits= skills=Agility=48,Biology=38,Communication=37,Endurance=34,Literature=70,Mathematics=48,PhysicalEducation=51,RussianLanguage=26,Strength=40,UkrainianLanguage=21
person f20.c1 Павлова Валентина Игоревна female=True roles=student class=class-classroom-03 born=2001-01-24 traits= skills=Agility=46,BelarusianLanguage=19,Biology=50,Communication=32,Endurance=50,Literature=44,Mathematics=19,PhysicalEducation=52,RussianLanguage=39,Strength=38,UkrainianLanguage=27
person f20.p0 Павлов Игорь Никитич female=False roles=parent class=- born=1968-08-01 traits=HotTempered,Leader skills=Agility=72,Communication=57,Endurance=43,Informatics=54,Physics=43,RussianLanguage=49,Strength=43
person f20.p1 Павлова Людмила Дмитриевна female=True roles=parent class=- born=1970-01-17 traits= skills=Agility=60,BelarusianLanguage=28,Communication=48,Cooking=71,Endurance=56,RussianLanguage=63,Strength=46
person f21.c0 Ильин Андрей Константинович female=False roles=student class=class-classroom-02 born=2002-05-12 traits= skills=Agility=31,BelarusianLanguage=28,Biology=59,Communication=61,Endurance=48,Literature=47,Mathematics=34,PhysicalEducation=60,RussianLanguage=22,Strength=54
person f21.p0 Ильин Константин Никитич female=False roles=parent class=- born=1971-01-21 traits=Diligent,Quiet skills=Agility=45,BelarusianLanguage=30,Communication=53,Endurance=40,Medicine=40,Pedagogy=74,PhysicalEducation=48,Physics=57,RussianLanguage=45,Strength=44,UkrainianLanguage=19
person f21.p1 Ильина Яна Борисовна female=True roles=parent class=- born=1975-04-20 traits=Curious skills=Agility=35,BelarusianLanguage=13,Communication=62,Endurance=55,Informatics=60,Pedagogy=42,RussianLanguage=68,Strength=53,UkrainianLanguage=20
person f22.c0 Захаров Никита Виталиевич female=False roles=student class=class-classroom-03 born=2000-09-14 traits=Diligent,Quiet skills=Agility=48,Biology=62,Communication=33,Endurance=59,Literature=64,Mathematics=32,PhysicalEducation=49,RussianLanguage=70,Strength=69
person f22.c1 Захаров Денис Виталиевич female=False roles=student class=class-classroom-02 born=2001-09-11 traits=AbsentMinded skills=Agility=51,BelarusianLanguage=27,Biology=53,Communication=57,Endurance=53,Literature=74,Mathematics=18,PhysicalEducation=46,RussianLanguage=63,Strength=61
person f22.p0 Захаров Виталий Андреевич female=False roles=parent class=- born=1966-04-08 traits= skills=Agility=29,BelarusianLanguage=2,Communication=62,Cooking=40,Endurance=82,English=62,Librarianship=50,RussianLanguage=64,Strength=30
person f22.p1 Захарова Елизавета Егоровна female=True roles=parent class=- born=1967-09-05 traits=Diligent,HotTempered skills=Administration=51,Agility=51,BelarusianLanguage=6,Biology=40,Communication=56,Endurance=52,English=53,Librarianship=50,Literature=79,RussianLanguage=62,Strength=62
person f23.c0 Орловская Нина Константиновна female=True roles=student class=class-classroom-02 born=2001-11-01 traits=Neat skills=Agility=55,Biology=45,Communication=40,Endurance=55,Literature=16,Mathematics=38,PhysicalEducation=57,RussianLanguage=39,Strength=45,UkrainianLanguage=15
person f23.c1 Орловская Полина Константиновна female=True roles=student class=class-classroom-01 born=2003-03-30 traits=Leader,Neat skills=Agility=51,BelarusianLanguage=20,Biology=51,Communication=22,Endurance=42,Literature=39,Mathematics=14,PhysicalEducation=54,RussianLanguage=24,Strength=40
person f23.p0 Орловский Константин Михаилович female=False roles=parent class=- born=1965-04-02 traits=Diligent,HotTempered skills=Agility=45,Communication=55,Endurance=50,History=57,Librarianship=42,Mathematics=40,Pedagogy=35,RussianLanguage=46,Strength=50
person f23.p1 Орловская Яна Степановна female=True roles=parent class=- born=1965-10-22 traits= skills=Agility=42,Communication=52,Endurance=55,RussianLanguage=46,Strength=34,UkrainianLanguage=10
person f24.c0 Орлов Фёдор Алексеевич female=False roles=student class=class-classroom-03 born=2000-12-05 traits= skills=Agility=56,Biology=45,Communication=20,Endurance=35,Literature=67,Mathematics=23,PhysicalEducation=33,RussianLanguage=65,Strength=36
person f24.c1 Орлова Оксана Алексеевна female=True roles=student class=class-classroom-00 born=2004-03-01 traits=Neat skills=Agility=55,BelarusianLanguage=4,Biology=40,Communication=43,Endurance=43,Literature=39,Mathematics=17,PhysicalEducation=56,RussianLanguage=27,Strength=26,UkrainianLanguage=25
person f24.p0 Орлов Алексей Денисович female=False roles=parent class=- born=1977-04-17 traits= skills=Agility=45,BelarusianLanguage=21,Communication=51,Endurance=18,English=62,Geography=46,RussianLanguage=67,Strength=46
person f24.p1 Орлова Надежда Владиславовна female=True roles=parent class=- born=1977-12-04 traits=Quiet skills=Agility=65,Biology=64,Communication=70,Cooking=41,Endurance=45,Librarianship=49,RussianLanguage=71,Strength=65
person f25.c0 Петрова Александра Игоревна female=True roles=student class=class-classroom-02 born=2001-12-19 traits=AbsentMinded,Lazy skills=Agility=51,BelarusianLanguage=20,Biology=58,Communication=40,Endurance=54,Literature=65,Mathematics=50,PhysicalEducation=35,RussianLanguage=32,Strength=57
person f25.p1 Петрова Полина Юриевна female=True roles=parent class=- born=1965-12-11 traits=Kind,Neat skills=Agility=53,BelarusianLanguage=15,Communication=50,Endurance=59,RussianLanguage=54,Strength=45
person f26.c0 Яковлев Павел Михаилович female=False roles=student class=class-classroom-01 born=2002-12-29 traits=Curious skills=Agility=59,BelarusianLanguage=27,Biology=79,Communication=32,Endurance=57,Literature=35,Mathematics=10,PhysicalEducation=64,RussianLanguage=35,Strength=45
person f26.c1 Яковлев Вадим Михаилович female=False roles=student class=class-classroom-00 born=2004-06-28 traits=Neat skills=Agility=54,BelarusianLanguage=17,Biology=66,Communication=43,Endurance=52,Literature=40,Mathematics=18,PhysicalEducation=34,RussianLanguage=22,Strength=45
person f26.p0 Яковлев Михаил Степанович female=False roles=parent class=- born=1975-12-27 traits=HotTempered,Neat skills=Administration=44,Agility=44,Biology=52,Communication=59,Cooking=40,Endurance=66,English=56,Mathematics=55,RussianLanguage=52,Strength=53
person f26.p1 Яковлева Марина Кирилловна female=True roles=parent class=- born=1976-12-10 traits=HotTempered,Kind skills=Agility=37,BelarusianLanguage=21,Communication=47,Cooking=44,Endurance=31,Pedagogy=40,RussianLanguage=68,Strength=48,UkrainianLanguage=27
person f27.c0 Иванов Виктор Константинович female=False roles=student class=class-classroom-01 born=2002-12-27 traits=AbsentMinded,Curious skills=Agility=35,Biology=50,Communication=26,Endurance=35,Literature=60,Mathematics=1,PhysicalEducation=46,RussianLanguage=57,Strength=38
person f27.c1 Иванов Владислав Константинович female=False roles=student class=class-classroom-00 born=2004-07-04 traits= skills=Agility=50,BelarusianLanguage=24,Biology=61,Communication=24,Endurance=76,Literature=72,Mathematics=25,PhysicalEducation=46,RussianLanguage=34,Strength=45,UkrainianLanguage=17
person f27.c2 Иванов Александр Константинович female=False roles=student class=class-classroom-00 born=2004-05-25 traits=Kind,Neat skills=Agility=65,BelarusianLanguage=28,Biology=49,Communication=43,Endurance=68,Literature=42,Mathematics=46,PhysicalEducation=52,RussianLanguage=35,Strength=45,UkrainianLanguage=32
person f27.p0 Иванов Константин Иванович female=False roles=parent class=- born=1974-08-25 traits=Neat skills=Administration=49,Agility=44,BelarusianLanguage=34,Communication=77,Endurance=42,English=55,RussianLanguage=36,Strength=64,UkrainianLanguage=26
person f27.p1 Иванова Марина Константиновна female=True roles=parent class=- born=1969-11-29 traits=Quiet skills=Agility=46,BelarusianLanguage=21,Communication=61,Endurance=32,English=46,Librarianship=53,RussianLanguage=54,Strength=37
person f28.c0 Иванов Пётр Петрович female=False roles=student class=class-classroom-02 born=2002-08-02 traits=AbsentMinded,Neat skills=Agility=73,Biology=62,Communication=42,Endurance=43,Literature=59,Mathematics=48,PhysicalEducation=39,RussianLanguage=11,Strength=45
person f28.c1 Иванова Наталья Петровна female=True roles=student class=class-classroom-03 born=2000-12-07 traits=Bully,Lazy skills=Agility=64,BelarusianLanguage=30,Biology=46,Communication=27,Endurance=59,Literature=34,Mathematics=67,PhysicalEducation=69,RussianLanguage=51,Strength=45,UkrainianLanguage=23
person f28.c2 Иванов Максим Петрович female=False roles=student class=class-classroom-00 born=2004-04-05 traits=Lazy skills=Agility=67,BelarusianLanguage=13,Biology=59,Communication=26,Endurance=54,Literature=31,Mathematics=29,PhysicalEducation=63,RussianLanguage=55,Strength=51,UkrainianLanguage=25
person f28.p0 Иванов Пётр Олегович female=False roles=parent class=- born=1965-06-23 traits=AbsentMinded,Kind skills=Agility=75,BelarusianLanguage=26,Communication=60,Endurance=74,Informatics=60,Literature=57,Pedagogy=56,RussianLanguage=39,Strength=48
person f28.p1 Иванова Полина Алексеевна female=True roles=parent class=- born=1965-11-18 traits= skills=Agility=17,BelarusianLanguage=24,Chemistry=40,Communication=52,Endurance=35,Librarianship=59,Medicine=69,Physics=42,RussianLanguage=50,Strength=61,UkrainianLanguage=21
person f29.c0 Макарова Ксения Александровна female=True roles=student class=class-classroom-01 born=2002-11-08 traits=Bully skills=Agility=52,BelarusianLanguage=27,Biology=62,Communication=35,Endurance=53,Literature=71,Mathematics=48,PhysicalEducation=35,RussianLanguage=41,Strength=45
person f29.p0 Макаров Александр Николаевич female=False roles=parent class=- born=1981-11-08 traits=AbsentMinded skills=Administration=40,Agility=50,BelarusianLanguage=25,Chemistry=42,Communication=44,Endurance=55,Geography=56,Librarianship=66,RussianLanguage=69,Strength=40,UkrainianLanguage=19
person f29.p1 Макарова Мария Владиславовна female=True roles=parent class=- born=1977-10-31 traits=HotTempered skills=Agility=45,BelarusianLanguage=23,Chemistry=42,Communication=37,Endurance=70,Literature=20,RussianLanguage=54,Strength=44,UkrainianLanguage=25
person f3.c0 Макарова Вероника Петровна female=True roles=student class=class-classroom-02 born=2002-05-15 traits=Curious,Diligent skills=Agility=37,BelarusianLanguage=32,Biology=32,Communication=61,Endurance=71,Literature=63,Mathematics=27,PhysicalEducation=60,RussianLanguage=66,Strength=81
person f3.c1 Макаров Роман Петрович female=False roles=student class=class-classroom-02 born=2002-04-16 traits= skills=Agility=40,BelarusianLanguage=28,Biology=55,Communication=32,Endurance=34,Literature=51,Mathematics=41,PhysicalEducation=49,RussianLanguage=44,Strength=37
person f3.p0 Макаров Пётр Егорович female=False roles=parent class=- born=1977-02-28 traits=Diligent,Neat skills=Agility=67,Communication=28,Endurance=53,English=57,Librarianship=39,RussianLanguage=45,Strength=42,UkrainianLanguage=26
person f3.p1 Макарова Алина Антоновна female=True roles=parent class=- born=1978-04-05 traits= skills=Agility=62,BelarusianLanguage=26,Communication=63,Endurance=39,RussianLanguage=64,Strength=45
person f30.c0 Иванова Светлана Владимировна female=True roles=student class=class-classroom-03 born=2000-10-08 traits= skills=Agility=38,Biology=51,Communication=37,Endurance=48,Literature=46,Mathematics=39,PhysicalEducation=44,RussianLanguage=33,Strength=45,UkrainianLanguage=38
person f30.c1 Иванова Надежда Владимировна female=True roles=student class=class-classroom-03 born=2000-12-10 traits=Bully skills=Agility=27,Biology=46,Communication=49,Endurance=61,Literature=36,Mathematics=38,PhysicalEducation=72,RussianLanguage=39,Strength=45,UkrainianLanguage=27
person f30.p0 Иванов Владимир Денисович female=False roles=parent class=- born=1974-06-12 traits=Lazy skills=Agility=40,BelarusianLanguage=26,Biology=37,Communication=72,Endurance=50,Librarianship=45,Physics=66,RussianLanguage=46,Strength=40
person f30.p1 Иванова Мария Андреевна female=True roles=parent class=- born=1973-09-24 traits= skills=Administration=44,Agility=52,Communication=61,Endurance=62,RussianLanguage=46,Strength=45,UkrainianLanguage=30
person f31.c0 Иванов Николай Вадимович female=False roles=student class=class-classroom-01 born=2003-08-29 traits= skills=Agility=41,Biology=43,Communication=32,Endurance=44,Literature=45,Mathematics=53,PhysicalEducation=47,RussianLanguage=7,Strength=45,UkrainianLanguage=21
person f31.p0 Иванов Вадим Андреевич female=False roles=parent class=- born=1985-06-23 traits=Diligent,Quiet skills=Agility=45,BelarusianLanguage=25,Communication=54,Endurance=71,Medicine=57,PhysicalEducation=60,RussianLanguage=56,Strength=53,UkrainianLanguage=25
person f31.p1 Иванова Александра Юриевна female=True roles=parent class=- born=1980-08-20 traits=Diligent skills=Administration=54,Agility=75,BelarusianLanguage=19,Chemistry=43,Communication=65,Cooking=53,Endurance=50,PhysicalEducation=67,RussianLanguage=36,Strength=48,UkrainianLanguage=37
person f32.c0 Петров Артём Евгениевич female=False roles=student class=class-classroom-02 born=2002-07-14 traits=Quiet skills=Agility=31,BelarusianLanguage=34,Biology=33,Communication=5,Endurance=20,Literature=45,Mathematics=21,PhysicalEducation=64,RussianLanguage=42,Strength=80,UkrainianLanguage=25
person f32.c1 Петрова Елена Евгениевна female=True roles=student class=class-classroom-00 born=2003-10-27 traits=Quiet skills=Agility=47,BelarusianLanguage=30,Biology=51,Communication=68,Endurance=48,Literature=46,Mathematics=37,PhysicalEducation=59,RussianLanguage=25,Strength=38,UkrainianLanguage=22
person f32.c2 Петрова Ирина Евгениевна female=True roles=student class=class-classroom-02 born=2001-09-18 traits=HotTempered,Kind skills=Agility=54,BelarusianLanguage=29,Biology=54,Communication=28,Endurance=49,Literature=31,Mathematics=41,PhysicalEducation=67,RussianLanguage=50,Strength=52
person f32.p0 Петров Евгений Станиславович female=False roles=parent class=- born=1963-05-02 traits= skills=Agility=45,BelarusianLanguage=23,Chemistry=61,Communication=66,Endurance=43,Mathematics=49,Pedagogy=34,RussianLanguage=58,Strength=41,UkrainianLanguage=29
person f33.c0 Морозова Елизавета Григориевна female=True roles=student class=class-classroom-00 born=2003-11-04 traits=Diligent,Quiet skills=Agility=21,BelarusianLanguage=25,Biology=38,Communication=41,Endurance=55,Literature=54,Mathematics=53,PhysicalEducation=66,RussianLanguage=42,Strength=45
person f33.p0 Морозов Григорий Михаилович female=False roles=parent class=- born=1968-05-01 traits= skills=Administration=71,Agility=28,BelarusianLanguage=22,Communication=68,Endurance=62,English=53,Librarianship=36,RussianLanguage=52,Strength=51,UkrainianLanguage=14
person f33.p1 Морозова Марина Владимировна female=True roles=parent class=- born=1972-10-24 traits=HotTempered skills=Agility=65,BelarusianLanguage=23,Communication=28,Endurance=40,Pedagogy=57,RussianLanguage=56,Strength=40,UkrainianLanguage=11
person f34.c0 Кузнецова Валентина Ивановна female=True roles=student class=class-classroom-00 born=2004-03-25 traits=Curious,Kind skills=Agility=29,BelarusianLanguage=22,Biology=48,Communication=21,Endurance=69,Literature=30,Mathematics=39,PhysicalEducation=35,RussianLanguage=28,Strength=45,UkrainianLanguage=24
person f34.p0 Кузнецов Иван Сергеевич female=False roles=parent class=- born=1970-02-02 traits= skills=Agility=44,Communication=43,Endurance=58,English=73,Geography=37,Physics=49,RussianLanguage=77,Strength=40
person f34.p1 Кузнецова Дарья Валериевна female=True roles=parent class=- born=1967-03-25 traits=Lazy skills=Administration=60,Agility=69,BelarusianLanguage=23,Communication=67,Cooking=44,Endurance=47,German=38,RussianLanguage=70,Strength=48,UkrainianLanguage=15
person f4.c0 Васильев Денис Федорович female=False roles=student class=class-classroom-01 born=2003-02-01 traits=Neat skills=Agility=50,BelarusianLanguage=6,Biology=39,Communication=27,Endurance=35,Literature=59,Mathematics=36,PhysicalEducation=88,RussianLanguage=47,Strength=21,UkrainianLanguage=13
person f4.p0 Васильев Фёдор Игоревич female=False roles=parent class=- born=1970-05-21 traits=AbsentMinded skills=Agility=66,BelarusianLanguage=31,Communication=49,Cooking=45,Endurance=44,English=36,Literature=48,Pedagogy=62,RussianLanguage=54,Strength=44
person f4.p1 Васильева Анастасия Федоровна female=True roles=parent class=- born=1975-01-20 traits=AbsentMinded skills=Agility=45,BelarusianLanguage=22,Communication=70,Endurance=53,English=43,Librarianship=49,Medicine=75,RussianLanguage=49,Strength=73,UkrainianLanguage=13
person f5.c0 Захарова Екатерина Борисовна female=True roles=student class=class-classroom-02 born=2002-07-13 traits=Kind skills=Agility=43,Biology=46,Communication=44,Endurance=43,Literature=38,Mathematics=52,PhysicalEducation=52,RussianLanguage=45,Strength=32
person f5.p0 Захаров Борис Николаевич female=False roles=parent class=- born=1980-04-15 traits= skills=Agility=45,Communication=37,Endurance=51,English=44,RussianLanguage=57,Strength=29
person f5.p1 Захарова Вероника Григориевна female=True roles=parent class=- born=1979-06-22 traits= skills=Agility=27,Communication=47,Endurance=76,English=24,RussianLanguage=63,Strength=45,UkrainianLanguage=31
person f6.c0 Козловская Юлия Олеговна female=True roles=student class=class-classroom-00 born=2004-08-15 traits= skills=Agility=45,BelarusianLanguage=20,Biology=36,Communication=42,Endurance=61,Literature=49,Mathematics=27,PhysicalEducation=45,RussianLanguage=40,Strength=70
person f6.c1 Козловская Светлана Олеговна female=True roles=student class=class-classroom-02 born=2001-12-31 traits=HotTempered,Leader skills=Agility=53,Biology=47,Communication=36,Endurance=40,Literature=59,Mathematics=52,PhysicalEducation=70,RussianLanguage=36,Strength=40
person f6.c2 Козловская Вероника Олеговна female=True roles=student class=class-classroom-00 born=2003-09-29 traits= skills=Agility=17,BelarusianLanguage=17,Biology=38,Communication=36,Endurance=27,Literature=54,Mathematics=10,PhysicalEducation=51,RussianLanguage=16,Strength=29,UkrainianLanguage=40
person f6.p0 Козловский Олег Станиславович female=False roles=parent class=- born=1967-12-18 traits=Kind skills=Agility=42,Biology=44,Communication=82,Endurance=64,Mathematics=33,RussianLanguage=29,Strength=52
person f6.p1 Козловская Ирина Кирилловна female=True roles=parent class=- born=1963-12-28 traits= skills=Administration=90,Agility=48,BelarusianLanguage=11,Communication=29,Endurance=57,English=48,Librarianship=57,RussianLanguage=48,Strength=61
person f7.c0 Андреев Виктор Степанович female=False roles=student class=class-classroom-01 born=2003-07-19 traits=Bully,Leader skills=Agility=20,Biology=38,Communication=31,Endurance=75,Literature=54,Mathematics=40,PhysicalEducation=60,RussianLanguage=8,Strength=45,UkrainianLanguage=7
person f7.p0 Андреев Степан Андреевич female=False roles=parent class=- born=1973-08-21 traits= skills=Administration=51,Agility=64,BelarusianLanguage=35,Chemistry=42,Communication=76,Endurance=36,Medicine=23,Physics=30,RussianLanguage=67,Strength=46,UkrainianLanguage=27
person f7.p1 Андреева Мария Алексеевна female=True roles=parent class=- born=1977-07-16 traits= skills=Agility=59,Communication=68,Cooking=41,Endurance=49,History=47,Mathematics=54,Medicine=44,RussianLanguage=63,Strength=35,UkrainianLanguage=40
person f8.c0 Фролов Евгений Павелович female=False roles=student class=class-classroom-00 born=2003-12-20 traits=Bully skills=Agility=52,Biology=45,Communication=20,Endurance=78,Literature=61,Mathematics=33,PhysicalEducation=64,RussianLanguage=31,Strength=45,UkrainianLanguage=19
person f8.c1 Фролов Станислав Павелович female=False roles=student class=class-classroom-03 born=2000-10-11 traits=Curious skills=Agility=58,BelarusianLanguage=24,Biology=57,Communication=18,Endurance=69,Literature=55,Mathematics=33,PhysicalEducation=48,RussianLanguage=42,Strength=67,UkrainianLanguage=28
person f8.p0 Фролов Павел Егорович female=False roles=parent class=- born=1968-06-07 traits=Leader skills=Agility=71,BelarusianLanguage=22,Communication=87,Endurance=39,RussianLanguage=64,Strength=44
person f8.p1 Фролова Виктория Степановна female=True roles=parent class=- born=1963-10-04 traits= skills=Agility=59,BelarusianLanguage=25,Communication=51,Endurance=55,Geography=48,Pedagogy=58,RussianLanguage=25,Strength=63
person f9.c0 Кузьмина Любовь Александровна female=True roles=student class=class-classroom-01 born=2003-06-13 traits=Kind skills=Agility=45,BelarusianLanguage=23,Biology=43,Communication=31,Endurance=32,Literature=46,Mathematics=44,PhysicalEducation=62,RussianLanguage=29,Strength=39,UkrainianLanguage=5
person f9.c1 Кузьмин Сергей Александрович female=False roles=student class=class-classroom-03 born=2001-08-20 traits=Curious,Quiet skills=Agility=11,BelarusianLanguage=18,Biology=37,Communication=41,Endurance=59,Literature=59,Mathematics=25,PhysicalEducation=67,RussianLanguage=41,Strength=38
person f9.c2 Кузьмина Алина Александровна female=True roles=student class=class-classroom-03 born=2001-01-22 traits= skills=Agility=52,Biology=50,Communication=29,Endurance=53,Literature=38,Mathematics=52,PhysicalEducation=56,RussianLanguage=54,Strength=31
person f9.p0 Кузьмин Александр Денисович female=False roles=parent class=- born=1981-12-09 traits= skills=Agility=40,Communication=58,Cooking=58,Endurance=78,Literature=42,Medicine=65,Physics=58,RussianLanguage=68,Strength=42
person f9.p1 Кузьмина Анастасия Сергеевна female=True roles=parent class=- born=1977-01-01 traits=AbsentMinded skills=Agility=68,BelarusianLanguage=27,Communication=96,Endurance=46,Librarianship=43,Pedagogy=48,RussianLanguage=61,Strength=40,UkrainianLanguage=21
+57 -5
View File
@@ -1,3 +1,4 @@
using HSchool.Ai;
using HSchool.Content;
using HSchool.People;
using HSchool.Schedule;
@@ -51,6 +52,44 @@ public class LunchTests
Assert.All(hunger.Values, value => Assert.True(value > 0.5f, $"somebody came back to school at {value:F2}"));
}
/// <summary>
/// Measured once: people arrive full, hit about 0.4 by their own lunch sitting, leave hungry,
/// and come back full the next morning. The numbers live in data; this test is the lock.
/// </summary>
[Fact]
public void Hunger_FollowsTheSchoolDayCurve()
{
using var school = StaffedSchool();
var pupils = school.Roster!.People.Where(person => person.IsStudent).Select(person => person.Id)
.ToHashSet(StringComparer.Ordinal);
var (junior, senior) = Parallels(school);
AdvanceTo(school, new DateTime(2012, 4, 3, 8, 40, 0, DateTimeKind.Utc));
var morning = Hunger(school, pupils, onCampus: true);
Assert.NotEmpty(morning);
Assert.All(morning.Values, value => Assert.InRange(value, 0.85f, 1f));
AdvanceTo(school, new DateTime(2012, 4, 3, 11, 0, 0, DateTimeKind.Utc));
var beforeJuniorLunch = Hunger(school, junior, onCampus: true);
Assert.NotEmpty(beforeJuniorLunch);
Assert.InRange(Median(beforeJuniorLunch.Values), 0.35f, 0.50f);
AdvanceTo(school, new DateTime(2012, 4, 3, 12, 5, 0, DateTimeKind.Utc));
var beforeSeniorLunch = Hunger(school, senior, onCampus: true);
Assert.NotEmpty(beforeSeniorLunch);
Assert.InRange(Median(beforeSeniorLunch.Values), 0.20f, 0.50f);
AdvanceTo(school, new DateTime(2012, 4, 3, 14, 45, 0, DateTimeKind.Utc));
var leaving = Hunger(school, pupils, onCampus: true);
Assert.NotEmpty(leaving);
Assert.True(Median(leaving.Values) < 0.55f, $"median hunger at the last lessons was {Median(leaving.Values):F2}");
AdvanceTo(school, new DateTime(2012, 4, 4, 8, 0, 0, DateTimeKind.Utc));
var nextMorning = Hunger(school, pupils, onCampus: false);
Assert.NotEmpty(nextMorning);
Assert.All(nextMorning.Values, value => Assert.InRange(value, 0.9f, 1f));
}
private static School StaffedSchool()
{
var (catalog, map) = Vanilla();
@@ -108,20 +147,33 @@ public class LunchTests
.Select(row => row.PersonId)
.ToArray();
private static Dictionary<string, float> Hunger(School school, HashSet<string> pupils)
private static Dictionary<string, float> Hunger(School school, HashSet<string> pupils, bool onCampus = false)
{
var values = new Dictionary<string, float>(StringComparer.Ordinal);
var query = new Arch.Core.QueryDescription().WithAll<PersonIdentity, PersonNeeds>();
school.World.Query(in query, (ref PersonIdentity identity, ref PersonNeeds needs) =>
var query = new Arch.Core.QueryDescription().WithAll<PersonIdentity, PersonNeeds, Presence>();
school.World.Query(in query, (ref PersonIdentity identity, ref PersonNeeds needs, ref Presence presence) =>
{
if (pupils.Contains(identity.Id) && needs.Values.TryGetValue("Hunger", out var value))
if (!pupils.Contains(identity.Id) || !needs.Values.TryGetValue("Hunger", out var value))
{
values[identity.Id] = value;
return;
}
if (onCampus && !presence.IsOnCampus)
{
return;
}
values[identity.Id] = value;
});
return values;
}
private static float Median(IReadOnlyCollection<float> values)
{
var sorted = values.OrderBy(value => value).ToArray();
return sorted[sorted.Length / 2];
}
private static void AdvanceTo(School school, DateTime until)
{
while (school.Clock.Time < until)