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:
@@ -0,0 +1,157 @@
|
||||
using HSchool.Content;
|
||||
using HSchool.People;
|
||||
using HSchool.Schedule;
|
||||
|
||||
namespace HSchool.Ai;
|
||||
|
||||
/// <summary>
|
||||
/// Where this person ought to be right now. The timetable and the job, not the walk graph.
|
||||
/// </summary>
|
||||
public static class Duty
|
||||
{
|
||||
/// <summary>
|
||||
/// The room of the current obligation, or <see langword="null"/> when they should be off campus.
|
||||
/// A hole in the class table sends the pupil to their homeroom.
|
||||
/// </summary>
|
||||
public static string? RoomAt(
|
||||
Person person,
|
||||
SchoolClass? schoolClass,
|
||||
Timetable? timetable,
|
||||
DefCatalog catalog,
|
||||
DateTime time,
|
||||
int weekDays)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(person);
|
||||
ArgumentNullException.ThrowIfNull(catalog);
|
||||
|
||||
if (!ComesToday(person, timetable, catalog, time, weekDays))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (IsOtherStaff(person))
|
||||
{
|
||||
return person.WorkplaceRoomId;
|
||||
}
|
||||
|
||||
var utc = DateTime.SpecifyKind(time, DateTimeKind.Utc);
|
||||
if (!SchoolDay.IsWorkday(catalog, utc, weekDays))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var slot = SchoolDay.At(catalog, utc, weekDays);
|
||||
var day = SchoolDay.WeekdayIndex(utc);
|
||||
var lessons = LessonsToday(person, schoolClass, timetable, day);
|
||||
if (lessons.Count == 0)
|
||||
{
|
||||
return person.WorkplaceRoomId;
|
||||
}
|
||||
|
||||
if (slot.Kind == DaySlotKind.Lesson)
|
||||
{
|
||||
var current = lessons.FirstOrDefault(lesson => lesson.Period == slot.Index);
|
||||
if (current is not null)
|
||||
{
|
||||
return current.RoomId;
|
||||
}
|
||||
|
||||
return schoolClass?.RoomId ?? person.WorkplaceRoomId;
|
||||
}
|
||||
|
||||
if (slot.Kind == DaySlotKind.Break)
|
||||
{
|
||||
var next = lessons.Where(lesson => lesson.Period > slot.Index).OrderBy(lesson => lesson.Period).FirstOrDefault();
|
||||
return next?.RoomId ?? schoolClass?.RoomId ?? person.WorkplaceRoomId;
|
||||
}
|
||||
|
||||
var frame = catalog.DayFrame;
|
||||
if (frame is not null
|
||||
&& SchoolDay.TryParseTime(frame.FirstLesson, out var first)
|
||||
&& utc.TimeOfDay < first.ToTimeSpan())
|
||||
{
|
||||
return lessons[0].RoomId;
|
||||
}
|
||||
|
||||
if (frame is not null
|
||||
&& SchoolDay.TryLastBell(catalog, out var last)
|
||||
&& utc.TimeOfDay >= last.ToTimeSpan())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return lessons[0].RoomId;
|
||||
}
|
||||
|
||||
public static bool ComesToday(
|
||||
Person person,
|
||||
Timetable? timetable,
|
||||
DefCatalog catalog,
|
||||
DateTime time,
|
||||
int weekDays)
|
||||
{
|
||||
if (person.IsParent && !person.IsStaff && !person.IsStudent)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SchoolDay.IsWorkday(catalog, time, weekDays))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsOtherStaff(person))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var day = SchoolDay.WeekdayIndex(time);
|
||||
if (person.IsStudent)
|
||||
{
|
||||
return timetable?.Lessons.Any(lesson =>
|
||||
lesson.ClassId == person.ClassId && lesson.Day == day) == true;
|
||||
}
|
||||
|
||||
if (person.IsStaff)
|
||||
{
|
||||
return timetable?.Lessons.Any(lesson =>
|
||||
lesson.TeacherId == person.Id && lesson.Day == day) == true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsOtherStaff(Person person) =>
|
||||
person.IsStaff && !Staffing.TeacherPosition.Equals(person.Position, StringComparison.Ordinal);
|
||||
|
||||
public static IReadOnlyList<LessonPlacement> LessonsToday(
|
||||
Person person,
|
||||
SchoolClass? schoolClass,
|
||||
Timetable? timetable,
|
||||
int day)
|
||||
{
|
||||
if (timetable is null)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
if (person.IsStudent)
|
||||
{
|
||||
var classId = person.ClassId ?? schoolClass?.Id;
|
||||
return timetable.Lessons
|
||||
.Where(lesson => lesson.ClassId == classId && lesson.Day == day)
|
||||
.OrderBy(lesson => lesson.Period)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
if (person.IsStaff)
|
||||
{
|
||||
return timetable.Lessons
|
||||
.Where(lesson => lesson.TeacherId == person.Id && lesson.Day == day)
|
||||
.OrderBy(lesson => lesson.Period)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user