using System; using System.Collections.Generic; using System.Linq; namespace spplus; public class CourseCrafter { public class CourseInstance { public Sport Sport = null!; public int Remaining; public List Students = new(); } public static List<(int Semester, CourseInstance Instance)> GeneratedCourses = new(); public static void Craft() { GeneratedCourses = new(); var settings = Settings.Instance; var students = settings.Students; var sports = settings.Sports; if (students.Count == 0 || sports.Count == 0) return; int semesterCount = sports.Max(s => s.Semester.Length); // Result initialisieren foreach (var st in students) st.Result = Enumerable.Repeat("Fehler", semesterCount).ToList(); // Mapping Name + Alternativen → Sport var nameMap = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (var sp in sports) { nameMap[sp.Name] = sp; foreach (var alt in sp.AlternativeNames) nameMap[alt] = sp; } // ===== Semesterweise Planung ===== for (int sem = 0; sem < semesterCount; sem++) { int remainingCourseSlots = settings.NumCoursesPerSemester; // Interessenten dieses Semesters var interested = new Dictionary>(); foreach (var sp in sports) interested[sp] = new List(); foreach (var st in students) { if (st.SelectedCourseNames.Count <= sem) continue; var sel = st.SelectedCourseNames[sem]; if (nameMap.TryGetValue(sel, out var sp)) interested[sp].Add(st); } var instances = new List(); // ===== Kurse erzeugen ===== foreach (var sp in sports) { if (sem >= sp.Semester.Length) continue; int demand = interested[sp].Count; if (demand < sp.MinStudents) continue; int needed = (int)Math.Ceiling(demand / (double)sp.MaxStudents); int allowed = Math.Min(needed, sp.Semester[sem]); allowed = Math.Min(allowed, remainingCourseSlots); if (allowed <= 0) continue; remainingCourseSlots -= allowed; for (int i = 0; i < allowed; i++) { var instance = new CourseInstance { Sport = sp, Remaining = sp.MaxStudents }; instances.Add(instance); GeneratedCourses.Add((sem, instance)); } } // ===== Schüler verteilen ===== foreach (var sp in sports) { var pool = interested[sp]; if (pool.Count == 0) continue; var targets = instances.Where(i => i.Sport == sp).ToList(); if (targets.Count == 0) continue; int idx = 0; foreach (var st in pool) { if (st.SelectedCourseNames.Count <= sem) continue; if (st.Result![sem] != "Fehler") continue; bool assigned = false; for (int t = 0; t < targets.Count; t++) { var inst = targets[(idx + t) % targets.Count]; if (inst.Remaining > 0) { inst.Remaining--; inst.Students.Add(st); st.Result[sem] = sp.Name; idx++; assigned = true; break; } } if (!assigned) continue; } } // ===== Alternativen ===== foreach (var st in students) { if (st.SelectedCourseNames.Count <= sem) continue; if (st.Result![sem] != "Fehler") continue; var sel = st.SelectedCourseNames[sem]; if (!nameMap.TryGetValue(sel, out var wanted)) continue; foreach (var altId in wanted.AlternativeCourses) { var altSport = sports.FirstOrDefault(s => s.ID == altId); if (altSport == null) continue; var inst = instances.FirstOrDefault(i => i.Sport == altSport && i.Remaining > 0); if (inst == null) continue; inst.Remaining--; inst.Students.Add(st); st.Result[sem] = altSport.Name; break; } } } } public static string GenerateStatistics() { var settings = Settings.Instance; var students = settings.Students; if (GeneratedCourses == null || GeneratedCourses.Count == 0) return "Keine Kurse generiert."; int semesterCount = students .Where(s => s.Result != null) .Select(s => s.Result!.Count) .DefaultIfEmpty(0) .Max(); var sb = new System.Text.StringBuilder(); sb.AppendLine($"Anzahl generierter Kurse: {GeneratedCourses.Count}"); sb.AppendLine("Übersicht:"); // ===== Kursübersicht ===== var grouped = GeneratedCourses .GroupBy(g => new { g.Semester, g.Instance.Sport.Name }) .OrderBy(g => g.Key.Semester) .ThenBy(g => g.Key.Name); foreach (var group in grouped) { int counter = 1; foreach (var entry in group) { int semester = group.Key.Semester + 1; string sportName = group.Key.Name; string number = counter.ToString("D2"); int count = entry.Instance.Students.Count; sb.AppendLine( $"Semester {semester}: {sportName} {number}: {count} Schüler*innen" ); counter++; } } sb.AppendLine(); sb.AppendLine("Fehlerübersicht:"); // ===== Fehler pro Semester ===== for (int sem = 0; sem < semesterCount; sem++) { int errors = students.Count(st => st.Result != null && st.Result.Count > sem && st.Result[sem] == "Fehler"); sb.AppendLine($"Semester {sem + 1}: {errors} Fehler"); } return sb.ToString(); } }