#!/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) -> None: self.kuerzel: str = kuerzel self.name: str = name self.personen_anzahl: int = personen_anzahl def __str__(self) -> str: return f"{self.kuerzel} ({self.name}): {self.personen_anzahl} Person(en)" def __repr__(self) -> str: return f"Dienst('{self.kuerzel}', '{self.name}', {self.personen_anzahl})" 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), Dienst('P', 'Putznotdienst', 1), Dienst('E', 'Essensausgabenotdienst', 1), Dienst('K', 'Kochen', 1), Dienst('A', 'Elternabend', 2) ] # Datenstrukturen self.planungszeitraum: List[date] = [] self.eltern: List[Eltern] = [] self.benoetigte_dienste: Dict[date, List[Dienst]] = {} self.verfügbarkeit: Dict[Tuple[Eltern, date], bool] = {} self.präferenzen: 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 self.eltern, self.planungszeitraum, self.benoetigte_dienste, self.verfügbarkeit, self.präferenzen = \ EingabeParser.parse_eingabe_csv(eingabe_datei, self.get_dienst) # Eltern CSV: Dienstfaktoren self.dienstfaktoren = EingabeParser.parse_eltern_csv(eltern_datei) # 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)