diff --git a/crafter.cs b/crafter.cs index 50280cf..c6c3795 100644 --- a/crafter.cs +++ b/crafter.cs @@ -1,9 +1,213 @@ +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; + } + } + } } -} \ No newline at end of file + + 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(); + } +}