import { JavaObject, cast_java_lang_Object } from '../../java/lang/JavaObject'; import { KursblockungDynFachart, cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynFachart } from '../../core/kursblockung/KursblockungDynFachart'; import { KursblockungDynStatistik, cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynStatistik } from '../../core/kursblockung/KursblockungDynStatistik'; import { KursblockungStatic, cast_de_nrw_schule_svws_core_kursblockung_KursblockungStatic } from '../../core/kursblockung/KursblockungStatic'; import { KursblockungMatrix, cast_de_nrw_schule_svws_core_kursblockung_KursblockungMatrix } from '../../core/kursblockung/KursblockungMatrix'; import { KursblockungInputSchueler, cast_de_nrw_schule_svws_core_data_kursblockung_KursblockungInputSchueler } from '../../core/data/kursblockung/KursblockungInputSchueler'; import { KursblockungDynKurs, cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynKurs } from '../../core/kursblockung/KursblockungDynKurs'; import { JavaString, cast_java_lang_String } from '../../java/lang/JavaString'; import { Vector, cast_java_util_Vector } from '../../java/util/Vector'; import { System, cast_java_lang_System } from '../../java/lang/System'; import { KursblockungOutputFachwahlZuKurs, cast_de_nrw_schule_svws_core_data_kursblockung_KursblockungOutputFachwahlZuKurs } from '../../core/data/kursblockung/KursblockungOutputFachwahlZuKurs'; export class KursblockungDynSchueler extends JavaObject { private readonly representation : String; private fachartArr : Array; private fachartZuGUI : Array; private fachartZuKurs : Array; private fachartZuKursSaveS : Array; private fachartZuKursSaveK : Array; private readonly statistik : KursblockungDynStatistik; private nichtwahlen : number = 0; private readonly schieneBelegt : Array; private static dummy : KursblockungMatrix = new KursblockungMatrix(0, 0); private matrix : KursblockungMatrix; /** * Im Konstruktor wird {@code pSchueler} in ein Objekt dieser Klasse * umgewandelt. * * @param pStatistik Referenz um die Nichtwahlen mitzuteilen. * @param pSchueler Die Schüler-Daten von der GUI/DB. * @param pSchienenAnzahl Wir benötigt, um {@link #schieneBelegt} zu * initialisieren. */ constructor(pSchueler : KursblockungInputSchueler, pStatistik : KursblockungDynStatistik, pSchienenAnzahl : number) { super(); this.representation = pSchueler.representation; this.statistik = pStatistik; this.fachartArr = Array(0).fill(null); this.fachartZuGUI = Array(0).fill(0); this.fachartZuKurs = Array(0).fill(null); this.fachartZuKursSaveS = Array(0).fill(null); this.fachartZuKursSaveK = Array(0).fill(null); this.nichtwahlen = 0; this.schieneBelegt = Array(pSchienenAnzahl).fill(false); this.matrix = KursblockungDynSchueler.dummy; } public toString() : String { return this.representation; } /** * Eine String-Darstellung des Schülers. Beinhaltet meistens den Vornamen, den * Nachnamen, das Geburtsdatum und das Geschlecht. * * @return Eine String-Darstellung des Schülers. */ gibRepresentation() : String { return this.representation; } /** * Liefert die aktuelle Anzahl an Nichtwahlen. * * @return Die aktuelle Anzahl an Nichtwahlen. */ gibNichtwahlen() : number { return this.nichtwahlen; } /** * Liefert ein Array aller Facherten (= Fachwahlen) des Schülers. * * @return Ein Array aller Facherten (= Fachwahlen) des Schülers. */ gibFacharten() : Array { return this.fachartArr; } /** * Setzt alle Facharten (=Fachwahlen) des Schülers. * * @param pFacharten Die Facharten des Schülers. * @param pIDs Die zur Fachwahl zugehörige ID der GUI bzw. Datenbank. */ aktionSetzeFachartenUndIDs(pFacharten : Array, pIDs : Array) : void { let nFacharten : number = pFacharten.length; this.fachartArr = pFacharten; this.fachartZuGUI = pIDs; this.fachartZuKurs = Array(nFacharten).fill(null); this.fachartZuKursSaveS = Array(nFacharten).fill(null); this.fachartZuKursSaveK = Array(nFacharten).fill(null); this.statistik.aktionNichtwahlenVeraendern(nFacharten); this.nichtwahlen = nFacharten; for (let i : number = 1; i < nFacharten; i++){ for (let j : number = i; j >= 1; j--){ let anzL : number = this.fachartArr[j - 1].gibKurseMax(); let anzR : number = this.fachartArr[j].gibKurseMax(); if (anzL > anzR) { let fL : KursblockungDynFachart = this.fachartArr[j - 1]; let fR : KursblockungDynFachart = this.fachartArr[j]; let valL : number = this.fachartZuGUI[j - 1]; let valR : number = this.fachartZuGUI[j]; this.fachartArr[j - 1] = fR; this.fachartArr[j] = fL; this.fachartZuGUI[j - 1] = valR; this.fachartZuGUI[j] = valL; } } } this.matrix = new KursblockungMatrix(nFacharten, this.schieneBelegt.length); } /** * Speichert die aktuell belegten Kurse im Zustand S. */ aktionZustandSpeichernS() : void { System.arraycopy(this.fachartZuKurs, 0, this.fachartZuKursSaveS, 0, this.fachartZuKurs.length); } /** * Speichert die aktuell belegten Kurse im Zustand K. */ aktionZustandSpeichernK() : void { System.arraycopy(this.fachartZuKurs, 0, this.fachartZuKursSaveK, 0, this.fachartZuKurs.length); } /** * Entfernt zunächst den Schüler aus seinen aktuellen Kursen und setzt ihn dann * in die Kurse, die zuvor im Zustand S gespeichert wurden. */ aktionZustandLadenS() : void { this.aktionWaehleKurse(this.fachartZuKursSaveS); } /** * Entfernt zunächst den Schüler aus seinen aktuellen Kursen und setzt ihn dann * in die Kurse, die zuvor im Zustand K gespeichert wurden. */ aktionZustandLadenK() : void { this.aktionWaehleKurse(this.fachartZuKursSaveK); } private aktionWaehleKurse(wahl : Array) : void { this.aktionKurseAlleEntfernen(); for (let i : number = 0; i < this.fachartZuKurs.length; i++){ let kurs : KursblockungDynKurs | null = wahl[i]; if (kurs !== null) { this.aktionKursHinzufuegen(i, kurs); } } } /** * Entfernt den Schüler aus seinen aktuell zugeordneten Kursen. */ aktionKurseAlleEntfernen() : void { for (let i : number = 0; i < this.fachartArr.length; i++){ let kurs : KursblockungDynKurs | null = this.fachartZuKurs[i]; if (kurs !== null) { this.aktionKursEntfernen(i, kurs); } } } /** * Geht die Facharten durch (Facharten mit einer kleineren Kursanzahl zuerst) * und geht dann pro Fachart alle Kurse durch (Kurse mit kleinerer Schüleranzahl * zuerst). Falls der Kurs wählbar ist, wird der Schüler hinzugefügt und es geht * weiter mit der nächsten Fachart. Ein Kurs ist wählbar, wenn nicht bereits ein * Kurs zugeordnet wurde und die Schienen in den der Kurs sind frei sind.
* * Falls der Paramter {@code pNurMultikurse} TRUE ist, dann werden nur * Multikurse verteilt. * * @param pNurMultikurse Falls TRUE ist, dann werden nur Multikurse verteilt. */ aktionKurseZufaelligVerteilen(pNurMultikurse : boolean) : void { let perm : Array = KursblockungStatic.gibPermutation(this.fachartArr.length); for (let p : number = 0; p < this.fachartArr.length; p++){ let i : number = perm[p]; if (this.fachartZuKurs[i] !== null) { continue; } let fachart : KursblockungDynFachart = this.fachartArr[i]; if (pNurMultikurse) { if (!fachart.gibHatMultikurs()) { continue; } } let kurse : Array = fachart.gibKurse(); let perm2 : Array = KursblockungStatic.gibPermutation(kurse.length); for (let p2 : number = 0; p2 < perm2.length; p2++){ let i2 : number = p2; let kurs : KursblockungDynKurs = kurse[i2]; let waehlbar : boolean = true; for (let nr of kurs.gibSchienenLage()) { if (this.schieneBelegt[nr]) { waehlbar = false; } } if (waehlbar) { this.aktionKursHinzufuegen(i, kurs); break; } } } } /** * Verteilt alle Kurse die über genau 1 Schiene gehen mit Hilfe eines Matching * Algorithmus. */ aktionKurseMitBipartiteMatchingVerteilen() : void { let data : Array> = this.matrix.getMatrix(); for (let r : number = 0; r < this.fachartArr.length; r++){ for (let c : number = 0; c < this.schieneBelegt.length; c++){ data[r][c] = 0; } if (this.fachartZuKurs[r] !== null) { continue; } if (this.fachartArr[r].gibHatMultikurs()) { continue; } for (let kurs of this.fachartArr[r].gibKurse()) { for (let nr of kurs.gibSchienenLage()) { if (!this.schieneBelegt[nr]) { data[r][nr] = 1; } } } } let r2c : Array = this.matrix.gibMaximalesBipartitesMatching(true); for (let r : number = 0; r < this.fachartArr.length; r++){ if (this.fachartZuKurs[r] !== null) { continue; } let c : number = r2c[r]; if (c === -1) { continue; } let kursGefunden : KursblockungDynKurs | null = null; for (let kurs of this.fachartArr[r].gibKurse()) { for (let nr of kurs.gibSchienenLage()) { if ((nr === c) && (kursGefunden === null)) { kursGefunden = kurs; } } } if (kursGefunden !== null) this.aktionKursHinzufuegen(r, kursGefunden); } } /** * Erzeugt pro Fachwahl ein Objekt des Typs * {@link KursblockungOutputFachwahlZuKurs} und fügt es dem Vector * {@code vFachwahlZuKurs} hinzu. Die GUI kann daraus die * Schüler-Zu-Kurs-Zuordnungen rekonstruiern. * * @param vFachwahlZuKurs Fügt diesem Vector pro Fachwahl ein Objekt des Typs * {@link KursblockungOutputFachwahlZuKurs} hinzu. */ aktionOutputsErzeugen(vFachwahlZuKurs : Vector) : void { for (let i : number = 0; i < this.fachartArr.length; i++){ let fachwahlZuKurs : KursblockungOutputFachwahlZuKurs = new KursblockungOutputFachwahlZuKurs(); fachwahlZuKurs.fachwahl = this.fachartZuGUI[i]; let tmpKurs : KursblockungDynKurs | null = this.fachartZuKurs[i]; fachwahlZuKurs.kurs = (tmpKurs === null) ? -1 : tmpKurs.gibID(); vFachwahlZuKurs.add(fachwahlZuKurs); } } /** * Liefert TRUE, falls der Schüler mindestens einen Multikurs hat. Ein Multikurs * ist ein Kurs, der über mehr als eine Schiene geht. * * @return TRUE, falls der Schüler mindestens einen Multikurs hat. */ gibHatMultikurs() : boolean { for (let fachart of this.fachartArr) { if (fachart.gibHatMultikurs()) { return true; } } return false; } private aktionKursHinzufuegen(fachartIndex : number, kurs : KursblockungDynKurs) : void { kurs.aktionSchuelerHinzufügen(); this.statistik.aktionNichtwahlenVeraendern(-1); this.nichtwahlen--; for (let nr of kurs.gibSchienenLage()) { if (this.schieneBelegt[nr]) { console.log(JSON.stringify("FEHLER: Schienen-Doppelbelegung! " + this.representation.valueOf())); } this.schieneBelegt[nr] = true; } this.fachartZuKurs[fachartIndex] = kurs; } private aktionKursEntfernen(fachartIndex : number, kurs : KursblockungDynKurs) : void { kurs.aktionSchuelerEntfernen(); this.statistik.aktionNichtwahlenVeraendern(+1); this.nichtwahlen++; for (let nr of kurs.gibSchienenLage()) { if (!this.schieneBelegt[nr]) { console.log(JSON.stringify("FEHLER: Kurs ist gar nicht in Schiene ! " + this.representation.valueOf())); } this.schieneBelegt[nr] = false; } this.fachartZuKurs[fachartIndex] = null; } isTranspiledInstanceOf(name : string): boolean { return ['de.nrw.schule.svws.core.kursblockung.KursblockungDynSchueler'].includes(name); } } export function cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynSchueler(obj : unknown) : KursblockungDynSchueler { return obj as KursblockungDynSchueler; }