Bessere Verteilung: Strafen/Mutation, plus Abstammungsbaum mit Id-Herkunft
Weniger vermeidbare Gruppentrennungen:
- strafen.cfg: Tischbesetzung bestraft jetzt gestaffelt nach freien
Plaetzen (teilbelegte Tische am teuersten, mit Fallback auf den
naechstkleineren Eintrag), Trennungsstrafen deutlich erhoeht - so
werden Gruppen nicht mehr getrennt, obwohl leere Tische danebenstehen
- gibPunkte('Tischbesetzung') mit Naechst-kleiner-Fallback
- mutieren() setzt geraeumte Gruppen groesste-zuerst neu
(GruppenSetzen(GrosseZuerst=True)), damit grosse Gruppen die frei
gewordenen ganzen Tische bekommen und wieder zusammenkommen
(uebrig bleiben nur physisch unvermeidbare Trennungen, Gruppe > Tisch)
Abstammungsbaum (neuer Schalter --show-lineage -> Abstammung.svg):
- neue Klasse ga.Abstammung zeichnet den vollen Mutationsbaum aller
Loesungen; der Ast der finalen besten Loesung ist hervorgehoben und
mit ihrer Id beschriftet
- hierarchische Loesungs-Ids (Farm._WurzelId/_KindId): Wurzel '7',
Mutationskind '7.2', dessen Kind '7.2.1' - die ganze Abstammung ist
direkt aus der Id ablesbar
Tests (15 gruen), README und CLAUDE.md aktualisiert; Beispiele mit den
neuen Strafen und beiden Grafiken neu berechnet.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+39
-12
@@ -398,10 +398,20 @@ class Strafliste:
|
||||
# je groesser der Abstand, desto mehr Strafe.
|
||||
return self.AbstandFaktor * Abstand
|
||||
elif Typ == 'Tischbesetzung':
|
||||
try:
|
||||
# Strafe fuer freie Plaetze an einem (teil-)belegten Tisch. Gibt
|
||||
# es keinen exakten Eintrag fuer 'freiePlaetze', wird auf den
|
||||
# naechstkleineren konfigurierten Wert zurueckgegriffen, damit man
|
||||
# nicht jede moegliche Platzzahl auflisten muss (z.B. deckt ein
|
||||
# Eintrag fuer 4 auch 5..7 ab, bis der naechste Eintrag greift).
|
||||
# Auch ein komplett leerer Tisch (freiePlaetze == Plaetze) wird
|
||||
# bewertet - er trifft in der Regel den hoechsten konfigurierten
|
||||
# Eintrag (z.B. 8 frei bei 8er-Tisch) oder dessen Fallback.
|
||||
if freiePlaetze in self.TischWert:
|
||||
return self.TischWert[freiePlaetze]
|
||||
except KeyError:
|
||||
return 0
|
||||
kleinere = [ k for k in self.TischWert if k < freiePlaetze ]
|
||||
if kleinere:
|
||||
return self.TischWert[ max(kleinere) ]
|
||||
return 0
|
||||
elif Typ == 'Trennung':
|
||||
if (N_Teilungen == 0):
|
||||
return 0
|
||||
@@ -746,7 +756,10 @@ class Sitzplatzverteilung:
|
||||
G = self.Gruppen.vonId(Gid)
|
||||
self.GruppeEntfernen(G)
|
||||
SchlechteGruppen.append(G)
|
||||
self.GruppenSetzen( SchlechteGruppen )
|
||||
# beim Reseat die groessten zuerst, damit sie die durch das Entfernen
|
||||
# frei gewordenen (ganzen) Tische bekommen und wieder zusammenkommen,
|
||||
# statt erneut getrennt zu werden
|
||||
self.GruppenSetzen( SchlechteGruppen, GrosseZuerst=True )
|
||||
self.bewerten()
|
||||
|
||||
print("mutiert: ", self.value)
|
||||
@@ -828,20 +841,34 @@ class Sitzplatzverteilung:
|
||||
self.PersonSetzen( neuePerson, Tisch )
|
||||
|
||||
# Gruppenspezifische Funktionen
|
||||
def GruppenSetzen(self, Gruppen ):
|
||||
"""setzt mal die grossen mal die kleinen Gruppen auf beliebige Plaetze"""
|
||||
# Mache Liste der Gruppen, der Groesse nach sortiert
|
||||
def GruppenSetzen(self, Gruppen, GrosseZuerst=False ):
|
||||
"""setzt Gruppen auf freie Plaetze.
|
||||
|
||||
GrosseZuerst=False (Erstbelegung): mal die grossen, mal die kleinen
|
||||
zuerst (Zufall) - erzeugt Vielfalt in der Startpopulation.
|
||||
GrosseZuerst=True (Mutation): konsequent die groesste Gruppe zuerst,
|
||||
damit sie einen noch komplett freien Tisch bekommt und nicht getrennt
|
||||
werden muss, weil kleine Gruppen die freien Tische schon anbrechen.
|
||||
"""
|
||||
# Mache Liste der Gruppen, der Groesse nach sortiert
|
||||
Gruppenliste = []
|
||||
for G in Gruppen:
|
||||
Gruppenliste.append(G)
|
||||
|
||||
# uns setzte sie auf freie Plaetze
|
||||
while len(Gruppenliste) > 0:
|
||||
wahl = choice(['grosse', 'kleine'])
|
||||
if wahl == 'grosse':
|
||||
G = Gruppenliste.pop(0)
|
||||
else:
|
||||
G = Gruppenliste.pop(-1)
|
||||
if GrosseZuerst:
|
||||
# groesste zuerst: sie beanspruchen die noch komplett freien
|
||||
# Tische, bevor kleine Gruppen diese teilbelegen (sonst muessen
|
||||
# grosse Gruppen mangels ganzem Tisch getrennt werden)
|
||||
G = max( Gruppenliste, key=lambda g: g.Anzahl() )
|
||||
Gruppenliste.remove(G)
|
||||
else:
|
||||
wahl = choice(['grosse', 'kleine'])
|
||||
if wahl == 'grosse':
|
||||
G = Gruppenliste.pop(0)
|
||||
else:
|
||||
G = Gruppenliste.pop(-1)
|
||||
self.GruppeSetzen(G)
|
||||
def GruppeSetzen(self, Gruppe, Tisch=None ):
|
||||
"""setzt eine Gruppe irgendwohin wo Platz ist
|
||||
|
||||
Reference in New Issue
Block a user