Enhance AI and simulation components with presence management and routing capabilities
- Introduced the `HSchool.Ai` project, responsible for routing, day plans, and presence management. - Updated the `HSchool.Simulation` project to integrate with the new AI functionalities, improving decision-making and presence tracking. - Added `travelMinutes` to room and territory definitions, ensuring accurate movement calculations within the simulation. - Enhanced the `School` class to manage presence and implement empty-time skipping functionality. - Updated documentation to reflect the new AI features and their impact on school simulation. - Added tests for presence management and routing to ensure robust functionality and reliability.
This commit is contained in:
@@ -86,6 +86,52 @@ public class CalendarTests
|
||||
Assert.Equal(DaySlot.BreakAfter(2), slot);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NextWorkMorning_FromSaturdayLandsOnMondaySix()
|
||||
{
|
||||
var catalog = LoadVanilla();
|
||||
var next = SchoolDay.NextWorkMorning(catalog, new DateTime(2012, 4, 7, 10, 0, 0, DateTimeKind.Utc), weekDays: 5);
|
||||
|
||||
Assert.Equal(new DateTime(2012, 4, 9, 6, 0, 0, DateTimeKind.Utc), next);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NextWorkMorning_FromTuesdayNightLandsOnThatMorning()
|
||||
{
|
||||
var catalog = LoadVanilla();
|
||||
var next = SchoolDay.NextWorkMorning(catalog, new DateTime(2012, 4, 3, 3, 0, 0, DateTimeKind.Utc), weekDays: 5);
|
||||
|
||||
Assert.Equal(new DateTime(2012, 4, 3, 6, 0, 0, DateTimeKind.Utc), next);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NextWorkMorning_FromTuesdayEveningLandsOnWednesday()
|
||||
{
|
||||
var catalog = LoadVanilla();
|
||||
var next = SchoolDay.NextWorkMorning(catalog, new DateTime(2012, 4, 3, 22, 0, 0, DateTimeKind.Utc), weekDays: 5);
|
||||
|
||||
Assert.Equal(new DateTime(2012, 4, 4, 6, 0, 0, DateTimeKind.Utc), next);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InWorkWindow_SevenOnAWorkday_IsAlreadyOpen()
|
||||
{
|
||||
var catalog = LoadVanilla();
|
||||
var seven = new DateTime(2012, 4, 3, 7, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
Assert.True(SchoolDay.IsWorkday(catalog, seven, weekDays: 5));
|
||||
Assert.True(SchoolDay.InWorkWindow(catalog, seven, weekDays: 5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InWorkWindow_DoesNotNeedTeachers()
|
||||
{
|
||||
var catalog = LoadVanilla();
|
||||
var morning = new DateTime(2012, 4, 3, 10, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
Assert.True(SchoolDay.InWorkWindow(catalog, morning, weekDays: 5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Subject_UnknownRoom_FailsTheCatalog()
|
||||
{
|
||||
|
||||
@@ -106,7 +106,7 @@ public class CatalogLoaderTests
|
||||
CatalogLoader.CorePackId,
|
||||
"rooms",
|
||||
"office",
|
||||
"""{ "defName": "Office", "slots": [{ "key": "chair", "thing": "Chair" }], "positions": ["Principal"] }"""),
|
||||
"""{ "defName": "Office", "slots": [{ "key": "chair", "thing": "Chair" }], "positions": ["Principal"], "travelMinutes": 1 }"""),
|
||||
]));
|
||||
|
||||
Assert.Contains("Chair", ex.Message);
|
||||
@@ -126,4 +126,28 @@ public class CatalogLoaderTests
|
||||
Assert.Equal("Мебель", catalog.Label("ru", catalog.Things["Chair"]));
|
||||
Assert.Equal("Chair", catalog.Label("en", catalog.Things["Chair"]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConcreteRoomWithoutTravelMinutes_FailsTheCatalog()
|
||||
{
|
||||
var ex = Assert.Throws<ContentLoadException>(() => _loader.Load(
|
||||
[CatalogLoader.CorePackId],
|
||||
[
|
||||
PackDocuments.Def(CatalogLoader.CorePackId, "rooms", "office", """{ "defName": "Office" }"""),
|
||||
]));
|
||||
|
||||
Assert.Contains("travelMinutes", ex.Message, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConcreteTerritoryWithoutTravelMinutes_FailsTheCatalog()
|
||||
{
|
||||
var ex = Assert.Throws<ContentLoadException>(() => _loader.Load(
|
||||
[CatalogLoader.CorePackId],
|
||||
[
|
||||
PackDocuments.Def(CatalogLoader.CorePackId, "territories", "yard", """{ "defName": "Yard" }"""),
|
||||
]));
|
||||
|
||||
Assert.Contains("travelMinutes", ex.Message, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class InheritanceTests
|
||||
var ex = Assert.Throws<ContentLoadException>(() => _loader.Load(
|
||||
[CatalogLoader.CorePackId],
|
||||
[
|
||||
PackDocuments.Def(CatalogLoader.CorePackId, "rooms", "office", """{ "defName": "Office" }"""),
|
||||
PackDocuments.Def(CatalogLoader.CorePackId, "rooms", "office", """{ "defName": "Office", "travelMinutes": 1 }"""),
|
||||
PackDocuments.Def(CatalogLoader.CorePackId, "things", "chair", """{ "defName": "Chair", "parent": "Office" }"""),
|
||||
]));
|
||||
|
||||
|
||||
@@ -125,14 +125,14 @@ public class MapValidationTests
|
||||
CatalogLoader.CorePackId,
|
||||
"territories",
|
||||
"yard",
|
||||
abstractYard ? """{ "defName": "Yard", "abstract": true }""" : """{ "defName": "Yard" }"""),
|
||||
abstractYard ? """{ "defName": "Yard", "abstract": true }""" : """{ "defName": "Yard", "travelMinutes": 1 }"""),
|
||||
PackDocuments.Def(CatalogLoader.CorePackId, "buildings", "main", """{ "defName": "Main" }"""),
|
||||
PackDocuments.Def(CatalogLoader.CorePackId, "floors", "floor", """{ "defName": "Floor" }"""),
|
||||
PackDocuments.Def(
|
||||
CatalogLoader.CorePackId,
|
||||
"rooms",
|
||||
"office",
|
||||
"""{ "defName": "Office", "slots": [{ "key": "seat", "thing": "Chair" }], "positions": ["Principal"] }"""),
|
||||
"""{ "defName": "Office", "slots": [{ "key": "seat", "thing": "Chair" }], "positions": ["Principal"], "travelMinutes": 1 }"""),
|
||||
];
|
||||
|
||||
private static MapLayout MiniMap(
|
||||
|
||||
@@ -62,7 +62,7 @@ public class MapViewTests
|
||||
new ContentDocument(
|
||||
CatalogLoader.CorePackId,
|
||||
"defs/territories/yard.jsonc",
|
||||
"""{ "defName": "Yard" }"""),
|
||||
"""{ "defName": "Yard", "travelMinutes": 1 }"""),
|
||||
new ContentDocument(
|
||||
CatalogLoader.CorePackId,
|
||||
"localizations/ru.jsonc",
|
||||
|
||||
@@ -74,7 +74,8 @@ public class PatchTests
|
||||
{
|
||||
"defName": "Office",
|
||||
"slots": [ { "key": "seat", "thing": "Chair" } ],
|
||||
"works": ["TeachLesson", "WalkSchool"]
|
||||
"works": ["TeachLesson", "WalkSchool"],
|
||||
"travelMinutes": 1
|
||||
}
|
||||
"""),
|
||||
PackDocuments.Patch(
|
||||
|
||||
@@ -57,6 +57,13 @@ public class VanillaCoreTests
|
||||
Assert.DoesNotContain(map.Rooms, room => room.Label is "1A" or "1B" or "2A" or "2B");
|
||||
Assert.Equal(16, map.Rooms.Single(room => room.Id == "classroom-101").Seats);
|
||||
Assert.Empty(map.Rooms.Single(room => room.Id == "classroom-101").Slots);
|
||||
Assert.Equal(0.5f, catalog.Rooms["Classroom"].TravelMinutes);
|
||||
Assert.Equal(1.5f, catalog.Rooms["Corridor"].TravelMinutes);
|
||||
Assert.Equal(1.5f, catalog.Rooms["Stairwell"].TravelMinutes);
|
||||
Assert.Equal(1f, catalog.Rooms["EntranceHall"].TravelMinutes);
|
||||
Assert.Equal(3f, catalog.Territories["SchoolYard"].TravelMinutes);
|
||||
Assert.Equal(4, catalog.Traits["Diligent"].CommuteMinutes);
|
||||
Assert.Equal(-4, catalog.Traits["Lazy"].CommuteMinutes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user