Compare commits

4 Commits

Author SHA1 Message Date
fierke 71dc63f2a2 [file:] added logo 2026-04-18 16:04:14 +02:00
fierke 68f673c8d7 Update README.md 2026-04-15 11:48:44 +00:00
fierke d5b7fd7af3 [file:] uploaded app-screenshots 2026-04-15 13:45:37 +02:00
fierke 573e7c86e8 [fix:] course amount per semester synchronized with NumCoursesPerSemester, fixing #1 2026-04-15 13:22:12 +02:00
5 changed files with 92 additions and 0 deletions
+4
View File
@@ -2,6 +2,8 @@
Plattformunabhängiger (Windows, Linux, Mac), interaktiver Sportkursplaner für Oberstufen auf Basis einer Sportkurswahl durch SuS.
![spplus-Hauptbildschirm](img/spplus_planung.png)
## Features
* \+ Import von CSV-Dateien mit Kurswahl
* \+ Wahlansicht
@@ -21,3 +23,5 @@ Plattformunabhängiger (Windows, Linux, Mac), interaktiver Sportkursplaner für
* Suche `spplus` bzw. `spplus.exe` und führe aus
* Linux/MacOS evl.: `chmod +x spplus`
![spplus-Sportkursübersicht](img/spplus_sport.png)
+88
View File
@@ -193,6 +193,94 @@ public class CourseCrafter
} while (changed && iteration < maxIterations);
// // --- Kurse nachträglich aufteilen, um NumCoursesPerSemester exakt zu erreichen ---
// foreach (var course in GeneratedCourses)
// {
// int sem_count_total = GeneratedCourses.Count(tuple => tuple.Semester == course.Semester);
// if (sem_count_total >= Settings.Instance.NumCoursesPerSemester) break;
//
// int sem_count = GeneratedCourses.Count(tuple => tuple.Semester == course.Semester && tuple.Instance.Sport.Name == course.Instance.Sport.Name);
//
//
// if (sem_count < course.Instance.Sport.Semester[course.Semester - 1] && course.Instance.Students.Count >= course.Instance.Sport.MinStudents *2)
// {
// // hier aufteilen
// Console.WriteLine("Könnte aufgeteilt werden.");
// }
// }
//
// --- Kurse nachträglich aufteilen, um NumCoursesPerSemester exakt zu erreichen ---
for (int semester = 1; semester <= 4; semester++)
{
int cancel = 0;
while (GeneratedCourses.Count(c => c.Semester == semester) < Settings.Instance.NumCoursesPerSemester)
{
cancel++;
if (cancel >= 5) break;
// Kandidaten suchen: splittbare Kurse, deren Sport noch Kapazität hat
var candidate = GeneratedCourses
.Where(c => c.Semester == semester)
.Where(c => c.Instance.Students.Count >= c.Instance.Sport.MinStudents * 2)
.Where(c =>
{
int sportCount = GeneratedCourses.Count(g =>
g.Semester == semester &&
g.Instance.Sport.Name == c.Instance.Sport.Name);
int allowed = c.Instance.Sport.Semester[semester - 1];
return sportCount < allowed;
})
.OrderByDescending(c => c.Instance.Students.Count)
.FirstOrDefault();
try
{
var students = candidate.Instance.Students;
var newCourse = new CourseInstance
{
Sport = candidate.Instance.Sport,
Students = new List<string>()
};
List<string> moved = new();
for (int i = students.Count - 1; i >= 0; i--)
{
string stud = students[i];
if (newCourse.Students.Count >= candidate.Instance.Sport.MaxStudents)
break;
// Sicherstellen, dass beide Kurse >= MinStudents bleiben
if (students.Count - moved.Count <= candidate.Instance.Sport.MinStudents)
break;
newCourse.Students.Add(stud);
moved.Add(stud);
}
// Validierung
if (newCourse.Students.Count < candidate.Instance.Sport.MinStudents)
break;
// Move durchführen
foreach (var s in moved)
{
candidate.Instance.Students.Remove(s);
}
GeneratedCourses.Add((semester, newCourse));
}
catch
{
}
}
}
bool isStudentFree(int semester, string studentID)
{
Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB