diff --git a/Core/Calculation/TeamSchedulerSolution.cs b/Core/Calculation/TeamSchedulerSolution.cs index e3ac173..785797f 100644 --- a/Core/Calculation/TeamSchedulerSolution.cs +++ b/Core/Calculation/TeamSchedulerSolution.cs @@ -41,4 +41,11 @@ public class TeamSchedulerSolution( ).ToArray(); } + + public Team[] StudentUnassignedTeams(Student student) + { + var meetingTeams = TimeSlots.SelectMany(t => t); + return + student.Teams.Where(e => !meetingTeams.Contains(e)).ToArray(); + } } \ No newline at end of file diff --git a/Core/Calculation/UnassignedStudentScheduler.cs b/Core/Calculation/UnassignedStudentScheduler.cs index 7e09c2b..f4981d4 100644 --- a/Core/Calculation/UnassignedStudentScheduler.cs +++ b/Core/Calculation/UnassignedStudentScheduler.cs @@ -12,7 +12,7 @@ public class UnassignedStudentScheduler { _teams = teams; _students = teams.SelectMany(t => t.Students).Distinct().ToArray(); - _timeSlots = timeslots.Select(ts => ts.Select(t => t.Clone()).ToList()).ToArray(); + _timeSlots = timeslots.Select(ts => ts.Select(t => t.Clone()).ToList()).ToArray>(); } public static IEnumerable UnassignedStudents(IList students, IList timeSlot) => students.Where(s => !timeSlot.SelectMany(t => t.Students).Contains(s)); @@ -20,9 +20,9 @@ public class UnassignedStudentScheduler public static IEnumerable[] UnassignedStudents(IList students, IList[] schedule) => schedule.Select(ts => UnassignedStudents(students, ts)).ToArray(); - public TeamSchedulerSolution ScheduleStrategy(UnassignedScheduleStrategy scheduleStrategy) + public Team[] ScheduleStrategy(UnassignedScheduleStrategy scheduleStrategy) { - var ss = scheduleStrategy switch + var assignments = scheduleStrategy switch { UnassignedScheduleStrategy.BiggestGroup => ScheduleStrategy(GetAvailableTeams_BiggestGroup), UnassignedScheduleStrategy.IndividualEvents => ScheduleStrategy(GetAvailableTeams_Individual), @@ -32,14 +32,15 @@ public class UnassignedStudentScheduler _ => throw new ArgumentOutOfRangeException(nameof(scheduleStrategy), scheduleStrategy, null) }; - return new TeamSchedulerSolution(ss, "Success?"); + return assignments; } - public Team[][] ScheduleStrategy(Func, IEnumerable, IEnumerable> availableTeamSelector) + public Team[] ScheduleStrategy(Func, IEnumerable, IEnumerable> availableTeamSelector) { // Find stuff for unassigned students in each timeslot var scheduledTeams = _timeSlots.SelectMany(list => list).Distinct().ToList(); - foreach (var slot in _timeSlots) + var additions = new List(); + foreach (var slot in _timeSlots) { var unassigned = UnassignedStudents(_students, slot).ToList(); while (unassigned.Count > 0) @@ -54,14 +55,15 @@ public class UnassignedStudentScheduler slot.Add(teamToAdd); scheduledTeams.Add(teamToAdd); + additions.Add(teamToAdd); - foreach (var student in teamToAdd.Students) + foreach (var student in teamToAdd.Students) unassigned.Remove(student); } } - return _timeSlots.Select(e => e.ToArray()).ToArray(); - } + return additions.ToArray(); + } // find teams where several unassigned students can work together private IEnumerable GetAvailableTeams_BiggestGroup( diff --git a/Core/Entities/Team.cs b/Core/Entities/Team.cs index d40e76b..9a32561 100644 --- a/Core/Entities/Team.cs +++ b/Core/Entities/Team.cs @@ -4,7 +4,8 @@ namespace Core.Entities; public class Team { public int Id { get; set; } - + + [Required] public EventDefinition Event { get; set; } public List Students { get; set; } = []; @@ -47,7 +48,7 @@ public class Team { var studentsToOmitList = studentsToOmit.ToList(); var omittedStudents = Students.Where(studentsToOmitList.Contains).ToList(); - if (!omittedStudents.Any()) + if (omittedStudents.Count == 0) return new Team{Captain = Captain, Event = Event, Students = Students.ToList(), Identifier = Identifier}; var remainingStudents = Students.Where(s => !studentsToOmitList.Contains(s)).ToList(); diff --git a/Tests/Calculation/TeamSchedulerTest.cs b/Tests/Calculation/TeamSchedulerTest.cs index f38db74..eb9a358 100644 --- a/Tests/Calculation/TeamSchedulerTest.cs +++ b/Tests/Calculation/TeamSchedulerTest.cs @@ -48,8 +48,8 @@ public class TeamSchedulerTest solution = teamScheduler.Solve(); } - solution = new UnassignedStudentScheduler(allTeams, solution.TimeSlots).ScheduleStrategy(UnassignedScheduleStrategy.BiggestGroup); - solution = new UnassignedStudentScheduler(allTeams, solution.TimeSlots).ScheduleStrategy(UnassignedScheduleStrategy.IndividualEvents); + //solution = new UnassignedStudentScheduler(allTeams, solution.TimeSlots).ScheduleStrategy(UnassignedScheduleStrategy.BiggestGroup); + //solution = new UnassignedStudentScheduler(allTeams, solution.TimeSlots).ScheduleStrategy(UnassignedScheduleStrategy.IndividualEvents); var i = 1; foreach (var slot in solution.TimeSlots) diff --git a/WebApp/Components/Pages/MeetingSchedulePages/Index.razor b/WebApp/Components/Pages/MeetingSchedulePages/Index.razor index c19651c..9edb193 100644 --- a/WebApp/Components/Pages/MeetingSchedulePages/Index.razor +++ b/WebApp/Components/Pages/MeetingSchedulePages/Index.razor @@ -10,33 +10,43 @@ - Include: @string.Join(", ", _requiredTeams) + @* Include: @string.Join(", ", _requiredTeams) *@ - - + + + + Add High Effort Add Regionals + Remove Individual + Remove Low Effort + + @string.Join(", ", (_possibleAdditions ?? []).Select(e => e.ToString())) + Vertical="true" + CheckMark> @foreach (var team in _teams.OrderBy(e => e.Event.Name)) { - + + s.FirstName))"> +
+ @team.ToString() + +
+
+
}
- -
- @* *@ - - + Time Slots + Solve @@ -44,6 +54,7 @@ + Time slot: @context @{ var ol = TeamSchedulerSolution.GetStudentTeamOverlaps(context); } @@ -61,14 +72,18 @@ } *@ - @{ var notInTimeSLot = TeamSchedulerSolution.GetStudentsNotInTimSlot(context, _students); } - @if (notInTimeSLot.Any()) + @{ var unscheduled = TeamSchedulerSolution.GetStudentsNotInTimSlot(context, _students); } + @if (unscheduled.Any()) { - - - Not scheduled: @string.Join(", ", notInTimeSLot.Select(s => s.FirstName)) - - + Unscheduled + foreach (var student in unscheduled) + { + + @student.FirstName + @string.Join(", ", _solution.StudentUnassignedTeams(student).Select(e => e.ToString())) + + } + } @@ -76,12 +91,8 @@
- -
- - @code { private Team[]? _teams; private Student[]? _students; @@ -90,30 +101,44 @@ private TeamSchedulerOptions _parameters; bool _isSolving = false; private IEnumerable _requiredTeams = []; + + private Team[]? _possibleAdditions; //private Team[] _requiredTeams = []; - private void OnSelectedValuesChanged(IEnumerable obj) + private async Task OnSelectedValuesChanged(IEnumerable obj) { - _requiredTeams = obj.ToList(); + await _solutionData.ReloadServerData(); } - private void AddRegionals() + private async Task AddRegionals() { _requiredTeams = _teams.Where(e => e.Event.RegionalEvent).Concat(_requiredTeams).Distinct(); } - private void RemoveIndividual() + private async Task AddHighLevelOfEffort() + { + _requiredTeams + = _teams.Where(e => e.Event.LevelOfEffort >= 3).Concat(_requiredTeams).Distinct(); + } + + private async Task RemoveIndividual() { _requiredTeams = _requiredTeams.Where(t => t.Event.EventFormat != EventFormat.Individual); } + private async Task RemoveLowLevelOfEffort() + { + _requiredTeams + = _requiredTeams.Where(t => t.Event.LevelOfEffort > 1); + } + protected override async Task OnInitializedAsync() { _parameters = new TeamSchedulerOptions( - timeSlots: 4, + timeSlots: 2, mustIncludeEvents: [ // "Medical Technology", "Electrical Applications" , "RegionalTeam", @@ -140,7 +165,6 @@ ] ); - _teams = await Context.Teams .Include(e => e.Event) @@ -160,10 +184,9 @@ private async Task> SolveSchedule(TableState arg1, CancellationToken arg2) { - var requiredTeams = _teams; - + _isSolving = true; var teamScheduler = new TeamScheduler(_requiredTeams, _parameters.TimeSlots); - + // teamScheduler // .ScheduleSeparate( // _teams.First(e => e.Event.Name.Contains("Data Science")), @@ -172,15 +195,28 @@ _solution = teamScheduler.Solve(); + var loe = new UnassignedStudentScheduler(_teams, _solution.TimeSlots).ScheduleStrategy(UnassignedScheduleStrategy.LevelOfEffort); + var biggest = new UnassignedStudentScheduler(_teams, _solution.TimeSlots).ScheduleStrategy(UnassignedScheduleStrategy.BiggestGroup); + var individual = new UnassignedStudentScheduler(_teams, _solution.TimeSlots).ScheduleStrategy(UnassignedScheduleStrategy.IndividualEvents); + var anyNotMeetingAlready = new UnassignedStudentScheduler(_teams, _solution.TimeSlots).ScheduleStrategy(UnassignedScheduleStrategy.AnyNotMeetingAlready); + + _possibleAdditions = loe; + if (_possibleAdditions.Length == 0) + _possibleAdditions = biggest; + if (_possibleAdditions.Length == 0) + _possibleAdditions = anyNotMeetingAlready; + + if (_possibleAdditions.Length == 0) + _possibleAdditions = individual; + await InvokeAsync(StateHasChanged); // let the UI know that the solution has been found + _isSolving = false; return new TableData { Items = _solution.TimeSlots}; } - private void Solve() { _solutionData.ReloadServerData(); } - } diff --git a/WebApp/Properties/launchSettings.json b/WebApp/Properties/launchSettings.json index c451f24..7922131 100644 --- a/WebApp/Properties/launchSettings.json +++ b/WebApp/Properties/launchSettings.json @@ -55,6 +55,16 @@ }, "publishAllPorts": true, "useSSL": true + }, + "Scheduler": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "meeting-schedule", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7235;http://localhost:5013" } }, "$schema": "http://json.schemastore.org/launchsettings.json",