import { JavaObject, cast_java_lang_Object } from '../../java/lang/JavaObject'; import { KursblockungStatic, cast_de_nrw_schule_svws_core_kursblockung_KursblockungStatic } from '../../core/kursblockung/KursblockungStatic'; import { KursblockungDynDaten, cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynDaten } from '../../core/kursblockung/KursblockungDynDaten'; import { KursblockungAlgorithmusK, cast_de_nrw_schule_svws_core_kursblockung_KursblockungAlgorithmusK } from '../../core/kursblockung/KursblockungAlgorithmusK'; import { KursblockungDynSchueler, cast_de_nrw_schule_svws_core_kursblockung_KursblockungDynSchueler } from '../../core/kursblockung/KursblockungDynSchueler'; import { Logger, cast_de_nrw_schule_svws_logger_Logger } from '../../logger/Logger'; import { System, cast_java_lang_System } from '../../java/lang/System'; export class KursblockungAlgorithmusKMatching extends KursblockungAlgorithmusK { private static readonly MAX_RUNDEN_IN_FOLGE_OHNE_VERBESSERUNG : number = 2000; private readonly schuelerAlle : Array; /** * Im Konstruktor kann die Klasse die jeweiligen Datenstrukturen aufbauen. Kurse * dürfen in diese Methode noch nicht auf Schienen verteilt werden. * * @param pLogger Logger für Benutzerhinweise, Warnungen und Fehler. * @param pDynDat Die dynamischen Blockungsdaten. */ public constructor(pLogger : Logger, pDynDat : KursblockungDynDaten) { super(pLogger, pDynDat); this.schuelerAlle = this.dynDaten.gibSchuelerArray(false); } /** * Der Algorithmus entfernt zunächst alle SuS aus ihren Kursen. Anschließend * werden die Kurse zufällig verteilt. Anschließend verändert der Algorithmus * die Lage eines zufälligen Kurses. Falls sich die Bewertung verschlechter, * wird die Veränderung rückgängig gemacht. */ public berechne(pMaxTimeMillis : number) : void { if (this.dynDaten.gibKurseDieFreiSindAnzahl() === 0) { return; } let timeStart : number = System.currentTimeMillis(); this.dynDaten.aktionSchuelerAusAllenKursenEntfernen(); this.dynDaten.aktionKurseFreieZufaelligVerteilen(); this.dynDaten.aktionZustandSpeichernK(); let countKeineVerbesserung : number = 0; while (System.currentTimeMillis() - timeStart < pMaxTimeMillis) { if (this.berechneSchritt()) { countKeineVerbesserung = 0; } else { countKeineVerbesserung++; if (countKeineVerbesserung === KursblockungAlgorithmusKMatching.MAX_RUNDEN_IN_FOLGE_OHNE_VERBESSERUNG) { break; } } } } /** * Die Lage einiger Kurse wird verändert. Falls sich die Bewertung * verschlechter, wird die Veränderung rückgängig gemacht. */ private berechneSchritt() : boolean { let maxChanges : number = 1; while (Math.random() < 0.5) { maxChanges++; } for (let changes : number = 0; changes < maxChanges; changes++){ this.dynDaten.aktionSchuelerAusAllenKursenEntfernen(); this.dynDaten.aktionKursFreienEinenZufaelligVerteilen(); this.verteileSuS(); if (this.dynDaten.gibBewertungJetztBesserAlsK() > 0) { this.dynDaten.aktionZustandSpeichernK(); return true; } } this.dynDaten.aktionZustandLadenK(); return false; } /** * Verteilt die SuS. Multikurse werden zufällig verteilt. Alle anderen Kurse mit * Hilfe eines Matching-Algorithmus. */ private verteileSuS() : void { let perm : Array = KursblockungStatic.gibPermutation(this.schuelerAlle.length); for (let p : number = 0; p < perm.length; p++){ let i : number = perm[p]; let schueler : KursblockungDynSchueler | null = this.schuelerAlle[i]; schueler.aktionKurseZufaelligVerteilen(true); schueler.aktionKurseMitBipartiteMatchingVerteilen(); } } isTranspiledInstanceOf(name : string): boolean { return ['de.nrw.schule.svws.core.kursblockung.KursblockungAlgorithmusK', 'de.nrw.schule.svws.core.kursblockung.KursblockungAlgorithmusKMatching'].includes(name); } } export function cast_de_nrw_schule_svws_core_kursblockung_KursblockungAlgorithmusKMatching(obj : unknown) : KursblockungAlgorithmusKMatching { return obj as KursblockungAlgorithmusKMatching; }