@page "/meeting-schedule" @attribute [Authorize] @using System.Text @using Core.Calculation @using Microsoft.EntityFrameworkCore @inject IConfiguration Configuration @inject AppDbContext Context @inject ClipboardService ClipboardService @Configuration["ChapterSettings:Shortname"] TSA Schedule @Configuration["ChapterSettings:CompetitionYear"] @Configuration["ChapterSettings:Shortname"] TSA Schedule @Configuration["ChapterSettings:CompetitionYear"] Time Slots Add High Effort Add Regionals Remove Individual Remove Low Effort Invert Reset Solve @context.Name @foreach (var team in context.Teams.OrderBy(e => e.ToString())) { var removed = !_scheduledTeams.Contains(team); @team - @{var first = true;} @foreach (var student in team.Students) { var overlap = context.StudentHasOverlaps(student); var isAbsent = _absentStudents.Contains(student); var color = overlap ? Color.Warning : Color.Default; @if(!first) {, } {first = false;}  @student.FirstName@(overlap ? "*" : "")@(isAbsent ? " (absent)" : "") } } @if (context.UnscheduledStudents.Any()) { Unscheduled @foreach (var student in context.UnscheduledStudents) { var isAbsent = _absentStudents.Contains(student); @student.FirstName@(isAbsent ? " (absent)" : "")  @{var first = true;} @foreach (var unassignedTeam in _solution.StudentUnassignedTeams(student)) { var color = _possibleAdditions.Contains(unassignedTeam, new TeamIdComparer()) ? Color.Success : Color.Default; var added = _scheduledTeams.Contains(unassignedTeam); @if(!first) {, } {first = false;} @unassignedTeam } } } Absent Students Scheduled Teams @foreach (var team in _teams.OrderBy(e => e.Event.Name)) {
@team.ToString()
}
@code { private Team[]? _teams; private Student[]? _students; MudTable _solutionData; private TeamSchedulerSolution _solution; private TeamSchedulerOptions _parameters; bool _isSolving; private IEnumerable _scheduledTeams = []; private IEnumerable _absentStudents = []; private IEnumerable _possibleAdditions = []; private async Task AddRegionals() { _scheduledTeams = _teams.Where(e => e.Event.RegionalEvent).Concat(_scheduledTeams).Distinct(); } private async Task AddHighLevelOfEffort() { _scheduledTeams = _teams.Where(e => e.Event.LevelOfEffort >= 3).Concat(_scheduledTeams).Distinct(); } private async Task RemoveIndividual() { _scheduledTeams = _scheduledTeams.Where(t => t.Event.EventFormat != EventFormat.Individual); } private async Task RemoveLowLevelOfEffort() { _scheduledTeams = _scheduledTeams.Where(t => t.Event.LevelOfEffort > 1); } private async Task Invert() { var rt = _scheduledTeams.ToArray(); _scheduledTeams = _teams.Where(t => !rt.Contains(t)); } private async Task Reset() { _scheduledTeams = []; } private void ToggleRequiredTeam(Team unassignedTeam) { if (_scheduledTeams.Contains(unassignedTeam)) _scheduledTeams = _scheduledTeams.Where(t => t != unassignedTeam); else { _scheduledTeams = _scheduledTeams.Concat(new[] { unassignedTeam }); } } protected override async Task OnInitializedAsync() { _parameters = new TeamSchedulerOptions( 2, mustIncludeEvents: [ // "Medical Technology", "Electrical Applications" , "RegionalTeam", // ,"Dragster", "Flight" ], extended: [ // "Invention", "Construction Challenge", "Mechanical", "Mass", "Micro" //"STEM" //"Community", "Vlogging"// "Microcontroller" ], omittedEvents: [ // "Vlogging", "Junior", "Community Service Video", "Digital Photography", // "STEM" //"Leadership",// "Electrical", //"Construction" // "Forensic", //"CAD" //"I&I Team 1", "I&I Team 2"//, "Website Design", ], absentStudents: [ ] ); _teams = await Context.Teams .Include(e => e.Event) .Include(e => e.Students) .OrderBy(e => e.Event.Name) .ThenBy(e => e.Identifier) .ToArrayAsync(); _students = await Context.Students .Include(e => e.Teams) .ThenInclude(e => e.Captain) .Include(e => e.EventRankings) .ThenInclude(e => e.EventDefinition) .OrderBy(e => e.FirstName).ToArrayAsync(); } private async Task> SolveSchedule(TableState arg1, CancellationToken arg2) { _isSolving = true; // Filter out absent students var availableStudents = _students.Where(s => !_absentStudents.Contains(s)).ToArray(); // Update parameters with absent student names _parameters.AbsentStudents = _absentStudents.Select(s => s.FirstNameLastName).ToArray(); var teamScheduler = new TeamScheduler(_scheduledTeams, _parameters.TimeSlots, availableStudents); _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.Any()) _possibleAdditions = biggest; if (!_possibleAdditions.Any()) _possibleAdditions = anyNotMeetingAlready; if (!_possibleAdditions.Any()) _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(); } async Task CopyToClipboard() { var sb = new StringBuilder(); foreach (var timeslot in _solution.TimeSlots) { //var overlaps // = TeamSchedulerSolution.GetStudentTeamOverlaps(timeslot).Select(e => e.Item1).ToArray(); foreach (var scheduledTeam in timeslot.Teams.OrderBy(e => e.ToString())) { var t = scheduledTeam.ToString(); var s = string.Join(", ", scheduledTeam.Students .OrderBy(e => e == scheduledTeam.Captain) .ThenBy(e => e.FirstName) .Select(e => e.FirstName + (timeslot.StudentHasOverlaps(e) ? "*" : "") + (_absentStudents.Contains(e) ? " (absent)" : ""))); if (scheduledTeam.Event.EventFormat is EventFormat.Individual) sb.Append(t); else sb.Append($"{t} - {s}"); sb.Append(Environment.NewLine); } if (timeslot.UnscheduledStudents.Any()) { sb.Append("--Unscheduled"); sb.Append(Environment.NewLine); foreach (var student in timeslot.UnscheduledStudents) { var s = student.FirstName + (_absentStudents.Contains(student) ? " (absent)" : ""); var unassignedTeams = _solution.StudentUnassignedTeams(student); var t = string.Join(", ", unassignedTeams.Select(e => e.ToString())); sb.Append($"{s} - {t}"); sb.Append(Environment.NewLine); } } sb.Append(Environment.NewLine); } try { await ClipboardService.WriteTextAsync(sb.ToString()); } catch { Console.WriteLine("Cannot write text to clipboard"); } } }