using System; using System.Collections.Generic; using System.Linq; namespace spplus; public class CourseCrafter { private class CourseInstance { public Sport Sport = null!; public int Remaining; public List Students = new(); } public static void Craft() { 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++) { instances.Add(new CourseInstance { Sport = sp, Remaining = sp.MaxStudents }); } } // ===== 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; var sports = settings.Sports; if (students.Count == 0 || sports.Count == 0) return "Keine Daten vorhanden."; int semesterCount = sports.Max(s => s.Semester.Length); // Kurszählung: (Semester, SportName) → Liste Schüler var dict = new Dictionary<(int, string), List>(); foreach (var st in students) { if (st.Result == null) continue; for (int sem = 0; sem < st.Result.Count; sem++) { var course = st.Result[sem]; if (string.IsNullOrWhiteSpace(course) || course == "Fehler") continue; var key = (sem, course); if (!dict.ContainsKey(key)) dict[key] = new List(); dict[key].Add(st); } } var sb = new System.Text.StringBuilder(); sb.AppendLine($"Anzahl generierter Kurse: {dict.Count}"); sb.AppendLine("Übersicht:"); foreach (var entry in dict.OrderBy(e => e.Key.Item1).ThenBy(e => e.Key.Item2)) { int semester = entry.Key.Item1 + 1; string name = entry.Key.Item2; int count = entry.Value.Count; sb.AppendLine($"Semester {semester}: {name} — {count} Schüler*innen"); } return sb.ToString(); } }