#!/usr/bin/env python3 """ Datenmodell für Elterndienstplaner Enthält alle Daten und deren Laden sowie gemeinsame Type Aliases """ from datetime import date from collections import defaultdict from typing import Dict, List, Tuple, DefaultDict, Optional, TypeAlias import pulp from csv_io import EingabeParser class Dienst: """Repräsentiert einen Diensttyp mit allen seinen Eigenschaften""" def __init__(self, kuerzel: str, name: str, personen_anzahl: int = 1, aufwand: int = 1) -> None: self.kuerzel: str = kuerzel self.name: str = name self.personen_anzahl: int = personen_anzahl self.aufwand: int = aufwand def __str__(self) -> str: return f"{self.kuerzel} ({self.name}): {self.personen_anzahl} Person(en), Aufwand={self.aufwand}" def __repr__(self) -> str: return f"Dienst('{self.kuerzel}', '{self.name}', {self.personen_anzahl}, {self.aufwand})" def braucht_mehrere_personen(self) -> bool: """Gibt True zurück, wenn mehr als eine Person benötigt wird""" return self.personen_anzahl > 1 # Eltern: Ihnen koennen Dienste zugewiesen werden Eltern: TypeAlias = str # Verteilung von Diensten auf Eltern. # - Zielsumme der Dienste ueber den Planungszeitraum # - Kann nicht-ganzzahlig und negativ sein Zielverteilung: TypeAlias = DefaultDict[Eltern, DefaultDict[Dienst, float]] # Entscheidungsvariablen des Optimierungsproblems # Variable: Eltern wird am Datum Dienst zugewiesen Entscheidungsvariablen: TypeAlias = Dict[Tuple[Eltern, date, Dienst], pulp.LpVariable] class ElterndienstplanerDaten: """Datenmodell für den Elterndienstplaner""" def __init__(self) -> None: # Dienste als Liste definieren self.dienste: List[Dienst] = [ Dienst('F', 'Frühstücksdienst', 1, aufwand=3), Dienst('P', 'Putznotdienst', 1, aufwand=1), Dienst('E', 'Essensausgabenotdienst', 1, aufwand=1), Dienst('K', 'Kochen', 1, aufwand=3), Dienst('A', 'Elternabend', 2, aufwand=2) ] # Datenstrukturen self.planungszeitraum: List[date] = [] self.eltern: List[Eltern] = [] self.benoetigte_dienste: Dict[date, List[Dienst]] = {} self.verfuegbarkeit: Dict[Tuple[Eltern, date], bool] = {} self.praeferenzen: Dict[Tuple[Eltern, date, Dienst], int] = {} # dienstfaktoren[eltern][tag] = faktor. # Wenn es eltern nicht gibt -> keyerror # Wenn es tag nicht gibt -> default 0.0 self.dienstfaktoren: Dict[Eltern, DefaultDict[date, float]] = {} self.historische_dienste: List[Tuple[date, Eltern, Dienst]] = [] def get_dienst(self, kuerzel: str) -> Optional[Dienst]: """Gibt das Dienst-Objekt für ein Kürzel zurück""" for dienst in self.dienste: if dienst.kuerzel == kuerzel: return dienst return None def add_dienst(self, kuerzel: str, name: str, personen_anzahl: int = 1) -> Dienst: """Fügt einen neuen Dienst hinzu""" dienst = Dienst(kuerzel, name, personen_anzahl) self.dienste.append(dienst) return dienst def print_dienste_info(self) -> None: """Druckt Informationen über alle konfigurierten Dienste""" print("Konfigurierte Dienste:") for dienst in self.dienste: print(f" {dienst}") def lade_daten( self, eingabe_datei: str, eltern_datei: str, vorherige_datei: Optional[str] = None ) -> None: """Lädt alle benötigten CSV-Dateien Args: eingabe_datei: Pfad zur eingabe.csv mit Terminen und Präferenzen eltern_datei: Pfad zur eltern.csv mit Dienstfaktoren vorherige_datei: Optionaler Pfad zur vorherige-ausgaben.csv für Fairness-Constraints """ # Eingabe CSV: Termine, Präferenzen, Verfügbarkeit # Eltern CSV: Dienstfaktoren (erst einlesen, damit self.eltern daraus abgeleitet wird) self.dienstfaktoren = EingabeParser.parse_eltern_csv(eltern_datei) # Fülle self.eltern aus den Einträgen in eltern.csv (Vertrauensquelle für Elternnamen) self.eltern = list(self.dienstfaktoren.keys()) # Eingabe CSV: Termine, Präferenzen, Verfügbarkeit # Wir verwenden die Elterndefinition aus eltern.csv; die von parse_eingabe_csv # zurückgegebene Eltern-Liste wird ignoriert, damit die Quell-of-truth konsistent bleibt. _, self.planungszeitraum, self.benoetigte_dienste, self.verfuegbarkeit, self.praeferenzen = \ EingabeParser.parse_eingabe_csv(eingabe_datei, self.get_dienst) # Vorherige Ausgaben CSV (optional): Historische Dienste für Fairness if vorherige_datei: self.historische_dienste = \ EingabeParser.parse_vorherige_ausgaben_csv(vorherige_datei, self.eltern, self.dienste)