diff --git a/CLAUDE.md b/CLAUDE.md
index 6145998..d92395a 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -10,11 +10,27 @@ sizes/neighbor relationships, and a penalty scheme. It reads an XML order/guest
table layout, runs a small custom GA framework to search for a good seating, and writes the
result to text/CSV output files.
-**This is Python 2 code** (print statements, `ConfigParser`, `sets.Set`, `UserList`,
-`string.split`, old-style `raise Exception, "msg"`, `xrange`, `dict.has_key`,
-`dict.iteritems`). It will not run under Python 3 without a 2to3-style port. There is no
-build system, test suite, or linter configured in this repo. `requirements.txt` exists but
-is empty/commented — everything used is standard library — it's there only so
+**This is Python 3 code**, migrated from an original Python 2 implementation (the git
+history / old comments may still say "Python 2" — that's now stale). Notable migration
+artifacts to be aware of when touching this code:
+- `Gruppe`, `Loesung`, and `Sitzplatzverteilung` use `@functools.total_ordering` with
+ `__eq__`/`__lt__` instead of the old Python 2 `__cmp__` (Python 3 dropped `__cmp__` and
+ `cmp()` entirely; `max()`/`.sort()` need rich comparisons).
+- `sets.Set` → builtin `set`; `ConfigParser` → `configparser`; `string.split` →
+ `str.split`; `xrange` → `range`; `dict.has_key(k)` → `k in dict`; `dict.iteritems()` →
+ `dict.items()`; old-style `raise Exception, "msg"` → `raise Exception("msg")`.
+- `Strukturdaten.LeuteAllein()` was fixed to skip people with no entry in
+ `self.Gruppen.GvonPid` (e.g. VIP-group members who were never added to the regular
+ `Gruppen` container) instead of letting `GruppeVonPid` raise `KeyError` — this was a
+ latent bug that only surfaced once VIP data (`work/test2`) was actually exercised
+ end-to-end.
+- `HandleBestellung()` had a `G.Anzahl` comparison (`G.Anzahl > 0`) that used to silently
+ compare a bound method to an int under Python 2's permissive cross-type ordering;
+ Python 3 raises `TypeError` for that, which is what surfaced it. Fixed to call
+ `G.Anzahl()`.
+
+There is no build system, test suite, or linter configured in this repo. `requirements.txt`
+exists but is empty/commented — everything used is standard library — it's there only so
`bin/install_py.*` has something to install into the `.venv`.
## Running the program
@@ -39,8 +55,8 @@ Entry point is `libs/platz.py`, invoked via the scripts in `bin/` (each provided
"$PLATZ_LIBS/platz.py"`. This is the actual program entry point (replaces the old
`bin/run` / `bin/run.bat`, which hardcoded absolute paths and have been removed).
-`libs/platz.py` requires a command-line switch `--indir
` (parsed with `optparse`,
-since this is Python 2) pointing at a directory that holds the per-run input files and
+`libs/platz.py` requires a command-line switch `--indir ` (parsed with `optparse`)
+pointing at a directory that holds the per-run input files and
receives the output files — e.g. `work/test1/`, `work/test2/`, or any new folder following
the same layout:
- `tische.ini` — table definitions: id, `Nummer`, `Hof` (venue/court), `Plaetze` (seats),
@@ -79,7 +95,7 @@ Domain-agnostic and reusable in principle:
- `Farm` — owns the population (`Pool`/`PoolNeu`), and executes a `Zyklus` action-by-action
against instances of a given solution class (passed as `Klasse` plus its constructor
args/kwargs). `Bester()` returns the fittest (`max()`) solution found; solutions are ordered
- via `__cmp__` on `self.value`.
+ via `__eq__`/`__lt__` (`@total_ordering`) on `self.value`.
### `Strukturdaten.py` — domain model for this specific seating problem
- `Person`, `Gruppe` (group — a `Set` of people, splittable via `teilen()`), `Tisch` (table —
diff --git a/README.md b/README.md
index 440beb9..943a0c2 100644
--- a/README.md
+++ b/README.md
@@ -5,10 +5,9 @@ given group memberships, table sizes/neighbor relationships, and a configurable
scheme. It reads a guest list (XML) and a table layout (INI), searches for a good seating
using a small custom GA framework, and writes the result to text/CSV output files.
-**This is Python 2 code** (print statements, `ConfigParser`, `sets.Set`, `UserList`,
-`string.split`, old-style `raise Exception, "msg"`, `xrange`, `dict.has_key`,
-`dict.iteritems`). There are no third-party dependencies (standard library only), so
-`requirements.txt` is empty — it exists only so `bin/install_py` has something to install.
+**This is Python 3 code** (migrated from an original Python 2 implementation). There are no
+third-party dependencies (standard library only), so `requirements.txt` is empty — it
+exists only so `bin/install_py` has something to install.
## Project structure
diff --git a/libs/Strukturdaten.py b/libs/Strukturdaten.py
index 73b4cbf..0582a77 100755
--- a/libs/Strukturdaten.py
+++ b/libs/Strukturdaten.py
@@ -9,12 +9,11 @@ __date__ = "$Date: $"
__copyright__ = "Copyright (c) 2005 Michael Stangl"
__license__ = "Python"
-from sets import Set
from itertools import chain
-from UserList import UserList
from random import *
-import ConfigParser, os
+import configparser, os
import copy
+from functools import total_ordering
from xml.dom import minidom
@@ -29,14 +28,14 @@ class Person:
def __repr__(self):
return ' Person %s: "%s %s %s"' % ( self.Id, self._Titel,
self._Vorname, self._Name)
- print self.__repr__
+@total_ordering
class Gruppe:
"""enthalt alle Daten zu einer Gruppe"""
Art = 'Gruppe'
def __init__(self, Id, Personen=[]):
self.Id = Id
- self._Personen = Set()
+ self._Personen = set()
self._Anzahl = 0
self.PvonId = {}
for P in Personen:
@@ -47,9 +46,6 @@ class Gruppe:
result = result + repr(P.Id) + ','
result = result + ' %s Person(en)' % (self._Anzahl)
return result
- print self
- for P in self._Personen:
- print P
def Person_dazu(self, P):
self._Personen.add(P)
self._Anzahl = self._Anzahl + 1
@@ -59,16 +55,16 @@ class Gruppe:
self._Personen.remove(P)
self._Anzahl = self._Anzahl - 1
else:
- raise KeyError, "Person ist nicht enthalten"
+ raise KeyError("Person ist nicht enthalten")
def teilen(self, NeueGroesse=0):
if self._Anzahl == 1:
- raise IndexError, "Gruppe ist nur noch einer"
+ raise IndexError("Gruppe ist nur noch einer")
if NeueGroesse == 0:
NeueGroesse = int(self._Anzahl/2)
one = Gruppe( self.Id, self._Personen )
two = Gruppe( self.Id, self._Personen )
two._Personen.clear()
- for i in xrange(NeueGroesse):
+ for i in range(NeueGroesse):
two._Personen.add(one._Personen.pop())
one._Anzahl = len(one._Personen)
two._Anzahl = len(two._Personen)
@@ -78,21 +74,21 @@ class Gruppe:
def Anzahl(self):
return self._Anzahl
def __contains__(self, P):
- return P in self._Personen
+ return P in self._Personen
def __iter__(self):
for P in self._Personen:
- yield(P)
- def __cmp__(self,other):
- if self._Anzahl < other._Anzahl: return -1
- elif self._Anzahl == other._Anzahl: return 0
- else: return 1
+ yield(P)
+ def __eq__(self,other):
+ return self._Anzahl == other._Anzahl
+ def __lt__(self,other):
+ return self._Anzahl < other._Anzahl
def __getattr__(self, attrname):
if attrname == 'Anzahl':
- return self._Anzahl
+ return self._Anzahl
elif attrname == 'Id':
- return self.Id
+ return self.Id
else:
- raise AttributeError, attrname
+ raise AttributeError(attrname)
class Tisch(Gruppe):
"""enthalt alle Daten zu einem Tisch"""
@@ -103,7 +99,7 @@ class Tisch(Gruppe):
self.Nummer = Nummer
self.X_Koordinate = Koordinaten[0]
self.Y_Koordinate = Koordinaten[1]
- self.Nachbarn = Set(Nachbarliste)
+ self.Nachbarn = set(Nachbarliste)
Gruppe.__init__( self, Id, pids )
def istvoll(self, n=0):
if ((self._Anzahl + n) == self._Plaetze ):
@@ -126,12 +122,12 @@ class Tisch(Gruppe):
return self._Anzahl
def Person_dazu(self, P):
if (self._Anzahl == self._Plaetze ):
- raise IndexError, "Tisch voll"
+ raise IndexError("Tisch voll")
else:
Gruppe.Person_dazu( self, P )
def Person_weg(self, P):
if (self._Anzahl == 0 ):
- raise IndexError, "Tisch schon leer"
+ raise IndexError("Tisch schon leer")
else:
Gruppe.Person_weg( self, P )
def teilen(self):
@@ -140,7 +136,7 @@ class Tisch(Gruppe):
result = ( Gruppe.__repr__( self ) +
' fuer [%s], %s noch frei,' %
(self._Plaetze,
- self._Plaetze - self._Anzahl)
+ self._Plaetze - self._Anzahl)
)
result = result + " Nachbarn:"
for N in chain(self.Nachbarn):
@@ -148,20 +144,20 @@ class Tisch(Gruppe):
return result
def __getattr__(self, attrname):
if attrname == 'Anzahl':
- return self._Anzahl
+ return self._Anzahl
if attrname == 'Plaetze':
return self._Plaetze
elif attrname == 'Id':
- return self.Id
+ return self.Id
else:
- raise AttributeError, attrname
+ raise AttributeError(attrname)
# Containerklassen Personen, Gruppen, Tische, Plaetze
class Personen:
"""ein Pool mit mehreren Personen"""
def __init__( self, Personen=[] ):
- self._Personen = Set(Personen)
+ self._Personen = set(Personen)
self.PvonId = {}
for P in Personen:
self.PvonId[ P.Id ] = P
@@ -192,7 +188,7 @@ class Gruppen:
self.NLeute = 0
for G in chain( GruppenListe ):
self.Gruppe_dazu( G )
- print "gruppen hinzugefuegt"
+ print("gruppen hinzugefuegt")
def __iter__( self):
sortiert = self.GruppenListe[:]
sortiert.sort()
@@ -254,8 +250,8 @@ class Tische:
for T in sortiert:
yield(T)
def laden( self, FileName ):
- ## print "-- Tische laden"
- config = ConfigParser.ConfigParser()
+ ## print("-- Tische laden")
+ config = configparser.ConfigParser()
config.read( os.path.expanduser(FileName) )
for section in config.sections():
Tid = int(section)
@@ -288,14 +284,14 @@ class Plaetze:
self.__TIDsNFreie = []
self.__Groesster = Tische.Groesster
self.__Tische = Tische
- for i in range( self.__Groesster + 1 ):
- self.__TIDsNFreie.append( Set() )
+ for i in range( self.__Groesster + 1 ):
+ self.__TIDsNFreie.append( set() )
for T in Tische.TischListe:
n_freie = T.freiePlaetze()
self.__TIDsNFreie[n_freie].add(T.Id)
def __repr__(self):
result = "\n-- Tische mit n Freien Plaetzen:\n"
- for i in xrange(self.__Groesster+1):
+ for i in range(self.__Groesster+1):
result = result + " " +repr(i) + " :" + repr(self.__TIDsNFreie[i]) + "\n"
return result
def IdsnFreie(self, n_freie):
@@ -381,33 +377,33 @@ class Strafliste:
self.NichtNachbar,
self.Allein) )
def gibPunkte(self, Typ, Gruppengroesse=0, N_Teilungen=0, freiePlaetze=0):
- if cmp(Typ,'allein') == 0:
+ if Typ == 'allein':
return self.Allein
- elif cmp(Typ,'nichtNachbar')== 0:
+ elif Typ == 'nichtNachbar':
return self.NichtNachbar
- elif cmp(Typ,'Tischbesetzung')== 0:
+ elif Typ == 'Tischbesetzung':
try:
return self.TischWert[freiePlaetze]
except KeyError:
return 0
- elif cmp(Typ,'Trennung')== 0:
+ elif Typ == 'Trennung':
if (N_Teilungen == 0):
return 0
elif (N_Teilungen == 1) & (Gruppengroesse < 2):
- raise IndexError, "Gruppe sind mindestens zwei Leute"
+ raise IndexError("Gruppe sind mindestens zwei Leute")
elif (N_Teilungen == 2) & (Gruppengroesse < 3):
- raise IndexError, "mindestens drei Leute noetig"
+ raise IndexError("mindestens drei Leute noetig")
elif (N_Teilungen > 2):
return -50
- if self.GruppenTrennen[N_Teilungen].has_key(Gruppengroesse):
+ if Gruppengroesse in self.GruppenTrennen[N_Teilungen]:
return self.GruppenTrennen[N_Teilungen][Gruppengroesse]
else:
return self.gibPunkte('Trennung',Gruppengroesse-1, N_Teilungen)
else:
- raise IndexError, "Bezeichner gibts nicht"
+ raise IndexError("Bezeichner gibts nicht")
def laden( self, FileName ):
- print "-- Strafliste laden"
- config = ConfigParser.ConfigParser()
+ print("-- Strafliste laden")
+ config = configparser.ConfigParser()
config.read( os.path.expanduser(FileName) )
self.NichtNachbar = eval(config.get( 'Globals', 'NichtNachbar' ))
self.Allein = eval(config.get( 'Globals', 'Allein' ))
@@ -417,6 +413,7 @@ class Strafliste:
# Sitzplatzverteilung, bestehend aus den Einzelelementen
+@total_ordering
class Sitzplatzverteilung:
"""Loesungsvorschlag fuer eine Sitzplatzordung"""
@@ -432,11 +429,11 @@ class Sitzplatzverteilung:
- zuerst alle kleinsten Gruppen, da man die nicht mehr teilen
sollte
"""
- #print "+ Sitzplatzverteilung\n"
+ #print("+ Sitzplatzverteilung\n")
if Gruppen.NLeute > Tische.NStuehle:
- print "Anzahl der Leute:", Gruppen.NLeute
- print "Anzahl der Plaetze:", Tische.NStuehle
- raise IndexError, "zu wenig Stuehle"
+ print("Anzahl der Leute:", Gruppen.NLeute)
+ print("Anzahl der Plaetze:", Tische.NStuehle)
+ raise IndexError("zu wenig Stuehle")
self.MutationsGroesse = 2
self.VIP = VIPs
@@ -463,8 +460,8 @@ class Sitzplatzverteilung:
self.GruppenSetzen( Gruppen )
# die Sitzplatzverteilung bepunkten
- self.bewerten()
- print "erzeugt: ", self.value
+ self.bewerten()
+ print("erzeugt: ", self.value)
def __repr__(self):
"""Ausgabe der Sitzplatzverteilung an der Konsole"""
r = "-- Sitzplatzverteilung:\n"
@@ -544,20 +541,20 @@ class Sitzplatzverteilung:
self.GruppeEntfernen(G)
SchlechteGruppen.append(G)
self.GruppenSetzen( SchlechteGruppen )
- self.bewerten()
-
- print "mutiert: ", self.value
+ self.bewerten()
+
+ print("mutiert: ", self.value)
return self
- def __cmp__(self,other):
- if self.value < other.value: return -1
- elif self.value == other.value: return 0
- else: return 1
+ def __eq__(self,other):
+ return self.value == other.value
+ def __lt__(self,other):
+ return self.value < other.value
def bewerten(self):
"""Errechnet die momentane Wertigkeit der Sitzplaetze"""
self.GesamtWertSet( 0 )
# Tische bewerten
for T in self.Tische:
- #print T
+ #print(T)
n_freie = T.freiePlaetze()
Strafpunkte = self.Strafen.gibPunkte( 'Tischbesetzung', freiePlaetze=n_freie )
self.TischWertSet( T, Strafpunkte )
@@ -610,7 +607,7 @@ class Sitzplatzverteilung:
# uns setzte sie auf freie Plaetze
while len(Gruppenliste) > 0:
wahl = choice(['grosse', 'kleine'])
- if cmp(wahl,'grosse')== 0:
+ if wahl == 'grosse':
G = Gruppenliste.pop(0)
else:
G = Gruppenliste.pop(-1)
@@ -671,8 +668,8 @@ class Sitzplatzverteilung:
Ids = self.Gid_Tid[Gruppe.Id]
Ids.add(Tisch.Id)
except KeyError:
- s = Set()
- s.add(Tisch.Id)
+ s = set()
+ s.add(Tisch.Id)
self.Gid_Tid[Gruppe.Id] = s
def GruppeEntfernen(self, Gruppe):
"""entfernt eine Gruppe von Ihren Tischen"""
@@ -751,16 +748,20 @@ class Sitzplatzverteilung:
Anzahl_von_Gid = {}
Gids = []
for P in Tisch:
- G = self.Gruppen.GruppeVonPid(P.Id)
try:
- Anzahl_von_Gid[G.Id] = Anzahl_von_Gid[G.Id] + 1
+ G = self.Gruppen.GruppeVonPid(P.Id)
except KeyError:
- Anzahl_von_Gid[G.Id] = 1
- for Gid, Anzahl in Anzahl_von_Gid.iteritems():
+ # Person gehoert zu keiner Gruppe in self.Gruppen (z.B. VIP)
+ continue
+ try:
+ Anzahl_von_Gid[G.Id] = Anzahl_von_Gid[G.Id] + 1
+ except KeyError:
+ Anzahl_von_Gid[G.Id] = 1
+ for Gid, Anzahl in Anzahl_von_Gid.items():
if Anzahl == 1:
Gids.append(Gid)
return Gids
-
+
# Funktionen fuer mehrere Einheiten (Information)
def SchlechteTischeTopX(self, Anzahl=-1):
@@ -779,7 +780,7 @@ class Sitzplatzverteilung:
def VIPsSetzen(self, VIPListe, VIPs, Tische ):
"""setze die VIPs auf Ihre Plaetze"""
#print " VIPsSetzen:"
- for PersonId, TischId in VIPListe.iteritems():
+ for PersonId, TischId in VIPListe.items():
#print " VIPsSetzen: PersonId", PersonId
#print " VIPsSetzen: TischId", TischId
Person = VIPs.PersonVonPid(PersonId)
@@ -791,7 +792,7 @@ class Sitzplatzverteilung:
RListe=[]
Wertigkeit=[]
# TODO filter verwenden
- for Id, Wert in Liste.iteritems():
+ for Id, Wert in Liste.items():
if Wert <= Min:
RListe.append(Id)
Wertigkeit.append(Wert)
@@ -830,13 +831,13 @@ class XMLConfig:
GN = Gruppen()
VIPGruppe = Gruppe( 0 )
- print '-HandleBestellung'
+ print('-HandleBestellung')
AlleGruppenXML = Bestellung.getElementsByTagName("Gruppe")
PID = 0
GID = 0
for GruppeXML in AlleGruppenXML:
GID = GID + 1
- print '-- GID ' + repr(GID)
+ print('-- GID ' + repr(GID))
G = Gruppe( GID )
IsVip = False
@@ -844,42 +845,42 @@ class XMLConfig:
for Node in GruppeXML.childNodes:
if Node.nodeName == 'Tisch':
TischNr = self.getText(Node.childNodes)
- print 'TischNr:', TischNr
+ print('TischNr:', TischNr)
IsVip = True
if Node.nodeName == 'Anzahl':
AnzahlReservierungen = int(self.getText(Node.childNodes))
- print 'Anzahl der Reservierungen:', AnzahlReservierungen
+ print('Anzahl der Reservierungen:', AnzahlReservierungen)
IsContingent = True
- for Node in GruppeXML.childNodes:
+ for Node in GruppeXML.childNodes:
if Node.nodeName == 'Person':
NRes = 0
for i in range(int(AnzahlReservierungen)):
NRes = NRes + 1
PID = PID + 1
- print "PID =" + repr(PID)
+ print("PID =" + repr(PID))
info = self.handlePersonNode( Node )
-
- Vorname = info["Vorname"]
- Nachname = info["Nachname"]
- Titel = info["Titel"]
- P = Person( PID, Vorname, Nachname, Titel)
+
+ Vorname = info["Vorname"]
+ Nachname = info["Nachname"]
+ Titel = info["Titel"]
+ P = Person( PID, Vorname, Nachname, Titel)
if IsVip == True:
PidListe.append( int(PID) )
VipHash[ int(PID) ] = int(TischNr)
- VIPGruppe.Person_dazu( P )
+ VIPGruppe.Person_dazu( P )
else:
PN.PersonAdd( P )
- G.Person_dazu( P )
- if (G.Anzahl > 0) & (IsVip != True):
- GN.Gruppe_dazu( G )
+ G.Person_dazu( P )
+ if (G.Anzahl() > 0) & (IsVip != True):
+ GN.Gruppe_dazu( G )
if IsVip == True:
GID = GID - 1
- print PN
- print GN
- print VIPGruppe
- print VipHash
- print '=========='
+ print(PN)
+ print(GN)
+ print(VIPGruppe)
+ print(VipHash)
+ print('==========')
return [ PN, GN, VIPGruppe, VipHash ]
def laden(self, Bestellung):
"""lese alle Eingangsdaten aus einem XML File ein"""
@@ -891,113 +892,113 @@ class XMLConfig:
if __name__ == '__main__':
- print "\n-- Erzeuge Personen:"
+ print("\n-- Erzeuge Personen:")
P1 = Person( 1, 'Michael', 'Stangl')
P2 = Person( 2, 'Magnus', 'Mueller')
P3 = Person( 3, 'Bernd Robert', 'Hoehn')
P4 = Person( 4, 'Heinz', 'Ruehmann')
P5 = Person( 5, 'Franz', 'Bruegge')
P6 = Person( 6, 'Hubert', 'K')
- print P1
- print P2
- print P3
- print P4
- print P5
- print P6
+ print(P1)
+ print(P2)
+ print(P3)
+ print(P4)
+ print(P5)
+ print(P6)
- print "\n-- Mehrzahl von Personen:"
+ print("\n-- Mehrzahl von Personen:")
PN = Personen([P1, P2, P3, P4, P5, P6])
- print PN
+ print(PN)
- print "\n-- Erzeuge Gruppen mit den Personen:"
+ print("\n-- Erzeuge Gruppen mit den Personen:")
G1 = Gruppe( 1, [P1, P2] )
- G1.Person_dazu( P3 )
+ G1.Person_dazu( P3 )
G2 = Gruppe( 2 )
- G2.Person_dazu( P4 )
+ G2.Person_dazu( P4 )
G3 = Gruppe( 3, [P5,P6] )
- print "\n-- Stelle Gruppen dar:"
- print G1
- print G2
- print G3
+ print("\n-- Stelle Gruppen dar:")
+ print(G1)
+ print(G2)
+ print(G3)
- print "\n-- Durchlaufe Gruppe 3:"
+ print("\n-- Durchlaufe Gruppe 3:")
for P in G3:
- print P
+ print(P)
- print "\n-- Mache Liste der Gruppen:"
+ print("\n-- Mache Liste der Gruppen:")
GN = Gruppen([G1,G2,G3])
- print GN
+ print(GN)
- print "\n-- Durchlaufe Gruppen sortiert:"
+ print("\n-- Durchlaufe Gruppen sortiert:")
for G in GN:
- print G
+ print(G)
- print "\n-- Teile Gruppe:"
+ print("\n-- Teile Gruppe:")
[GX, GY] = G1.teilen()
- print GX
- print GY
+ print(GX)
+ print(GY)
[GX, GY] = G1.teilen(3)
- print GX
- print GY
+ print(GX)
+ print(GY)
- print "\n-- Erzeuge Tische mit Personen:"
+ print("\n-- Erzeuge Tische mit Personen:")
T1 = Tisch( 1, Plaetze=5, Koordinaten=(1,2), pids=[P1, P2], Nachbarliste=[2] )
- print T1
+ print(T1)
T2 = Tisch( 2, Plaetze=4, Koordinaten=(3,2), Nachbarliste=[1,3] )
- T2.Person_dazu( P3 )
- print T2
- T2.Person_dazu( P4 )
- print T2
- T2.Person_weg( P4 )
- print T2
+ T2.Person_dazu( P3 )
+ print(T2)
+ T2.Person_dazu( P4 )
+ print(T2)
+ T2.Person_weg( P4 )
+ print(T2)
T3 = Tisch( 3, Plaetze=2, Koordinaten=(5,2), Nachbarliste=[2] )
- print "\n-- Ist Tisch 2 voll oder leer?:"
- print "ist voll = ", T2.istvoll()
- print "ist leer = ", T2.istleer()
+ print("\n-- Ist Tisch 2 voll oder leer?:")
+ print("ist voll = ", T2.istvoll())
+ print("ist leer = ", T2.istleer())
- print "\n-- Wieviele Plaetze sind an Tisch 1 noch frei ?:"
- print "Freie Plaetze = ", T1.freiePlaetze()
- print "Besetzte Plaetze = ", T1.besetztePlaetze()
+ print("\n-- Wieviele Plaetze sind an Tisch 1 noch frei ?:")
+ print("Freie Plaetze = ", T1.freiePlaetze())
+ print("Besetzte Plaetze = ", T1.besetztePlaetze())
- print "\n-- Stelle Tische dar:"
- print T1
- print T2
- print T3
- print "\n-- Ist Person Nummer 3 an Tisch 1 ?:"
- print P1 in T1
- print "-- Ist Person Nummer 4 an Tisch 1 ?:"
- print P4 in T1
+ print("\n-- Stelle Tische dar:")
+ print(T1)
+ print(T2)
+ print(T3)
+ print("\n-- Ist Person Nummer 3 an Tisch 1 ?:")
+ print(P1 in T1)
+ print("-- Ist Person Nummer 4 an Tisch 1 ?:")
+ print(P4 in T1)
TE = Tische([T1,T2,T3])
- print TE
+ print(TE)
- print "\n-- Hole Tisch 2 aufgrund seiner Id :"
+ print("\n-- Hole Tisch 2 aufgrund seiner Id :")
TX = TE.vonId( 2 )
- print TX
-
- print "\n-- Hole Gruppe 2 aufgrund ihrer Id :"
- GX = GN.vonId( 2 )
- print GX
-
- print "\n-- Hole Person 2 aufgrund ihrer Id aus den Gruppen:"
- PX = GN.PersonVonPid( 2 )
- print PX
-
- print "\n-- schau wo noch mindestens 3 Plaetze frei sind:"
- info = Plaetze(TE)
- print info.mindestensNFreie( 3 )
+ print(TX)
- print "\n-- schau wo zwei Gruppen bestimmter Groesse nebeneinander sitzen koennen:"
- print " zwei neben drei:"
+ print("\n-- Hole Gruppe 2 aufgrund ihrer Id :")
+ GX = GN.vonId( 2 )
+ print(GX)
+
+ print("\n-- Hole Person 2 aufgrund ihrer Id aus den Gruppen:")
+ PX = GN.PersonVonPid( 2 )
+ print(PX)
+
+ print("\n-- schau wo noch mindestens 3 Plaetze frei sind:")
+ info = Plaetze(TE)
+ print(info.mindestensNFreie( 3 ))
+
+ print("\n-- schau wo zwei Gruppen bestimmter Groesse nebeneinander sitzen koennen:")
+ print(" zwei neben drei:")
[TX,TY] = info.NachbarTische(2, 3)
- print TX
- print TY
- print " drei neben zwei:"
+ print(TX)
+ print(TY)
+ print(" drei neben zwei:")
[TX,TY] = info.NachbarTische(3, 2)
- print TX
- print TY
+ print(TX)
+ print(TY)
P1 = Person( 1, 'Michael', 'Stangl')
P2 = Person( 2, 'Magnus', 'Mueller')
@@ -1013,37 +1014,37 @@ if __name__ == '__main__':
P12 = Person( 12, 'Bla', 'Button')
P13 = Person( 13, 'Heinz Harald', 'Frenzen')
-#
-# T1 T2 T3 T4
-# <3> <5> <3> <4>
-#
-# G1 G2 G3 G4
-# <3> <2> <2> <6>
-#
- print "\n-- Mache Gruppen:"
+#
+# T1 T2 T3 T4
+# <3> <5> <3> <4>
+#
+# G1 G2 G3 G4
+# <3> <2> <2> <6>
+#
+ print("\n-- Mache Gruppen:")
VIPGruppe = ( Gruppe( 1, [P1, P2, P3] ) )
G2 = ( Gruppe( 2, [P4, P5] ) )
G3 = ( Gruppe( 3, [P6, P7] ) )
G4 = ( Gruppe( 4, [P8, P9, P10, P11, P12, P13] ) )
GN = Gruppen([G2,G3,G4])
- print GN
+ print(GN)
- print "\n-- Mache Tische:"
+ print("\n-- Mache Tische:")
T1 = ( Tisch( 1, Plaetze=3, Koordinaten=(1,1), Nachbarliste=[2] ) )
T2 = ( Tisch( 2, Plaetze=5, Koordinaten=(2,1), Nachbarliste=[1,3] ) )
T3 = ( Tisch( 3, Plaetze=3, Koordinaten=(3,1), Nachbarliste=[2,4] ) )
T4 = ( Tisch( 4, Plaetze=4, Koordinaten=(4,1), Nachbarliste=[3] ) )
TE = Tische([T1,T2,T3,T4])
- print TE
+ print(TE)
- print "\n-- Mache Listen:"
+ print("\n-- Mache Listen:")
# Personenid - Tischid
VIPListePT = { 3:1, 2:1, 1:1 }
- print "VIP Liste:", VIPListePT
+ print("VIP Liste:", VIPListePT)
- # Strafliste
- # die Teilung einer grossen Gruppe ist nicht so schlimm
+ # Strafliste
+ # die Teilung einer grossen Gruppe ist nicht so schlimm
# wie die einer kleinen
Teilung = list()
Teilung.append({'x':'x'})
@@ -1053,40 +1054,36 @@ if __name__ == '__main__':
# Ein Platz an einem Tisch frei ist schlechter als zwei Plaetze frei
TischWertigkeiten={ 1:-3, 2:-2, 3:-1 }
SL = Strafliste(GruppenTrennen=Teilung, NichtNachbar=-3, Allein=-30, TischWert=TischWertigkeiten)
- print SL
+ print(SL)
- print "\n-- Teste Strafliste:"
- print "SL.gibPunkte('Trennung', 7,1):", SL.gibPunkte('Trennung', 7,1)
- print "SL.gibPunkte('Trennung', 5,1):", SL.gibPunkte('Trennung', 5,1)
- print "SL.gibPunkte('Trennung', 3,1):", SL.gibPunkte('Trennung', 3,1)
+ print("\n-- Teste Strafliste:")
+ print("SL.gibPunkte('Trennung', 7,1):", SL.gibPunkte('Trennung', 7,1))
+ print("SL.gibPunkte('Trennung', 5,1):", SL.gibPunkte('Trennung', 5,1))
+ print("SL.gibPunkte('Trennung', 3,1):", SL.gibPunkte('Trennung', 3,1))
try:
- print "SL.gibPunkte('Trennung',(1,1):",SL.gibPunkte('Trennung',1,1)
+ print("SL.gibPunkte('Trennung',(1,1):",SL.gibPunkte('Trennung',1,1))
except IndexError:
- print "Gruppe sind mindestens zwei"
+ print("Gruppe sind mindestens zwei")
- print "\n-- Baue Sitzplatzverteilung:"
- SV = Sitzplatzverteilung(Tische=TE, Gruppen=GN, Strafen=SL,
+ print("\n-- Baue Sitzplatzverteilung:")
+ SV = Sitzplatzverteilung(Tische=TE, Gruppen=GN, Strafen=SL,
VIPListe=VIPListePT, VIPs=VIPGruppe)
- print SV
+ print(SV)
- print "\n-- Mutiere Sitzplatzverteilung:"
+ print("\n-- Mutiere Sitzplatzverteilung:")
SV.mutieren()
- print SV
+ print(SV)
- print "\n-- Gibt die 3 Tische mit der schlechtesten Wertung:"
+ print("\n-- Gibt die 3 Tische mit der schlechtesten Wertung:")
[TischIds, Wertigkeit]=SV.SchlechteTischeTopX(3)
- print "TischIds:", TischIds
- print "Wertigkeit:", Wertigkeit
+ print("TischIds:", TischIds)
+ print("Wertigkeit:", Wertigkeit)
- print "\n-- Gibt die Gruppen mit der schlechtesten Wertung:"
+ print("\n-- Gibt die Gruppen mit der schlechtesten Wertung:")
[GruppenIds, Wertigkeit]=SV.SchlechteGruppenTopX(3)
- print "GruppenIds:", GruppenIds
- print "Wertigkeit:", Wertigkeit
+ print("GruppenIds:", GruppenIds)
+ print("Wertigkeit:", Wertigkeit)
else:
pass
-
-
-
-
diff --git a/libs/ga.py b/libs/ga.py
index b4e0c00..630fb90 100755
--- a/libs/ga.py
+++ b/libs/ga.py
@@ -4,9 +4,9 @@ Enthaelt alle Datenstrukturen um die einen genetischen Algorithmus darzustellen
"""
from random import *
from itertools import chain
-from string import split
from copy import deepcopy
-import ConfigParser, os
+from functools import total_ordering
+import configparser, os
__author__ = "Michael Stangl"
@@ -15,29 +15,30 @@ __date__ = "$Date: $"
__copyright__ = "Copyright (c) 2005 Michael Stangl"
__license__ = "Python"
+@total_ordering
class Loesung:
"""ein einfaches Loesungsobjekt. Taugt um es als Superklasse zu ueberladen"""
def __init__(self, *Argumente, **keywords):
self.Id = -1 * randint(1,100)
self.value = self.Id
- print " initialisiere Loesung " + repr(self.Id)
+ print(" initialisiere Loesung " + repr(self.Id))
def mutieren(self):
- print " mutiere Loesung " + repr(self.Id)
+ print(" mutiere Loesung " + repr(self.Id))
self.Id = -1 * randint(1,100)
self.value = self.Id
return self
def kreuzen(self,obj):
- print " kreuze Loesung " + repr(self.Id)
+ print(" kreuze Loesung " + repr(self.Id))
def laden(self):
- print " lade Loesung " + repr(self.Id)
+ print(" lade Loesung " + repr(self.Id))
def speichern(self):
- print " speichere Loesung " + repr(self.Id)
+ print(" speichere Loesung " + repr(self.Id))
def __repr__(self):
- return ' L '+ repr(self.Id)
- def __cmp__(self,other):
- if self.value < other.value: return -1
- elif self.value == other.value: return 0
- else: return 1
+ return ' L '+ repr(self.Id)
+ def __eq__(self,other):
+ return self.value == other.value
+ def __lt__(self,other):
+ return self.value < other.value
class Zyklus:
"""Definiert wie ein Zyklus ablaufen soll:
@@ -45,21 +46,21 @@ class Zyklus:
wann sollen Objekte generiert, gekreuzt, mutiert und selektiert werden
wieviele sind davon jeweils betroffen
"""
- def __init__(self, Name='default',
- Abfolge='e,m,s',
+ def __init__(self, Name='default',
+ Abfolge='e,m,s',
Anzahl='10,10,10'):
self.Name = Name
- self.Abfolge = split(Abfolge, ',')
- self.Anzahl = split(Anzahl,',')
+ self.Abfolge = Abfolge.split(',')
+ self.Anzahl = Anzahl.split(',')
def __repr__(self):
return( "Zyklus: %s\n"
" Zyklusabfolge: %s\n"
" Anzahl : %s\n"
- % ( self.Name,
- self.Abfolge,
+ % ( self.Name,
+ self.Abfolge,
self.Anzahl ) )
def laden(self, FileName, ZyklusName):
- config = ConfigParser.ConfigParser()
+ config = configparser.ConfigParser()
ZyklusPath= os.path.split( FileName )
ZyklusPath= os.path.join( FileName )
config.read( ZyklusPath )
@@ -102,93 +103,91 @@ class Farm:
pass
def LoesungenErzeugen(self, N, Klasse, *Arguments, **keywords):
""" Erzeuge Loesungen"""
- for i in xrange(N):
+ for i in range(N):
L = Klasse( *Arguments, **keywords )
self.Pool.append(L)
- #print repr(len(self.Pool)) + ' Loesungsobjekte erzeugt'
+ #print(repr(len(self.Pool)) + ' Loesungsobjekte erzeugt')
def LoesungenKreuzen(self,N):
"""mache aus zwei Loesungen eine neue"""
- #print "+ Loesungen kreuzen"
- for i in xrange(N):
+ #print("+ Loesungen kreuzen")
+ for i in range(N):
self.Pool.append(self.Pool[i].kreuzen())
def LoesungenMutieren(self, N):
"""veraendere die Loesung, so dass sie hoffentlich besser wird"""
- print "+ Loesungen mutieren: ", N
- for n in xrange(N):
- #print " -"+repr(n+1)+" mal"
+ print("+ Loesungen mutieren: ", N)
+ for n in range(N):
+ #print(" -"+repr(n+1)+" mal")
for L in chain(self.Pool):
O = deepcopy(L)
self.PoolNeu.append(O.mutieren())
- #print self
+ #print(self)
def LoesungenBehalten(self):
"""Behalte alle Eltern aus dem alten Pool"""
- print "+ alten Loesungspool behalten"
+ print("+ alten Loesungspool behalten")
self.PoolNeu = self.PoolNeu + self.Pool
- #print self
+ #print(self)
def NeueGeneration(self):
"""Loesche alle bisherigen Eltern und mache einen neuen Zyklus"""
- print "+ Neue Generation erzeugen"
+ print("+ Neue Generation erzeugen")
self.Pool = self.PoolNeu
self.PoolNeu = []
- #print self
- #print "---------------"
+ #print(self)
+ #print("---------------")
def LoesungenAuswaehlen(self, N):
"""Selektiere die besten Loesungen"""
- print "+ die besten -", repr(N) +" - Loesungen auswaehlen -"
- for i in xrange(N):
+ print("+ die besten -", repr(N) +" - Loesungen auswaehlen -")
+ for i in range(N):
L = max(self.Pool)
self.PoolNeu.append(L)
self.Pool.remove(L)
- #print self
+ #print(self)
def LoesungenZufaelligAuswaehlen(self, N):
"""Selektiere zufaellig Loesungen"""
- print "+ zufaellig auswaehlen -"+ repr(N) + "-"
- for i in xrange(N):
+ print("+ zufaellig auswaehlen -"+ repr(N) + "-")
+ for i in range(N):
self.PoolNeu.append(choice(self.Pool))
- #print self
+ #print(self)
def __repr__(self):
"""Drucke die Farm am Bildschirm aus"""
return( " gewaehlte Objekte (%d): %s\n"
" Elternobjekte (%d) : %s\n"
- % ( len(self.PoolNeu), self.PoolNeu,
+ % ( len(self.PoolNeu), self.PoolNeu,
len(self.Pool), self.Pool))
def laden(self):
- print "+ laden"
+ print("+ laden")
def speichern(self):
- print "+ speichern"
+ print("+ speichern")
def Bester(self):
- return max(self.Pool)
+ return max(self.Pool)
if __name__ == '__main__':
- print "\n-- Erzeuge Zyklus:"
- #Z = Zyklus( Name='Easy',
+ print("\n-- Erzeuge Zyklus:")
+ #Z = Zyklus( Name='Easy',
#Abfolge='e,s,+,m,j,S,+',
#Anzahl='10,5,x,2,x,5,x'
#)
- Z = Zyklus( Name='Easy',
- Abfolge='e,'+'s,z,m,j,z,'*3+'s',
- Anzahl='10,'+'5,x,2,x,x,'*3+'1'
+ Z = Zyklus( Name='Easy',
+ Abfolge='e,'+'s,z,m,j,z,'*3+'s',
+ Anzahl='10,'+'5,x,2,x,x,'*3+'1'
)
- print Z
+ print(Z)
- print "\n-- Erzeuge Loesungen:"
+ print("\n-- Erzeuge Loesungen:")
L1 = Loesung()
L2 = Loesung()
L3 = Loesung()
- print L1, L2, L3
- print 'L1 > L2 =', L1 > L2
- print 'L2 > L3 =', L2 > L3
- print 'L1 > L3 =', L1 > L3
+ print(L1, L2, L3)
+ print('L1 > L2 =', L1 > L2)
+ print('L2 > L3 =', L2 > L3)
+ print('L1 > L3 =', L1 > L3)
A=2
B=3
- print "\n-- Erzeuge Farm:"
+ print("\n-- Erzeuge Farm:")
F1 = Farm( Z, Loesung, Arg1=A, Arg2=B, Arg3=L1 )
- print F1
+ print(F1)
else:
pass
-
-
diff --git a/libs/platz.py b/libs/platz.py
index 32deaa2..f48f581 100755
--- a/libs/platz.py
+++ b/libs/platz.py
@@ -11,7 +11,7 @@ __license__ = "Python"
from ga import *
from Strukturdaten import *
-import ConfigParser
+import configparser
import optparse
@@ -33,7 +33,7 @@ if __name__ == '__main__':
parser.error( "--indir '%s' ist kein Verzeichnis" % InDir )
# lade Vorgaben fuer Optimierungszyklus und
- config = ConfigParser.ConfigParser()
+ config = configparser.ConfigParser()
ConfigPath= os.path.join( os.getenv('PLATZ_CFG'), 'platz.cfg')
config.read( os.path.expandvars( ConfigPath ))
@@ -55,26 +55,26 @@ if __name__ == '__main__':
Z = Zyklus()
Z.laden( Zyklusconfig, Zyklusart )
- print Z
+ print(Z)
SL = Strafliste()
SL.laden( Strafenconfig )
- print SL
+ print(SL)
TE = Tische()
TE.laden( Tischconfig )
- print TE
+ print(TE)
InputFile = XMLConfig()
[ PN, GN, VIPGruppe, VIPListePT ] = InputFile.laden( Bestellung )
- print PN
- print GN
- print VIPGruppe
- print VIPListePT
+ print(PN)
+ print(GN)
+ print(VIPGruppe)
+ print(VIPListePT)
- print "\n-- Erzeuge Farm:"
+ print("\n-- Erzeuge Farm:")
F1 = Farm( Z, Sitzplatzverteilung, Tische=TE, Gruppen=GN, Strafen=SL, VIPListe=VIPListePT, VIPs=VIPGruppe )
- #print F1
+ #print(F1)
S = F1.Bester()
- print S
+ print(S)
S.speichern( AusgabeTP, AusgabePT )
else:
diff --git a/requirements.txt b/requirements.txt
index 00b347d..8f9924e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,7 @@
# Python-Abhaengigkeiten fuer platz
#
# Aktuell werden nur Module aus der Standardbibliothek verwendet
-# (ConfigParser, xml.dom.minidom, sets, UserList, random, ...).
+# (configparser, xml.dom.minidom, random, ...).
# Keine externen Pakete erforderlich.
#
# Beispiel: