diff --git a/MainWindow.axaml b/MainWindow.axaml
index 6b18d6b..2ca5aa2 100644
--- a/MainWindow.axaml
+++ b/MainWindow.axaml
@@ -20,7 +20,7 @@
-
+
@@ -100,22 +100,112 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
+
+
+
+
+
diff --git a/MainWindow.axaml.cs b/MainWindow.axaml.cs
index c6bb26a..c0c2bf8 100644
--- a/MainWindow.axaml.cs
+++ b/MainWindow.axaml.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using Avalonia.Controls;
+using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
@@ -119,6 +120,30 @@ public partial class MainWindow : Window
private void BtnCraftCourses_OnClick(object? sender, RoutedEventArgs e)
{
// Craft courses here / call course-crafter
+ CourseCrafter.Craft();
+ RefreshResultView();
+ TbiResults.Focus();
+ }
+
+ private void RefreshResultView()
+ {
+ LbResult.Items.Clear();
+ foreach (Student s in Settings.Instance.Students)
+ {
+ try
+ {
+ for(int i = 0; i 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();
+ }
+}
diff --git a/structs.cs b/structs.cs
index 8bca1a5..9b492ba 100644
--- a/structs.cs
+++ b/structs.cs
@@ -1,32 +1,56 @@
using System.Collections.Generic;
+using Avalonia.Data;
namespace spplus;
public class Sport
{
+ public int ID { get; set; } = 0;
public string Name { get; set; } = "Neuer Kurs"; // Kursname
- public int MaxCoursesPerSemester { get; set; } = 1; // Maximale Anzahl an Kursen pro Semester
- public int MaxStudents { get; set; } = 20; // Maximale Anzahl an Schülern pro Kurs
+
+ public int MaxStudents { get; set; } = 25; // Maximale Anzahl an Schülern pro Kurs
public int MinStudents { get; set; } = 5; // Minimale Anzahl an Schülern pro Kurs
- public int[] Semester { get; set; } = [1, 2, 3, 4]; // Angebot in diesen Semestern
+ public int[] Semester { get; set; } = [2, 2, 2, 2]; // Maximale Anzahl an Angeboten in den jeweiligen Index-Semestern (0 => 1. Semester)
+ public List AlternativeNames { get; set; } = new();
+ public List AlternativeCourses { get; set; } = new();
protected Sport()
{
}
- protected Sport(string name)
+ public Sport(string name)
{
Name = name;
}
- protected Sport(string name, int maxCoursesPerSemester, int maxStudents, int minStudents, int[] semester)
+ public Sport(string name, int maxCoursesPerSemester, int maxStudents, int minStudents, int[] semester, List alternativeNames)
{
Name = name;
- MaxCoursesPerSemester = maxCoursesPerSemester;
MaxStudents = maxStudents;
MinStudents = minStudents;
Semester = semester;
+ AlternativeNames = alternativeNames;
+ }
+
+ public void AddAlternativeSport(int id)
+ {
+ AlternativeCourses.Add(id);
+ }
+
+ public void ClearAlternativeSport()
+ {
+ AlternativeCourses.Clear();
+ }
+
+ public override string ToString()
+ {
+ var alt = "";
+ foreach (var s in AlternativeNames)
+ {
+ alt += s + ", ";
+ }
+ return $"{Name} ({alt})";
}
}
@@ -34,7 +58,6 @@ public class Student
{
public string ID { get; set; } = ""; // ID des Schüler (z.B. NolteSeb)
public string Name { get; set; } = ""; // Name des Schülers
- public Sport[] SelectedCourses { get; set; } = new Sport[4]; // Kurswahl
public List SelectedCourseNames { get; set; } = new();
public List? Result { get; set; } = null;
@@ -62,6 +85,7 @@ public class Settings
public List Students { get; set; } = [];
public List Sports { get; set; } = [];
+ public int NumCoursesPerSemester { get; set; } = 10;
public Settings()
{
@@ -72,4 +96,34 @@ public class Settings
{
// Hier importieren...
}
+
+ public static void ImportInitial()
+ {
+ Instance.Sports.Add(new Sport("Tischtennis"){ AlternativeNames = {"Sport_TT"}});
+ Instance.Sports.Add(new Sport("Badminton"){ AlternativeNames = {"Sport_BM"}});
+ Instance.Sports.Add(new Sport("Gymnastik/Tanz"){ AlternativeNames = {"Sport_Gym"}});
+ Instance.Sports.Add(new Sport("Schwimmen"){ AlternativeNames = {"Sport_SW"}, Semester = [1, 1, 1, 1], MaxStudents = 18});
+ Instance.Sports.Add(new Sport("Bouldern"){ AlternativeNames = {"Sport_BO"}, Semester = [1, 1, 1, 1]});
+ Instance.Sports.Add(new Sport("Basketball"){ AlternativeNames = {"Sport_BS"}});
+ Instance.Sports.Add(new Sport("Fitness"){ AlternativeNames = {"Sport_Fit"}});
+ Instance.Sports.Add(new Sport("Fußball"){ AlternativeNames = {"Sport_Fuß"}, Semester = [1, 0, 1, 0]});
+ Instance.Sports.Add(new Sport("Handball"){ AlternativeNames = {"Sport_HB"}});
+ Instance.Sports.Add(new Sport("Leichtathletik"){ AlternativeNames = {"Sport_LA"}, Semester = [1, 0, 1, 0], MaxStudents = 18});
+ Instance.Sports.Add(new Sport("Tennis"){ AlternativeNames = {"Sport_Te"}});
+ Instance.Sports.Add(new Sport("Turnen"){ AlternativeNames = {"Sport_Tur"}});
+ Instance.Sports.Add(new Sport("Volleyball"){ AlternativeNames = {"Sport_VB"}});
+ }
+
+ public static string? GetSportNameFromID(int id)
+ {
+ foreach (var s in Instance.Sports)
+ {
+ if (s.ID == id)
+ {
+ return s.Name;
+ }
+ }
+
+ return null;
+ }
}
\ No newline at end of file