Loesungs-Dedup: getGruppenId/getPersonenId, keine doppelten Sitzordnungen

- getGruppenId (Gruppen-Ebene, personen-unabhaengig: welche Gruppen mit
  welcher Anzahl je Tisch) und getPersonenId (Personen-Ebene: alphabetische
  Namen je Tisch) an Sitzplatzverteilung; Basis-Methoden an Loesung. Gleiche
  Gruppen-Verteilung -> gleiche getGruppenId und damit gleiche Wertigkeit,
  egal welche Personen die geteilten Plaetze einnehmen.
- Farm verwirft nach jeder Erzeugung/Mutation Loesungen mit schon gesehener
  getGruppenId, so dass dieselbe Sitzordnung nicht mehrfach gehalten und
  bewertet wird (defensiv: Klassen ohne getGruppenId bleiben unberuehrt,
  Tests unveraendert).
- Web: Varianten-Vergleich ueber getGruppenId statt der person-basierten
  _Signatur; gruppenId und personenId zusaetzlich im Ergebnis-JSON.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Michael Stangl
2026-07-15 18:10:23 +02:00
parent b29b3b22d4
commit d4844ded67
3 changed files with 80 additions and 16 deletions
+39
View File
@@ -14,6 +14,7 @@ from random import *
import ast
import configparser, os
import copy
import hashlib
import html
import math
from collections import defaultdict
@@ -1114,6 +1115,44 @@ class Sitzplatzverteilung:
return len( self.Gid_Tid[Gruppe.Id] ) - 1
except KeyError:
return 0
def getGruppenId(self):
"""eindeutige Id der Loesung auf GRUPPEN-Ebene (personen-unabhaengig).
Signatur: je Tisch, welche Gruppen mit wie vielen Mitgliedern dort
sitzen. Zwei Loesungen mit identischer Gruppen-Verteilung bekommen
dieselbe Id - egal welche konkreten Personen die geteilten Plaetze
einnehmen (die Teilung einer 5er-Gruppe auf die Tische 3 und 4 ist
dieselbe Sitzordnung, gleich welche Personen wohin kommen). Da die
Bewertung (Strafliste) nur von den Gruppen-Anzahlen je Tisch, den
Nachbarschaften und der Auslastung abhaengt, haben Loesungen mit
gleicher getGruppenId auch dieselbe Wertigkeit. Diese Id dient dem
Vergleich der Loesungen (Dedup), damit dieselbe Sitzordnung nicht
mehrfach als eigene Loesung gehalten und bewertet wird."""
Teile = []
for T in sorted( self.Tische, key=lambda t: t.Id ):
Zaehler = {}
for P in T:
try:
Gid = self.Gruppen.GruppeVonPid( P.Id ).Id
except KeyError:
Gid = -1 # VIP / feste Platzierung (ohne GA-Gruppe)
Zaehler[Gid] = Zaehler.get( Gid, 0 ) + 1
Teile.append( (T.Id, tuple(sorted( Zaehler.items() ))) )
return hashlib.sha1( repr(Teile).encode('utf-8') ).hexdigest()[:16]
def getPersonenId(self):
"""eindeutige Id der Loesung auf PERSONEN-Ebene.
Signatur: je Tisch die alphabetisch sortierten Personennamen.
Identifiziert WIRKLICH identische Sitzbelegungen (dieselben Personen
an denselben Tischen) - feiner als getGruppenId, das nur die Gruppen-
Verteilung vergleicht."""
Teile = []
for T in sorted( self.Tische, key=lambda t: t.Id ):
Namen = sorted(
' '.join( s for s in (P._Titel, P._Vorname, P._Name) if s )
for P in T )
Teile.append( (T.Id, tuple(Namen)) )
return hashlib.sha1( repr(Teile).encode('utf-8') ).hexdigest()[:16]
def VIPsSetzen(self, VIPListe, VIPs, Tische ):
"""setze die VIPs auf Ihre Plaetze"""
#print " VIPsSetzen:"